Bill-boarding oriented rectangle

Started by
17 comments, last by Trienco 10 years, 9 months ago

Ok, here's a more complicated question. tongue.png

I have two 3D points which I have to "connect" with a rectangle.. sort of what I'd do drawing a LPD3DXLINE between them, however it needs to be a 3D mesh (i.e. perspective and distance resize it). The thing is, it also needs to bill-board itself towards the camera, and here I really don't know how to do it..

I could build a sin/cosine function that rotates 4 points around 2 vectors given a width, that's easy.. but how do I take care of the bill-boarding too?

I really don't have a clue about this one..

EDIT: here's an image as example...

g1WXL1s.png

Advertisement

The bilboard rotation is computed based on the direction of the object looking at the camera. If you have a look at function in your code, you can recompute the up,right and look vector based on the camera position and the object that is been bilboard position.

I don't have any "look at function".. but even if I had, I fail at math at this point, I don't have a clue about how the matrices and the vector computing actually work for the transformations, the projections, etc.. I just know how to apply them with DirectX APIs, up to this limit.

So not be rude at all but.. could you be a bit more specific on how to do this? '^^

looked challenging at first, but its not that bad.

the midpoint between your 2 points is where to draw the billboard.

its coordinates are just the average of the coordinates of the two points p1 and p2:

mid.x=(p1.x+p2.x)/2;

mid.y=(p1.y+p2.y)/2;

mid.z=(p1.z+p2.z)/2;

then you need a billboard quad.

if is just something simple like a 10x10 quad, no problem.

if the distance from p1 to p2 defines the width of the billboard, its a bit more work.

so the next question is: what size quad do you want to draw?

once you have a quad mesh and a point to draw at, aiming it at the camera is trivial, billboard xr = cam xr + 180, billboard yr = - cam yr, as i recall.

so, what size quad do you need?

its not too hard to create / scale a quad based on the distance between p1 and p2 if that's what you need.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

If the quad is the rectangle, it needs to be the distance between the points by a fixed length ("thickness"), as if I was to draw a textured stripe between them.

So yeah, it basically would need to be scaled according to their distance while maintaining its other dimension.

Make a quad, position at midpoint of p1 and p2. (trivial)

Scale it on lets say X by distance between p1 and p2. So the position matrix looks like:

(p1-p2).magnitude(), 0 , 0 , 0

0 , 1 , 0 , 0

0 , 0 , 1 , 0

midpoint.x , midpoint.y, midpoint.z, 1

(thats row major i think. bottom row is position)

Now you just need the matrix that looks from billboard to camera and use some math to combine them (multiply? in my own matrix code i need to do rotation and translation separately for it to work but it was written by me so... yeah.)

For the rotation matrix youll need:

-X axis direction (direction from midpoint/p1 to p2)

-Y axis direction (cross the above and the below vectors (X axis dir and Z axis dir))

-Z axis direction (direction from midpoint to camera)

So now we only need the direction from midpoint to camera, which is simply taking the unit vector from their difference.

What you need to know:

Matrices:

[local X axis direction] ,0

[local Y axis direction] ,0

[local Z axis direction] ,0

[position ] , 1 //1 means position 0 means vector/direction

Cross product:

Takes 2 vectors, gives a vector that is perpendicular to both (imagine the 2 vectors form a plane. The result is the normal of the plane. The 2 input vectors dont need to be perpendicular with each other!)

Magnitude/distance:

sqrt(xDifference^2 + yDifference^2 + zDifference^2)

Unit vector/direction:

Take the difference of 2 vectors (a-b), divide by the magnitude of the result. Gives direction vector with length 1.

That should be all that you need.

o3o

You know the object position and you know the camera position. So what you need to do is recompute the right up and look vector of the object based on the camera position relative to the object. That way the object will always look at the camera no matter what the camera position is. You do not need to mock around with the vertices position at all. I have attached a piece of code from my engine that will do just that. If you have any question, please feel free to ask. Another thing to know is that my matrix is row major. So your basic Axis's are row based not column based.

//**************************************************
//Build an billboard matrix.
//Using your own up vector.
//**************************************************
Matrix4x4 Matrix4x4::BillboardLookAt(const Vector3& objectPosition,const Vector3& target,const Vector3& up)
{
Vector3 lForward = (target-objectPosition).normalized();
Vector3 lRight = Vector3::Cross(up,lForward).normalized();
Vector3 lUp = Vector3::Cross(lForward,lRight).normalized();
return Matrix4x4::From(lRight,lUp,lForward,Vector3::one,objectPosition);
}

//**************************************************
//Build an matrix from a given set of vectors.
//**************************************************
Matrix4x4 Matrix4x4::From(const Vector3& right,const Vector3& up,const Vector3& forward,const Vector3& scale,const Vector3& position)
{
Matrix4x4 m = Matrix4x4::identity;
m.Array[0]=right.x*scale.x;
m.Array[1]=right.y*scale.x;
m.Array[2]=right.z*scale.x;
m.Array[4]=up.x*scale.y;
m.Array[5]=up.y*scale.y;
m.Array[6]=up.z*scale.y;
m.Array[8]=forward.x*scale.z;
m.Array[9]=forward.y*scale.z;
m.Array[10]=forward.z*scale.z;
m.Array[12]=position.x;
m.Array[13]=position.y;
m.Array[14]=position.z;
return m;
}

..sweet Jesus, my brain exploded. Hold on a sec *picks up brain*

@BornToCode

This kind of bill-boarding is not what I require, and I've also achieved it through a waaaay simpler way (same rotation matrix of the camera applied on the mesh).

In other words, if I apply the matrix to a rectangular mesh, it rotates it toward the camera with the original position fixedly projected on a plane. That's not supposed to happen in my case, as the rectangle has to be a connection between two 3D points ;)

@Waterlimon

Not to be rude.. but I just don't get a single word.. as I said, I HORRIBLY fail at math in this point..

Could you make it simpler? If possible, can you use DirectX APIs to do that?

I am trying to follow Waterlimon pseudo but can't get it to work right:


D3DXVECTOR3 start(0.0f, 0.0f, -5.0f);
    D3DXVECTOR3 end(0.0f, .0f, 5.0f);
    D3DXVECTOR3 mid = (end + start) * 0.5f;

    D3DXMATRIX lWorld, lRot, lTra, lWVP;
    D3DXMatrixTranslation(&lTra, mid.x, mid.y, mid.z);
    lTra.m[0][0] = D3DXVec3Length(&(end - start));
    D3DXMatrixIdentity(&lRot);
    D3DXVECTOR3 xDir = end - start;
    D3DXVec3Normalize(&xDir, &xDir);
    D3DXVECTOR3 zDir = cam->Position - mid;
    D3DXVec3Normalize(&zDir, &zDir);
    D3DXVECTOR3 yDir;
    D3DXVec3Cross(&yDir, &xDir, &zDir);
    D3DXVec3Normalize(&yDir, &yDir);
    lRot.m[0][0] = xDir.x; lRot.m[0][1] = xDir.y; lRot.m[0][2] = xDir.z;
    lRot.m[1][0] = yDir.x; lRot.m[1][1] = yDir.y; lRot.m[1][2] = yDir.z;
    lRot.m[2][0] = zDir.x; lRot.m[2][1] = zDir.y; lRot.m[2][2] = zDir.z;
    lWorld = lRot * lTra;
...

Quad doesn't scale along start-end point and orientation is wrong.

I might have a mistake there somewhere since matrices are kind of blurry to me too.
-Is the majorness correct? (rows being the vectors)
-Is the matrix multiplication order correct? (i usually have problems with the translation part so that might be wrong)

o3o

This topic is closed to new replies.

Advertisement