Drawing billboard on mesh edges

Started by
6 comments, last by belfegor 10 years, 11 months ago

Okay, I'm able to draw billboards on mesh for bullet impact.

Sometimes, the player will shoot at the edges which will result in undesired results:

[attachment=15644:unreal.png]

How do I fix it?

Maybe I should bend the billboard to make it appear on 2 triangles?

Advertisement

Why are you using billboards instead of decals ?

To fix this, you would need to compute the distance from the point of impact (that you already have) from the nearest edge. But not just any triangle edge (since the inner part of the mesh has plenty of those) - but you'd need to keep a separate outline edges.

For a full solution, you'd have to compute a silhouette mesh every frame and check against that - but that'd be an overkill.

It'd be easier if you just kept the hard edges in a separate array (you can compute them based on the angle between two neighbouring faces).

Then, during a check, just move the point of impact in the opposite direction of the vector connecting the point of impact with the edge.

BTW, plenty games just leave it as it is - since it's simply not so important to warrant the implementation of the above.

In the same time it will take you to implement the above, you can implement few more features that will make the game better (compared to a simple visual artifact that few people will notice in the heat of the game).

VladR My 3rd person action RPG on GreenLight: http://steamcommunity.com/sharedfiles/filedetails/?id=92951596

1. What are decals? what is the difference between billboards and decals?

2. How do I detect if the billboard will reach the edge so I don't draw it?

I was wandering when you gonna ask this question. biggrin.png

This is pretty hard-core to get right.

One of possible solutions is when you ray-cast/pick your mesh, you need to obtain list of triangles that are intersecting with decal aabb (or sphere), Bullet physics might have some functions to do that.

Then you need to clip those triangles against this aabb (if you mind fillrate problems).

I got this far:

decals1.jpg

Note, this is just to show how it looks like. Red outlined is a list of triangles that intersects aabb, the other thing in the middle are clipped triangles against aabb (blending disabled to show), additionally i skip triangles that are fabs(dot(hitnormal, trinorm)) < threshold so those texcoord stretching is not seen.

You might wanna look at Overgrowth article about projected decals.

Happy googling.

@belfegor: Right now the easiest way to fix this problem is to not draw the billboard when it's too close to the edge, how do I detect if it's very close to the edges?

I'll take a look at decals, but I want to first fix the problem then I will see possible ways for improvement.

I don't know easy/fast way to check when "billboard" is around edge.

I would go brute force:

1. Obtain raycast hit point and triangle normal that was hit

2. Make AABB from 4 points of your "billboard"

3. Make 6 planes from AABB

4. Go thru each triangle on mesh and test each of 3 points against planes to build list of triangles that "belong" to AABB

5. Test collected triangles normals against hit triangle normal


normalize( HitTriNrm );
for each tri
    triNrm = getTriNormal( tri );
    normalize( triNrm );
    if( dot(triNrm, HitTriNrm) < 0.6f ) // there is a hard edge
            do not add "billboard"
            break;
Although I got the idea, I don't understand how to do number 2 and 3 exactly, how do I create AABB from 4 points of my billboard? and how do I make 6 planes from AABB?

2.

struct AABB
{
    D3DXVECTOR3 minPt;
    D3DXVECTOR3 maxPt;
};
 
D3DXVECTOR3 billPts[4];
...
AABB bb;
bb.minPt = D3DXVECTOR3(FLT_MAX, FLT_MAX, FLT_MAX);
bb.maxPt = D3DXVECTOR3(FLT_MIN, FLT_MIN, FLT_MIN);
for(int i = 0; i < 4; ++i)
{
    // check min
    if(bb.minPt.x > billPts.x) bb.minPt.x = billPts.x;
    if(bb.minPt.y > billPts.y) bb.minPt.y = billPts.y;
    if(bb.minPt.z > billPts.z) bb.minPt.z = billPts.z;
 
    // check max
    if(bb.maxPt.x < billPts.x) bb.maxPt.x = billPts.x;
    if(bb.maxPt.y < billPts.y) bb.maxPt.y = billPts.y;
    if(bb.maxPt.z < billPts.z) bb.maxPt.z = billPts.z;
}

3.

struct _Plane
{
    float nx;
    float ny;
    float nz;
    float d;
};
 
_Plane PlaneFromPointNormal(const D3DXVECTOR3 &Pt, const D3DXVECTOR3 &Normal)
{
    _Plane Result;
    D3DXVECTOR3 NormalizedNormal;
    D3DXVec3Normalize(&NormalizedNormal, &Normal);
    Result.nx = NormalizedNormal.x;
    Result.ny = NormalizedNormal.y;
    Result.nz = NormalizedNormal.z;
    Result.d = -D3DXVec3Dot(&Pt, &NormalizedNormal);
    return Result;
}
 
std::array<_Plane, 6> ExtractPlanesFromBBox(const AABB* bb)
{
    std::array<_Plane, 6> out;
    D3DXVECTOR3 center = (bb->maxPt + bb->minPt) * 0.5f;
    D3DXVECTOR3 extent = (bb->maxPt - bb->minPt) * 0.5f;

    // up
    D3DXVECTOR3 ptUp  = center + D3DXVECTOR3(0.0f, extent.y, 0.0f);
    D3DXVECTOR3 nrmUp = center - ptUp;
    out[0] = PlaneFromPointNormal(ptUp, nrmUp);

    // down
    D3DXVECTOR3 ptDown  = center + D3DXVECTOR3(0.0f, -extent.y, 0.0f);
    D3DXVECTOR3 nrmDown = center - ptDown;
    out[1] = PlaneFromPointNormal(ptDown, nrmDown);

    // left
    D3DXVECTOR3 ptLeft  = center + D3DXVECTOR3(-extent.x, 0.0f, 0.0f);
    D3DXVECTOR3 nrmLeft = center - ptLeft;
    out[2] = PlaneFromPointNormal(ptLeft, nrmLeft);

    // right
    D3DXVECTOR3 ptRight  = center + D3DXVECTOR3(extent.x, 0.0f, 0.0f);
    D3DXVECTOR3 nrmRight = center - ptRight;
    out[3] = PlaneFromPointNormal(ptRight, nrmRight);

    // back
    D3DXVECTOR3 ptBack  = center + D3DXVECTOR3(0.0f, 0.0f, -extent.z);
    D3DXVECTOR3 nrmBack = center - ptBack;
    out[4] = PlaneFromPointNormal(ptBack, nrmBack);

    // front
    D3DXVECTOR3 ptFront  = center + D3DXVECTOR3(0.0f, 0.0f, extent.z);
    D3DXVECTOR3 nrmFront = center - ptFront;
    out[5] = PlaneFromPointNormal(ptFront, nrmFront);

    return out;
}

You'll need this also:

// plane - point relationship
float PlaneDotCoord(const _Plane* p, const D3DXVECTOR3* c)
{
    return ( (p->nx) * (c->x) + (p->ny) * (c->y) + (p->nz) * (c->z) + (p->d) );
}
result > 0 - in front of plane
result < 0 - back of plane
result == 0 - on plane

Happy copy/pasting. biggrin.png

This topic is closed to new replies.

Advertisement