I think he was wanting you to use the basic effect stuff but i don’t think it includes a shadowing function maybe i dunno.
Anyways its good to learn how to do your own shaders and its fun after a bit.
You typically do everything to the normals as you do to the positions they are ideologically welded to the polygon vertices and averaged out as the triangle is rasterized for positions between vertices.
That said i usually make a position 3d float3 and pass it to the vertice shader and pass the normal as is so i can work with them both in world space.
Edit it looks like whoever wrote this is doing the same
output.Normal = normalDirection;
// so they want the position world transformed then passed.
however here in the pixel shader.
float4 NdotL = saturate(dot(normal, float4(DiffuseDirection, 1.0)));
diffuse += NdotL * DiffuseColor;
Im guessing diffuseDirection is basically the light source direction at some far distance.
I typically pass in my light source position and calculate the direction to it directly.
Anyways.
You might want to make that negative -DiffuseDirection. at a glance dot( N, L) here could be backwards which is what you would see in your image if it was. The dot in this function wants both N and L to be pointing in basically the same way so actual sunlight directions or the normal direction one or the other is usually negated.
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;
// Standard positioning code
//precalculating the view and projection is fine.
float4x4 vp = mul(View, Projection);
// well need seperate world rotated positions before we leave though so save these.
float4 worldPosition = mul(input.Position, World);
float4 normalDirection = mul(input.Normal, World);
// we will pass these to the pixel shader as these have the full transformations to homoegenous space.
output.Position = mul(worldPosition, vp);
output.Normal = normalDirection;
output.TextureCoordinate = input.TextureCoordinate;
// Steping back to the world Position and normal direction lets compare them against the lightPosition we may pass into the shader as a global.
// this is now the intensity of the light on the surface by the angular theta between two normals.
// the angular difference between the calculated normal of the polygon surface to the light vector, this then doted against the normal of the polygon we passed as vertice data gives
// the angular theta any result ranging between 0 to 1 is the lights intensity.
float intensity = dot(normalDirection, normalize(WorldLightPosition - worldPosition));
// the dot can return a negative or a positive if both vectors are normalized this value ranges between -1 and 1
// this means basically if the part of the surface is opposite facing the light it is 0 or less if the light is shining on it how directly is how much towards 1 the result is from 0.
// so we saturate it and get rid of that negative.
intensity = saturate(intensity);
// You could right here in the vertice shader just pass the intensity by mulitplying it against the color.
// though it really shouldn't multiply against the alpha part of the color. So it the intensity is low near zero all the parts of the color will go towards zero it will darken.
float a = input.Color.a;
output.Color = input.Color * intensity;
output.Color.a = a;
return output;
}
Think of the normals as little arrows hanging off the edges of the points of your quads and models and they get stronger when they point at your light source and very weak when pointing at right angles to it.
<img src=https://proxy.duckduckgo.com/iu/?u=https%3A%2F%2Fuploads.toptal.io%2Fblog%2Fimage%2F123070%2Ftoptal-blog-image-1495085096912-8842b1a4d90ad60234b6324f0995bd77.jpg&f=1 />
So in that sort of case you can actually just calculate intensity in the vertice shader and pass it if you don’t want anything fancy.
That said here is one of my light shadow vertice shaders or part of it so you can see the vertex shader.
struct VsNormMapLightShadowInput
{
float4 Position : POSITION0;
float3 Normal : NORMAL0;
float2 TexureCoordinateA : TEXCOORD0;
float3 Tangent : NORMAL1;
};
struct VsNormMapLightShadowOutput
{
float4 Position : SV_Position;//: SV_POSITION;
float4 Position3D : TEXCOORD4;
float2 TexureCoordinateA : TEXCOORD0;
float3 Normal: TEXCOORD1;
float3 Tangent : TEXCOORD2;
};
VsNormMapLightShadowOutput VsNormMapLightShadow(VsNormMapLightShadowInput input)
{
VsNormMapLightShadowOutput output;
output.Position3D = mul(input.Position, World);
float4x4 vp = mul(View, Projection);
output.Position = mul(output.Position3D, vp);
output.Normal = input.Normal;
output.Tangent = input.Tangent;
output.TexureCoordinateA = input.TexureCoordinateA;
return output;
}
// this part is probably useless to you other then to look over for how intensity is calculated.
float4 PsNormMapLightShadow(VsNormMapLightShadowOutput input) : COLOR0
{
// Normal Map
float3 NormalMap = tex2D(TextureNormalSampler, input.TexureCoordinateA).rgb;
NormalMap.g = 1.0f - NormalMap.g; // flips the y. the program i used fliped the green.
NormalMap = normalize(NormalMap * 2.0 - 1.0);
float3 normal = input.Normal;
float3 tangent = input.Tangent;
float3x3 mat;
mat[0] = cross(normal, tangent); // right
mat[1] = tangent; // up
mat[2] = normal; // forward
NormalMap = mul(NormalMap, mat);
NormalMap = mul(NormalMap, World);
NormalMap = normalize(NormalMap); // we do this to ensure scaling wont break the normal.
// prep
float3 temp = WorldLightPosition - input.Position3D;
float distancePixelToLight = length(temp);
float3 surfaceToCamera = normalize(CameraPosition - input.Position3D);
float3 surfaceToLight = temp / distancePixelToLight; // cheapen the normalize. normalize(pixelToLight);
float3 lightToSurface = -surfaceToLight;
float shadowDepth = texCUBE(TextureDepthSampler, float4(lightToSurface, 0)).x;
float4 TexelColor = tex2D(TextureSamplerA, input.TexureCoordinateA) * (1.0f - LightVsTexelRatio) + (LightColor * LightVsTexelRatio); // LightVsTexelRatio == .5 is normal
// shadow
float lightFalloff = (1.0f - saturate(distancePixelToLight / (IlluminationRange + 0.001f)));
float LightDistanceIntensity = saturate(sign((shadowDepth + .2f) - distancePixelToLight)) * lightFalloff; // if removal.
// lighting
float3 surfNom = NormalMap;
// Ive added over or underdraw to the diffuse.
float diffuse = saturate((dot(lightToSurface, -surfNom) + DiffuseCresting) * (1.0f / (1.0f + DiffuseCresting)));
diffuse *= diffuse;
float3 reflectionTheta = dot(surfaceToCamera, -reflect(surfaceToLight, surfNom));
float specular = saturate(reflectionTheta - SpecularSharpness) * (1.0f / (1.0f - SpecularSharpness)); // this is for sharpness i didn't want to use powers.
// finalize it.
float3 inverseAmbientControl = 1.0f - AmbientStrength;
float3 additiveAmbient = AmbientStrength;
float3 additiveDiffuse = diffuse * DiffuseStrength * LightDistanceIntensity * inverseAmbientControl;
float3 additiveSpecular = specular * SpecularStrength * LightDistanceIntensity * inverseAmbientControl;
float3 FinalColor = TexelColor * (additiveAmbient + additiveDiffuse + additiveSpecular);
return float4(FinalColor, 1.0f);
}
technique NormalMapLightShadowDrawing
{
pass
{
VertexShader = compile VS_SHADERMODEL VsNormMapLightShadow();
PixelShader = compile PS_SHADERMODEL PsNormMapLightShadow();
}
}