Sign in to follow this  
piluve

Tessellation and normals.

Recommended Posts

Hello!

 

In the last post (http://www.gamedev.net/topic/683834-texturing-my-procedural-terrain/) I got a lot of feedback and help from you  guys. I´ve been working a lot with the terrain renderer. I improved a lot the noise generation and optimized the thing (frustum culling and some detail stuff in the shader).

 

Today I started working on tessellation and it worked nice! Well, I´m having one problem.How do I get the normals now? I´ve been using this method to get them:

 

float3 CalcNormal(float3 p, int d)
{
    float dp = 1.0f;
    int detail = d;
    float4 h;
    h[0] = GetHeight(float2(p.x - dp,p.z),detail);
    h[1] = GetHeight(float2(p.x + dp,p.z),detail);
    h[2] = GetHeight(float2(p.x,    p.z + dp),detail);
    h[3] = GetHeight(float2(p.x,    p.z - dp),detail);
    float3 n = float3(h[0] - h[1] , 2.0f , h[3] - h[2]);
    return normalize(n);
}

Basically I sample 4 points around  my current position p and average the normal. Previously, I knew the value of dp  , the delta between positions. If my terrain was 100m. and with 50 elements dp would be: 2.

GetHeight(...) is the function that returns the noise value at the given point (with the requested detail).

 

Now I´m tessellating each triangle of the terrain mesh:

 

PatchTess ConstantHS(InputPatch<VertexOut, 3> patch, uint patchID : SV_PrimitiveID)
{
PatchTess pt;


// Get tessellation factor
float3 centerL = 0.75f*(patch[0].PosL + patch[1].PosL + patch[2].PosL); // perform average value/3 = value*0.75
float3 centerW = mul(float4(centerL, 1.0f), gWorld).xyz;
float d = distance(centerW, gEyePosW);
float tess = lerp(1,4,d/90000.0f);


// Uniformly tessellate the patch.
pt.EdgeTess[0] = tess;
pt.EdgeTess[1] = tess;
pt.EdgeTess[2] = tess;
pt.InsideTess = tess;


return pt;
}

Now each triangle has a different shape:

 

PbsVaeQ.png

 

 

How should I get the delta between each point now? I guess that, as I´m performing an uniform tessellation there is a way to do it but I can´t figure it out.

 

See you!

Share this post


Link to post
Share on other sites

How does the "GetHeight" function compute the height for a point on your terrain? Does it sample from a height map? If so, perhaps you could pre-compute your normals and store them a texture. Computing normals from a height map is fairly standard technique: you just need to calculate the derivatives of your height value with respect to U and V (pretty much exactly how you're doing it in your "CalcNormal" function).

Edited by MJP

Share this post


Link to post
Share on other sites

How does the "GetHeight" function compute the height for a point on your terrain? Does it sample from a height map? If so, perhaps you could pre-compute your normals and store them a texture. Computing normals from a height map is fairly standard technique: you just need to calculate the derivatives of your height value with respect to U and V (pretty much exactly how you're doing it in your "CalcNormal" function).

 

CalcHeight returns fractal noise and the terrain is infinite so I don´t have a heightmap. I´m thinking that I could use compute shaders to generate the heightmaps and then use it in the shader. Any ideas?

Share this post


Link to post
Share on other sites

Hey again!

 

I´ve been trying a few diferent things, first I did the normal calculation in the pixel shader (with dx/dy) but it just gives the real normal of the surface (non smooth normals). Now I´m calculating the normals in the Domain Shader, basically I take the 3 input points , calculate the two tangents and then do the cross product, but I´m geting hard normals anyways.


[domain("tri")]
DomainOut DS(PatchTess patchTess, 
             float3 uvwCoord: SV_DomainLocation, 
             const OutputPatch<HullOut, 3> quad)
{
DomainOut dout;

// ..Positions and uv calculation...

// Calculate the normal 
float3 p0 = mul(float4(quad[0].PosL,1.0f),gWorld);
p0.y = GetHeight(float2(p0.x,p0.z),9);

float3 p1 = mul(float4(quad[1].PosL,1.0f),gWorld);
p1.y = GetHeight(float2(p1.x,p1.z),9);

float3 p2 = mul(float4(quad[2].PosL,1.0f),gWorld);
p2.y = GetHeight(float2(p2.x,p2.z),9);

float3 d1 = p1 - p0;
float3 d2 = p2 - p0;

float3 n  = normalize(cross(d1,d2));
dout.NorH = float4(n,1.0f);

return dout;
}

 

2WIrOLS.png

Edited by piluve

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this