# Re: Bill-boarding oriented rectangle

This topic is 2115 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Continuing from this topic (don't want to be necroposting or anything so I opened a new one just in case), I tried to apply what you guys (thank you very much) told me to be the best way to render a 3D rectangle bill-boarding towards the camera while only rotating on his length axis, defined by two fixed points in the space. This way I'd be able to draw 3D sprites, particles, beams and stuff like that with ease.

From what I understood, I had to:

- take the directional vector (A) of the distance between the two points (I took p2-p1)

- take a directional vector (B) that goes from the camera to the line the points form (I took camera-p1)

- build three vectors: normalized A which I call X, normalized cross product (AxB) which I call Z, normalized cross product (ZxB) which I call Y, then rebuild the second vector with cross product (XxY) that still gets me Z

- the 3x3 matrix that I get out of these three vectors (X, Z, Y) is the orientation matrix that I need to apply to the rectangle in order for it to face the camera

- since DirectX matrices are 4x4, I assume to put in the values manually, so I use the orientation matrix as the first 3x3 values of the 4x4 one, adding the last row as the rectangle world position - just to be sure, I first initialize the 4x4 matrix as an identity

Summed up, I wrote this function:

D3DXMATRIX OrientationMatrix(D3DXVECTOR3 A, D3DXVECTOR3 B, D3DXVECTOR3 pos)
{
D3DXMATRIX m; D3DXVECTOR3 X, Y, Z;
D3DXMatrixIdentity(&m);

D3DXVec3Normalize(&X, &A); // x
D3DXVec3Cross(&Z,&A,&B);
D3DXVec3Normalize(&Z, &Z); // z
D3DXVec3Cross(&Y,&Z,&B);
D3DXVec3Normalize(&Y, &Y); // y
D3DXVec3Cross(&Z,&X,&Y);
D3DXVec3Normalize(&Z, &Z); // z-2

m._11=X.x;
m._12=X.y;
m._13=X.z;
m._21=Z.x;
m._22=Z.y;
m._23=Z.z;
m._31=Y.x;
m._32=Y.y;
m._33=Y.z;
m._41=pos.x;
m._42=pos.y;
m._43=pos.z;

return m;
}


And then I build and render the rectangle this way:

void BBStrip(D3DXVECTOR3 p1, D3DXVECTOR3 p2, D3DXVECTOR3 camera, float thickness, LPDIRECT3DTEXTURE9 texture, LPDIRECT3DDEVICE9 device)
{
device->SetTexture(0, texture);
device->CreateVertexBuffer(4 * sizeof(TVERTEX), NULL, TVERTEX::FVF, D3DPOOL_DEFAULT, &pVBuffer, NULL);
device->SetStreamSource(0, pVBuffer, 0, sizeof(TVERTEX));
device->SetFVF(TVERTEX::FVF);

D3DXMATRIX w; w = OrientationMatrix(p2-p1, camera-p1, p1);
//D3DXMatrixIdentity(&w);

pVBuffer->Lock(0, 0, (void**)&vert, 0);
vert[0]=TVERTEX::TVERTEX(abs(p2.x-p1.x),thickness*0.5,0,0,0);
vert[1]=TVERTEX::TVERTEX(abs(p2.x-p1.x),-thickness*0.5,0,1,0);
vert[2]=TVERTEX::TVERTEX(0,-thickness*0.5,0,1,1);
vert[3]=TVERTEX::TVERTEX(0,thickness*0.5,0,0,1);
pVBuffer->Unlock();

device->SetRenderState(D3DRS_LIGHTING, false);
device->SetTransform(D3DTS_WORLD,&w);
device->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
device->SetRenderState(D3DRS_LIGHTING, true);
pVBuffer->Release();
}


However, strange things happen. (if you already caught some basic math errors or typos, you're probably thinking "duh" at this point)

To try it out, I generated a bunch of random points around the world origin and drew particles between it and them.

At first it seems fine, but the rectangles happen to be stretched when the points are aligned along the world Z axis.

The more they are aligned on the Z axis, the shorter the particles are. Also, they apparently stretch towards the first of the passed points, so switching the points either stretch the particles towards the random points or the origin.

This is what it looks like:

(point 1 is random, point 2 is 0,0,0)

So... What the flying Jupiter am I doing wrong here? XP

EDIT: Oh, if I don't to the rebuilding of Z, it apparently gives me better results.

Edited by Banderi

##### Share on other sites

So... What the flying Jupiter am I doing wrong here? XP

obviously, the matrices are not being created correctly.

a glance at the previous thread seems to show that kryzon's on target as to how to do it.

although i'd probably do it with d3d instead of directly creating matrices (my linear is too rusty, and i don't have my textbook anymore).

the vector approach works, and is probably the most elegant once its simplified as much as possible, but can be confusing.

seems these days that about twice a week now i'm wishing i still had my linear algebra book.

the key part of kryzon's algo is he has the part where you align the quad's horizontal axis to the line connecting p1 and p2.

like most 3d analytical geometry problems there are number of ways to go about solving it.

but again, kryon's approach seems to the be most straight forward (if not the most intuitive).

##### Share on other sites

Your vector names are somewhat confusing... using names like "forward", "beam direction", "cam to line" would probably help remember where they are all pointing to.

"- take the directional vector (A) of the distance between the two points (I took p2-p1)"

Let's call this rayDir

"- take a directional vector (B) that goes from the camera to the line the points form (I took camera-p1)"

Call it rayToCam or even "billboardNormal"

"- build three vectors: normalized A which I call X"

I'll it normRayDir

"normalized cross product (AxB) which I call Z"

Or "tmp", "beamRight"

"normalized cross product (ZxB) which I call Y"

Which doesn't seem to make sense and should probably be ZxA, or tmp x rayDir, because you want to create a normal for the billboard that intersects the "line of view" (to abuse the term a little).

"then rebuild the second vector with cross product (XxY) that still gets me Z"

Why?

Your matrix needs "right", "up" and "forward" (x,y,z). for convenience, equal "forward" with "where the beam is going", "up" with "normal" or "pointing roughly towards the camera" and "right" with "that vector I need to fix my normal".

"forward" is p2-p1

"tmp up" is cam - p1

"right" is "forward" x "tmp up"

"up" is "right" x "forward"

My cross products might be backward, I always found trial and swap easier than wrapping my head around it.

##### Share on other sites

@Norman

Eh, I'd love for D3D APIs, but nobody suggested there were any, so I thought there weren't and tried the direct math approach..

Now that I think of it.. did I also forget to align the quad to the axis before creating the matrices? Uhm, I've gotta check.

@Trienco

Well, I somewhat found symbols or quick names way easier to read and remember, but that's just the way I'm used to.

I'm sorry if I made so much confusion between the operation, I tried my best to follow what you suggested but it seems I failed.. and I still don't understand how matrices work, so is easy for me to erroneously switch vectors in cross products. xD

I'll change my code and give it a try!

EDIT: Ehm, by the way, I did what you said, "and after that use another cross product between the first and third vector to "fix" the second one"

The second and the third vectors are X and Y... unless your order was different from the one Kryzon was basing himself upon (X, Z, Y).

EDIT2: Oh? Apparently, I'd already actually got everything alright. I changed the code and the result is exactly the same.. so the error is somewhere else, and my code is equivalent to your solution, although semantically (or conventionally) incorrect? Math rules!

EDIT3: Yup. What was wrong is I was building the points on length (or "forward") = abs (p1.x - p2.x) instead of actually building the distance between them. What a stupid error...

Anyways, it works just fine now! Thanks a bunch you guys! ;)

Edited by Banderi

• 21
• 13
• 9
• 17
• 13