Jump to content

  • Log In with Google      Sign In   
  • Create Account

Interested in a FREE copy of HTML5 game maker Construct 2?

We'll be giving away three Personal Edition licences in next Tuesday's GDNet Direct email newsletter!

Sign up from the right-hand sidebar on our homepage and read Tuesday's newsletter for details!


Carandiru

Member Since 27 Aug 2001
Offline Last Active Oct 29 2013 01:57 PM

#5086672 Terrain lighting seams?

Posted by Carandiru on 16 August 2013 - 10:20 PM

Well I had a crack at using neighbour patches to calculate the edge normals and here is my result:

scs-20130816.png

 

Which is worse than before with no neighbour patch sampling:

scs-20130816-2.png

 

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 );
}



#5069836 DWORD instead of std::bitset fails

Posted by Carandiru on 14 June 2013 - 02:19 PM

I would recommend using bitmagic http://bmagic.sourceforge.net/

A way better version of the std::bitset for game programming purposes.




PARTNERS