Advertisement

Wierdly diamond shaped terrain normals

Started by April 04, 2020 02:07 PM
1 comment, last by Steve_Segreto 4 years, 10 months ago

I found a way to generate terrain normals on the fly. The problem is they have some wierd diamond shape to them that I cant quite figure out why. Below is the world normals:

This is the corresponding wireframe:

VertexOut vs_main(VertexIn input)
{
    const uint transformIndex = gTransformOffset + input.mInstanceID;
    // silly that we have to transpose this...
    const float4x4 worldTransform = transpose( gTerrainWorldTransforms.Load( transformIndex ) );
    const uint LODlevel = gTerrainLODLevels.Load( transformIndex );
    const float4 worldPos = mul( worldTransform, float4( input.mPosition, 1 ) );
    bool doMorphing = LODlevel > 0;

    float morphLerpK = 0.0f;
    float2 texcoord;
    float4 outWorldPos = worldPos;
    if ( doMorphing )
    {
        float4 preMorphPos = worldPos;
        float2 preMorphTexcoord = GetTextureCoordinates( preMorphPos.xyz );
        preMorphPos.y += SampleHeightmap( preMorphTexcoord ) * gHeightModifier;

        float scaleX = worldTransform[ 0 ][ 0 ];
        float scaleZ = worldTransform[ 2 ][ 2 ];

        float cameraDistanceToVertex = distance( preMorphPos.xyz, gWorldEyePos );
        float2 morphConstants = gLODMorphConstants.Load( LODlevel );

        morphLerpK  = 1.0f - clamp( morphConstants.x - cameraDistanceToVertex * morphConstants.y, 0.0f, 1.0f );

        float meshSize = ( float) gTerrainMeshSize;
        float gridDimHalf = meshSize / 2.0f;
        float oneOverGridDim = 2.0f / meshSize;

        float2 fracPart = ( frac( input.mPosition.xz * float2( gridDimHalf, gridDimHalf ) ) * float2( oneOverGridDim, oneOverGridDim ) ) * float2( scaleX, scaleZ );
        preMorphPos.xz = preMorphPos.xz - ( fracPart * morphLerpK );

        float2 postMorphTexcoord = GetTextureCoordinates( preMorphPos.xyz );

        texcoord = postMorphTexcoord;
        outWorldPos.xz = preMorphPos.xz;
        outWorldPos.y += SampleHeightmap( postMorphTexcoord ) * gHeightModifier;
    }
    else
    {
        texcoord = GetTextureCoordinates( outWorldPos.xyz );
        outWorldPos.y += SampleHeightmap( texcoord ) * gHeightModifier;
    }

    float4 h;
    int mipmap = 0;
    h[0] = gHeightmap.SampleLevel(gAnisotropicSampler, texcoord, mipmap, float2( 0, -1) ).r * gHeightModifier;
    h[1] = gHeightmap.SampleLevel(gAnisotropicSampler, texcoord, mipmap, float2( -1, 0 ) ).r * gHeightModifier;
    h[2] = gHeightmap.SampleLevel(gAnisotropicSampler, texcoord, mipmap, float2( 1, 0) ).r * gHeightModifier;
    h[3] = gHeightmap.SampleLevel(gAnisotropicSampler, texcoord, mipmap, float2( 0, 1) ).r * gHeightModifier;

    normal.z = h[0] - h[3];
    normal.x = h[1] - h[2];
    normal.y = 1;
    normal = normalize( normal ); 

    VertexOut ret;
    ret.mPosition = mul( gFrameViewProj, outWorldPos );
#ifdef TERRAIN_DEBUG_NORMAL
    ret.mWorldNormal = normal;
#endif
    ret.mNormal = mul( ( float3x3 )gFrameView, normal );
    ret.mNormal = normalize( ret.mNormal );
    ret.mLOD = LODlevel;
    ret.mMorph = morphLerpK;

    return ret;
}

That's the vertex shader. I basically sample adjacent heightmap values and combine them to get a normal.

Any idea why it ends up in this non-smooth wierd diamond shape?

https://www.gamedev.net/forums/topic/661719-terrain-lighting-artifacts/

This topic is closed to new replies.

Advertisement