This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

| Textured Lines In D3D Submitted by

Here's a way to solve a recurrent problem : emulating glLineWidth in Direct3D. Better : you can use this code to draw textured lines, which are often needed to create a lot of special effects (lightning bolts, toon-like silhouettes, etc). The code computes a world quad from a segment in world space. Simply render the quad instead of the segment! If you have a line-strip, compute one quad for each segment, then render everything as a single non-indexed tristrip of 4 * NbSegments vertices. You should be able to use it with any flexible vertex format (FVF). All matrices are 4x4 D3D-compliant matrices. mRenderWidth is the width of the render window (ex: 640) I hope it will be useful to some of you. I know I would have loved to have this right from the start (read: included in D3D...). By the way, it's not supposed to be optimized so don't bother telling me it's not :)
Pierre

Download Associated File: d3dtexturedlines.txt (4,586 bytes)

    /*

    Here's a way to solve a recurrent problem : emulating glLineWidth in Direct3D. Better : you can use this code to draw textured lines, which are often needed to create a lot of special effects (lightning bolts, toon-like silhouettes, etc).

    The code computes a world quad from a segment in world space. Simply render the quad instead of the segment! If you have a line-strip, compute one quad for each segment, then render everything as a single non-indexed tristrip of 4 * NbSegments vertices.

    You should be able to use it with any flexible vertex format (FVF).

    Here's the main routine :

    */

    //////////////////////////////////////////////////////////////////////////////////////////////////////////
    /**
     * Computes a screen quad aligned with a world segment.
     * \param  inverseview  [in] inverse view matrix
     * \param  view   [in] view matrix
     * \param  proj   [in] projection matrix
     * \param  verts   [out] 4 quad vertices in world space (forming a tri-strip)
     * \param  uvs    [out] 4 quad uvs
     * \param  stride   [in] size of vertex (FVF stride)
     * \param  p0    [in] segment's first point in world space
     * \param  p1    [in] segment's second point in world space
     * \param  size   [in] size of segment/quad
     * \param  constantsize [in] true to keep the quad's screen size constant (e.g. needed to emulate glLineWidth)
     */
    //////////////////////////////////////////////////////////////////////////////////////////////////////////
    void Renderer::ComputeScreenQuad(const ViewMatrix& inverseview, const ViewMatrix& view, const ProjMatrix& proj, ubyte* verts, ubyte* uvs, udword stride, const Point& p0, const Point& p1, float size, bool constantsize)
    {
     // Compute delta in camera space
     Point Delta; TransformPoint3x3(Delta, p1-p0, view);

     // Compute size factors
     float SizeP0 = size;
     float SizeP1 = size;

     if(constantsize)
     {
      // Compute scales so that screen-size is constant
      SizeP0 *= ComputeConstantScale(p0, view, proj);
      SizeP1 *= ComputeConstantScale(p1, view, proj);
     }

     // Compute quad vertices
     float Theta0 = atan2f(-Delta.x, -Delta.y);
     float c0 = SizeP0 * cosf(Theta0);
     float s0 = SizeP0 * sinf(Theta0);
     ComputePoint(*((Point*)verts),  c0, -s0, inverseview, p0); verts+=stride;
     ComputePoint(*((Point*)verts),  -c0, s0, inverseview, p0); verts+=stride;

     float Theta1 = atan2f(Delta.x, Delta.y);
     float c1 = SizeP1 * cosf(Theta1);
     float s1 = SizeP1 * sinf(Theta1);
     ComputePoint(*((Point*)verts),  -c1, s1, inverseview, p1); verts+=stride;
     ComputePoint(*((Point*)verts),  c1, -s1, inverseview, p1); verts+=stride;

     // Output uvs if needed
     if(uvs)
     {
      *((float*)uvs) = 0.0f; *((float*)(uvs+4)) = 1.0f; uvs+=stride;
      *((float*)uvs) = 0.0f; *((float*)(uvs+4)) = 0.0f; uvs+=stride;
      *((float*)uvs) = 1.0f; *((float*)(uvs+4)) = 1.0f; uvs+=stride;
      *((float*)uvs) = 1.0f; *((float*)(uvs+4)) = 0.0f; uvs+=stride;
     }
    }

    inline void ComputePoint(Point& dest, float x, float y, const Matrix4x4& rot, const Point& trans)
    {
     dest.x = trans.x + x * rot.m[0][0] + y * rot.m[1][0];
     dest.y = trans.y + x * rot.m[0][1] + y * rot.m[1][1];
     dest.z = trans.z + x * rot.m[0][2] + y * rot.m[1][2];
    }

    And extra used functions:

    // Quickly rotates a vector, using the 3x3 part of a 4x4 matrix
     inline void TransformPoint3x3(Point& dest, const Point& source, const Matrix4x4& rot)
     {
      dest.x = source.x * rot.m[0][0] + source.y * rot.m[1][0] + source.z * rot.m[2][0];
      dest.y = source.x * rot.m[0][1] + source.y * rot.m[1][1] + source.z * rot.m[2][1];
      dest.z = source.x * rot.m[0][2] + source.y * rot.m[1][2] + source.z * rot.m[2][2];
     }

    float Renderer::ComputeConstantScale(const Point& pos, const ViewMatrix& view, const ProjMatrix& proj)
    {
     Point ppcam0 = pos * view;
     Point ppcam1 = ppcam0;
     ppcam1.x += 1.0f;

     float l1 = 1.0f/(ppcam0.x*proj.m[0][3] + ppcam0.y*proj.m[1][3] + ppcam0.z*proj.m[2][3] + proj.m[3][3]);
     float c1 =  (ppcam0.x*proj.m[0][0] + ppcam0.y*proj.m[1][0] + ppcam0.z*proj.m[2][0] + proj.m[3][0])*l1;
     float l2 = 1.0f/(ppcam1.x*proj.m[0][3] + ppcam1.y*proj.m[1][3] + ppcam1.z*proj.m[2][3] + proj.m[3][3]);
     float c2 =  (ppcam1.x*proj.m[0][0] + ppcam1.y*proj.m[1][0] + ppcam1.z*proj.m[2][0] + proj.m[3][0])*l2;
     float CorrectScale = 1.0f/(c2 - c1);
     return CorrectScale / float(mRenderWidth);
    }

    All matrices are 4x4 D3D-compliant matrices. mRenderWidth is the width of the render window (ex: 640)

    I hope it will be useful to some of you. I know I would have loved to have this right from the start (read: included in D3D...). By the way, it's not supposed to be optimized so don't bother telling me it's not :)

    Pierre

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.