Lit Sphere Volume
This shader attempts to fake lighting on the volume from a _sun
coordinate using raystepping.
Shader
Shader "Shaders/Volume/SphereVolumeLitMaterial" {
Properties {
_center ("Center", Vector) = (0, 0, 0)
_sun ("Sun", Vector) = (0, 0, 0)
_size ("Size", Float) = 0
_samplePoints ("Sample Points", Range(0,10)) = 1
_sampleStep ("Sample Step", Range(0,10)) = 0.1
_baseLight ("Base Light", Range(0,1)) = 0.1
}
SubShader {
Blend SrcAlpha OneMinusSrcAlpha
Tags { "Queue" = "Transparent" "RenderType"="Transparent" }
CGPROGRAM
#pragma surface surf Lambert alpha
#define IF(a, b, c) lerp(b, c, step((fixed) (a), 0));
#define MAX_DENSITY 1.0
uniform float3 _center;
uniform float3 _sun;
uniform float _size;
uniform float _samplePoints;
uniform float _sampleStep;
uniform float _baseLight;
struct Input {
float3 worldPos;
};
float density(float3 point);
// Calculate how obscured a point is
float obscured(float3 point, float3 normal) {
float rtn = 0;
int steps = floor(_samplePoints);
for (int i = 0; i < steps; ++i) {
rtn += density(point + i * _sampleStep * normal);
}
return rtn / (float) steps / 10.0;
}
// Calculate density at a point
float density(float3 point) {
float dist = distance(point, _center);
return IF((dist > 0) && (dist < _size), MAX_DENSITY * (_size - dist) / _size, 0);
}
// Calculate the relative distance from the center point
void surf (Input IN, inout SurfaceOutput o) {
float3 sunNormal = normalize(_sun - _center);
float value = density(IN.worldPos);
float color = value * (obscured(IN.worldPos, sunNormal) + _baseLight);
o.Albedo = fixed3(color, color, color);
o.Alpha = value;
}
ENDCG
}
Fallback "Diffuse"
}
Shader Notes
Notice that because this is a surface shader, it already has the normal lighting model applied, and normal lights will continue to affect the polygons the shader is rendered to.