Coordinate transformation in voxel ray-tracing?

I am implementing voxelization. I can't understand the coordinate transformation through shader.

I have read some papers and code, the first step in the geometry shader is project the triangle along its dominant axis.

What's the difference between this method and using projection matrix?

In usual ways, we transform data from local space,world space, view space, then to projection space.

Does project the triangle means we transform from view space to projection space ?
What should we get after these process, in the end of pixel shader?

• Are you talking about ray-tracing voxels? – Engineer Mar 5 '17 at 13:26
• yes the target is to implement ray tracing using svo, but i am confused in the voxelization part... – HUAQ Mar 5 '17 at 14:28

I am just through implementing scene voxelization myself, and I am doing the dominant axis selection for a primitive like this in the geometry shader:

// First calculate the face normal
float3 facenormal = abs(normalize(input[0].normal + input[1].normal + input[2].normal));
// Then the dominant axis is the face normal's max component:
uint maxi = facenormal[1] > facenormal[0] ? 1 : 0;
maxi = facenormal[2] > facenormal[maxi] ? 2 : maxi;

for( uint i = 0; i < 3; ++i )
{
// The position is in World space, transform to voxel space:
output[i].pos = float4((input[i].pos.xyz - (float3)VoxelSceneCenterPos / (float)VoxelSceneScale, 1);

// Projection matrix is unnecessary, just a swizzle is enough:
if (maxi == 0)
{
output[i].pos.xyz = output[i].pos.zyx;
}
else if (maxi == 1)
{
output[i].pos.xyz = output[i].pos.xzy;
}
// And if the dominant axis is Z, then I do nothing because that is the default projection plane for me.

// Then I just project the voxel space pos like this:
output[i].pos.xy /= (float)VoxelSceneResolution;
output[i].pos.zw = 1;
// After this step, the output[i].pos is in clip space, the rasterization will take place on this value.
}


In my code, input is the three vertices from the vertex shader stage, output is the TriangleStream which the geometry shader emits (which is also three vertices).

VoxelSceneCenterPos is a uniform from a constant buffer which is the center of the voxelization (for example (0,0,0) vector).
VoxelSceneScale is a uniform from a constant buffer which is the size of a single voxel (default value is 1).
VoxelSceneResolution is a uniform from a constant buffer which is the resolution of the voxel grid (for example for a 256*256*256 grid this value is 256).

My main idea comes from this cool presentation by NVIDIA.

Good luck!

• thank you for your answer, I meet some troubles in sending data from texture3d today. Do you have some idea about how to get data from texture3D? For example in directx, we use gVoxelList.SampleLevel(SamplerFilter, voxel_pos, mipmapLevel); How can I get pos of every voxel? – HUAQ Mar 10 '17 at 8:30
• Do you mean like this? worldPos = voxelization_center_worldpos + (voxel_pos * float3(2,-2,2) - 1) * voxelSize – János Turánszki Mar 10 '17 at 9:38
• finished! Thank you very much for your kindly help! – HUAQ Mar 10 '17 at 18:31

Raycasting projection is fundamentally different from regular triangle projection that is commonly used in most games today. Forget what you know about vertex shader projection at this point.

There is no need for you to render polygons at all - meaning you typically don't have a vertex shader stage for this (it's what called passthrough vertex shader, i.e. it doesn't do much). That also means the vertex shader doesn't really manage any transformations via model, view and project matrices, in the usual OpenGL/DirectX sense. (See more on what the vertex shader does do, below.)

Each ray is oriented by the CPU or compute GPU (not the vertex shader), according to where the player is looking, with some offset such that each ray represents a pixel on the screen; "look direction" is the centremost ray/pixel of the screen, while all other rays have a slight angular offset from that:

Now we "cast" the rays through the world and find where they collide with obstacles, whereupon we read the colour and write it to the texture position assigned to this ray.

Finally, the texture containing these colours is rendered to a fullscreen, textured quad which is the only thing that your vertex shader will actually render - you don't need to transform the whole world space. Instead you have transformed every ray individually at an earlier stage in the pipeline!

So because we are using individual rays to read the world, we don't do the usual OpenGL thing of projection matrices to transform triangles. Instead each ray is multiplied by some matrix or modified in some other way, and is then fired into the world to retrieve the colour at its screen pixel.

• Then again, I could just be referring to one style of voxel raycasting and maybe your sources are suggesting that you do this in a completely different way. Maybe someone will learn something from this, in any case. – Engineer Mar 5 '17 at 14:47