Applying scorch decals

Sage
Posts: 1,199
Joined: 2004.10
Post: #1
Some months ago I implemented a crude scorch damage system for my game, where I apply quads ( with a scorch texture ) to terrain or other geometry. I apply N quads, randomly scattered around the damage location -- each set to be coplanar to the triangle beneath it, and each is drawn with alpha 1 / N -- so the result is more or less effective.

Well, it's actually *less* effective. There's a lot of "overhang" where a quad is larger than the triangle beneath it and hangs off the edge, or goes under an adjacent triangle. When it looks good, it looks pretty good.

You can see pretty good looking sortching on the ground here

But here, close up, you can see overhang

So, what I'm wondering is how you guys would do this.

Right now, I'm investigating an approach where I get all the triangles that intersect a small spherical volume ( the damage radius ) and then I'll tessellate a bunch of triangles to map directly to the terrain or other object. That ought not be too hard, though I suspect robust texture coordinate generation will be non-trivial ( unless I limit myself to doing this on heightmapped terrain, in which case it will be dirt-simple )

It occurs to me that projected texturing might be the answer. But, I know *nothing* of projected texturing. For example, do you need a free texture unit for *each* projected texture? I would need hundreds then, since I've got a lot of scorch damage in my game, as you can see from the first ( "Death from above" ) screenshot.

Basically, how would you guys approach this?
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #2
having done some research on projected texturing, it looks like I have to draw in multiple passes, one for each projection. Is that right? If so, I could limit the drawing to those triangles which intersect the damage sphere.

But then, I still know nothing of projected texturing. I find plenty of source code, but essentially nothing that describes it from a 10,000 foot perspective in pseudocode.
Quote this message in a reply
Member
Posts: 79
Joined: 2002.08
Post: #3
The 3D Game Programming book by Eric Lengyel shows how to do this. Basically the quad is split into triangles along the edges of the underlying mesh and each triangle is placed in the same plane as the mesh triangle below it. Works good. Was not too difficult to implement.

Looking at the stuff in the book now and it actually doesn't give too much info about it. I found some example code somewhere when I implemented my decal class but now I have no idea where I got it from. I did this a few years ago.

KenD

CodeBlender Software - http://www.codeblender.com
Quote this message in a reply
Member
Posts: 79
Joined: 2002.08
Post: #4
One more note. It's possible I found the code in one of Game Programming Gems books but I don't have them here right now so I can't take a look.

KenD

CodeBlender Software - http://www.codeblender.com
Quote this message in a reply
Member
Posts: 184
Joined: 2004.07
Post: #5
TomorrowPlusX Wrote:Right now, I'm investigating an approach where I get all the triangles that intersect a small spherical volume ( the damage radius ) and then I'll tessellate a bunch of triangles to map directly to the terrain or other object. That ought not be too hard, though I suspect robust texture coordinate generation will be non-trivial ( unless I limit myself to doing this on heightmapped terrain, in which case it will be dirt-simple )

This basic idea is probably the best way to go. If you try to do this in one pass you will be limited by the number of texture units, so you might as well draw each decal separately. I assume you're trying to simulate a mark from sort of spherical explosion, so maybe you could just find what triangles the sphere intersects, and then for the texture coordinate at each vertex of the triangles you could assign based on how deeply the vertex penetrates the sphere. You could even use a 3d texture, though I doubt it would look much better.
If you doing those sort of decals on more than terrain you could potentially do the exact same thing except draw every triangle- you could even use a vertex shader or some more simple texcoord generation so you don't have to send a texcoord array to the video card. That might help with the terrain case as well if you break the terrain into chunks.
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #6
I've decided to pursue the tessellation approach, since it involves match and processes which I understand Wink

Also, it occurred to me that with texture clamping set I can use phydeaux's premise of just setting texture coordinates as distance from the damage origin. Then I don't need to do anything hairy like subdivision of the scene triangles to get optimal texture coordinate assignment.

I'll keep you all posted, probably with stupid questions. Right now I'm hacking up a test state for my game where I can quickly prototype the code.
Quote this message in a reply
Member
Posts: 196
Joined: 2003.10
Post: #7
Wow, neat screenshots. When will you have something we can play around with?
Quote this message in a reply
Member
Posts: 79
Joined: 2002.08
Post: #8
The implementation for the decal stuff is in the "Game Programming Gems 2" book. The chapter is written by Lengyel so it's basically the same as in his book and the CD contains an implementation of it.

KenD

CodeBlender Software - http://www.codeblender.com
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #9
So, over the weekend when I had time ( had to do easter with my GF's family ) I managed to get tex-genned texture mapping working for top-down projection. E.g., the setup basically looked like this ( leaving out a lot of other junk )

Code:
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );

glTexGenfv( GL_S, GL_OBJECT_PLANE, vec4( 1, 0, 0, -_position.x ).v );
glTexGenfv( GL_T, GL_OBJECT_PLANE, vec4( 0, 1, 0, -_position.y ).v );

glMatrixMode( GL_TEXTURE );
{
    glLoadIdentity();
    glScalef( 1.0 / scale, 1.0f / scale, 1.0f );
    glTranslatef( scale * 0.5f, scale * 0.5f, 0.0f );
}
glMatrixMode( GL_MODELVIEW );

Where scale is the size of the texture in world units ( calculated as distance from the center of the damage sphere ) and _position is the location in world units of the damage sphere.

This works *great* so long as I'm only concerned with top-down projection.

What I've been trying to figure out, however, is how to get an arbitrary projection to work correctly. By arbitrary projection, I mean projection against an arbitrary plane, as in something other than ( 0,0,1,0 ).

So far, I have tex gen's axes for S and T working for an arbitrary plane. The trouble is figuring out an offset so the texture is centered around the vector along which I'm projecting.

This is what I'm doing, and basically what's failing is the fourth component of the GL_OBJECT_PLANE parameter, the offset of the plane from the origin. I'm drawing a blank as to how to calculate this value.

For reference, _position is the center of the damage sphere, & closestProjection is an "optimal" center for the texture map in world space.

Code:
//make a normalized vector from texture center to damage origin
vec3 projectionDirection( closestProjection - _position );
projectionDirection.normalize();

vec3 posY( 0, 1, 0 );
vec3 sAxis, tAxis;

//make perpendicular s & t axes
sAxis.cross( projectionDirection, posY );
sAxis.normalize();

tAxis.cross( sAxis, projectionDirection );
tAxis.normalize();


glDisable( GL_LIGHTING );
glDisable( GL_CULL_FACE );
glDisable( GL_DEPTH_TEST );

glPolygonMode( GL_FRONT, GL_FILL );

glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, _texID );
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );

glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );

glMatrixMode( GL_TEXTURE );
{
    glLoadIdentity();
    glScalef( 1.0 / scale, 1.0f / scale, 1.0f );
    glTranslatef( scale * 0.5f, scale * 0.5f, 0.0f );
}
glMatrixMode( GL_MODELVIEW );
            
/*
     THIS CODE IS FOOBAR...
     I'm trying to come up with plane offset to center the texture around closestProjection.
*/
float sOffset = sAxis.x * closestProjection.x + sAxis.y * closestProjection.x + sAxis.z * closestProjection.x;
float tOffset = tAxis.x * closestProjection.y + tAxis.y * closestProjection.y + tAxis.z * closestProjection.y;

glTexGenfv( GL_S, GL_OBJECT_PLANE, vec4( sAxis.x, sAxis.y, sAxis.z, -sOffset ).v );
glTexGenfv( GL_T, GL_OBJECT_PLANE, vec4( tAxis.x, tAxis.y, tAxis.z, -tOffset ).v );

As far as I can tell the *axes* are correct, e.g., a circle texture projected against a nearly vertical surface is correctly applied, as in it looks circular when the camera is along the normal vector of the surface. But, the trouble here is offsetting the translation in the texture matrix, or as I'm trying here offsetting along the fourth component of the plane equation, so the texture is centered around the chosen point in world space.

I may just have to buy "Game Programming Gems 2"... but any help from you guys would be appreciated.

Also, one more thing, this code is written to prototype the idea, not to be an example of efficiency! I'll make it fast *after* I get it working Wink
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #10
Oh, and to blobbo: I'm getting close to posting it in the work in progress forum. I have a few bugs to trounce, first.
Quote this message in a reply
Member
Posts: 184
Joined: 2004.07
Post: #11
I think it might be easier to understand if instead of scaling your matrix in the GL_TEXTURE matrix, you inherently scale your texture by using different plane GL_OBJECT_LINEAR parameters- I think it's easier to understand because you're then working on object space (since the plane is in object space.) Then, you only have to translate the texture coordinates from the origin to closestProjection (which I think you are doing correctly by taking the dot product of each axis and closestProjection.)

I think the math is a little harder to work out if you want to scale the 2d texture coordinates directly.

(edit)
It also occured to me you could do this without using any GL_TEXTURE matrix operations at all since you essentially have an offset with the w coefficient in the plane equation. It may be easier to compute without involving any texture transformations.
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #12
You're right, phydeaux, I can eliminate the texture matrix operations just by scaling the x,y,z components of the object plane parameters.

That said, I'm still examining how exactly I am to calculate the w component.

So far, the best thing I can come up with is this. To get w, I need to know the position of the point "closestProjection" on the plane, in the plane's 2d coordinate system. That's the offset I need to get the texture to center correctly.

So, to calculate this, what I need to do is to figure out how to pack a matrix to un-transform an arbitrary plane ( a,b,c,d ) to, for example, the z plane ( 0,0,1,0 ). Then, I'd multiply "closestProjection" by that matrix, thereby putting it on z = 0. I could then use its x & y values as the w parameters for the GL_OBJECT_PLANE.

The issue then is how to come up with a matrix to untransform a plane. Does anybody here know how to do this? Or where I can find out how? I did some googling, but it turned up very little, except for a post on flipcode's forums but it was a little too ivory-tower and I couldn't wrap my soft, squishy brain around it.
Quote this message in a reply
Member
Posts: 184
Joined: 2004.07
Post: #13
TomorrowPlusX Wrote:So far, the best thing I can come up with is this. To get w, I need to know the position of the point "closestProjection" on the plane, in the plane's 2d coordinate system. That's the offset I need to get the texture to center correctly.

That's correct, but I think it's a lot easier than having to do anything particularly complicated with matrices. You just want to find the projection on the s-t plane, so you would just take the dot product of closestProjection and s-axis to find the offset for s, and the same for the t-axis.

Now, you still want to scale it and translate it, but I think the easiest way to do that is still work in the s/t coordinate frame. To scale, you'd simply scale the x,y,z coefficients of GL_OBJECT_PLANE, and then to translate to center, you'd just add -0.5 to the w coefficient. This should work because you should be subtracting half a unit in the s or t direction.
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #14
I can't believe I overlooked the obvious use of the dot product against the s & t axes to get the position. Thanks for showing me the way, phydeaux, if I could, I'd buy you a beer.

It works! Now, I've just got to clean it up, and add some special code to handle the exceptional circumstance that the origin is 0,0,0 ( everywhere else it works, correctly ). And then I'll pull out the texture matrix code, since it's overkill.

Then, of course I've got to make it generic... but that's easy.
Quote this message in a reply
Member
Posts: 184
Joined: 2004.07
Post: #15
Congrats- by the way, your game looks great so far.
Quote this message in a reply
Post Reply