How do i do a manual transformation calculation(ie without D3D)

Started by
2 comments, last by Promit 22 years, 3 months ago
For some single face meshes, I want to bypass the D3D transformation and provide it with already transformed verts(ie D3DFVF_XYZRHW). Only i still need to actually do the transformation. Where can i find out how? ----------------------------- The sad thing about artificial intelligence is that it lacks artifice and therefore intelligence.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
Advertisement
Method 1: Use a vertex shader, its main purpose is for people who need to perform some sort of custom transform of vertices. You get the contents of the vertex buffer as input, and you send the clip-space vertex out as output. The software vertex processing vertex shaders is damn fast (it compiles your shader into straight SSE/SSE2/3DNow! when you create it), and also is supported in hardware on some newer cards.


Method 2: If you really must do it by hand (there aren''t many reasons you''d need to which couldn''t use a vertex shader!):

a) Concatenate your WORLD, VIEW and PROJECTION matrices.

b) Expand your vertex to homogenous form (e.g. a 4D vector instead of a 3D vector. The extra component is called w, set this to 1 for every vertex, so {x,y,z} becomes {x,y,z,1}.

b) Multiply every 4D vertex by the concatenated matrix.

c) Perform manual clipping (if you leave the D3D clipping on for D3DFVF_XYRHW vertices it''ll have to back transform the vertices into camera space which can be slow).

d) Divide all components of the vertex by w and 1 by w:
x'' = x/w
y'' = y/w
z'' = z/w
rhw = 1/w
[a small optimisation here is to calc rhw first and multiply x,y,z by that]


e) Transform x'',y'',z'' by the viewport scaling matrix defined in the docs (Viewports and Clipping->Viewport Scaling) to get the final screen space values.

f) the sx,sy,sz output from the viewport matrix go into those parts of the vertex, as does the rhw from the homogenous divide.


[A vertex shader lets you write parts a & b yourself]

Important docs to read:
DirectX Graphics ->
Programmers Guide ->
Transforms -> *.*
Viewports and Clipping -> *.*


--
Simon O''''Connor
Creative Asylum Ltd
www.creative-asylum.com

Simon O'Connor | Technical Director (Newcastle) Lockwood Publishing | LinkedIn | Personal site

I''m actually working on a new bilboarding technique, which uses the z coordinate for scaling and thus I need to transform/clip (clipping is the more important) the data. By using textures, I think i can get a very fast bilboarding effect.

Could you show some sample code or at least psuedo-code for the non-vertex shader method?

-----------------------------
The sad thing about artificial intelligence is that it lacks artifice and therefore intelligence.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
Ok.

1. There are simpler ways of billboarding, including with shaders, but its probably best to let you try all methods so you can come to that conclusion on your own...



2. Absolute simplest way to transform vertices by hand, and get them clipped and ready to send off to Draw*Primitive*() is the IDirect3DDevice*:rocessVertices() call, you give that an output vertex buffer which you can then lock and modify post transform before handing the vertices off to Draw*Primitive*(). ProcessVertices() gives you the advantage of providing clipping information.



3. When you transform yourself, unless the card has the D3DPMISCCAPS_CLIPTLVERTS cap you have to do the clip yourself.
Full, manual clipping of *arbitrarily* oriented triangles which are partway off screen involves:
a) finding the points where each edge of the triangle intersects the edges of the screen.
b) adding new edges to the polygon along the edges of the screen the polygon intersects.
c) which means the polygon ends up not being a triangle, so...
d) ...any non-triangular clipped poly has to be subdivided back into smaller triangles which all fit on the screen.

Posting and describing the full algorithm is beyond the scope of a post to a forum like this, look up the "Sutherland-Hodgman" or "Liang-Barsky" algorithms (both very well documented).



4. For quad based billboards, since they are always square on the screen (unless you rotate them around the Z axis - something you can do more cheaply by rotating the texture coordinates instead), you can clip them in a 2D way like sprites - since the outside edges of each triangle are aligned with the screen. (I''ll leave textures as an excercise to the reader - hint: work out the percentage that the quad has gone off screen).



5. Here is some code which transforms vertices in a similar way to D3D. I modified the Matrices tutorial from the SDK to use a D3DFVF_XYZRHW vertex format and called it TRANSFORMEDVERTEX, with D3DFVF_TRANSFORMEDVERTEX FVF code. It assumes that you''ve created a new vertex buffer with the TRANSFORMEDVERTEX type, and that you''ve left the SetTransform() and SetViewport() calls from the sample alone:

      ///////////////////////////////////    // disabled since I demonstrate simple clipping below    g_pd3dDevice->SetRenderState( D3DRS_CLIPPING, FALSE );    #define NUM_VERTICES 3    // untransformed vertices [source]    CUSTOMVERTEX g_vertices[] =    {        { -1.0f,-1.0f, 0.0f, 0xffff0000, },        {  1.0f,-1.0f, 0.0f, 0xff0000ff, },        {  0.0f, 1.0f, 0.0f, 0xffffffff, },    };        // get currently set matrices    D3DXMATRIX mWorld;    g_pd3dDevice->GetTransform( D3DTS_WORLD, &mWorld );    D3DXMATRIX mView;    g_pd3dDevice->GetTransform( D3DTS_VIEW, &mView );    D3DXMATRIX mProjection;    g_pd3dDevice->GetTransform( D3DTS_PROJECTION, &mProjection );    // concatenate matrices into a single transform matrix    D3DXMATRIX mConcatenated;    mConcatenated = mWorld * mView * mProjection;    // make the viewport matrix (see "Viewport Scaling" in the docs)    D3DVIEWPORT8 vp;    g_pd3dDevice->GetViewport( &vp );    D3DXMATRIX mViewportScale;    D3DXMatrixIdentity( &mViewportScale );    mViewportScale._11 = vp.Width / 2.0f;    mViewportScale._22 = -(vp.Height / 2.0f);    mViewportScale._33 = vp.MaxZ - vp.MinZ;    mViewportScale._41 = vp.X + (vp.Width / 2.0f);    mViewportScale._42 = vp.Y + (vp.Height / 2.0f);    mViewportScale._43 = vp.MinZ;    mViewportScale._44 = 1.0f;    // lock the D3DFVF_XYZRHW buffer    TRANSFORMEDVERTEX* pv;    g_pTVB->Lock( 0, sizeof(TRANSFORMEDVERTEX)*3, (BYTE**)&pv, 0 );    // do the transform    for (int i=0; i<NUM_VERTICES; ++i)    {        // vec = homogenous vertex position         D3DXVECTOR4 vec;        vec.x = g_vertices[i].x;        vec.y = g_vertices[i].y;        vec.z = g_vertices[i].z;        vec.w = 1.0f;        // vec_trans = vec * world_view_projection;        D3DXVECTOR4 vec_trans;        D3DXVec4Transform( &vec_trans, &vec, &mConcatenated );        // clipping.        // this is only required if the graphics hardware        // doesn''t have the D3DPMISCCAPS_CLIPTLVERTS cap set        // See "Clipping Volumes" in the docs.        //        // -w < x < w        // -w < y < w        //  0 < z < w        vec_trans.x = __max( -vec_trans.w, vec_trans.x );   // if (x < -w)  x = -w        vec_trans.x = __min(  vec_trans.x, vec_trans.w );   // if (x >  w)  x =  w        vec_trans.y = __max( -vec_trans.w, vec_trans.y );   // if (y < -w)  y = -w        vec_trans.y = __min(  vec_trans.y, vec_trans.w );   // if (y >  w)  y =  w          vec_trans.z = __max(         0.0f, vec_trans.z );   // if (z <  0)  z =  0        vec_trans.z = __min(  vec_trans.z, vec_trans.w );   // if (z >  w)  z =  w        // Apply the viewport scaling matrix (see "Viewport Scaling" in the docs)        // vec_trans = vec_trans * viewport_scale_matrix        D3DXVec4Transform( &vec_trans, &vec_trans, &mViewportScale );        // the homogenous divide (back to 3D space)        D3DXVECTOR3 vec_screen;        float rhw = 1.0f / vec_trans.w;        vec_screen.x = vec_trans.x * rhw;        vec_screen.y = vec_trans.y * rhw;        vec_screen.z = vec_trans.z * rhw;        // copy the screen x,y pos, z depth and rhw to the vertex        pv[i].x   = vec_screen.x;        pv[i].y   = vec_screen.y;        pv[i].z   = vec_screen.z;        pv[i].rhw = rhw;        // copy diffuse colour        pv[i].color = g_vertices[i].color;    }    g_pTVB->Unlock();    // Render the vertex buffer contents    g_pd3dDevice->SetStreamSource( 0, g_pTVB, sizeof(TRANSFORMEDVERTEX) );    g_pd3dDevice->SetVertexShader( D3DFVF_TRANSFORMEDVERTEX );    g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 1 );    ///////////////////////////////////  



In real life you wouldn''t be calling GetTransform() and GetViewport() every frame, the viewport matrix would already be set up, and you''d have the matrices pre-concatenated with code to re-concatenate each time one of them changes.

--
Simon O''''Connor
Creative Asylum Ltd
www.creative-asylum.com

Simon O'Connor | Technical Director (Newcastle) Lockwood Publishing | LinkedIn | Personal site

This topic is closed to new replies.

Advertisement