Hi and thanks for your time!

So over the past few days I have been playing with isosurface construction from volume textures, I have it running on the cpu and all is well from a "just got it working" stand point eg. surface reconstruction works and I have my really cool voxel mesh drawing.

I have based my code(converted to VB.net) on Paul Bourke's work here: Polygonising a scalar field and like I said it works well apart from the fact that my normals are wrong and I have these strange fully black on both sides triangles, I think I'm doing my normals wrong but the way they are now is the beast I can get, I tried a few ways to build the normals and this one is the only way I could get smooth normals.


Here you can see how my normals are wrong, green should be up, gray\dark should be unlit and the hay'ish colour is the lit side.

I have tried to flip and invert them but as you can see they are not wrong all the same way.

HLSL Normals 1st try:

float3x3 cotangent_frame(float3 N, float3 p, float2 uv)

// get edge vectors of the pixel triangle
float3 dp1 = ddx(p);
float3 dp2 = ddy(p);
float2 duv1 = ddx(uv);
float2 duv2 = ddy(uv);

// solve the linear system
float3 dp2perp = cross(dp2, N);
float3 dp1perp = cross(N, dp1);
float3 T = dp2perp * duv1.x + dp1perp * duv2.x;
float3 B = dp2perp * duv1.y + dp1perp * duv2.y;

// construct a scale-invariant frame 
float invmax =   -sqrt(max(dot(T, T), dot(B, B)));
return float3x3(T * invmax, B * invmax, N);

HLSL Normals 2nd try:

NormalData CalcWS_Normal(float2 WS_TexCoord, float3 WS_Pos)

NormalData dout;

float3 dp1 = ddx(WS_Pos);
float3 dp2 = ddy(WS_Pos);
float2 duv1 = ddx(WS_TexCoord);
float2 duv2 = ddy(WS_TexCoord);

float3x3 M = float3x3(dp1, dp2, cross(dp1, dp2));
float2x3 inverseM = float2x3(cross(M[1], M[2]), cross(M[2], M[0]));

float3 t = mul(float2(duv1.x, duv2.x), inverseM);
float3 b = mul(float2(duv1.y, duv2.y), inverseM);
float3 normal = normalize(cross(normalize(b), normalize(t)));

dout.Normal = normal;
dout.Tang = t;
dout.BiTang = b;

return dout;

Heres is how I'm doing it now, takes a vertex and then samples the volume texture


   Private Function vGetNormal(fX As Single, fY As Single, fZ As Single, fScale As Single) As Vector3
    Dim rfNormal As Vector3
    rfNormal.X = fSample1(fX - fScale, fY, fZ) - fSample1(fX + fScale, fY, fZ)
    rfNormal.Y = fSample1(fX, fY - fScale, fZ) - fSample1(fX, fY + fScale, fZ)
    rfNormal.Z = fSample1(fX, fY, fZ - fScale) - fSample1(fX, fY, fZ + fScale)
    Return Vector3.Normalize(rfNormal)
End Function

Private Function vGetNormal(fX As Single, fY As Single, fZ As Single, fScale As Vector3) As Vector3
    Dim rfNormal As Vector3
    rfNormal.X = fSample1(fX - fScale.X, fY, fZ) - fSample1(fX + fScale.X, fY, fZ)
    rfNormal.Y = fSample1(fX, fY - fScale.Y, fZ) - fSample1(fX, fY + fScale.Y, fZ)
    rfNormal.Z = fSample1(fX, fY, fZ - fScale.Z) - fSample1(fX, fY, fZ + fScale.Z)
    Return Vector3.Normalize(rfNormal)
End Function

Volume sampling code:


Public Function GetVolumeData(_pos As Vector3) As Half
    Dim x2 As Single = Math.Abs((_pos.X / CellsPerPatch * 32) Mod mWidth)
    Dim y2 As Single = Math.Abs((_pos.Y / CellsPerPatch * 8) Mod mDepth)
    Dim z2 As Single = Math.Abs((_pos.Z / CellsPerPatch * 32) Mod mHeight)

    Return mScalars(CInt(Math.Truncate(x2)) + (CInt(Math.Truncate(z2)) * mWidth) + (CInt(Math.Truncate(y2) * mWidth * mWidth)))
End Function

The rest of the isosurface construction code is just a copy-> convert-> paste of Paul Bourke's c code.

Just to makes sure everyone knows what I'm asking: Can anyone tell me what I'm doing wrong? Is it a problem with my normals or the isosurface stuffs or both?

All of the above is just so u have some context, I'm happy to post more code if ppl need to see it

[EDIT]: Black squares come from having no depth info at that point so my deferred render hates those spots, this is leading back to maybe a problem with the surface reconstruction? But why its only happening in those spots, one would think that it would happen everywhere?


1 Answer 1


I didn't sleep last night, turns out I was doing it all wrong.

Ill list my !#@! up's then show you how it looks now.

Strange looking mesh:

a). Marching cubes in world space and trying to scale the world space voxel positons to pixels in the volume texture. Just march over the volume per pixel and scale in the vertex shader with a world matrix.

b). Have an index buffer now too.

Black triangles:

Iso value to big, I had it at 23 but now have it at 0.001.

Normals wrong:

a). Pick the right culling state and don't use cullnone. b). Once I changed the way I was marching I was able to get the vGetNormal function to work and convert face normal to vertex normal(still a bit messy).

Almost there

As you can see its looking much better some faces are still a bit funky and I need to redo my lighting because its been set for just height based terrain.

The dark green comes from my SH lighting that is baked for my old terrain so once I re generate that it should look a bit nicer

I also added triplanar mapping so it looks a bit nicer than having just rocks everywhere and by fixing all that I got my mem usage down by heaps and my isosurface build time down to 5sec using threads.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .