Carandiru

Members
  • Content count

    126
  • Joined

  • Last visited

Community Reputation

212 Neutral

About Carandiru

  • Rank
    Member

Personal Information

  1. Well I ran into some problems implementing the border vertices for sampling normals actually became quite complex. So I reverted it and now I'm back to where I was before. I'll have to tackle this bug again. I have to move onto some important features and mechanics. 
  2. Haha a border so simple. Will implement and get back to you. Also will see if I can verify the normals. I added sobel calculation as it gives a noticeable enhancement with normal mapping. It is based purely off the height map. The tangent and binomial are calculated differently with the y axis now factored in with is important for surfaces that are not flat. The normal from this final calculation is then averaged with the sobel calc to give a good enough, visually, result.
  3. Oh I should also mention all textures I use are made seamless.
  4. Well I had a crack at using neighbour patches to calculate the edge normals and here is my result:   Which is worse than before with no neighbour patch sampling:   I purposely made it flat to debug the terrain. I also disabled normal map sampling and parallax mapping in the shader to make sure its not that. I'm positing the code here.   GenerateTerrainPatch bool const cTerrainRender::GenerateTerrainPatch( cTerrainPatch* const& pSourcePatch, LPTERRAINRENDERACTIVEPATCH const& pActivePatch ) { __m128 fRegOne, fRegTwo, fRegXZScale, fRegHeightMapRadius, fRegUVScale; D3DX_ALIGN16 unsigned int vertexiDx[4]; D3DX_ALIGN16 float fXCoord[4], fZCoord, fUCoord[4], fVCoord; XMFLOAT3A const vStartNormal(0.0f, 1.0f, 0.0f); D3DX_ALIGN16 float fX(0.0f), fZ(0.0); D3DX_ALIGN16 unsigned int vertexiDz(0); // Resolve Unique Vertex Arrays // D3DX_ALIGN16 float const* const pHeightMap( pSourcePatch->getHeightMapRaw() ); D3DX_ALIGN16 TERRAINVERTEX* const pTerrainSrcPatchBuffer(pActivePatch->getUniqueVertexArray()); fRegHeightMapRadius = XMM128::LoadAll( m_fLocalSpaceHeightMapRadius ); fRegXZScale = XMM128::LoadAll( m_fLocalSpaceXZScale ); fRegUVScale = XMM128::LoadAll( m_fLocalSpaceUVScale ); // Build Terrain Patch from Heightmap Data // for ( unsigned int iDz = 0; iDz < m_uiNumVerticesXZ ; ++iDz, fZ += 1.0f ) { fX = 0.0f; vertexiDz = ( iDz * m_uiNumVerticesXZ ); fRegOne = XMM128::LoadOne( fZ ); fRegTwo = _mm_mul_ss( fRegOne, fRegUVScale ); XMM128::StoreOne( &fVCoord, fRegTwo ); fRegOne = _mm_mul_ss( fRegOne, fRegXZScale ); fRegOne = _mm_sub_ss( fRegOne, fRegHeightMapRadius ); XMM128::StoreOne( &fZCoord, fRegOne ); for ( unsigned int iDx = 0; iDx < m_uiNumVerticesXZ ; iDx += 4, fX += 4.0f ) { // to map the 2D array coordaintes into a 1D array vertexiDx[0] = vertexiDz + iDx; vertexiDx[1] = vertexiDz + iDx + 1; vertexiDx[2] = vertexiDz + iDx + 2; vertexiDx[3] = vertexiDz + iDx + 3; fRegOne = XMM128::Load( fX, fX + 1.0f, fX + 2.0f, fX + 3.0f); fRegTwo = _mm_mul_ps( fRegOne, fRegUVScale ); XMM128::Store( fUCoord, fRegTwo ); fRegOne = _mm_mul_ps( fRegOne, fRegXZScale ); fRegOne = _mm_sub_ps( fRegOne, fRegHeightMapRadius ); XMM128::Store( fXCoord, fRegOne ); pTerrainSrcPatchBuffer[vertexiDx[0]].p = XMFLOAT3A(fXCoord[0], pHeightMap[vertexiDx[0]], fZCoord); pTerrainSrcPatchBuffer[vertexiDx[1]].p = XMFLOAT3A(fXCoord[1], pHeightMap[vertexiDx[1]], fZCoord); pTerrainSrcPatchBuffer[vertexiDx[2]].p = XMFLOAT3A(fXCoord[2], pHeightMap[vertexiDx[2]], fZCoord); pTerrainSrcPatchBuffer[vertexiDx[3]].p = XMFLOAT3A(fXCoord[3], pHeightMap[vertexiDx[3]], fZCoord); // Temporary Tangent & Binormal & Normal // //pTerrainSrcPatchBuffer[vertexiDx[0]].t = pTerrainSrcPatchBuffer[vertexiDx[0]].b = pTerrainSrcPatchBuffer[vertexiDx[0]].n = vStartNormal; //pTerrainSrcPatchBuffer[vertexiDx[1]].t = pTerrainSrcPatchBuffer[vertexiDx[1]].b = pTerrainSrcPatchBuffer[vertexiDx[1]].n = vStartNormal; //pTerrainSrcPatchBuffer[vertexiDx[2]].t = pTerrainSrcPatchBuffer[vertexiDx[2]].b = pTerrainSrcPatchBuffer[vertexiDx[2]].n = vStartNormal; //pTerrainSrcPatchBuffer[vertexiDx[3]].t = pTerrainSrcPatchBuffer[vertexiDx[3]].b = pTerrainSrcPatchBuffer[vertexiDx[3]].n = vStartNormal; // Set the u,v values so one texture covers the entire terrain pTerrainSrcPatchBuffer[vertexiDx[0]].tu = fUCoord[0]; pTerrainSrcPatchBuffer[vertexiDx[1]].tu = fUCoord[1]; pTerrainSrcPatchBuffer[vertexiDx[2]].tu = fUCoord[2]; pTerrainSrcPatchBuffer[vertexiDx[3]].tu = fUCoord[3]; pTerrainSrcPatchBuffer[vertexiDx[0]].tv = fVCoord; pTerrainSrcPatchBuffer[vertexiDx[1]].tv = fVCoord; pTerrainSrcPatchBuffer[vertexiDx[2]].tv = fVCoord; pTerrainSrcPatchBuffer[vertexiDx[3]].tv = fVCoord; } } // Remap Vertices for Vertex Cache Optimization // // Copy the vertex data into a temp buffer. TERRAINVERTEX *OldVertices = new TERRAINVERTEX[ m_uiNumVertices ]; memcpy( OldVertices, pTerrainSrcPatchBuffer, sizeof(TERRAINVERTEX) * m_uiNumVertices ); // Perform the remapping const DWORD *CurrentRemap = m_pVertexCacheIndexRemap; const TERRAINVERTEX *OldVertex = OldVertices; for( DWORD i = 0; i < m_uiNumVertices; ++i ) { pTerrainSrcPatchBuffer[ *( CurrentRemap++ ) ] = *( OldVertex++ ); } delete[] OldVertices; return(true); } GenerateTangentBinormalNormal bool const cTerrainRender::GenerateTangentBinormalNormal( TERRAINVERTEX* const& pTerrainSrcPatchBuffer, float const* const pHeightMap, ZoneSphere const* const* const pAdjacentZoneSpheres ) const { D3DX_ALIGN16 unsigned int vertexiDx(0), iDx(0), iDz(0), iDzMin(0), iDzMax(0), iDxMin(0), iDxMax(0); D3DX_ALIGN16 DWORD const* const CurrentRemap(m_pVertexCacheIndexRemap); /*D3DX_ALIGN16 cTerrainPatch const* pTerrainPatchAdj(NULL); D3DX_ALIGN16 float const* pHeightMapAdj(NULL); D3DX_ALIGN16 TERRAINVERTEX const* pTerrainSrcPatchBufferAdj(NULL); // Check to see if we have adjacent terrain patches we need // if ( !pAdjacentZoneSpheres[ZONE_LEFT] || !pAdjacentZoneSpheres[ZONE_LEFT]->getTerrainPatch()->getOwnedActivePatch() ) return(false); if ( !pAdjacentZoneSpheres[ZONE_RIGHT] || !pAdjacentZoneSpheres[ZONE_RIGHT]->getTerrainPatch()->getOwnedActivePatch() ) return(false); if ( !pAdjacentZoneSpheres[ZONE_TOP] || !pAdjacentZoneSpheres[ZONE_TOP]->getTerrainPatch()->getOwnedActivePatch() ) return(false); if ( !pAdjacentZoneSpheres[ZONE_BOTTOM] || !pAdjacentZoneSpheres[ZONE_BOTTOM]->getTerrainPatch()->getOwnedActivePatch() ) return(false); // Now we have todo the edge vertices on z and axis' by sampling adjacent terrain patches that have already // been generated. They have already been generated as where this function is called from // // Top of this patch, bottom of adjacent patch pTerrainPatchAdj = pAdjacentZoneSpheres[ZONE_BOTTOM]->getTerrainPatch(); CalculateNormalsTOP(m_uiNumVerticesXZ-1, pTerrainSrcPatchBuffer, pTerrainPatchAdj->getOwnedActivePatch()->getUniqueVertexArray(), pHeightMap, pTerrainPatchAdj->getHeightMapRaw(), CurrentRemap); // Bottom of this patch, top of adjacent patch pTerrainPatchAdj = pAdjacentZoneSpheres[ZONE_TOP]->getTerrainPatch(); CalculateNormalsBOTTOM(0, pTerrainSrcPatchBuffer, pTerrainPatchAdj->getOwnedActivePatch()->getUniqueVertexArray(), pHeightMap, pTerrainPatchAdj->getHeightMapRaw(), CurrentRemap); // Left of this patch, right of adjacent patch pTerrainPatchAdj = pAdjacentZoneSpheres[ZONE_RIGHT]->getTerrainPatch(); CalculateNormalsLEFT(m_uiNumVerticesXZ-1, pTerrainSrcPatchBuffer, pTerrainPatchAdj->getOwnedActivePatch()->getUniqueVertexArray(), pHeightMap, pTerrainPatchAdj->getHeightMapRaw(), CurrentRemap); // Right of this patch, left of adjacent patch pTerrainPatchAdj = pAdjacentZoneSpheres[ZONE_LEFT]->getTerrainPatch(); CalculateNormalsRIGHT(0, pTerrainSrcPatchBuffer, pTerrainPatchAdj->getOwnedActivePatch()->getUniqueVertexArray(), pHeightMap, pTerrainPatchAdj->getHeightMapRaw(), CurrentRemap);*/ // ZONE_NUM_ADJACENT // Now the rest of the inside of the patch // tbb::parallel_for( tbb::blocked_range<unsigned int>(0, m_uiNumVerticesXZ), [=](const tbb::blocked_range<unsigned int>& r) { for( unsigned int iDz = r.begin(); iDz != r.end(); ++iDz ) { unsigned int vertexiDx(0), iDzMin(0), iDzMax(0), iDxMin(0), iDxMax(0); iDzMin = iDz > 0 ? iDz-1 : iDz; iDzMax = iDz < m_uiNumVerticesXZ - 1 ? iDz+1 : iDz; // iDz -1 : iDz +1 //iDzMin = iDz-1; //iDzMax = iDz+1; for ( unsigned int iDx = 0 ; iDx < m_uiNumVerticesXZ ; ++iDx ) { iDxMin = iDx > 0 ? iDx-1 : iDx; iDxMax = iDx < m_uiNumVerticesXZ - 1 ? iDx+1 : iDx; // iDx -1 : iDx +1 //iDxMin = iDx-1; //iDxMax = iDx+1; // to map the 2D array coordaintes into a 1D array vertexiDx = CurrentRemap[( iDz * m_uiNumVerticesXZ ) + iDx]; CalculateNormal(iDx, iDz, iDxMin, iDxMax, iDzMin, iDzMax, vertexiDx, pTerrainSrcPatchBuffer, pHeightMap, CurrentRemap); } } }); return(true); } CalculateNormal void cTerrainRender::CalculateNormal( unsigned int const& iDx, unsigned int const& iDz, unsigned int const& iDxMin, unsigned int const& iDxMax, unsigned int const& iDzMin, unsigned int const& iDzMax, unsigned int const& vertexiDx, TERRAINVERTEX* const& pTerrainSrcPatchBuffer, float const* const& pHeightMap, DWORD const* const& CurrentRemap ) const { XMVECTOR xmX, xmZ, xmN; D3DX_ALIGN16 float tl, l, bl, t, b, tr, r, br, dX, dY; D3DX_ALIGN16 float const normalStrength(4.0f); tl = pHeightMap[ ( iDzMin * m_uiNumVerticesXZ) + iDxMin ]; l = pHeightMap[ ( iDzMin * m_uiNumVerticesXZ) + iDx ]; bl = pHeightMap[ ( iDzMin * m_uiNumVerticesXZ) + iDxMax ]; t = pHeightMap[ ( iDz * m_uiNumVerticesXZ) + iDxMin ]; b = pHeightMap[ ( iDz * m_uiNumVerticesXZ) + iDxMax ]; tr = pHeightMap[ ( iDzMax * m_uiNumVerticesXZ) + iDxMin ]; r = pHeightMap[ ( iDzMax * m_uiNumVerticesXZ) + iDx ]; br = pHeightMap[ ( iDzMax * m_uiNumVerticesXZ) + iDxMax ]; // Compute dx using Sobel: // -1 0 1 // -2 0 2 // -1 0 1 dX = tr + 2*r + br -tl - 2*l - bl; // Compute dy using Sobel: // -1 -2 -1 // 0 0 0 // 1 2 1 dY = bl + 2*b + br -tl - 2*t - tr; // Build the DETAIL normal xmN = XMLoadFloat3A( &XMFLOAT3A(dX, normalStrength, dY) ); // Use the adjoing vertices along both axis to compute the correct normal // // Tangent Vector : t = (1, 0, heightmap[x+1, y] - heightmap[x-1, y]) // Binormal Vector : ß = (0, 1, heightmap[x, y+1] - heightmap[x, y-1]) xmX = XMVectorSubtract( XMLoadFloat3(&pTerrainSrcPatchBuffer[ CurrentRemap[( iDz * m_uiNumVerticesXZ) + iDxMax] ].p), XMLoadFloat3(&pTerrainSrcPatchBuffer[ CurrentRemap[( iDz * m_uiNumVerticesXZ) + iDxMin] ].p) ); xmZ = XMVectorSubtract( XMLoadFloat3(&pTerrainSrcPatchBuffer[ CurrentRemap[( iDzMax * m_uiNumVerticesXZ) + iDx] ].p), XMLoadFloat3(&pTerrainSrcPatchBuffer[ CurrentRemap[( iDzMin * m_uiNumVerticesXZ) + iDx] ].p) ); // Average DETAIL normal from sobel calculation of heightmap with normal computed from vertices xmN = XMVectorAdd(XMVector3Normalize(xmN), XMVector3Normalize(XMVector3Cross(xmZ, xmX))); xmN = XMVectorMultiply(xmN, XMM128::LoadAll(0.5f)); xmN = XMVector3Normalize( xmN ); XMStoreFloat3(&pTerrainSrcPatchBuffer[vertexiDx].n, xmN); // Assign Correct Tangent // xmX = XMVector3Normalize(xmX); XMStoreFloat3(&pTerrainSrcPatchBuffer[vertexiDx].t, xmX); // Calculate BiNormal From CrossProduct of Tangent and the Final Normal // xmZ = XMVector3Normalize( XMVector3Cross(xmN, xmX) ); XMStoreFloat3(&pTerrainSrcPatchBuffer[vertexiDx].b, xmZ); } CalculateNormalsTop void cTerrainRender::CalculateNormalsTOP( unsigned int const iDzADJ, TERRAINVERTEX* const& pTerrainSrcPatchBuffer, TERRAINVERTEX const* const& pTerrainSrcPatchBufferAdj, float const* const& pHeightMap, float const* const& pHeightMapAdj, DWORD const* const& CurrentRemap ) const { XMVECTOR xmX, xmZ, xmN; D3DX_ALIGN16 float tl, l, bl, t, b, tr, r, br, dX, dY; D3DX_ALIGN16 float const normalStrength(4.0f); // iDz -1 : iDz +1 // must sample adjacent iDzMin = iDz-1; D3DX_ALIGN16 unsigned int const iDz(0), iDzMax(iDz+1); D3DX_ALIGN16 unsigned int vertexiDx(0), iDxMin(0), iDxMax(0); for ( unsigned int iDx = 1 ; iDx < m_uiNumVerticesXZ - 1 ; ++iDx ) // except sides on xaxis & corners { // to map the 2D array coordaintes into a 1D array vertexiDx = CurrentRemap[( iDz * m_uiNumVerticesXZ ) + iDx]; // iDx -1 : iDx +1 iDxMin = iDx-1; iDxMax = iDx+1; tl = pHeightMapAdj[ ( iDzADJ * m_uiNumVerticesXZ) + iDxMin ]; l = pHeightMapAdj[ ( iDzADJ * m_uiNumVerticesXZ) + iDx ]; bl = pHeightMapAdj[ ( iDzADJ * m_uiNumVerticesXZ) + iDxMax ]; t = pHeightMap[ ( iDz * m_uiNumVerticesXZ) + iDxMin ]; b = pHeightMap[ ( iDz * m_uiNumVerticesXZ) + iDxMax ]; tr = pHeightMap[ ( iDzMax * m_uiNumVerticesXZ) + iDxMin ]; r = pHeightMap[ ( iDzMax * m_uiNumVerticesXZ) + iDx ]; br = pHeightMap[ ( iDzMax * m_uiNumVerticesXZ) + iDxMax ]; // Compute dx using Sobel: // -1 0 1 // -2 0 2 // -1 0 1 dX = tr + 2*r + br -tl - 2*l - bl; // Compute dy using Sobel: // -1 -2 -1 // 0 0 0 // 1 2 1 dY = bl + 2*b + br -tl - 2*t - tr; // Build the DETAIL normal xmN = XMLoadFloat3A( &XMFLOAT3A(dX, normalStrength, dY) ); // Use the adjoing vertices along both axis to compute the correct normal // // Tangent Vector : t = (1, 0, heightmap[x+1, y] - heightmap[x-1, y]) // Binormal Vector : ß = (0, 1, heightmap[x, y+1] - heightmap[x, y-1]) xmX = XMVectorSubtract( XMLoadFloat3(&pTerrainSrcPatchBuffer[ CurrentRemap[( iDz * m_uiNumVerticesXZ) + iDxMax] ].p), XMLoadFloat3(&pTerrainSrcPatchBuffer[ CurrentRemap[( iDz * m_uiNumVerticesXZ) + iDxMin] ].p) ); xmZ = XMVectorSubtract( XMLoadFloat3(&pTerrainSrcPatchBuffer[ CurrentRemap[( iDzMax * m_uiNumVerticesXZ) + iDx] ].p), XMLoadFloat3(&pTerrainSrcPatchBufferAdj[ CurrentRemap[( iDzADJ * m_uiNumVerticesXZ) + iDx] ].p) ); // Average DETAIL normal from sobel calculation of heightmap with normal computed from vertices xmN = XMVectorAdd(XMVector3Normalize(xmN), XMVector3Normalize(XMVector3Cross(xmZ, xmX))); xmN = XMVectorMultiply(xmN, XMM128::LoadAll(0.5f)); xmN = XMVector3Normalize( xmN ); XMStoreFloat3(&pTerrainSrcPatchBuffer[vertexiDx].n, xmN); // Assign Correct Tangent // xmX = XMVector3Normalize(xmX); XMStoreFloat3(&pTerrainSrcPatchBuffer[vertexiDx].t, xmX); // Calculate BiNormal From CrossProduct of Tangent and the Final Normal // xmZ = XMVector3Normalize( XMVector3Cross(xmN, xmX) ); XMStoreFloat3(&pTerrainSrcPatchBuffer[vertexiDx].b, xmZ); } } CalculateNormalsBOTTOM void cTerrainRender::CalculateNormalsBOTTOM( unsigned int const iDzADJ, TERRAINVERTEX* const& pTerrainSrcPatchBuffer, TERRAINVERTEX const* const& pTerrainSrcPatchBufferAdj, float const* const& pHeightMap, float const* const& pHeightMapAdj, DWORD const* const& CurrentRemap ) const { XMVECTOR xmX, xmZ, xmN; D3DX_ALIGN16 float tl, l, bl, t, b, tr, r, br, dX, dY; D3DX_ALIGN16 float const normalStrength(4.0f); // iDz -1 : iDz +1 // must sample adjacent iDzMax = iDz+1; D3DX_ALIGN16 unsigned int const iDz(m_uiNumVerticesXZ - 1), iDzMin(iDz-1); D3DX_ALIGN16 unsigned int vertexiDx(0), iDxMin(0), iDxMax(0); for ( unsigned int iDx = 1 ; iDx < m_uiNumVerticesXZ - 1 ; ++iDx ) // except sides on xaxis & corners { // to map the 2D array coordaintes into a 1D array vertexiDx = CurrentRemap[( iDz * m_uiNumVerticesXZ ) + iDx]; // iDx -1 : iDx +1 iDxMin = iDx-1; iDxMax = iDx+1; tl = pHeightMap[ ( iDzMin * m_uiNumVerticesXZ) + iDxMin ]; l = pHeightMap[ ( iDzMin * m_uiNumVerticesXZ) + iDx ]; bl = pHeightMap[ ( iDzMin * m_uiNumVerticesXZ) + iDxMax ]; t = pHeightMap[ ( iDz * m_uiNumVerticesXZ) + iDxMin ]; b = pHeightMap[ ( iDz * m_uiNumVerticesXZ) + iDxMax ]; tr = pHeightMapAdj[ ( iDzADJ * m_uiNumVerticesXZ) + iDxMin ]; r = pHeightMapAdj[ ( iDzADJ * m_uiNumVerticesXZ) + iDx ]; br = pHeightMapAdj[ ( iDzADJ * m_uiNumVerticesXZ) + iDxMax ]; // Compute dx using Sobel: // -1 0 1 // -2 0 2 // -1 0 1 dX = tr + 2*r + br -tl - 2*l - bl; // Compute dy using Sobel: // -1 -2 -1 // 0 0 0 // 1 2 1 dY = bl + 2*b + br -tl - 2*t - tr; // Build the DETAIL normal xmN = XMLoadFloat3A( &XMFLOAT3A(dX, normalStrength, dY) ); // Use the adjoing vertices along both axis to compute the correct normal // // Tangent Vector : t = (1, 0, heightmap[x+1, y] - heightmap[x-1, y]) // Binormal Vector : ß = (0, 1, heightmap[x, y+1] - heightmap[x, y-1]) xmX = XMVectorSubtract( XMLoadFloat3(&pTerrainSrcPatchBuffer[ CurrentRemap[( iDz * m_uiNumVerticesXZ) + iDxMax] ].p), XMLoadFloat3(&pTerrainSrcPatchBuffer[ CurrentRemap[( iDz * m_uiNumVerticesXZ) + iDxMin] ].p) ); xmZ = XMVectorSubtract( XMLoadFloat3(&pTerrainSrcPatchBufferAdj[ CurrentRemap[( iDzADJ * m_uiNumVerticesXZ) + iDx] ].p), XMLoadFloat3(&pTerrainSrcPatchBuffer[ CurrentRemap[( iDzMin * m_uiNumVerticesXZ) + iDx] ].p) ); // Average DETAIL normal from sobel calculation of heightmap with normal computed from vertices xmN = XMVectorAdd(XMVector3Normalize(xmN), XMVector3Normalize(XMVector3Cross(xmZ, xmX))); xmN = XMVectorMultiply(xmN, XMM128::LoadAll(0.5f)); xmN = XMVector3Normalize( xmN ); XMStoreFloat3(&pTerrainSrcPatchBuffer[vertexiDx].n, xmN); // Assign Correct Tangent // xmX = XMVector3Normalize(xmX); XMStoreFloat3(&pTerrainSrcPatchBuffer[vertexiDx].t, xmX); // Calculate BiNormal From CrossProduct of Tangent and the Final Normal // xmZ = XMVector3Normalize( XMVector3Cross(xmN, xmX) ); XMStoreFloat3(&pTerrainSrcPatchBuffer[vertexiDx].b, xmZ); } } CalculateNormalsLEFT void cTerrainRender::CalculateNormalsLEFT( unsigned int const iDxADJ, TERRAINVERTEX* const& pTerrainSrcPatchBuffer, TERRAINVERTEX const* const& pTerrainSrcPatchBufferAdj, float const* const& pHeightMap, float const* const& pHeightMapAdj, DWORD const* const& CurrentRemap ) const { XMVECTOR xmX, xmZ, xmN; D3DX_ALIGN16 float tl, l, bl, t, b, tr, r, br, dX, dY; D3DX_ALIGN16 float const normalStrength(4.0f); // iDx -1 : iDx +1 // must sample adjacent iDxMin = iDx-1; D3DX_ALIGN16 unsigned int const iDx(0), iDxMax(iDx+1); D3DX_ALIGN16 unsigned int vertexiDx(0), iDzMin(0), iDzMax(0); for ( unsigned int iDz = 1 ; iDz < m_uiNumVerticesXZ - 1 ; ++iDz ) // except sides on zaxis & corners { // to map the 2D array coordaintes into a 1D array vertexiDx = CurrentRemap[( iDz * m_uiNumVerticesXZ ) + iDx]; // iDx -1 : iDx +1 iDzMin = iDz-1; iDzMax = iDz+1; tl = pHeightMapAdj[ ( iDzMin * m_uiNumVerticesXZ) + iDxADJ ]; l = pHeightMap[ ( iDzMin * m_uiNumVerticesXZ) + iDx ]; bl = pHeightMap[ ( iDzMin * m_uiNumVerticesXZ) + iDxMax ]; t = pHeightMapAdj[ ( iDz * m_uiNumVerticesXZ) + iDxADJ ]; b = pHeightMap[ ( iDz * m_uiNumVerticesXZ) + iDxMax ]; tr = pHeightMapAdj[ ( iDzMax * m_uiNumVerticesXZ) + iDxADJ ]; r = pHeightMap[ ( iDzMax * m_uiNumVerticesXZ) + iDx ]; br = pHeightMap[ ( iDzMax * m_uiNumVerticesXZ) + iDxMax ]; // Compute dx using Sobel: // -1 0 1 // -2 0 2 // -1 0 1 dX = tr + 2*r + br -tl - 2*l - bl; // Compute dy using Sobel: // -1 -2 -1 // 0 0 0 // 1 2 1 dY = bl + 2*b + br -tl - 2*t - tr; // Build the DETAIL normal xmN = XMLoadFloat3A( &XMFLOAT3A(dX, normalStrength, dY) ); // Use the adjoing vertices along both axis to compute the correct normal // // Tangent Vector : t = (1, 0, heightmap[x+1, y] - heightmap[x-1, y]) // Binormal Vector : ß = (0, 1, heightmap[x, y+1] - heightmap[x, y-1]) xmX = XMVectorSubtract( XMLoadFloat3(&pTerrainSrcPatchBuffer[ CurrentRemap[( iDz * m_uiNumVerticesXZ) + iDxMax] ].p), XMLoadFloat3(&pTerrainSrcPatchBufferAdj[ CurrentRemap[( iDz * m_uiNumVerticesXZ) + iDxADJ] ].p) ); xmZ = XMVectorSubtract( XMLoadFloat3(&pTerrainSrcPatchBuffer[ CurrentRemap[( iDzMax * m_uiNumVerticesXZ) + iDx] ].p), XMLoadFloat3(&pTerrainSrcPatchBuffer[ CurrentRemap[( iDzMin * m_uiNumVerticesXZ) + iDx] ].p) ); // Average DETAIL normal from sobel calculation of heightmap with normal computed from vertices xmN = XMVectorAdd(XMVector3Normalize(xmN), XMVector3Normalize(XMVector3Cross(xmZ, xmX))); xmN = XMVectorMultiply(xmN, XMM128::LoadAll(0.5f)); xmN = XMVector3Normalize( xmN ); XMStoreFloat3(&pTerrainSrcPatchBuffer[vertexiDx].n, xmN); // Assign Correct Tangent // xmX = XMVector3Normalize(xmX); XMStoreFloat3(&pTerrainSrcPatchBuffer[vertexiDx].t, xmX); // Calculate BiNormal From CrossProduct of Tangent and the Final Normal // xmZ = XMVector3Normalize( XMVector3Cross(xmN, xmX) ); XMStoreFloat3(&pTerrainSrcPatchBuffer[vertexiDx].b, xmZ); } } CalculateNormalsRIGHT void cTerrainRender::CalculateNormalsRIGHT( unsigned int const iDxADJ, TERRAINVERTEX* const& pTerrainSrcPatchBuffer, TERRAINVERTEX const* const& pTerrainSrcPatchBufferAdj, float const* const& pHeightMap, float const* const& pHeightMapAdj, DWORD const* const& CurrentRemap ) const { XMVECTOR xmX, xmZ, xmN; D3DX_ALIGN16 float tl, l, bl, t, b, tr, r, br, dX, dY; D3DX_ALIGN16 float const normalStrength(4.0f); // iDx -1 : iDx +1 // must sample adjacent iDxMax = iDx+1; D3DX_ALIGN16 unsigned int const iDx(m_uiNumVerticesXZ - 1), iDxMin(iDx-1); D3DX_ALIGN16 unsigned int vertexiDx(0), iDzMin(0), iDzMax(0); for ( unsigned int iDz = 1 ; iDz < m_uiNumVerticesXZ - 1 ; ++iDz ) // except sides on zaxis & corners { // to map the 2D array coordaintes into a 1D array vertexiDx = CurrentRemap[( iDz * m_uiNumVerticesXZ ) + iDx]; // iDx -1 : iDx +1 iDzMin = iDz-1; iDzMax = iDz+1; tl = pHeightMap[ ( iDzMin * m_uiNumVerticesXZ) + iDxMin ]; l = pHeightMap[ ( iDzMin * m_uiNumVerticesXZ) + iDx ]; bl = pHeightMapAdj[ ( iDzMin * m_uiNumVerticesXZ) + iDxADJ ]; t = pHeightMap[ ( iDz * m_uiNumVerticesXZ) + iDxMin ]; b = pHeightMapAdj[ ( iDz * m_uiNumVerticesXZ) + iDxADJ ]; tr = pHeightMap[ ( iDzMax * m_uiNumVerticesXZ) + iDxMin ]; r = pHeightMap[ ( iDzMax * m_uiNumVerticesXZ) + iDx ]; br = pHeightMapAdj[ ( iDzMax * m_uiNumVerticesXZ) + iDxADJ ]; // Compute dx using Sobel: // -1 0 1 // -2 0 2 // -1 0 1 dX = tr + 2*r + br -tl - 2*l - bl; // Compute dy using Sobel: // -1 -2 -1 // 0 0 0 // 1 2 1 dY = bl + 2*b + br -tl - 2*t - tr; // Build the DETAIL normal xmN = XMLoadFloat3A( &XMFLOAT3A(dX, normalStrength, dY) ); // Use the adjoing vertices along both axis to compute the correct normal // // Tangent Vector : t = (1, 0, heightmap[x+1, y] - heightmap[x-1, y]) // Binormal Vector : ß = (0, 1, heightmap[x, y+1] - heightmap[x, y-1]) xmX = XMVectorSubtract( XMLoadFloat3(&pTerrainSrcPatchBufferAdj[ CurrentRemap[( iDz * m_uiNumVerticesXZ) + iDxADJ] ].p), XMLoadFloat3(&pTerrainSrcPatchBuffer[ CurrentRemap[( iDz * m_uiNumVerticesXZ) + iDxMin] ].p) ); xmZ = XMVectorSubtract( XMLoadFloat3(&pTerrainSrcPatchBuffer[ CurrentRemap[( iDzMax * m_uiNumVerticesXZ) + iDx] ].p), XMLoadFloat3(&pTerrainSrcPatchBuffer[ CurrentRemap[( iDzMin * m_uiNumVerticesXZ) + iDx] ].p) ); // Average DETAIL normal from sobel calculation of heightmap with normal computed from vertices xmN = XMVectorAdd(XMVector3Normalize(xmN), XMVector3Normalize(XMVector3Cross(xmZ, xmX))); xmN = XMVectorMultiply(xmN, XMM128::LoadAll(0.5f)); xmN = XMVector3Normalize( xmN ); XMStoreFloat3(&pTerrainSrcPatchBuffer[vertexiDx].n, xmN); // Assign Correct Tangent // xmX = XMVector3Normalize(xmX); XMStoreFloat3(&pTerrainSrcPatchBuffer[vertexiDx].t, xmX); // Calculate BiNormal From CrossProduct of Tangent and the Final Normal // xmZ = XMVector3Normalize( XMVector3Cross(xmN, xmX) ); XMStoreFloat3(&pTerrainSrcPatchBuffer[vertexiDx].b, xmZ); } } And the shader: VS_OUTPUT vsTerrainParallax( VS_INPUT i ) { VS_OUTPUT o; o.vPosition = mul(i.vPosition,uModelViewProj); o.vTex0 = i.vTex0; float3x3 TBN = {i.vTangent,i.vBinormal,i.vNormal}; TBN = transpose(mul(TBN,uModel)); float3 WPos = mul(i.vPosition,uModel); // Rotate Light & View Vector Into Tangent-Space o.vLightDir = mul(uLightVec - WPos,TBN); o.vViewDir = mul(uViewVec - WPos,TBN); o.vHalfAngleDir = o.vLightDir + o.vViewDir; o.vShadowTex = mul(i.vPosition, uTexBiasModelLightViewProj); return(o); } void psTerrainParallax( PS_INPUT i, out float4 oColor0 : COLOR0 ) { float3 vViewDirNormalized = normalize(i.vViewDir); // Sample Height GrayScale Portion of Parallax Map and Calculate New UV Coordinates // //float2 vNewUv = ParallaxMappedUV(tParallaxMap, i.vTex0, vViewDirNormalized.xy); // Sample Main Diffuse Texture // float3 vDiffuseTex = tex2D(tDiffuseMap,i.vTex0); /*this is how you uncompress a normal map*/ //float3 vNormalMap = tex2D(tParallaxMap,vNewUv) * 2.0f - 1.0f; float3 vNormalMap = float3(0.0f,1.0f,0.0f);//tex2D(tParallaxMap,vNewUv) * 2.0f - 1.0f; oColor0 = LitDiffuseSpecular( vDiffuseTex, vNormalMap, normalize(i.vLightDir), vViewDirNormalized, normalize(i.vHalfAngleDir), i.vShadowTex ); }
  5. I'm having a similar problem. Wish I knew how to fix it. I figured my over coordinates were off but they are correct. The chunks are also perfectly aligned. Nonetheless there is a visible seam on the x and zaxis where chunks meet. They also have exactly the same amount of vertices no lod here just bruteforce 64x64 terrain quads. I've basically moved onto other things can't figure it out even tried skirts didn't help sigh
  6. Awesome-sauce!!!
  7. Nah I suggest you do what I did. Build a terrarium, but a giant tarantula in it and perch the ring inside on the sand. Then if she really loves you she'll get it. Exception here being my wife loves spiders
  8. Ah ok maybe I'm being to cheap. I'm gonna just save up the money and buy it I think I'm a little passed that I missed out on the 40 percent off sigh.
  9. Well I don't think it has anything todo with PR or being disrespectful. Neither are we forcing anyone todo anything. This is just giving them the visibility of having a product offer for Genetica Pro at a discounted price for independent developers that make less than $xxx per year.   I would love to buy there product but not able to afford it. If they see the visibility of multiple developers on this thread in the same situation they have potential buyers and a lot of sales to gain at a discounted price.   Doing it privately is not neccesary, and really defeats the whole purpose.
  10. Hey just wondering if there is an option for Genetica 4.0 Indie Pricing, specifically the Pro version because of the support for normal map generation is pretty much required. Maybe we can rally enough people to convince them to give us a fair price for indie developers!!! http://www.spiralgraphics.biz/buygen.htm $400 bucks is way too much.
  11. I would recommend using bitmagic http://bmagic.sourceforge.net/ A way better version of the std::bitset for game programming purposes.
  12. http://www.indiedb.com/members/carandiru/blogs
  13. Thank you, I got it working - sorta. So as I travel to the edge of the world, imagine a cube and I hit the top,bottom,left,right,far,near plane of the level bounds the position jumps to the opposite side. Awesome, yes as the player wraps to the other side of the world. But since it is first-person, when you get the the level bound and you are repositioned to the opposite side of the world - everything you see changes. So what I'm wondering now, is how to see everything "infinitely". So instead of a "pop" to the opposite side of the world, it would appear "seamless".
  14. I'm trying to wrap my head around it. I'm guessing I would be checking the boundaries for the positions of such objects and then having two objects of the same type until it is 100% on one side or the other of the wraparound! Lol I bet that was a mindtwister.... If anyone can recommend a simple, concise implementation for a 3D level wraparound based on defined size of the level for where the wraparound begins... please let me know!!!
  15. I just wanted to post my personal experience, and why I'm no longer a professional software developer. Salary, I will never again in my entire life accept salary again. Either you pay me overtime, time and a half, double time or forget it. Until the industry pays overtime like the trades, it just isn't practical for me. So now I'm in the Telecommunications trade, and I get paid WAY more than I ever did as a software developer, and I love my job because of the work life balance I'm able to have - so grateful. It was a learning experience, a hard one to learn, but eventually I did the right thing. Now I'm Independent, get to work on my game whenever I want, how I want and It's a lot of fun.