Files
directx-plane-game/Graphics2/TerrainShaders.hlsl
iDunnoDev f6bba67897 Added follow cam
Added "Controlled" mesh classes
Added Global Lighting Class
Added Gamepad controls
Split terrain nodes into Height and Perlin classes
Fixed Splitmesh node stuff
2022-05-09 17:50:22 +01:00

169 lines
5.4 KiB
HLSL

cbuffer ConstantBuffer
{
float4x4 completeTransformation;
float4x4 worldTransformation;
float4 cameraPosition;
float4 lightVector; // the light's vector
float4 lightColor; // the light's color
float4 ambientColor; // the ambient light's color
float4 diffuseCoefficient; // The diffuse reflection cooefficient
float4 specularCoefficient; // The specular reflection cooefficient
float shininess; // The shininess factor
float opacity; // The opacity (transparency) of the material. 0 = fully transparent, 1 = fully opaque
// Vars to deal with the water, also padding because the cbuffer needs to be a multiple of 16
float waterHeight;
float waterShininess;
float4 waterColor;
// Padded with a float array, floats being 4 bytes each, the above just hits the multiple of 16 but added extra incase this was the issue, will remove later most likely
float padding[4];
}
Texture2D BlendMap : register(t0);
Texture2DArray TexturesArray : register(t1);
Texture2D WaterNormalMap : register(t2);
Texture2D snowTest : register(t3);
SamplerState ss
{
Filter = MIN_MAG_MIP_LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};
struct VertexShaderInput
{
float3 Position : POSITION;
float3 Normal : NORMAL;
float2 TexCoord : TEXCOORD0;
float2 BlendMapTexCoord : TEXCOORD1;
};
struct PixelShaderInput
{
float4 Position : SV_POSITION;
float4 PositionWS: TEXCOORD2;
float4 PositionOG: TEXCOORD4;
float4 NormalWS : TEXCOORD3;
float2 TexCoord : TEXCOORD0;
float2 BlendMapTexCoord : TEXCOORD1;
};
float2 UVRotate(float2 uvCoord, float2 pivotPoint, float rotation)
{
float2x2 rotateMatrix = float2x2(float2(sin(rotation), -cos(rotation)), float2(cos(rotation), sin(rotation)));
uvCoord -= pivotPoint;
uvCoord = mul(uvCoord, rotateMatrix);
uvCoord += pivotPoint;
return uvCoord;
}
PixelShaderInput VShader(VertexShaderInput vin)
{
PixelShaderInput output;
float3 position = vin.Position;
output.PositionOG = output.PositionWS = mul(worldTransformation, float4(position, 1.0f));
output.TexCoord = vin.TexCoord;
// Check if the y pos is lower than the water point, and set the position to it minus a tiny offset because the textures were clipping and causing a weird effect
if (position.y < waterHeight)
{
position.y = waterHeight;
}
output.Position = mul(completeTransformation, float4(position, 1.0f));
output.PositionWS = mul(worldTransformation, float4(position, 1.0f));
output.NormalWS = float4(mul((float3x3)worldTransformation, vin.Normal), 1.0f);
output.BlendMapTexCoord = vin.BlendMapTexCoord;
return output;
}
float4 hash4(float2 v)
{
float4 p = mul(float4x2(127.1, 311.7, 269.5, 183.3, 113.5, 271.9, 246.1, 124.6), v);
return frac(sin(p) * 43758.5453123);
}
float4 PShader(PixelShaderInput input) : SV_TARGET
{
float4 directionToCamera = normalize(input.PositionWS - cameraPosition);
float4 directionToLight = normalize(-lightVector);
float surfaceShininess = shininess;
float4 adjustedNormal = normalize(input.NormalWS);
float currentHeightPer = (waterHeight - input.PositionOG.y) / waterHeight;
if (input.PositionOG.y < waterHeight)
{
// Sample the normal from the water normal map and calculate it with the worldtransform
float3 n0 = 2.0f * (float3)WaterNormalMap.Sample(ss, input.TexCoord) - 1.0f;
float4 n2 = float4(mul((float3x3)worldTransformation, n0), 1.0f);
adjustedNormal = normalize(n2);
surfaceShininess = waterShininess;
}
// Calculate diffuse lighting
float NdotL = max(0, dot(adjustedNormal, directionToLight));
float4 diffuse = saturate(lightColor * NdotL * diffuseCoefficient);
diffuse.a = 1.0f;
// Calculate specular component
float4 R = 2 * NdotL * adjustedNormal - directionToLight;
float RdotV = max(0, dot(R, directionToCamera));
float4 specular = saturate(lightColor * pow(RdotV, surfaceShininess) * specularCoefficient);
specular.a = 1.0f;
// Calculate ambient lighting
float4 ambientLight = ambientColor * diffuseCoefficient;
float4 color;
// Randomly rotate the UV coordinates using the noise map
float2 scaleCenter = float2(0.5f, 0.5f);
// The noise map is greyscale so we only need to check 1 channel since they should all be the same value
float2 scaledUV = frac(UVRotate(input.TexCoord, scaleCenter, input.BlendMapTexCoord.x)); // (input.TexCoord - scaleCenter) * currentScale + scaleCenter;
float2 xChange = ddx(scaledUV);
float2 yChange = ddy(scaledUV);
/*if (xChange.x < 0)
{
xChange = float2(0, 0);
}
if (yChange.y < 0)
{
yChange = float2(0, 0);
}*/
// Sample layers in texture array.
float4 c0 = TexturesArray.SampleGrad(ss, float3(scaledUV, 0.0f), xChange, yChange);
float4 c1 = TexturesArray.SampleGrad(ss, float3(scaledUV, 1.0f), xChange, yChange);
float4 c2 = TexturesArray.SampleGrad(ss, float3(scaledUV, 2.0f), xChange, yChange);
float4 c3 = TexturesArray.SampleGrad(ss, float3(scaledUV, 3.0f), xChange, yChange);
//float4 c4 = TexturesArray.SampleGrad(ss, float3(scaledUV, 4.0f), xChange, yChange);
float4 c4 = snowTest.SampleGrad(ss, float2(scaledUV), xChange, yChange);
// Sample the blend map.
float4 t = BlendMap.Sample(ss, input.BlendMapTexCoord);
// Blend the layers on top of each other.
color = c0;
color = lerp(color, c1, t.r);
color = lerp(color, c2, t.g);
color = lerp(color, c3, t.b);
color = lerp(color, c4, t.a);
// Combine all components
if (input.PositionOG.y < waterHeight)
{
// Tint the water
color = saturate(color) * waterColor;
}
color = (ambientLight + diffuse) * color;
color = saturate(color + specular);
return color;
}