Jump to content

  • Log In with Google      Sign In   
  • Create Account

We need your feedback on a survey! Each completed response supports our community and gives you a chance to win a $25 Amazon gift card!


Carandiru

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

Posts I've Made

In Topic: Terrain lighting seams?

25 August 2013 - 12:40 AM

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. 


In Topic: Terrain lighting seams?

19 August 2013 - 02:58 AM

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.

In Topic: Terrain lighting seams?

16 August 2013 - 10:24 PM

Oh I should also mention all textures I use are made seamless.


In Topic: Terrain lighting seams?

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

In Topic: Terrain lighting seams?

15 August 2013 - 05:51 PM

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

PARTNERS