7
\$\begingroup\$

I'm currently trying to develop a Voxel Engine using Direct3D 9 and C++. To keep the memory usage low, i'm only passing the position, the orientation and the offset of the current voxels texture in the texture atlas of each vertex to the vertex shader.

The vertex shader then calculates the normal and passes it to the pixel shader. I found this article which covers, how to texture voxels with just their position and normal in glsl.

This is the part that calculates the texture coordinates in my pixel shader (SM3):

float2 tileUV = float2(dot(input.normal.zxy, input.pos3D), 
    dot(input.normal.yzx, input.pos3D));
float2 texcoord = input.texOffset + tileSize * frac(tileUV);

This code works fine for faces that point in negative z-direction (normal [0,0,-1]), however, the back is flipped by 180° and the sides and top/bottom squares are flipped by 90°/270°.

I am not sure, if this is correctly translated from glsl, because this behaviour should be the expected one in hlsl, if I calculate it by hand. Is there anything that I have overseen or should I aim for a different approach?

Edit:

I have now managed to successfully texture the faces by replacing the previous calculation with the following:

if(input.normal.y != 0.0f) // handle top/bottom surfaces as front/back faces
{
    input.pos3D.y = input.pos3D.z;
    input.normal.z = -input.normal.y;
    input.normal.y = 0.0f;
}
texcoord.x = input.texOffset.x + tileSize * frac(float3(1.0f, 1.0f, 1.0f) +   cross(frac(input.pos3D), input.normal)).y;
texcoord.y = input.texOffset.y + tileSize * (1.0f - frac(input.pos3D.y));

Is there any way that I can simplify/optimize the equation? I may also mention that the voxels are all axis aligned and clamped to integer coordinates.

Edit2:

This is the modified formula of zogi's answer which works as expected.

float3 n = abs(normal.xyz);
float2 texcoord = float2(input.texOffset.x + tileSize * dot(n, frac(input.pos3D.zxx)),
    input.texOffset.y + tileSize + tileSize * dot(-n, frac(input.pos3D.yzy)));
\$\endgroup\$
2
\$\begingroup\$

The first formula you mentioned is not suitable for the result you want to achieve. I suggest the following formula instead:

float3 n = abs(input.normal.xyz);
float2 tileUV = float2(dot(n,  input.pos3D.zxx),
                       dot(-n, input.pos3D.yzy));

The n vector basically selects the side of the cube, as exactly one coordinate is 1, the others are 0. Because the origin in texture coordinate space is at the top left corner of the texture in DirectX, while it is at the bottom left in OpenGL, the second texture coordinate has to be negated.

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ Thanks, with small modifications, this works as expected. See my edit for the final formula. \$\endgroup\$ – user000user Jul 22 '14 at 11:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.