243 lines
9.2 KiB
C#
243 lines
9.2 KiB
C#
//------------------------------------------------------------------------------------------------------------------
|
|
// Volumetric Lights
|
|
// Created by Kronnect
|
|
//------------------------------------------------------------------------------------------------------------------
|
|
|
|
using UnityEngine;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace VolumetricLights {
|
|
|
|
public partial class VolumetricLight : MonoBehaviour {
|
|
|
|
#region Particle support
|
|
|
|
const string PARTICLE_SYSTEM_NAME = "DustParticles";
|
|
|
|
Material particleMaterial;
|
|
|
|
[NonSerialized]
|
|
public ParticleSystem ps;
|
|
|
|
ParticleSystemRenderer psRenderer;
|
|
Vector3 psLastPos;
|
|
Quaternion psLastRot;
|
|
|
|
void ParticlesDisable() {
|
|
if (Application.isPlaying) {
|
|
if (psRenderer != null) {
|
|
psRenderer.enabled = false;
|
|
}
|
|
} else {
|
|
if (ps != null) {
|
|
ps.gameObject.SetActive(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ParticlesResetIfTransformChanged() {
|
|
if (ps != null && (ps.transform.position != psLastPos || ps.transform.rotation != psLastRot)) {
|
|
ParticlesPopulate();
|
|
}
|
|
}
|
|
|
|
void ParticlesPopulate() {
|
|
if (dustPrewarm) {
|
|
ps.Clear();
|
|
ps.Simulate(100);
|
|
}
|
|
psLastPos = ps.transform.position;
|
|
psLastRot = ps.transform.rotation;
|
|
}
|
|
|
|
void ParticlesCheckSupport() {
|
|
if (!enableDustParticles) {
|
|
ParticlesDisable();
|
|
return;
|
|
}
|
|
|
|
bool psNew = false;
|
|
if (ps == null) {
|
|
Transform childPS = transform.Find(PARTICLE_SYSTEM_NAME);
|
|
if (childPS != null) {
|
|
ps = childPS.GetComponent<ParticleSystem>();
|
|
if (ps == null) {
|
|
DestroyImmediate(childPS.gameObject);
|
|
}
|
|
}
|
|
if (ps == null) {
|
|
GameObject psObj = Resources.Load<GameObject>("Prefabs/DustParticles") as GameObject;
|
|
if (psObj == null) return;
|
|
psObj = Instantiate(psObj);
|
|
psObj.name = PARTICLE_SYSTEM_NAME;
|
|
psObj.transform.SetParent(transform, false);
|
|
ps = psObj.GetComponent<ParticleSystem>();
|
|
}
|
|
ps.gameObject.layer = 1;
|
|
psNew = true;
|
|
}
|
|
|
|
if (particleMaterial == null) {
|
|
particleMaterial = Instantiate(Resources.Load<Material>("Materials/DustParticle")) as Material;
|
|
}
|
|
|
|
if (keywords == null) {
|
|
keywords = new List<string>();
|
|
} else {
|
|
keywords.Clear();
|
|
}
|
|
|
|
// Configure particle material
|
|
if (useCustomBounds) {
|
|
keywords.Add(ShaderParams.SKW_CUSTOM_BOUNDS);
|
|
}
|
|
|
|
switch (generatedType) {
|
|
case LightType.Spot:
|
|
if (cookieTexture != null) {
|
|
keywords.Add(ShaderParams.SKW_SPOT_COOKIE);
|
|
particleMaterial.SetTexture(ShaderParams.CookieTexture, cookieTexture);
|
|
particleMaterial.SetVector(ShaderParams.CookieTexture_ScaleAndSpeed, new Vector4(cookieScale.x, cookieScale.y, cookieSpeed.x, cookieSpeed.y));
|
|
particleMaterial.SetVector(ShaderParams.CookieTexture_Offset, new Vector4(cookieOffset.x, cookieOffset.y, 0, 0));
|
|
particleMaterial.SetFloat(ShaderParams.NearClipDistance, nearClipDistance);
|
|
} else {
|
|
keywords.Add(ShaderParams.SKW_SPOT);
|
|
}
|
|
break;
|
|
case LightType.Point:
|
|
keywords.Add(ShaderParams.SKW_POINT);
|
|
break;
|
|
case LightType.Rectangle:
|
|
keywords.Add(ShaderParams.SKW_AREA_RECT);
|
|
break;
|
|
case LightType.Disc:
|
|
keywords.Add(ShaderParams.SKW_AREA_DISC);
|
|
break;
|
|
}
|
|
if (attenuationMode == AttenuationMode.Quadratic) {
|
|
keywords.Add(ShaderParams.SKW_PHYSICAL_ATTEN);
|
|
}
|
|
if (enableShadows) {
|
|
if (usesCubemap) {
|
|
keywords.Add(ShaderParams.SKW_SHADOWS_CUBEMAP);
|
|
} else if (usesTranslucency) {
|
|
keywords.Add(ShaderParams.SKW_SHADOWS_TRANSLUCENCY);
|
|
} else {
|
|
keywords.Add(ShaderParams.SKW_SHADOWS);
|
|
}
|
|
}
|
|
particleMaterial.shaderKeywords = keywords.ToArray();
|
|
|
|
particleMaterial.renderQueue = renderQueue + 1;
|
|
particleMaterial.SetFloat(ShaderParams.Penumbra, penumbra);
|
|
particleMaterial.SetFloat(ShaderParams.RangeFallOff, rangeFallOff);
|
|
particleMaterial.SetVector(ShaderParams.FallOff, new Vector3(attenCoefConstant, attenCoefLinear, attenCoefQuadratic));
|
|
UpdateParticleColor();
|
|
particleMaterial.SetFloat(ShaderParams.ParticleDistanceAtten, dustDistanceAttenuation * dustDistanceAttenuation);
|
|
if (psRenderer == null) {
|
|
psRenderer = ps.GetComponent<ParticleSystemRenderer>();
|
|
}
|
|
psRenderer.material = particleMaterial;
|
|
|
|
// Main properties
|
|
ParticleSystem.MainModule main = ps.main;
|
|
main.simulationSpace = ParticleSystemSimulationSpace.World;
|
|
ParticleSystem.MinMaxCurve startSize = main.startSize;
|
|
startSize.mode = ParticleSystemCurveMode.TwoConstants;
|
|
startSize.constantMin = dustMinSize;
|
|
startSize.constantMax = dustMaxSize;
|
|
main.startSize = startSize;
|
|
|
|
// Set emission bounds
|
|
ParticleSystem.ShapeModule shape = ps.shape;
|
|
switch (generatedType) {
|
|
case LightType.Spot:
|
|
shape.shapeType = ParticleSystemShapeType.ConeVolume;
|
|
shape.angle = generatedSpotAngle * 0.5f;
|
|
shape.position = Vector3.zero;
|
|
shape.radius = tipRadius;
|
|
shape.length = generatedRange;
|
|
shape.scale = Vector3.one;
|
|
break;
|
|
case LightType.Point:
|
|
shape.shapeType = ParticleSystemShapeType.Sphere;
|
|
shape.position = Vector3.zero;
|
|
shape.scale = Vector3.one;
|
|
shape.radius = generatedRange;
|
|
break;
|
|
case LightType.Rectangle:
|
|
case LightType.Disc:
|
|
shape.shapeType = ParticleSystemShapeType.Box;
|
|
shape.position = new Vector3(0, 0, generatedRange * 0.5f);
|
|
shape.scale = GetComponent<MeshFilter>().sharedMesh.bounds.size;
|
|
break;
|
|
}
|
|
|
|
// Set wind speed
|
|
ParticleSystem.VelocityOverLifetimeModule velocity = ps.velocityOverLifetime;
|
|
Vector3 windDirection = transform.InverseTransformDirection(this.windDirection);
|
|
ParticleSystem.MinMaxCurve velx = velocity.x;
|
|
velx.constantMin = (-0.1f + windDirection.x) * dustWindSpeed;
|
|
velx.constantMax = (0.1f + windDirection.x) * dustWindSpeed;
|
|
velocity.x = velx;
|
|
ParticleSystem.MinMaxCurve vely = velocity.y;
|
|
vely.constantMin = (-0.1f + windDirection.y) * dustWindSpeed;
|
|
vely.constantMax = (0.1f + windDirection.y) * dustWindSpeed;
|
|
velocity.y = vely;
|
|
ParticleSystem.MinMaxCurve velz = velocity.z;
|
|
velz.constantMin = (-0.1f + windDirection.z) * dustWindSpeed;
|
|
velz.constantMax = (0.1f + windDirection.z) * dustWindSpeed;
|
|
velocity.z = velz;
|
|
|
|
if (!ps.gameObject.activeSelf) {
|
|
ps.gameObject.SetActive(true);
|
|
}
|
|
|
|
UpdateParticlesVisibility();
|
|
|
|
if (psNew || ps.particleCount == 0) {
|
|
ParticlesPopulate();
|
|
}
|
|
|
|
if (!ps.isPlaying) {
|
|
ps.Play();
|
|
}
|
|
}
|
|
|
|
|
|
void UpdateParticlesVisibility() {
|
|
UpdateParticleColor();
|
|
|
|
if (!Application.isPlaying || psRenderer == null) return;
|
|
|
|
bool visible = meshRenderer.isVisible;
|
|
if (visible && dustAutoToggle) {
|
|
float maxDistSqr = dustDistanceDeactivation * dustDistanceDeactivation;
|
|
visible = distanceToCameraSqr <= maxDistSqr;
|
|
}
|
|
if (visible) {
|
|
if (!psRenderer.enabled) {
|
|
psRenderer.enabled = true;
|
|
}
|
|
} else {
|
|
if (psRenderer.enabled) {
|
|
psRenderer.enabled = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
void UpdateParticleColor() {
|
|
if (particleMaterial != null) {
|
|
particleMaterial.SetColor(ShaderParams.ParticleLightColor, lightComp.color * mediumAlbedo * (lightComp.intensity * dustBrightness));
|
|
}
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
}
|
|
|
|
|
|
}
|