• 9
• 9
• 10
• 9
• 10

# Tessellation and normals.

This topic is 519 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## 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:

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 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 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 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,
{
DomainOut dout;

// ..Positions and uv calculation...

// Calculate the normal
p0.y = GetHeight(float2(p0.x,p0.z),9);

p1.y = GetHeight(float2(p1.x,p1.z),9);

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;
}

Edited by piluve