I’m making a shader for the rings around planets and I’ve ALMOST got it working.
I want the planet to cast shadows on the rings (but I think the distances I’m using are too big to get Unity’s in-built shadow system working - I also think it might just be cheaper to code shadows, in the few cases where I need them, into my shaders myself).
I’ve got the rings calculating a shadow depending on how near the current fragment is to the line that points from the sun through the planet. But I can’t seem to get that calculation factoring in the rotation of the rings. At the moment, the shadow falls as straight lines behind the planet but, if the rings are rotated steeply this won’t look right. This is because the shader isn’t taking into account the rings’ rotation.
I need to multiply the current vertex position by, effectively, the quaternion rotation of the rings. I have tried all of the matrix rotations on this page…
…and also unity_ObjectToWorld and unity_WorldToObject.
Here is the code from my shader:
- Shader “Materials/rings alpha blended” {
Properties {
_TintColor (“Tint Colour”, Color) = (0.5,0.5,0.5,0.5)
_MainTex (“Particle Texture”, 2D) = “white” {}
_InvFade (“Soft Particles Factor”, Range(0.01,3.0)) = 1.0
_sunDirection (“Sun Direction”, Vector) = (0, 0, 0, 0) // a Vector3 from Unity that describes the position of the sun relative to the planet these rings orbit
} - Category {
Tags { “Queue”=“Transparent” “IgnoreProjector”=“True” “RenderType”=“Transparent” “PreviewType”=“Plane” }
Blend SrcAlpha OneMinusSrcAlpha
ColorMask RGB
Cull Off Lighting Off ZWrite Off - SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 2.0
#pragma multi_compile_particles
#pragma multi_compile_fog
#include “UnityCG.cginc”
- sampler2D _MainTex;
fixed4 _TintColor;
float4 _sunDirection;
struct appdata_t {
float4 vertex : POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
- struct v2f {
float4 vertex : SV_POSITION;
float3 worldPos : TEXCOORD1;
float3 vertexFromCentre : TEXCOORD3;
float3 rotatedVertexFromCentre : TEXCOORD4;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
UNITY_FOG_COORDS(1)
#ifdef SOFTPARTICLES_ON
float4 projPos : TEXCOORD2;
#endif
};
float4 _MainTex_ST;
- v2f vert (appdata_t v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
o.vertexFromCentre = v.vertex; - o.rotatedVertexFromCentre = mul(UNITY_MATRIX_IT_MV, v.vertex).xyz;
- #ifdef SOFTPARTICLES_ON
o.projPos = ComputeScreenPos (o.vertex);
COMPUTE_EYEDEPTH(o.projPos.z);
#endif
o.color = v.color;
o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
} - sampler2D_float _CameraDepthTexture;
float _InvFade;
fixed4 frag (v2f i) : SV_Target
{
#ifdef SOFTPARTICLES_ON
float sceneZ = LinearEyeDepth (SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos)));
float partZ = i.projPos.z;
float fade = saturate (_InvFade * (sceneZ-partZ));
i.color.a *= fade;
#endif
fixed4 col = 2.0f * i.color * _TintColor * tex2D(_MainTex, i.texcoord);
UNITY_APPLY_FOG(i.fogCoord, col);
- float depthValue = sqrt(length(i.worldPos.xyz - _WorldSpaceCameraPos) * 0.25f);
col.a = col.a * saturate(depthValue) * i.vertex.z; - if (dot(normalize(_sunDirection), normalize(i.vertexFromCentre))<0) {
float distanceToLine = length( cross( _sunDirection, _sunDirection + i.vertexFromCentre ) ) / length(_sunDirection);
float sunlight = saturate((saturate(distanceToLine-1.9f) * 3) + 0.5f);
col = col * sunlight;
} - return col;
}
ENDCG
}
}
}
}
On the line that defines ‘distanceToLine’ I have tried using i.rotatedVertexFromCentre instead of i.vertexFromCentre and changing how rotatedVertexFromCentre is multiplied in the v2f vert function, using each of the matrix rotations on that page I linked to, but none works correctly. Anyone care to try this shader out and see if you can help?
That would be great!