Jump to content
  • Advertisement
Sign in to follow this  
b_thangvn

Help with spherical normal mapping

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

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi all, I have question about the spherical normal mapping. Does anyone here know good tutorial on this ? I tried it on my own but somehow I got some weird artifacts with the texture on my demo. This is how I do it: - First I create a Vertex Struct like this:

struct NMapVertex
{
   D3DXVECTOR3 pos;
   D3DXVECTOR3 tangent;
   D3DXVECTOR3 binormal;
   D3DXVECTOR3 normal;
   D3DXVECTOR2 tex0;

   static IDirect3DVertexDeclaration9* Decl;
};
 
Then, I just create a teapot, generate spherical coordination for its texture, and clone the mesh with that Vertex Declaration:

void WaterDemo::createTeapot()
{
   HR(D3DXCreateSphere(gd3dDevice, &mTeapot, 0));
   // Now generate spherical coordinate
   genSphericalTexCoords();

   // Get the vertex declaration for the NMapVertex
   D3DVERTEXELEMENT9 elems[MAX_FVF_DECL_SIZE];
   UINT numElems = 0;
   HR(NMapVertex::Decl->GetDeclaration(elems, &numElems));

   // Clone the mesh to the NMapVertex format
   ID3DXMesh* tempMesh = 0;
   HR(mTeapot->CloneMesh(D3DXMESH_MANAGED, elems, gd3dDevice, &tempMesh));

   // Now use D3DXComputeTangentFrameEx to build the TNB-basis for each vertex
   // in the mesh.  

   HR(D3DXComputeTangentFrameEx(
     tempMesh, // Input mesh
     D3DDECLUSAGE_TEXCOORD, 0, // Vertex element of input tex-coords.  
      D3DDECLUSAGE_BINORMAL, 0, // Vertex element to output binormal.
     D3DDECLUSAGE_TANGENT, 0,  // Vertex element to output tangent.
      D3DDECLUSAGE_NORMAL, 0,  // Vertex element to output normal.
      0, // Options
      0, // Adjacency
     0.01f, 0.25f, 0.01f, // Thresholds for handling errors
     &mTeapot, // Output mesh
     0));        // Vertex Remapping

   // Done with temps.
   ReleaseCOM(tempMesh);

   D3DXMatrixIdentity(&mTeapotWorld);
   D3DXMatrixTranslation(&mTeapotWorld, 0.0f, 5.0f, 0.0f);

   HR(D3DXCreateTextureFromFile(gd3dDevice, "bricks_color.bmp", &mTeapotTex));
   HR(D3DXCreateTextureFromFile(gd3dDevice, "Res/bricks_nmap.bmp", &mTeapotNormal));

   mTeapotMtrl.ambient  = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
   mTeapotMtrl.diffuse  = D3DXCOLOR(1.0f, 1.0f, 1.0f, 0.5f);
   mTeapotMtrl.spec      = D3DXCOLOR(0.8f, 0.8f, 0.8f, 1.0f);
   mTeapotMtrl.specPower = 16.0f;
}
 
This is the genSphericalTexCoords() method:

void WaterDemo::genSphericalTexCoords()
{
   // D3DXCreate* functions generate vertices with position 
   // and normal data.  But for texturing, we also need
   // tex-coords.  So clone the mesh to change the vertex
   // format to a format with tex-coords.

   D3DVERTEXELEMENT9 elements[64];
   UINT numElements = 0;
   NMapVertex::Decl->GetDeclaration(elements, &numElements);

   ID3DXMesh* temp = 0;
   HR(mTeapot->CloneMesh(D3DXMESH_SYSTEMMEM, 
      elements, gd3dDevice, &temp));

   ReleaseCOM(mTeapot);

   // Now generate texture coordinates for each vertex.
   NMapVertex* vertices = 0;
   HR(temp->LockVertexBuffer(0, (void**)&vertices));

   for(UINT i = 0; i < temp->GetNumVertices(); ++i)
   {
      // Convert to spherical coordinates.
      D3DXVECTOR3 p = vertices.pos;
   
      float theta = atan2f(p.z, p.x);
      float phi  = acosf(p.y / sqrtf(p.x*p.x+p.y*p.y+p.z*p.z));

      // Phi and theta give the texture coordinates, but are not in 
      // the range [0, 1], so scale them into that range.

      float u = theta / (2.0f*D3DX_PI);
      float v = phi  / D3DX_PI;
      
      // Save texture coordinates.
      
      vertices.tex0.x = u;
      vertices.tex0.y = v;
   }
   HR(temp->UnlockVertexBuffer());

   // Clone back to a hardware mesh.
   HR(temp->CloneMesh(D3DXMESH_MANAGED,
      elements, gd3dDevice, &mTeapot));

   ReleaseCOM(temp);
}
I suspect that by calling cloned the mesh again in createTeapot(), I somehow change the Position and Tex of the mesh that already generate in genSphericalTexCoords(), but it's just my thought. Any suggestions ? Best regards, Thang

Share this post


Link to post
Share on other sites
Advertisement
So nobody here ever do normal mapping on a teapot ? I have here a picture of the texture artifact that I'm talking about.

communityfile_download.php?fileid=613<br>

[Edited by - b_thangvn on July 17, 2008 10:15:37 PM]

Share this post


Link to post
Share on other sites
It works for you because you have a forum account at game institute, it won't work for anyone who doesn't. Probably better to use photo bucket or some other free image hosting site.

Share this post


Link to post
Share on other sites
I believe this a a problem with texture address mode.

The u texture coordinate is running from 0 to near 1 around the teapot and the "strip" of triangles that has the artifacts has u coordinates close to 1 and 0 where you want a small rightmost part of the texture to mapped, when in fact the large leftmost part of texture is being mapped.

If you set the texture address mode to wrap, the shortest path between two texture coordinates is chosen which should fix the problem.

Share this post


Link to post
Share on other sites
Thanks Donnie,

I'll try it tomorrow morning and let you know about the result. Thank you once again.

Best,

Thang

EDIT: I did the WRAP for the U address mode but it's still the same thing. This is the code from my effect file:

sampler TexS = sampler_state
{
Texture = <gTex>;
MinFilter = ANISOTROPIC;
MaxAnisotropy = 8;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};

sampler NormalMapS = sampler_state
{
Texture = <gNormalMap>;
MinFilter = ANISOTROPIC;
MaxAnisotropy = 8;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};

As you can see, for the texture sample, both the address mode for U and V is set to WRAP, but it still produces the same result. Do you need to see more from the effect file ? Maybe there's something wrong in there ?

Share this post


Link to post
Share on other sites
It's a problem with your texture coordinates. If you imagine the vertices where the artifact occurs the texture coordinates should currently look somewhat like this:
... 0.9 --- 0.95 --- 0.0 --- 0.05 ... where the vertex with 0.0 coordinates is duplicated to close the mesh. So Donnie was correct about the problem, but texture wrapping doesn't solve it (unless D3D works differently here than OGL, but I can't imagine it). The duplicated vertices need to have a u-coordinate of 1.0 so that the last row of faces doesn't get the whole texture from 0.0 to 0.95 squished into it.

Share this post


Link to post
Share on other sites
Hi Eternal,

So how do I fix that ? How do I make it so it will change into 1 ? Do you know any tutorial on how to texture map a teapot ? It's funny because I also use the same method for generating spherical coordinate with just texture ( without normal map ) and it works fine, take a look:

http://img389.imageshack.us/my.php?image=teapottextureix1.jpg


So I have no idea why using to ComputeTangentEx produces such an artifact.

Best,

Thang

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!