Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Source engine styled rope rendering

I am creating a 3D graphics engine and one of the requirements is ropes that behave like in Valve's source engine.

So in the source engine, a section of rope is a quad that rotates along it's direction axis to face the camera, so if the section of rope is in the +Z direction, it will rotate along the Z axis so it's face is facing the camera's centre position.

At the moment, I have the sections of ropes defined, so I can have a nice curved rope, but now I'm trying to construct the matrix that will rotate it along it's direction vector.

I already have a matrix for rendering billboard sprites based on this billboarding technique: Constructing a Billboard Matrix And at the moment I've been trying to retool it so that Right, Up, Forward vector match the rope segment's direction vector.

My rope is made up of multiple sections, each section is a rectangle made up of two triangles, as I said above, I can get the position and sections perfect, it's the rotating to face the camera that's causing me a lot of problems.

This is in OpenGL ES2 and written in C.

I have studied Doom 3's beam rendering code in Model_beam.cpp, the method used there is to calculate the offset based on normals rather than using matrices, so I have created a similar technique in my C code and it sort of works, at least it, works as much as I need it to right now.

So for those who are also trying to figure this one out, use the cross-product of the mid-point of the rope against the camera position, normalise that and then multiply it to how wide you want the rope to be, then when constructing the vertices, offset each vertex in either + or - direction of the resulting vector.

Further help would be great though as this is not perfect!

Thank you

like image 609
Felix Jones Avatar asked Apr 08 '13 14:04

Felix Jones


1 Answers

Check out this related stackoverflow post on billboards in OpenGL It cites a lighthouse3d tutorial that is a pretty good read. Here are the salient points of the technique:

void billboardCylindricalBegin(
                float camX, float camY, float camZ,
                float objPosX, float objPosY, float objPosZ) {

        float lookAt[3],objToCamProj[3],upAux[3];
        float modelview[16],angleCosine;

        glPushMatrix();

    // objToCamProj is the vector in world coordinates from the 
    // local origin to the camera projected in the XZ plane
        objToCamProj[0] = camX - objPosX ;
        objToCamProj[1] = 0;
        objToCamProj[2] = camZ - objPosZ ;

    // This is the original lookAt vector for the object 
    // in world coordinates
        lookAt[0] = 0;
        lookAt[1] = 0;
        lookAt[2] = 1;


    // normalize both vectors to get the cosine directly afterwards
        mathsNormalize(objToCamProj);

    // easy fix to determine wether the angle is negative or positive
    // for positive angles upAux will be a vector pointing in the 
    // positive y direction, otherwise upAux will point downwards
    // effectively reversing the rotation.

        mathsCrossProduct(upAux,lookAt,objToCamProj);

    // compute the angle
        angleCosine = mathsInnerProduct(lookAt,objToCamProj);

    // perform the rotation. The if statement is used for stability reasons
    // if the lookAt and objToCamProj vectors are too close together then 
    // |angleCosine| could be bigger than 1 due to lack of precision
       if ((angleCosine < 0.99990) && (angleCosine > -0.9999))
          glRotatef(acos(angleCosine)*180/3.14,upAux[0], upAux[1], upAux[2]);   
    }
like image 91
henderso Avatar answered Nov 01 '22 03:11

henderso