🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Billboarding a line

Started by
14 comments, last by irreversible 6 years, 10 months ago

Let me preface this by acknowledging that I suck at math.

I'm trying to billboard a volumetric spline ribbon with the option to keep it constant width. I don't want to project the end result, because I still want it to be depth tested. Here's the relevant bit from my geometry shader with my own comments on what I think the math does. I'm pretty sure I'm wrong, though:


	// seg has two points, a and b, whose position is in world space

	// convert the end points to view space
	vec4 vsp1 = gd_matModelView * vec4(seg.a.position.xyz, 1);
	vec4 vsp2 = gd_matModelView * vec4(seg.b.position.xyz, 1);

	// direction is an interpolated normal along the spline at knots (seg.a.position and seg.b.position);
	// convert these to view space as well
	vec4 vsn1 = gd_matModelView * vec4(seg.dir1, 1);
	vec4 vsn2 = gd_matModelView * vec4(seg.dir2, 1);
		
	// project and normalize
	dir1 = vec3(normalize(vsn1.xy), 0);
	dir2 = vec3(normalize(vsn2.xy), 0);

	// this part is definitely wrong, but I'm not sure what it should be; the idea is to avoid
	// segments whose end points change orientation from becoming twists (see below screenshot).
	// I'm basically trying to smooth out the discontinuity that arises at oblique angles.
	if(dot(dir1, dir2) < 0)
		dir2 = -dir2;
	
	// calculate the right vectors in view space
	vec3 n1 = vec3(-dir1.y, dir1.x, 0);
	vec3 n2 = vec3(-dir2.y, dir2.x, 0);
                                 
                                 
                                 
	....
                                 
                                 
	// the segments are issued as:
	// 	vsn1 + n1 * thickness1
	//	vsn1 - n1 * thickness1
	// 	vsn2 + n2 * thickness2
	// 	vsn2 - n2 * thickness2
                                 
	....

	// and finally, vertices are emitted after converting to clip space:
	gl_Position	= gd_matProjection * position;
                                 

There are several issues here, most of which are hilighted in the screenshot below. For this example I set the line thickness to something constant. The thickness is not adjusted for by distance.

ribbon.png.f8850466b537a3fa2dcb90d7258a08c4.png

From most directions the ribbon actually seems fine, but when the camera points increasingly down the direction of the spline:

1) the ribbon generates a twist

2) projection does not seem to work the way my little brain assumes it should

 

What am I doing wrong? :)

 

Advertisement

I'm not totally sure what your after, but it looks like the line thickness is the exact same throughout the entire thing, it appears to be 1 pixel thick all the way through.

If you don't want it to look like its smaller the further away it gets, could you try an orthographic projection matrix instead of a perspective projection?

6 minutes ago, iedoc said:

I'm not totally sure what your after, but it looks like the line thickness is the exact same throughout the entire thing, it appears to be 1 pixel thick all the way through.

If you don't want it to look like its smaller the further away it gets, could you try an orthographic projection matrix instead of a perspective projection?

Just to clarify, by thickness I mean width :). The line has no actual volumetric thickness - it's just a flat ribbon.

Ah OK, what about that twist? You don't want the twist?

5 minutes ago, iedoc said:

Ah OK, what about that twist? You don't want the twist?

No, I want all segments to be billboarded (facing the camera) so that the line is viewable from any direction and the desired width/thickness is maintained at all times. Right now my code fails to billboard the segments properly and also generates an undesirable twist.

this won't help the twist issue, but if you change gd_matProjection to be an orthographic projection, everything will appear the same size no matter how far away from the camera it is

EDIT: I just realized what you are talking about with the twists. You want the direction to be reversed once it's facing away from the camera, so once it reaches the point where its about to face away from the camera, the direction is reversed

1 minute ago, iedoc said:

this won't help the twist issue, but if you change gd_matProjection to be an orthographic projection, everything will appear the same size no matter how far away from the camera it is

Like I said in my original post, I want to keep the line in 3D as I want it to be depth tested. Orthographic projection doesn't help me here.

I'm probably still not understanding 100%, but orthographic projection would still get you depth. the only difference between orthographic projection and perspective projection is that in perspective projection, things further away appear smaller. depth is still written to the depth buffer in both of them.

1 hour ago, iedoc said:

I'm probably still not understanding 100%, but orthographic projection would still get you depth. the only difference between orthographic projection and perspective projection is that in perspective projection, things further away appear smaller. depth is still written to the depth buffer in both of them.

Okay - that would be an alternative to just scaling things based on distance in the shader. I prefer scaling things manually anyway, because that does not entail changing the projection mode on the client side. That being said, getting things to appear constant size is secondary right now as my primary concern is that my math for calculating the billboarded segments isn't working in the first place.

If you could tell me what is still unclear about my initial query, perhaps I could elaborate?

I'm not sure exactly what your doing in your geometry shader to get the final position, but it looks to me like your not taking the camera position into account. For the dot product, you should dot the normal of your segments with the camera-to-segment direction.

something like this maybe:


dot(segmentNormal, camPosition - segmentPosition) > 0) // reverse segment direction because segment is now facing away from camera

 

This topic is closed to new replies.

Advertisement