DirectX11 Shadow slope bias incorrect - c++

I've recently implemented shadows on my terrain project, using PCF filtering, however, the shadows on the slopes of the terrain appear incorrect, as you can see below:
How can I remove the artifacts caused on the slopes of the terrain? A quick search suggests implementing a slope based bias, but how would I calculate it?
Here is my pixel shader:
Texture2D shadowMap : register(t0);
SamplerComparisonState SampleTypeCmp : register(s0);
cbuffer SPerLightCB : register(b0)
{
float4 ambientColour;
float4 diffuseColour;
};
cbuffer SPerLightPosCB : register(b1)
{
float3 lightPos;
float padding;
};
struct PixelIn
{
float4 Pos : SV_POSITION;
float4 WPos : TEXCOORD0;
float4 LPos : TEXCOORD1;
float3 Normal : NORMAL;
};
float2 texOffset(int u, int v)
{
return float2(u * 1.0f / 1024.0f, v * 1.0f / 1024.0f);
}
float4 main(PixelIn pin) : SV_Target
{
//re-homogenize position after interpolation
pin.LPos.xyz /= pin.LPos.w;
//if position is not visible to the light - dont illuminate it
//results in hard light frustum
if (pin.LPos.x < -1.0f || pin.LPos.x > 1.0f ||
pin.LPos.y < -1.0f || pin.LPos.y > 1.0f ||
pin.LPos.z < 0.0f || pin.LPos.z > 1.0f)
{
return ambientColour;
}
//transform clip space coords to texture space coords (-1:1 to 0:1)
pin.LPos.x = pin.LPos.x / 2 + 0.5;
pin.LPos.y = pin.LPos.y / -2 + 0.5;
pin.LPos.z -= 0.001f; //apply bias
//PCF Sampling
float sum = 0.0f;
float x, y;
//perform PCF filtering
for (y = -1.5; y <= 1.5; y += 1.0)
{
for (x = -1.5; x <= 1.5; x += 1.0)
{
sum += shadowMap.SampleCmpLevelZero(SampleTypeCmp, pin.LPos.xy + texOffset(x, y), pin.LPos.z);
}
}
float shadowFactor = sum / 16.0;
//calculate ilumination
float3 L = normalize(lightPos - pin.WPos.xyz);
float ndotl = dot(normalize(pin.Normal), L);
return ambientColour + shadowFactor * diffuseColour * ndotl;
}

Related

DX12) Trying to Implement Volumetric Scattering for multiple Spot Light, but It's not going well

(This Image is What I want to implement)
I am attempting Post Processing using Compute Shader to implement Light Shaft for multiple Spot Lights in the DX12 framework.
The first thing I tried was the method at the following link:https://gitlab.com/tomasoh/100_procent_more_volume/-/blob/master/shaders/volumetric.frag
It's a very complicated and hard-to-understand kind of shader, but it's basically built on the premise of using multiple lights, so it's a kind of example for the purpose.
However, since the game I'm making has 32 light source limitations, considering that excessive amount of Frame Drop will occur in the part of calculating Visibility by making Shadow Map for all light sources, I decided to implement Visibility as 1.0 Constant and did not get the desired result. (Of course it's a result.)
Down below is how I did this thing:
#include "lighting.hlsl"
Texture2D<float4> inputTexture : register(t0);
Texture2D<float> depthTexture : register(t1);
RWTexture2D<float4> outputTexture : register(u0);
#define PI 3.141592653589793238f
cbuffer VolumetricCB : register(b1)
{
float absorptionTau : packoffset(c0);
float3 absorptionColor : packoffset(c0.y);
int scatteringSamples : packoffset(c1.x);
float scatteringTau : packoffset(c1.y);
float scatteringZFar : packoffset(c1.z);
float3 scatteringColor : packoffset(c2);
matrix gInvProj : packoffset(c3);
matrix gInvView : packoffset(c7);
float3 gCameraPos : packoffset(c11);
Light gLights[NUM_LIGHTS] : packoffset(c12);
}
float random(float2 co)
{
return frac(sin(dot(co.xy, float2(12.9898, 78.233))) * 43758.5453123);
}
float3 PixelWorldPos(float depthValue, int2 pixel)
{
uint width, height;
inputTexture.GetDimensions(width, height);
float2 fPixel = float2(pixel.x, pixel.y);
float x = (fPixel.x / width * 2) - 1;
float y = (fPixel.y / height * (-2)) + 1;
float z = depthValue;
float4 ndcCoords = float4(x, y, z, 1.0f);
float4 p = mul(ndcCoords, gInvProj);
p /= p.w;
float4 worldCoords = mul(p, gInvView);
return worldCoords.xyz;
}
float3 absorptionTransmittance(float dist)
{
return absorptionColor * exp(-dist * (absorptionTau + scatteringTau));
}
float phaseFunction(float3 inDir, float3 outDir)
{
float cosAngle = dot(inDir, outDir) / (length(inDir) * length(outDir));
float x = (1.0 + cosAngle) / 2.0;
float x2 = x * x;
float x4 = x2 * x2;
float x8 = x4 * x4;
float x16 = x8 * x8;
float x32 = x16 * x16;
float nom = 0.5 + 16.5 * x32;
float factor = 1.0 / (4.0 * PI);
return nom * factor;
}
float3 volumetricScattering(float3 worldPosition, Light light)
{
float3 result = float3(0.0, 0.0, 0.0);
float3 camToFrag = worldPosition - gCameraPos;
if (length(camToFrag) > scatteringZFar)
{
camToFrag = normalize(camToFrag) * scatteringZFar;
}
float3 deltaStep = camToFrag / (scatteringSamples + 1);
float3 fragToCamNorm = normalize(gCameraPos - worldPosition);
float3 x = gCameraPos;
float rand = random(worldPosition.xy + worldPosition.z);
x += (deltaStep * rand);
for (int i = 0; i < scatteringSamples; ++i)
{
float visibility = 1.0;
float3 lightToX = x - light.Position;
float lightDist = length(lightToX);
float omega = 4 * PI * lightDist * lightDist;
float3 Lin = absorptionTransmittance(lightDist) * visibility * light.Diffuse * light.SpotPower / omega;
float3 Li = Lin * scatteringTau * scatteringColor * phaseFunction(normalize(lightToX), fragToCamNorm);
result += Li * absorptionTransmittance(distance(x, gCameraPos)) * length(deltaStep);
x += deltaStep;
}
return result;
}
[numthreads(32, 32, 1)]
void CS(uint3 dispatchID : SV_DispatchThreadID)
{
int2 pixel = int2(dispatchID.x, dispatchID.y);
float4 volumetricColor = float4(0.0, 0.0, 0.0, 1.0);
float depthValue = depthTexture[pixel].r;
float3 worldPosition = PixelWorldPos(depthValue, pixel);
float fragCamDist = distance(worldPosition, gCameraPos);
for (int i = 0; i < NUM_LIGHTS; ++i)
{
if (gLights[i].Type == SPOT_LIGHT && gLights[i].FalloffEnd > length(gLights[i].Position - worldPosition))
volumetricColor += float4(volumetricScattering(worldPosition, gLights[i]), 0.0);
}
outputTexture[pixel] = volumetricColor + inputTexture[pixel];
}
(AbsorptionTau = -0.061f, ScatteringTau = 0.059f)
All these Codes for that Tiny Spot...
The second method was shown in Chapter 13 of GPU GEM3.
It was a method of drawing only Light Source on a separate Render Target, processing the Render Target using Post Processing Shder to create light scattering, and then merging it with a back buffer. (At least that's how I understand it.)
However, this method was designed only for one very strong light, and to fix it, I modified the code as below, but it didn't work well.
[numthreads(32, 32, 1)]
void CS(uint3 dispatchID : SV_DispatchThreadID)
{
uint2 pixel = dispatchID.xy;
uint width, height;
inputTexture.GetDimensions(width, height);
float4 result = inputTexture[pixel];
for (int i = 0; i < NUM_LIGHTS; ++i)
{
if(gLights[i].Type == SPOT_LIGHT)
{
float2 texCoord = float2(pixel.x / width, pixel.y / height);
float2 deltaTexCoord = (texCoord - mul(mul(float4(gLights[i].Position, 1.0f), gView), gProj).xy);
deltaTexCoord *= 1.0f / NUM_SAMPLES * Density;
float3 color = inputTexture[pixel].rgb;
float illuminationDecay = 1.0f;
for (int j = 0; j < NUM_SAMPLES; j++)
{
texCoord -= deltaTexCoord;
uint2 modifiedPixel = uint2(texCoord.x * width, texCoord.y * height);
float3 sample = inputTexture[modifiedPixel].rgb;
sample *= illuminationDecay * Weight;
color += sample;
illuminationDecay *= Decay;
}
result += float4(color * Exposure, 1);
}
}
outputTexture[pixel] = result;
}
this just 'Blur' these light source map, and surely it's not what I wanted.
Is there a similar kind of example to the implementation that I want, or is there a simpler way to do this? I've spent a week on this issue, but I haven't achieved much.
edit :
I did it! but there's some error about direction of light volume.
[numthreads(32, 32, 1)]
void CS(uint3 dispatchID : SV_DispatchThreadID)
{
float4 result = { 0.0f, 0.0f, 0.0f, 0.0f };
uint2 pixel = dispatchID.xy;
uint width, height;
inputTexture.GetDimensions(width, height);
float2 texCoord = (float2(pixel) + 0.5f) / float2(width, height);
float depth = depthTexture[pixel].r;
float3 screenPos = GetPositionVS(texCoord, depth);
float3 rayEnd = float3(0.0f, 0.0f, 0.0f);
const uint sampleCount = 16;
const float stepSize = length(screenPos - rayEnd) / sampleCount;
// Perform ray marching to integrate light volume along view ray:
[loop]
for (uint i = 0; i < NUM_LIGHTS; ++i)
{
[branch]
if (gLights[i].Type == SPOT_LIGHT)
{
float3 V = float3(0.0f, 0.0f, 0.0f) - screenPos;
float cameraDistance = length(V);
V /= cameraDistance;
float marchedDistance = 0;
float accumulation = 0;
float3 P = screenPos + V * stepSize * dither(pixel.xy);
for (uint j = 0; j < sampleCount; ++j)
{
float3 L = mul(float4(gLights[i].Position, 1.0f), gView).xyz - P;
const float dist2 = dot(L, L);
const float dist = sqrt(dist2);
L /= dist;
//float3 viewDir = mul(float4(gLights[i].Direction, 1.0f), gView).xyz;
float3 viewDir = gLights[i].Direction;
float SpotFactor = dot(L, normalize(-viewDir));
float spotCutOff = gLights[i].outerCosine;
[branch]
if (SpotFactor > spotCutOff)
{
float attenuation = DoAttenuation(dist, gLights[i].Range);
float conAtt = saturate((SpotFactor - gLights[i].outerCosine) / (gLights[i].innerCosine - gLights[i].outerCosine));
conAtt *= conAtt;
attenuation *= conAtt;
attenuation *= ExponentialFog(cameraDistance - marchedDistance);
accumulation += attenuation;
}
marchedDistance += stepSize;
P = P + V * stepSize;
}
accumulation /= sampleCount;
result += max(0, float4(accumulation * gLights[i].Color * gLights[i].VolumetricStrength, 1));
}
}
outputTexture[pixel] = inputTexture[pixel] + result;
}
this is my compute shader, but when I doesn't multiply view matrix to direction, it goes wrong like this :
as you can see, street lamp's volume direction is good, but vehicle's headlight's volume direction is different from it's spot light direction.
and when I multiply view matrix to direction :
head lights gone wrong AND street lamp goes wrong too.
I still finding where's wrong in my cpu codes, but I haven't find anything.
this might be helpful. here's my shader code about spot lighting.
float CalcAttenuation(float d, float falloffStart, float falloffEnd)
{
return saturate((falloffEnd - d) / (falloffEnd - falloffStart));
}
float3 BlinnPhongModelLighting(float3 lightDiff, float3 lightVec, float3 normal, float3 view, Material mat)
{
const float m = mat.Exponent;
const float f = ((mat.IOR - 1) * (mat.IOR - 1)) / ((mat.IOR + 1) * (mat.IOR + 1));
const float3 fresnel0 = float3(f, f, f);
float3 halfVec = normalize(view + lightVec);
float roughness = (m + 8.0f) * pow(saturate(dot(halfVec, normal)), m) / 8.0f;
float3 fresnel = CalcReflectPercent(fresnel0, halfVec, lightVec);
float3 specular = fresnel * roughness;
specular = specular / (specular + 1.0f);
return (mat.Diffuse.rgb + specular * mat.Specular) * lightDiff;
}
float3 ComputeSpotLight(Light light, Material mat, float3 pos, float3 normal, float3 view)
{
float3 result = float3(0.0f, 0.0f, 0.0f);
bool bCompute = true;
float3 lightVec = light.Position - pos;
float d = length(lightVec);
if (d > light.FalloffEnd)
bCompute = false;
if (bCompute)
{
lightVec /= d;
float ndotl = max(dot(lightVec, normal), 0.0f);
float3 lightDiffuse = light.Diffuse * ndotl;
float att = CalcAttenuation(d, light.FalloffStart, light.FalloffEnd);
lightDiffuse *= att;
float spotFactor = pow(max(dot(-lightVec, light.Direction), 0.0f), light.SpotPower);
lightDiffuse *= spotFactor;
result = BlinnPhongModelLighting(lightDiffuse, lightVec, normal, view, mat);
}
return result;
}

C++ and DirectX: Calculate tangent to mesh with arbitrary normals

I have a mesh with arbitrary normals and I have calculated them using standard method
Method to calculate the tangents..
void calcTangent(uint32_t idx1, uint32_t idx2, uint32_t idx3)
{
vertex v1 = _vertex[idx1];
vertex v2 = _vertex[idx2];
vertex v3 = _vertex[idx3];
float du1 = v3.Text.x - v1.Text.x;
float dv1 = v3.Text.y - v1.Text.y;
float du2 = v2.Text.x - v1.Text.x;
float dv2 = v2.Text.y - v1.Text.y;
float tx1 = v3.Pos.x - v1.Pos.x;
float ty1 = v3.Pos.y - v1.Pos.z;
float tz1 = v3.Pos.z - v1.Pos.z;
float tx2 = v2.Pos.x - v1.Pos.x;
float ty2 = v2.Pos.y - v1.Pos.z;
float tz2 = v2.Pos.z - v1.Pos.z;
float r = 1.0f / (du1 * dv2 - dv1 * du2);
float e1x = (dv2 * tx1 - dv1 * tx2) * r;
float e1y = (dv2 * ty1 - dv1 * ty2) * r;
float e1z = (dv2 * tz1 - dv1 * tz2) * r;
//Binormals
float e2x = (du1 * tx2 - du2 * tx1) * r;
float e2y = (du1 * ty2 - du2 * ty1) * r;
float e2z = (du1 * tz2 - du2 * tz1) * r;
XMFLOAT3 ot1 = Math::gramSchmidthF({ v1.Norm.x, v1.Norm.y, v1.Norm.z }, { e1x, e1y, e1z });
XMFLOAT3 ot2 = Math::gramSchmidthF({ v2.Norm.x, v2.Norm.y, v2.Norm.z }, { e1x, e1y, e1z });
XMFLOAT3 ot3 = Math::gramSchmidthF({ v3.Norm.x, v3.Norm.y, v3.Norm.z }, { e1x, e1y, e1z });
_vertex[idx1].Tangent = ot1;
_vertex[idx2].Tangent = ot2;
_vertex[idx3].Tangent = ot3;
}
the bitangent will not be passed to the shader, and will be calculated in PS..
vertex shader and pixel shaders..
struct VS_INPUT
{
float4 Position : POSITION;
float3 Normal : NORMAL;
float2 Texture : TEXCOORD;
float3 Tangent : TANGENT;
};
struct PS_INPUT
{
float4 Position : SV_POSITION;
float3 Normal : NORMAL;
float3 Tangent : TANGENT;
float3 Binormal : BINORMAL;
float2 Texture : TEXCOORD0;
float3 ViewDirection : TEXCOORD1;
};
PS_INPUT vertex_shader(VS_INPUT input)
{
PS_INPUT output = (PS_INPUT)0;
input.Position.w = 1.0f;
//transformations
output.Position = mul(input.Position, World);
output.Position = mul(output.Position, View);
output.Position = mul(output.Position, Projection);
//
output.Normal = normalize(mul(float4(input.Normal, 0), World).xyz);
output.Texture = input.Texture;
float3 worldPosition = mul(input.Position, World).xyz;
output.ViewDirection = normalize(CAMERA_POSITION - worldPosition);
//add the tangent and binormal
output.Tangent = normalize(mul(float4(input.Tangent, 0), World).xyz);
output.Binormal = normalize(cross(output.Normal, output.Tangent));
return output;
}
float4 ps(PS_INPUT input) : SV_Target
{
float4 OUT = (float4)0;
//texture normal
float3 sampledNormal = (2 * normalMapTexture.Sample(normalMapSampler, input.Texture).xyz) - 1.0; // Map normal from [0..1] to [-1..1]
//creating matrix
// Tangent
// Binormal
// Normal
float3x3 tbn = float3x3(input.Tangent, input.Binormal, input.Normal);
//convert tangent space to world space
sampledNormal = mul(sampledNormal, tbn); // Transform normal from normal map to world space
float3 viewDirection = normalize(input.ViewDirection);
//texture color
float4 color = colorTexture.Sample(samLinear, input.Texture); //getting the color from texture without normals..
//ambient color
float3 ambient = getVectorColorContribution(AMBIENT_COLOR, color.rgb); //mult AMBIENT_COLOR(.rgb) * AMBIENT_COLOR Intensity (.a) * color
float3 diffuse = (float3)0;
float3 specular = (float3)0;
float3 lightDirection = normalize(-LIGHT_DIR.xyz);
float n_dot_l = dot(sampledNormal, lightDirection);
//calculating the diffuse value
diffuse = saturate(n_dot_l) * LIGHT_COLOR.rgb * LIGHT_COLOR.a;
}
//changing the return types will change the result to basic or specular..
OUT.rgb = diffuse * color;
OUT.a = 1.0f;
return OUT;
}
Here it is the result, only using diffuse, to avoid specular errors..
please anyone knows why is this?
After a lot of digging, in DirectXMesh there is a function to calculate tangents right(ComputeTangentFrame) it saves the result in XMFLOAT4 tangent[3]array , works perfectly, so my problem was calculating tangents. Hope it helps anyone else..
Little Example using it:
uint32_t idx[3];
idx[0] = 0;
idx[1] = 1;
idx[2] = 2;
XMFLOAT3 pos[3];
pos[0] = Pos1;
pos[1] = Pos2;
pos[2] = Pos3;
XMFLOAT3 normals[3];
normals[0] = Normal1;
normals[1] = Normal2;
normals[2] = Normal3;
XMFLOAT2 t[3];
t[0] = TextureCoord1;
t[1] = TextureCoord2;
t[2] = TextureCoord3;
XMFLOAT4 tangent[3];
ComputeTangentFrame(idx,1, pos, normals,t,3, tangent);

Lighting abnormal when calculating in tangent space. Probably something wrong with coordinate transformation matrix

I'm trying to calculate lighting in tangent space. But I just keep getting abnormal results. I was modifying the book's demo code and I wander if there maybe something wrong with the transformation matrix I created.
I'm having trouble solving a problem in Introduction to 3D Game Programming with DirectX 11. I tried to use matrix TBN
Tx, Ty, Tz,
Bx, By, Bz,
Nx, Ny, Nz
as the book provided but I found the light vector to be wrongly transformed to tangent space and now I have no clue how to debug this shader.
Here is my Pixel Shader:
float4 PS1(VertexOut pin,
uniform int gLightCount,
uniform bool gUseTexure,
uniform bool gAlphaClip,
uniform bool gFogEnabled,
uniform bool gReflectionEnabled) : SV_Target{
// Interpolating normal can unnormalize it, so normalize it.
pin.NormalW = normalize(pin.NormalW);
pin.TangentW = normalize(pin.TangentW);
// The toEye vector is used in lighting.
float3 toEye = gEyePosW - pin.PosW;
// Cache the distance to the eye from this surface point.
float distToEye = length(toEye);
// Calculate normalMapSample
float3 normalMapSample =
normalize(SampledNormal2Normal(gNormalMap.Sample(samLinear, pin.Tex).rgb));
// normalize toEye
toEye = normalize(toEye);
// Default to multiplicative identity.
float4 texColor = float4(1, 1, 1, 1);
if (gUseTexure)
{
// Sample texture.
texColor = gDiffuseMap.Sample(samLinear, pin.Tex);
if (gAlphaClip)
{
// Discard pixel if texture alpha < 0.1. Note that we do this
// test as soon as possible so that we can potentially exit the shader
// early, thereby skipping the rest of the shader code.
clip(texColor.a - 0.1f);
}
}
//
// Lighting.
//
float4 litColor = texColor;
if (gLightCount > 0)
{
// Start with a sum of zero.
float4 ambient = float4(0.0f, 0.0f, 0.0f, 0.0f);
float4 diffuse = float4(0.0f, 0.0f, 0.0f, 0.0f);
float4 spec = float4(0.0f, 0.0f, 0.0f, 0.0f);
// Sum the light contribution from each light source.
[unroll]
for (int i = 0; i < gLightCount; ++i)
{
float4 A, D, S;
ComputeDirectionalLightInTangent(gMaterial, gDirLights[i],
normalMapSample, World2TangentSpace(pin.NormalW, pin.TangentW, gTexTransform), toEye,
A, D, S);
ambient += A;
diffuse += D;
spec += S;
}
litColor = texColor*(ambient + diffuse) + spec;
if (gReflectionEnabled)
{
float3 incident = -toEye;
float3 reflectionVector = reflect(incident, normalMapSample);
float4 reflectionColor = gCubeMap.Sample(samLinear, reflectionVector);
litColor += gMaterial.Reflect*reflectionColor;
}
}
//
// Fogging
//
if (gFogEnabled)
{
float fogLerp = saturate((distToEye - gFogStart) / gFogRange);
// Blend the fog color and the lit color.
litColor = lerp(litColor, gFogColor, fogLerp);
}
// Common to take alpha from diffuse material and texture.
litColor.a = gMaterial.Diffuse.a * texColor.a;
return litColor;
}
And Here are function SampledNormal2Normal, World2TangentSpace and ComputeDirectionalLightInTangent:
float3 SampledNormal2Normal(float3 sampledNormal)
{
float3 normalT = 2.0f*sampledNormal - 1.0f;
return normalT;
}
float3x3 World2TangentSpace(float3 unitNormalW, float3 tangentW, float4x4 texTransform)
{
// Build orthonormal basis.
float3 N = unitNormalW;
float3 T = normalize(tangentW - dot(tangentW, N)*N);
float3 B = cross(N, T);
float3x3 TBN = float3x3(T, B, N);
/*float3x3 invTBN = float3x3(T.x, T.y, T.z, B.x, B.y, B.z, N.x, N.y, N.z);
return invTBN;*/
float3 T_ = T - dot(N, T)*N;
float3 B_ = B - dot(N, B)*N - (dot(T_, B)*T_) / dot(T_, T_);
float3x3 invT_B_N = float3x3(T_.x, T_.y, T_.z, B_.x, B_.y, B_.z, N.x, N.y, N.z);
return invT_B_N;
}
void ComputeDirectionalLightInTangent(Material mat, DirectionalLight L,
float3 normalT, float3x3 toTS, float3 toEye,
out float4 ambient,
out float4 diffuse,
out float4 spec)
{
// Initialize outputs.
ambient = float4(0.0f, 0.0f, 0.0f, 0.0f);
diffuse = float4(0.0f, 0.0f, 0.0f, 0.0f);
spec = float4(0.0f, 0.0f, 0.0f, 0.0f);
// The light vector aims opposite the direction the light rays travel.
float3 lightVec = -L.Direction;
lightVec = mul(lightVec, toTS);
lightVec = normalize(lightVec);
// toEye to Tangent Space
toEye = mul(toEye, toTS);
toEye = normalize(toEye);
// Add ambient term.
ambient = mat.Ambient * L.Ambient;
// Add diffuse and specular term, provided the surface is in
// the line of site of the light.
float diffuseFactor = dot(lightVec, normalT);
// Flatten to avoid dynamic branching.
[flatten]
if (diffuseFactor > 0.0f)
{
float3 v = reflect(-lightVec, normalT);
float specFactor = pow(max(dot(v, toEye), 0.0f), mat.Specular.w);
diffuse = diffuseFactor * mat.Diffuse * L.Diffuse;
spec = specFactor * mat.Specular * L.Specular;
}
}
The result I got seem to be much darker in most places and too bright in several highlight area. I wonder if anyone can help me with my code or give me advice on how to debug a hlsl shader. My thousand thanks!

Metal - camera rotation in signed distance function

I am learning from this tutorial and got this metal code and change a bit to use mouse to control the position of the camera:
struct Ray {
float3 origin;
float3 direction;
Ray(float3 o, float3 d) {
origin = o;
direction = d;
}
};
struct Sphere {
float3 center;
float radius;
Sphere(float3 c, float r) {
center = c;
radius = r;
}
};
float distToSphere(Ray ray, Sphere s) {
return length(ray.origin - s.center) - s.radius;
}
float distToScene(Ray r) {
Sphere s = Sphere(float3(1.), 0.5);
Ray repeatRay = r;
repeatRay.origin = fmod(r.origin, 2.);
return distToSphere(repeatRay, s);
}
kernel void compute(texture2d<float, access::write> output [[texture(0)]],
constant float &mouseX [[buffer(1)]],
constant float &mouseY [[buffer(2)]],
uint2 gid [[thread_position_in_grid]]) {
int width = output.get_width();
int height = output.get_height();
float2 uv = float2(gid) / float2(width, height);
uv = uv * 2.0 - 1.0;
float3 camPos = float3(1000+mouseX*-0.05, 1000-mouseY*0.05, 1);
Ray ray = Ray(camPos, normalize(float3(uv.x,uv.y, 1.)));
float3 col = float3(0.);
for (int i=0.; i<100.; i++) {
float dist = distToScene(ray);
if (dist < 0.001) {
col = float3(1.);
break;
}
ray.origin += ray.direction * dist;
}
float3 posRelativeToCamera = ray.origin - camPos;
output.write(float4(col * abs((posRelativeToCamera) / 10.0), 1.), gid);
}
Everything works fine. Now, instead of position, I want to rotate the camera with mouse. I did some research from shadertoy.com and convert the setCamera() code into metal:
float3x3 setCamera( float3 origin, float3 target, float rotation) {
float3 forward = normalize(target - origin);
float3 orientation = float3(sin(rotation), cos(rotation), 0.0);
float3 left = normalize(cross(forward, orientation));
float3 up = normalize(cross(left, forward));
return float3x3(left, up, forward);
}
However, I don't know how to inject in my code to make it work.
How can I make this to work?

c++ DirectX lighting in pixel shader issue

I have a problem that I cant manage to figure out. I just added a point light to my project and it makes the textures go completely black. I have no idea why.
I think that it might be either the normal that is not updating correctly or it might be calculation of s.x, s.y and s.z.
I would be very happy if someone had time to take a look at it and help me. Thanks.
So. Here is my pixel shader :
Texture2D txDiffuse : register(t0);
SamplerState sampState;
cbuffer PointLight : register(b0)
{
float3 Pos;
float diff;
float amb;
float spec;
float range;
float intensity;
};
struct VS_IN
{
float4 Pos : SV_POSITION;
float2 Tex : TEXCOORD;
float4 Norm : NORMAL;
float4 Pos2 : POSITION;
};
float4 PS_main(VS_IN input) : SV_Target
{
float3 s = txDiffuse.Sample(sampState, input.Tex).xyz;
float3 lightPos = Pos;
float3 lightVector = lightPos - input.Pos2;
lightVector = normalize(lightVector);
float nDotL = dot(lightVector, input.Norm);
float diff1 = 0.8;
float amb1 = 0.1;
s.x = (s.x * diff * nDotL + s.x * amb);
s.y = (s.y * diff * nDotL + s.y * amb);
s.z = (s.z * diff * nDotL + s.z * amb);
return float4(s, 0.0);
};
Geometry shader :
cbuffer worldMatrix : register(b0)
{
matrix world;
}
cbuffer viewMatrix : register(b1)
{
matrix view;
}
cbuffer projectionMatrix : register(b2)
{
matrix projection;
}
struct VS_IN
{
float4 Pos : SV_POSITION;
float2 Tex : TEXCOORD;
};
struct VS_OUT
{
float4 Pos : SV_POSITION;
float2 Tex : TEXCOORD;
float4 Norm : NORMAL;
float4 Pos2 : POSITION;
};
[maxvertexcount(6)]
void main(triangle VS_IN input[3] : SV_POSITION, inout TriangleStream< VS_OUT > output2)
{
matrix wvp = mul(projection, mul(world, view));
matrix worldView = mul(world, view);
float4 normal = float4(cross(input[1].Pos - input[0].Pos, input[2].Pos - input[0].Pos), 0.0f);
normal = normalize(normal);
float4 rotNorm = mul(worldView, normal);
rotNorm = normalize(rotNorm);
VS_OUT output[3];
for (uint i = 0; i < 3; i++)
{
output[i].Pos = input[i].Pos;
output[i].Pos = mul(wvp, input[i].Pos);
output[i].Tex = input[i].Tex;
output[i].Norm = rotNorm;
output[i].Pos2 = mul(worldView, output[i].Pos);
output2.Append(output[i]);
}
output2.RestartStrip();
VS_OUT outputcopy[3];
for (uint i = 0; i < 3; i++)
{
outputcopy[i].Pos = input[i].Pos + (normal);
outputcopy[i].Pos = mul(wvp, outputcopy[i].Pos);
outputcopy[i].Tex = input[i].Tex;
outputcopy[i].Norm = rotNorm;
outputcopy[i].Pos2 = mul(worldView, outputcopy[i].Pos);
output2.Append(outputcopy[i]);
}
output2.RestartStrip();
}
Code to initializing the point light:
struct PointLight
{
Vector3 Pos;
float diff;
float amb;
float spec;
float range;
float intensity;
};
PointLight* pointLight = nullptr;
PointLight PL =
{
Vector3(0.0f, 0.0f, -3.0f),
0.8f,
0.2f,
0.0f,
100.0f,
1.0f
};
pointLight = &PL;
D3D11_BUFFER_DESC lightBufferDesc;
memset(&lightBufferDesc, 0, sizeof(lightBufferDesc));
lightBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
lightBufferDesc.Usage = D3D11_USAGE_DEFAULT;
lightBufferDesc.StructureByteStride = 0;
lightBufferDesc.MiscFlags = 0;
lightBufferDesc.ByteWidth = sizeof(PointLight);
D3D11_SUBRESOURCE_DATA pointLightData;
memset(&pointLightData, 0, sizeof(pointLightData));
pointLightData.pSysMem = &PL;
gDevice->CreateBuffer(&lightBufferDesc, &pointLightData, &lightBuffer);
and in render() i run
gDeviceContext->PSSetConstantBuffers(0, 1, &lightBuffer);
Texture will be black if s.x, s.y, s.z equal to zero.
s.x = (s.x * diff * nDotL + s.x * amb);
s.y = (s.y * diff * nDotL + s.y * amb);
s.z = (s.z * diff * nDotL + s.z * amb);
Try to change diff and amb with a non-zero constant so that you can be sure that you set contant buffer correctly or not. If after you change them, it's still black then it must be nDotL and/or sampled texture that is zero. Then try with non-zero constant for texture sample. If they're still causing texture to look black then your light vector calculation is the culprit.