Jump to content
• Advertisement  # Glenn Conner

Member

6

100 Neutral

## About Glenn Conner

• Rank
Newbie
1. Thanks Dawoodoz,I assume that code works with arbitrary geometry and as such is a bit too complex for me to comprehend given my lack of experience in 3d graphics I ended up solving the problem, and I'll post my solution here just in case anyone else ever has this issue. For a sphere you can calculate the tangent and binormal given a normal and a position (x,y,z) as follows //calculate TBN per pixel instead of per vertex to get rid of artifacts at the poles of spheres float theta = acos(input.LocalPosition.z/Radius); float phi = atan2(input.LocalPosition.y/Radius,input.LocalPosition.x/Radius); theta+=D3DX_PI/2; D3DXVECTOR3 tangent(sin(theta)*cos(phi),sin(theta)*sin(phi),cos(theta)); D3DXVECTOR3 binormal; D3DXVec3Cross(&binormal,&normal,&tangent); However given the geometry of the D3DX sphere you will always get tangent and binormal interpolation artifacts at the two poles on the Z axis, the only way I found to get around this was to calculate the TBN in the pixel shader i.e. per pixel instead of per vector in the mesh geometry, the hlsl for this is as follows //calculate TBN per pixel instead of per vertex to get rid of artifacts at the poles of spheres float theta = acos(input.LocalPosition.z/Radius); float phi = atan2(input.LocalPosition.y/Radius,input.LocalPosition.x/Radius); theta+=PI/2; float3 tangent = float3(sin(theta)*cos(phi),sin(theta)*sin(phi),cos(theta)); float3 binormal = cross(input.Normal,tangent); using this technique generates pixel perfect tangents and binormals across the entire sphere, so my bumpmapping code finally works correctly!
2. I've been trying to generate texture coordinates for a sphere created using D3DXCreateSphere in order to be able to add tangent/binormal data to the mesh however I've run into some problems. The tangents appear to be being calculated correctly except for one strip of the sphere where z~0 and x <=0 heres the problem with tangents shown in RGB [attachment=5420:problem.jpg] The code I'm using to create the sphere and generate the texture coordinates is as follows HR(D3DXCreateSphere(gd3dDevice, 1.0, 20,20, &mSceneMesh, 0)); // 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* clonedMesh = 0; HR(mSceneMesh->CloneMesh(mSceneMesh->GetOptions(), elems, gd3dDevice, &clonedMesh)); // lock the vertex buffer NMapVertex *pVerts; HR(clonedMesh->LockVertexBuffer(0,(void **)&pVerts)); // get vertex count int numVerts=clonedMesh->GetNumVertices(); // compute texture coordinates for (int i=0;i<numVerts;++i) { pVerts->tex0.x = (atan2(pVerts->pos.z,pVerts->pos.x)/(D3DX_PI* 2.0f)); pVerts->tex0.y = (asin(pVerts->pos.y)/D3DX_PI); ++pVerts; } // unlock the vertex buffer clonedMesh->UnlockVertexBuffer(); // Now use D3DXComputeTangentFrameEx to build the TNB-basis for each vertex // in the mesh. HR(D3DXComputeTangentFrameEx( clonedMesh, // 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. clonedMesh->GetOptions(), // Options 0, // Adjacency 0.01f, 0.25f, 0.01f, // Thresholds for handling errors &mSceneMesh, // Output mesh 0)); // Vertex Remapping Anyone have any ideas?
3. Thanks! I set some texture coordinates before calling D3DXComputeTangentFrameEx (don't know if I set them correctly though) and now my tangents and binormals are being set.
4. Hi, I've been trying to get normal mapping on a sphere working for a few days now with no success, I've narrowed the problem (i think) down to the fact that the tangent/binormal's on my mesh are all set to 0, but to my knowledge they should be being set correctly. I've torn out most of my pixel/vertex shader code so that now it just displays the binormal vector in RGB (this is how I know the binormals/tangents are always 0), however weirdly the normals are getting set correctly. Weirder still If I load a .x mesh from a file and process it, the binormals/tangents are set correctly, however if I use the same code on a mesh generated from the d3dXCreateSphere function the binormals/tangents are always 0. Any help would be much appreciated, my code is below. My vertex declaration D3DVERTEXELEMENT9 NMapVertexElements[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0}, {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BINORMAL, 0}, {0, 36, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0}, {0, 48, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, D3DDECL_END() }; HR(gd3dDevice->CreateVertexDeclaration(NMapVertexElements, &NMapVertex::Decl)); creating the mesh //This is the weird bit, If I use a mesh loaded from a .x file, and run it through this code, the tangent/binormals get set, however if I create the mesh myself using the d3dxCreateSphere function, //then the tangents/binormals don't get set properly //LoadXFile("BasicColumnScene.x", &tempMesh, mSceneMtrls, mSceneTextures); HR(D3DXCreateSphere(gd3dDevice, 1.0, 64,64, &mSceneMesh, 0)); // 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* clonedMesh = 0; HR(mSceneMesh->CloneMesh(mSceneMesh->GetOptions(), elems, gd3dDevice, &clonedMesh)); // Now use D3DXComputeTangentFrameEx to build the TNB-basis for each vertex // in the mesh. HR(D3DXComputeTangentFrameEx( clonedMesh, // 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. clonedMesh->GetOptions(), // Options 0, // Adjacency 0.01f, 0.25f, 0.01f, // Thresholds for handling errors &mSceneMesh, // Output mesh 0)); // Vertex Remapping
5. Thanks for the suggestion, but the problem turned out to be the c++ code I was using to generate the permutation and gradient textures, I was packing the color values into the texture data in the wrong order. For the permutation texture I was doing this imageData[index] = D3DCOLOR_ARGB(BB,BA,AB,AA); when it should have been imageData[index] = D3DCOLOR_ARGB(BB,AA,AB,BA); Likewise for the gradient texture I was doing this imageData[index] = D3DCOLOR_ARGB(q,w,v,u); when it should have been imageData[index] = D3DCOLOR_ARGB(u,v,w,q);
6. Hi guys, I'm relatively new to HLSL and shaders in general, I've been trying to get a perlin noise shader working and I think I'm almost there, however the rendered noise is covered in banding or seam artifacts and I can't figure out why. heres a picture of the problem Here I'm using c++ and directx 9, I'm generating a noise permutation texture and a gradient texture as inputs to the shader on the CPU using the following code IDirect3DTexture9 *ImprovedPerlinNoise::GeneratePermTexture(IDirect3DDevice9 *device) { IDirect3DTexture9 *tex; device->CreateTexture(256,256,1,NULL,D3DFMT_A8R8G8B8,D3DPOOL_MANAGED,&tex,NULL); D3DSURFACE_DESC surfaceDesc; tex->GetLevelDesc(0,&surfaceDesc); D3DLOCKED_RECT lockedRect; tex->LockRect(0,&lockedRect,NULL,NULL); DWORD *imageData = (DWORD*)lockedRect.pBits; for (int y=0;y<surfaceDesc.Height;++y) { for (int x=0;x<surfaceDesc.Width;++x) { int A = Perm2d(x) + y; int AA = Perm2d(A); int AB = Perm2d(A + 1); int B = Perm2d(x + 1) + y; int BA = Perm2d(B); int BB = Perm2d(B + 1); int index =y*lockedRect.Pitch / 4 + x; imageData[index] = D3DCOLOR_ARGB(BB,BA,AB,AA); } } tex->UnlockRect(0); return tex; } IDirect3DTexture9 *ImprovedPerlinNoise::GenerateGradientTexture(IDirect3DDevice9 *device) { IDirect3DTexture9 *tex; device->CreateTexture(256,1,1,NULL,D3DFMT_Q8W8V8U8,D3DPOOL_MANAGED,&tex,NULL); D3DSURFACE_DESC surfaceDesc; tex->GetLevelDesc(0,&surfaceDesc); D3DLOCKED_RECT lockedRect; tex->LockRect(0,&lockedRect,NULL,NULL); DWORD *imageData = (DWORD*)lockedRect.pBits; for (int y=0;y<surfaceDesc.Height;++y) { for (int x=0;x<surfaceDesc.Width;++x) { int index =y*lockedRect.Pitch / 4 + x; int q = _gradients[_permutation[x] % 16] * 127; int w = _gradients[_permutation[x] % 16] * 127; int v = _gradients[_permutation[x] % 16] * 127; int u = 1 * 127; imageData[index] = D3DCOLOR_ARGB(q,w,v,u); } } tex->UnlockRect(0); return tex; } The actual shader code is as follows float4x4 World; float4x4 View; float4x4 Projection; struct VertexShaderInput { float4 Position : POSITION0; float2 texCoord : TEXCOORD0; }; struct VertexShaderOutput { float4 Position : POSITION0; float2 texCoord : TEXCOORD0; float4 wPosition: TEXCOORD1; }; VertexShaderOutput VertexShaderFunction(VertexShaderInput input) { VertexShaderOutput output; float4 worldPosition = mul(input.Position, World); float4 viewPosition = mul(worldPosition, View); output.Position = mul(viewPosition, Projection); output.wPosition = mul(input.Position, World); output.texCoord = input.texCoord; return output; } texture permTexture2d; texture permGradTexture; sampler permSampler2d = sampler_state { texture = <permTexture2d>; AddressU = Wrap; AddressV = Wrap; MAGFILTER = POINT; MINFILTER = POINT; MIPFILTER = NONE; }; sampler permGradSampler = sampler_state { texture = <permGradTexture>; AddressU = Wrap; AddressV = Clamp; MAGFILTER = POINT; MINFILTER = POINT; MIPFILTER = NONE; }; float3 fade(float3 t) { return t * t * t * (t * (t * 6 - 15) + 10); // new curve } float4 perm2d(float2 p) { return tex2D(permSampler2d, p); } float gradperm(float x, float3 p) { float3 sample = tex1D(permGradSampler, x); return dot(sample, p); } float inoise(float3 p) { float3 P = fmod(floor(p), 256.0); // FIND UNIT CUBE THAT CONTAINS POINT p -= floor(p); // FIND RELATIVE X,Y,Z OF POINT IN CUBE. float3 f = fade(p); // COMPUTE FADE CURVES FOR EACH OF X,Y,Z. P = P / 256.0; const float one = 1.0 / 256.0; // HASH COORDINATES OF THE 8 CUBE CORNERS float4 AA = perm2d(P.xy) + P.z; // AND ADD BLENDED RESULTS FROM 8 CORNERS OF CUBE return lerp( lerp( lerp( gradperm(AA.x, p ), gradperm(AA.z, p + float3(-1, 0, 0) ), f.x), lerp( gradperm(AA.y, p + float3(0, -1, 0) ), gradperm(AA.w, p + float3(-1, -1, 0) ), f.x), f.y), lerp( lerp( gradperm(AA.x+one, p + float3(0, 0, -1) ), gradperm(AA.z+one, p + float3(-1, 0, -1) ), f.x), lerp( gradperm(AA.y+one, p + float3(0, -1, -1) ), gradperm(AA.w+one, p + float3(-1, -1, -1) ), f.x), f.y), f.z); } float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0 { float3 p = input.wPosition; float inz = inoise(p)*0.5+0.5; return float4(inz,inz,inz,1); } technique PerlinNoise { pass Pass1 { VertexShader = compile vs_3_0 VertexShaderFunction(); PixelShader = compile ps_3_0 PixelShaderFunction(); } } If anyone could point me in the right direction that would be fantastic, I really would like to be able to generate 3d noise in hlsl as its so much faster than doing it on the CPU (I have a working CPU implementation but it takes around 10 seconds to render a perlin cubemap for an object, the shader as I have it renders at 60FPS no problems at all) Thanks in advance, Glenn.
• Advertisement
×

## Important Information

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

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!