0
\$\begingroup\$

Using XNA, c#.

I'm writing a stellarium-type of program-- well, trying to :-) -- and I have a 'sun' texture that I'll be pasting onto triangle primitives. I'll also be floating some text above each node, which will probably be on the primitive as well.

My issue is how to force the primitives to always be facing the camera, despite rotations and movements of the viewport. I'm going through my XNA programming books, but there's no obvious solution. I'd appreciate a pointer in the right direction.

Note: I'm not using 3D models, so AFAIK there's no Matrix to work with. I have 3 vector3's that define a triangle, and I guess I have to modify their addresses on each update to face the camera. That seems pretty intensive, so I'm thinking I may be missing something obvious.

\$\endgroup\$
  • \$\begingroup\$ Further reading indicates that this can be done through billboarding. Unfortunately, I haven't been able to find a SIMPLE code sample that illustrates how to do this. Can it even be done using the default shader? All the samples I've been able to find are using a custom shader. \$\endgroup\$ – Donutz Mar 8 '15 at 21:15
1
\$\begingroup\$

Assuming you created your triangle strip in Model Space.

Use Matrix.CreateBillboard to create a transformation matrix that will rotate your triangle strip towards the camera. Note the below values should be in World Space.

public static Matrix CreateBillboard (
         Vector3 objectPosition,
         Vector3 cameraPosition,
         Vector3 cameraUpVector,
         Nullable<Vector3> cameraForwardVector
)

Apply this matrix to using Vector3.Transform(point, billboardMatrix); before applying the transformations you use to convert into world space (you might not have gotten this far yet).

PS: Even if you are not using models familiarize yourself with the existing spaces it will save you a lot of headache later. Also people use HLSL shaders because billboarding is typically used for things like grass, trees, particles and as such performance is major a concern.

\$\endgroup\$
0
\$\begingroup\$

The default shader is not designed for this. You will need either a custom shader or need to manually update the positions. This second option will have low performance, especially for large numbers of stars.

The standard shader is:

// in_p is the position from the vertex buffer
p_camera = modelview * in_p
out_p = projection * p_camera
// out_p goes to rasterizer as clip-space position

The shader you need is:

p_camera = modelview * in_p
// in_uv is in [0,1]x[0,1]
// in_size is a scalar
p_camera += vec4((in_uv.xy-vec2(0.5,0.5))*in_size, 0, 0);
p_out = projection * p_camera

Then you need to set up your vertex data so that in_p is the same position (the center) of your stars, in_uv encodes where on the face the vertex is (so if you are using two triangles to make a quad, you would have (0,0), (0,1), (1,0), and (1,1)), and in_size is the diameter of the star. You will have say four vertices in your buffer all with the same in_p and in_size, but the four different uv coords, and the index buffer will make two triangles out of them. This repetition is not an performance concern.1 This works because in camera space, adding to x or y will move the vertex orthogonally to the view direction.

Be careful with backface culling and accidentally inverting the order of your faces. If your modelview matrix is only a view matrix, i.e. only have rotations and translations, then sizes in camera space and world space match up. A final issue is this technique will have the textures always facing up from the cameras perspective, which will look weird if they are not radially symmetric.

1 If it is, you are doing something else very wrong, like trying to draw many more stars than pixels or killing your vertex pipeline. If you really feel you need to solve this, you will need geometry shaders.

\$\endgroup\$
0
\$\begingroup\$

Try see this tutorial, it can be what are you looking for.

P.S. I'm test my implementation of it with 1,000,000 enderman eyes (original 16x16 pixels texture) and performance was pretty good.

\$\endgroup\$

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.