Home Game Development shaders – DirectX12 lighting with weird stripes

shaders – DirectX12 lighting with weird stripes

0
shaders – DirectX12 lighting with weird stripes

[ad_1]

I’m currently implementing Moon terrain with DX12.

I use QuadSphere (CubeSphere) and apply tessellation.

Moon is sphere, so we can calculate texture coordinate from polar coordinate.
I used the UV for color map and displacement map.

Each map is divided into half horizontally, so I remap texture coordinate.
(one texture 23040×11520 -> two texture 11520×11520, 11520×11520)

int texIndex = round(gTexCoord.x);
float2 sTexCoord = float2(texIndex == 0 ? gTexCoord.x * 2 : (gTexCoord.x - 0.5f) * 2.0f, gTexCoord.y);

Everyting works fine, lighting works fine except for the problem below.
Lighting is a bit weird. You can see weird stripes.

I guess the problem is coming from normal calculated from displacement map, but not sure. (below code)

What causes the problem?

// texMap[0] - right color map, texMap[1] - left color map
// texMap[2] - right displacement map, texMap[3] - left displacement map
// Calculate local normal from height map.
float2 offxy = { off.x / nTex.x, off.y / nTex.y };
float2 offzy = { off.z / nTex.x, off.y / nTex.y };
float2 offyx = { off.y / nTex.x, off.x / nTex.y };
float2 offyz = { off.y / nTex.x, off.z / nTex.y };
float s01 = texMap[texIndex + 2].SampleLevel(samLinear, sTexCoord + offxy, 0).r;
float s21 = texMap[texIndex + 2].SampleLevel(samLinear, sTexCoord + offzy, 0).r;
float s10 = texMap[texIndex + 2].SampleLevel(samLinear, sTexCoord + offyx, 0).r;
float s12 = texMap[texIndex + 2].SampleLevel(samLinear, sTexCoord + offyz, 0).r;
float3 va = normalize(float3(size.xy, s21 - s01));
float3 vb = normalize(float3(size.yx, s12 - s10));

float3 localNormal = float3(cross(va, vb) / 2 + 0.5f);
localNormal = localNormal * 2.0f - 1.0f;

image

Pixel Shader Full Code.

static const float2 size = { 2.0, 0.0 };
static const float3 off = { -1.0, 0.0, 1.0 };
static const float2 nTex = { 11520, 11520 };

PS_OUTPUT PS(DS_OUT input)
{
    PS_OUTPUT output;

    // Convert cartesian to polar.
    float theta = atan2(input.normCatPos.z, input.normCatPos.x);
    theta = sign(theta) == -1 ? 2 * PI + theta : theta;
    float phi = acos(input.normCatPos.y);

    // Convert polar coordinates to texture coordinates.
    float2 gTexCoord = float2(theta / (2 * PI), phi / PI);

    // Divide texture coordinates into two parts and re-mapping.
    int texIndex = round(gTexCoord.x);
    float2 sTexCoord = float2(texIndex == 0 ? gTexCoord.x * 2 : (gTexCoord.x - 0.5f) * 2.0f, gTexCoord.y);

    // Calculate local normal from height map.
    float2 offxy = { off.x / nTex.x, off.y / nTex.y };
    float2 offzy = { off.z / nTex.x, off.y / nTex.y };
    float2 offyx = { off.y / nTex.x, off.x / nTex.y };
    float2 offyz = { off.y / nTex.x, off.z / nTex.y };
    float s01 = texMap[texIndex + 2].SampleLevel(samLinear, sTexCoord + offxy, 0).r;
    float s21 = texMap[texIndex + 2].SampleLevel(samLinear, sTexCoord + offzy, 0).r;
    float s10 = texMap[texIndex + 2].SampleLevel(samLinear, sTexCoord + offyx, 0).r;
    float s12 = texMap[texIndex + 2].SampleLevel(samLinear, sTexCoord + offyz, 0).r;
    float3 va = normalize(float3(size.xy, s21 - s01));
    float3 vb = normalize(float3(size.yx, s12 - s10));

    float3 localNormal = float3(cross(va, vb) / 2 + 0.5f);
    localNormal = localNormal * 2.0f - 1.0f;

    // Calculate TBN Matrix.
    float3 N = input.normCatPos;
    float3 T = float3(-sin(theta), 0, cos(theta));
    float3 B = cross(N, T);

    // Calculate Normal.
    float3x3 TBN = float3x3(normalize(T), normalize(B), normalize(N));
    float3 normal = normalize(mul(localNormal, TBN));

    // [Diffuse color]
    float4 texColor = texMap[texIndex].Sample(samLinear, sTexCoord);
    float3 diffuse = max(dot(normal, cb.lightDirection.xyz), 0.0f) * cb.lightColor.xyz;
    float3 ambient = float3(0.005f, 0.005f, 0.005f) * cb.lightColor.xyz;

    float4 final = float4(saturate((diffuse + ambient) * texColor.rgb), texColor.a);
    final.a = 1;
    output.color = final;
    
    return output;
}

HLSL Full Code (In-case)

#define PI 3.1415926538


//--------------------------------------------------------------------------------------
// Constant Buffer Variables
//--------------------------------------------------------------------------------------
struct ConstantBufferType
{
    float4x4    worldMatrix;
    float4x4    viewMatrix;
    float4x4    projectionMatrix;
    float4      cameraPosition;
    float4      lightDirection;
    float4      lightColor;
};

ConstantBuffer<ConstantBufferType> cb : register(b0);


//--------------------------------------------------------------------------------------
// I/O Structures
//--------------------------------------------------------------------------------------
struct VS_INPUT
{
    float4 position : POSITION;
};

struct VS_OUTPUT
{
    float4 position : SV_Position;
};

struct PS_OUTPUT
{
    float4 color : SV_Target;
};

struct PatchTess
{
    float edgeTess[4] : SV_TessFactor;
    float insideTess[2] : SV_InsideTessFactor;
};

struct HS_OUT
{
    float3 position : POSITION;
};

struct DS_OUT
{
    float4 position : SV_Position;
    float3 normCatPos : POSITION;
};


//--------------------------------------------------------------------------------------
// Texture & Sampler Variables
//--------------------------------------------------------------------------------------
Texture2D texMap[3] : register(t0);
SamplerState samLinear : register(s0);


//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
VS_OUTPUT VS(VS_INPUT input)
{
    VS_OUTPUT output;
    output.position = input.position;

    return output;
}


//--------------------------------------------------------------------------------------
// Constant Hull Shader
//--------------------------------------------------------------------------------------

static const float near = 20.0f;
static const float far = 150.0f;

float CalcTessFactor(float3 p)
{
    float d = distance(p, cb.cameraPosition.xyz);
    float s = saturate((d - near) / (far - near));
    return pow(2, -8 * pow(s, 2) + 8);
}

PatchTess ConstantHS(InputPatch<VS_OUTPUT, 4> patch, int patchID : SV_PrimitiveID)
{
    PatchTess output;

    float3 localPos = 0.25f * (patch[0].position + patch[1].position + patch[2].position + patch[3].position);
    float3 worldPos = mul(float4(localPos, 1.0f), cb.worldMatrix).xyz;

    float3 p0 = normalize(patch[0].position) * 150.0f;
    float3 p1 = normalize(patch[1].position) * 150.0f;
    float3 p2 = normalize(patch[2].position) * 150.0f;
    float3 p3 = normalize(patch[3].position) * 150.0f;

    float3 e0 = 0.5f * (p0 + p2);
    float3 e1 = 0.5f * (p0 + p1);
    float3 e2 = 0.5f * (p1 + p3);
    float3 e3 = 0.5f * (p2 + p3);
    float3 c = normalize(worldPos) * 150.0f;

    output.edgeTess[0] = CalcTessFactor(e0);
    output.edgeTess[1] = CalcTessFactor(e1);
    output.edgeTess[2] = CalcTessFactor(e2);
    output.edgeTess[3] = CalcTessFactor(e3);

    output.insideTess[0] = CalcTessFactor(c);
    output.insideTess[1] = output.insideTess[0];

    return output;
}


//--------------------------------------------------------------------------------------
// Control Point Hull Shader
//--------------------------------------------------------------------------------------
[domain("quad")]
[partitioning("integer")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(4)]
[patchconstantfunc("ConstantHS")]
HS_OUT HS(InputPatch<VS_OUTPUT, 4> input, int vertexIdx : SV_OutputControlPointID, int patchID : SV_PrimitiveID)
{
    HS_OUT output;
    output.position = input[vertexIdx].position;

    return output;
}


//--------------------------------------------------------------------------------------
// Domain Shader
//--------------------------------------------------------------------------------------

static const float2 size = { 2.0, 0.0 };
static const float3 off = { -1.0, 0.0, 1.0 };
static const float2 nTex = { 11520, 11520 };

[domain("quad")]
DS_OUT DS(const OutputPatch<HS_OUT, 4> input, float2 uv : SV_DomainLocation, PatchTess patch)
{
    DS_OUT output;
    
    // Bilinear interpolation (position).
    float3 v1 = lerp(input[0].position, input[1].position, uv.x);
    float3 v2 = lerp(input[2].position, input[3].position, uv.x);
    float3 position = lerp(v1, v2, uv.y);

    // Get tessellation level.
    float tess = patch.edgeTess[0];

    // Calculate LOD level for height map.
    // range is 0 ~ 5 (mipmap has 10 levels but use only 6).
    float level = max(0, 8 - sqrt(tess) - 3);

    // Get normalized cartesian position.
    float3 normCatPos = normalize(position);

    // Convert cartesian to polar.
    float theta = atan2(normCatPos.z, normCatPos.x);
    theta = sign(theta) == -1 ? 2 * PI + theta : theta;
    float phi = acos(normCatPos.y);

    // Convert polar coordinates to texture coordinates for height map.
    float2 gTexCoord = float2(theta / (2 * PI), phi / PI);

    // Divide texture coordinates into two parts and re-mapping.
    int texIndex = round(gTexCoord.x) + 2;
    float2 sTexCoord = float2(texIndex == 0 ? gTexCoord.x * 2 : (gTexCoord.x - 0.5f) * 2.0f, gTexCoord.y);

    // Get height from texture.
    float height = texMap[texIndex].SampleLevel(samLinear, sTexCoord, 0).r;

    // Multiply MVP matrices.
    output.position = mul(float4(normCatPos * (150.0f + height * 0.5f), 1.0f), cb.worldMatrix);
    output.position = mul(output.position, cb.viewMatrix);
    output.position = mul(output.position, cb.projectionMatrix);

    // Set normalized cartesian position for calc texture coordinates in pixel shader.
    output.normCatPos = normCatPos;

    return output;
}


//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------


PS_OUTPUT PS(DS_OUT input)
{
    PS_OUTPUT output;

    // Convert cartesian to polar.
    float theta = atan2(input.normCatPos.z, input.normCatPos.x);
    theta = sign(theta) == -1 ? 2 * PI + theta : theta;
    float phi = acos(input.normCatPos.y);

    // Convert polar coordinates to texture coordinates.
    float2 gTexCoord = float2(theta / (2 * PI), phi / PI);

    // Divide texture coordinates into two parts and re-mapping.
    int texIndex = round(gTexCoord.x);
    float2 sTexCoord = float2(texIndex == 0 ? gTexCoord.x * 2 : (gTexCoord.x - 0.5f) * 2.0f, gTexCoord.y);

    // Calculate local normal from height map.
    float2 offxy = { off.x / nTex.x, off.y / nTex.y };
    float2 offzy = { off.z / nTex.x, off.y / nTex.y };
    float2 offyx = { off.y / nTex.x, off.x / nTex.y };
    float2 offyz = { off.y / nTex.x, off.z / nTex.y };
    float s01 = texMap[texIndex + 2].SampleLevel(samLinear, sTexCoord + offxy, 0).r;
    float s21 = texMap[texIndex + 2].SampleLevel(samLinear, sTexCoord + offzy, 0).r;
    float s10 = texMap[texIndex + 2].SampleLevel(samLinear, sTexCoord + offyx, 0).r;
    float s12 = texMap[texIndex + 2].SampleLevel(samLinear, sTexCoord + offyz, 0).r;
    float3 va = normalize(float3(size.xy, s21 - s01));
    float3 vb = normalize(float3(size.yx, s12 - s10));

    float3 localNormal = float3(cross(va, vb) / 2 + 0.5f);
    localNormal = localNormal * 2.0f - 1.0f;

    // Calculate TBN Matrix.
    float3 N = input.normCatPos;
    float3 T = float3(-sin(theta), 0, cos(theta));
    float3 B = cross(N, T);

    // Calculate Normal.
    float3x3 TBN = float3x3(normalize(T), normalize(B), normalize(N));
    float3 normal = normalize(mul(localNormal, TBN));

    // [Diffuse color]
    float4 texColor = texMap[texIndex].Sample(samLinear, sTexCoord);
    float3 diffuse = max(dot(normal, cb.lightDirection.xyz), 0.0f) * cb.lightColor.xyz;
    float3 ambient = float3(0.005f, 0.005f, 0.005f) * cb.lightColor.xyz;

    float4 final = float4(saturate((diffuse + ambient) * texColor.rgb), texColor.a);
    final.a = 1;
    output.color = final;

    // [Normal map]
    // output.color = float4(localNormal, 1.0f);

    // [LOD level]
    // float lod = texMap[0].CalculateLevelOfDetail(samLinear, input.texCoord);
    // output.color = float4(lod, 1 - lod, 0.0f, 1.0f);

    // [Just gray color]
    // output.color = float4(0.5f, 0.5f, 0.5f, 1.0f);
    
    return output;
}
```

[ad_2]

Previous article Tales of Arise: Beyond the Dawn Review (PS5)
Next article Buy two video games, and get one free at Amazon and Target
Hello there! My name is YoleeTeam, and I am thrilled to welcome you to AmazonianGames.com. As the premier destination for all things related to Amazon Games' universe, we are dedicated to providing you with the most exciting and immersive gaming experiences out there. From captivating visuals to exhilarating gameplay, our website is packed with comprehensive insights, updates, and reviews to keep you ahead of the game. Whether you're a seasoned gamer or new to the scene, I am here to guide you through this virtual frontier. If you have any questions or suggestions, feel free to reach out to me at john@yoleesolutions.com. Embark on your Amazon gaming journey today with AmazonianGames.com and let the adventure begin!