Mie scatter + Reighleigh Scatter Shader No subshaders on GFX card, WHY?!?@#

I’ve worked on this translating this code from C++ hlsl to this, for a few hours and have gotten rid of all errors but one.
“No subshaders can run on this graphics card.”
Which I know is total BS. I have a Sapphire HD 6950 2gb dirt3 edition…

Does anyone know what’s wrong, I’ll be very great-full if you shared!

btw I JUST started using unity a few hours ago, but I have a sharp grasp for programming. :smile:

Shader "Custom/SkyFromSpace" {
	Properties {
		fPI ("PI Innumber", Float) =  3.14159265358979323846
		nSamples ("nNumber of samples", Float) =  2.0 
		fSamples ("fNumber of samples", Float) =  2.0 

		// Gravity
		gg ("Gravity", Float) =  -.98 
		gg2 ("Gravity2", Float) =  .9604 

		// Shader Constants
		Km ("Km", Float) =  0.0025
		Kr ("Kr", Float) =  0.0015
		ESun ("ESun", Float) =  10.0
		v3LightPos ("Light Position", Vector) = ( 0.5, 0.5, -0.5, 0.0 )
		v3InvWaveLength("Wave Length", Vector) = ( 5.6020447463324113301354994573019, 9.4732844379230354373782268493533, 9.4732844379230354373782268493533, 0.0 )
		fOuterRadius ("Outer Radius", Float) =  10.25 
		fInnerRadius ("Inner Radius", Float) =  10.0 
		fScaleDepth ("Depth Scale", Float) =  0.25 
	}
	
	Category {
	Tags { "Queue"="Geometry" "IgnoreProjector"="True" "RenderType"="Opaque" }
	Blend SrcAlpha OneMinusSrcAlpha
	AlphaTest Greater .01
	ColorMask RGB
	Cull back
	Lighting Off
	ZWrite Off
	//BindChannels {
	//	Bind "Position", vertex
	//}
	
	//CGINCLUDE
//#include "UnityCG.cginc"
// ---- Fragment program cards
	SubShader {
		Pass {
		
			CGPROGRAM
			#pragma target 5.0
			//#pragma hull DX11
			//#pragma domain DX11
			#pragma vertex vert
			#pragma fragment frag
			
			//#include "UnityCG.cginc"

			float fPI;
			float nSamples;
			float fSamples;

			// Gravity
			float gg;
			float gg2;

			// Shader Constants
			float Km;
			float Kr;
			float ESun;
			float4 v3LightPos;   // The direction vector to the light source
			float4 v3InvWaveLength;  // 1 / pow(wavelength, 4) for the red, green, and blue channels
			float fOuterRadius;   // The outer (atmosphere) radius
			float fInnerRadius;   // The inner (planetary) radius
			float fScaleDepth;   // The scale depth (the altitude at which the average atmospheric density is found)
			
			float fCameraHeight;
			float fCameraHeight2;
			float fOuterRadius2;
			float fInnerRadius2;
			float fKrESun;  // Kr * ESun
			float fKmESun;	// Km * ESun
			float fKr4PI;	// Kr * 4 * PI
			float fKm4PI;	// Km * 4 * PI
			float fScale;
			float fScaleOverDepth;
			float fInvScaleDepth;
			
			// The scale equation calculated by Vernier's Graphical Analysis
			float scale(float fCos)
			{
				float x = 1.0 - fCos;
				return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
			};

			// Calculates the Mie phase function
			float getMiePhase(float fCos, float fCos2, float g, float g2)
			{
				return 1.5 * ((1.0 - gg2) / (2.0 + gg2)) * (1.0 + fCos2) / pow(abs(1.0 + gg2 - 2.0*gg*fCos), 1.5);
			};

			// Calculates the Rayleigh phase function
			float getRayleighPhase(float fCos2)
			{
				//return 1.0;
				return 0.75 + 0.75*fCos2;
			};

			// Returns the near intersection point of a line and a sphere
			float getNearIntersection(float3 v3Pos, float3 v3Ray, float fDistance2, float fRadius2)
			{
				float B = 2.0 * dot(v3Pos, v3Ray);
				float C = fDistance2 - fRadius2;
				float fDet = max(0.0, B*B - 4.0 * C);
				return 0.5 * (-B - sqrt(fDet));
			};

			// Returns the far intersection point of a line and a sphere
			float getFarIntersection(float3 v3Pos, float3 v3Ray, float fDistance2, float fRadius2)
			{
				float B = 2.0 * dot(v3Pos, v3Ray);
				float C = fDistance2 - fRadius2;
				float fDet = max(0.0, B*B - 4.0 * C);
				return 0.5 * (-B + sqrt(fDet));
			};



			struct VS_INPUT
			{
				float4 Position : POSITION;
			};

			struct VS_OUTPUT
			{
				float4 Position : POSITION;
				float3 PositionWS : TEXCOORD0;
				float3 v3CameraPos : TEXCOORD1;
				//float fCameraHeight;
				//float fCameraHeight2;
				//float fOuterRadius2;
				//float fInnerRadius2;
				//float fKrESun;  // Kr * ESun
				//float fKmESun;	// Km * ESun
				//float fKr4PI;	// Kr * 4 * PI
				//float fKm4PI;	// Km * 4 * PI
				//float fScale;
				//float fScaleOverDepth;
				//float fInvScaleDepth;
			};

			VS_OUTPUT vert( VS_INPUT vIn )
			{
				// Finally, scale the Mie and Rayleigh colors
				VS_OUTPUT OUT;

				//OUT.PositionWS = vIn.Position.xyz;
				OUT.Position = mul(vIn.Position, UNITY_MATRIX_MVP);
				OUT.PositionWS = vIn.Position.xyz;
				OUT.v3CameraPos = _WorldSpaceCameraPos.xyz;
				//OUT.fCameraHeight = (_WorldSpaceCameraPos.xyz - vIn.Position.xyz) + fOuterRadius;
				//OUT.fCameraHeight2 = pow((_WorldSpaceCameraPos.xyz - vIn.Position.xyz) + fOuterRadius, 2);
				//OUT.fOuterRadius2 = pow(fOuterRadius, 2);
				//OUT.fInnerRadius2 = pow(fInnerRadius, 2);
				//OUT.fKrESun = Kr * ESun;
				//OUT.fKmESun = Km * ESun;
				//OUT.fKr4PI = Kr * 4 * fPI;
				//OUT.fKm4PI = Km * 4 * fPI;
				//OUT.fScale = 1 / (fOuterRadius - fInnerRadius);
				//OUT.fScaleOverDepth = (1 / (fOuterRadius - fInnerRadius)) / fScaleDepth;
				//OUT.fInvScaleDepth = 1.0f / fScaleDepth;
				
				fCameraHeight = (_WorldSpaceCameraPos.xyz - vIn.Position.xyz) + fOuterRadius;
				fCameraHeight2 = pow((_WorldSpaceCameraPos.xyz - vIn.Position.xyz) + fOuterRadius, 2);
				fOuterRadius2 = pow(fOuterRadius, 2);
				fInnerRadius2 = pow(fInnerRadius, 2);
				fKrESun = Kr * ESun;
				fKmESun = Km * ESun;
				fKr4PI = Kr * 4 * fPI;
				fKm4PI = Km * 4 * fPI;
				fScale = 1 / (fOuterRadius - fInnerRadius);
				fScaleOverDepth = (1 / (fOuterRadius - fInnerRadius)) / fScaleDepth;
				fInvScaleDepth = 1.0f / fScaleDepth;

				return OUT;
			};



			float4 frag( VS_OUTPUT input ) : COLOR
			{
				// Get the ray from the camera to the vertex and its length (which
				// is the far point of the ray passing through the atmosphere)
				float3 v3Pos = input.PositionWS.xyz;
				float3 v3Ray = v3Pos - input.v3CameraPos;
				float fFar = length(v3Ray);
				v3Ray /= fFar;

				// Calculate the closest intersection of the ray with
				// the outer atmosphere (point A in Figure 16-3)
				float fNear = getNearIntersection(input.v3CameraPos.xyz, v3Ray, fCameraHeight2,
												fOuterRadius2);

				// Calculate the ray's start and end positions in the atmosphere,
				// then calculate its scattering offset

				float3 v3Start = input.v3CameraPos.xyz + v3Ray * fNear;
				fFar -= fNear;
				float fStartAngle = dot(v3Ray, v3Start) / fOuterRadius;
				float fStartDepth = exp(-fInvScaleDepth);
				float fStartOffset = fStartDepth * scale(fStartAngle);

				// Initialize the scattering loop variables
				float fSampleLength = fFar / fSamples;
				float fScaledLength = fSampleLength * fScale;
				float3 v3SampleRay = v3Ray * fSampleLength;
				float3 v3SamplePoint = v3Start + v3SampleRay * 0.5;

				float3 v3FrontColor = float3(0.0, 0.0, 0.0);

				for(int i = 0; i < (float)nSamples; i++)
				{
					float fHeight = length(v3SamplePoint);
					float fDepth = exp(fScaleOverDepth * (fInnerRadius - fHeight));
					float fLightAngle = dot(v3LightPos.xyz, v3SamplePoint) / fHeight;
					float fCameraAngle = dot(v3Ray, v3SamplePoint) / fHeight;
					float fScatter = (fStartOffset + fDepth * (scale(fLightAngle) - scale(fCameraAngle)));
					float3 v3Attenuate = exp(-fScatter * (v3InvWaveLength.xyz * fKr4PI + fKm4PI));
					float3 v3FrontColor = v3Attenuate * (fDepth * fScaledLength);
					v3SamplePoint += v3SampleRay;
				}

				float3 Color0 = v3FrontColor * (v3InvWaveLength.xyz * fKrESun);
				float3 Color1 = v3FrontColor * fKmESun;
				float3 v3Direction = input.v3CameraPos - v3Pos;
				float fCos = dot(v3LightPos.xyz, v3Direction) / length(v3Direction);
				float fCos2 = fCos * fCos;
				float3 color = float3(getRayleighPhase(fCos2) * Color0 +
							getMiePhase(fCos, fCos2, gg, gg2) * Color1);
				//color.a = color.b;

				return float4(color.r, color.g, color.b, color.b);
			};
			ENDCG
		}
	}
	
}
}

Have you tried setting Unity to DX11 mode? :wink:
Edit → Project Settings → Use DirectX11

And don’t comment out

#include UnityCG.cginc

you’ll need it.

for loop must have a static input, it wont be able to unroll your nsamples.
Also i am not sure but you calculating the whole deal in fragment is expensive, it might have something to do with that.

Irrelevant but this shader is capable of working with SM2.0.

I get a santax error on the line with it not commented out…dunno why.

I had thought a solution may be to flip the shader to what I originally had, mostly on the vertex shader (especially the loop.), because apparently for loops on frag shader isn’t possible on SM 3 or less. I have the shader running in another rendering program, no errors, but something isn’t right with it and I wasn’t able to figure it out. The shader was right. I only say that because I ran it both ways to test speed, vertex favored for the loop was only slightly faster, but it was.

EDIT: I Switched most the work back over to the vert program leaving only this:

float4 frag( VS_OUTPUT input ) : COLOR
			{
				float3 Color0 = input.v3FrontColor * (v3InvWaveLength.xyz * fKrESun);
				float3 Color1 = input.v3FrontColor * fKmESun;
				float3 v3Direction = input.v3CameraPos - input.v3Pos;
				float fCos = dot(v3LightPos.xyz, v3Direction) / length(v3Direction);
				float fCos2 = fCos * fCos;
				float3 color = float3(getRayleighPhase(fCos2) * Color0 +
							getMiePhase(fCos, fCos2, gg, gg2) * Color1);
				//color.a = color.b;

				return float4(color.r, color.g, color.b, color.b);
			};

I worked out all the errors, it compiles. Now I’m trying to figure out how to apply it to a sphere mesh…it doesn’t drag and drop.

EDIT again: I’m a dummy, had to apply it to a material. All should work now! :smile:

There is no Use Dx11 or anything relevant in my version. Probably as I am using the free version?

Now you look at the documents for Shader.SetFloat and SetVector functions and write a small appropriate script to pass your values to your shader.
And then make a material using your shader and apply this material to your sphere.

You will need this script to control passing in and out of atmosphere sphere anyways.

Your frag still doesnt look the same as the original shader, you dont have to calculate the color0 and color1 in frag its based on vertex positions anyways.