Exemplo n.º 1
0
// ***************************************************************************
void		CVisualCollisionMesh::receiveShadowMap(const NLMISC::CMatrix &instanceMatrix, const CShadowContext &shadowContext)
{
	// empty mesh => no op
	if(_Vertices.empty())
		return;

	// The VertexBuffer RefPtr has been released? quit
	if(_VertexBuffer == NULL)
		return;


	// **** Select triangles to be rendered with quadGrid
	// select with quadGrid local in mesh
	CAABBox		localBB;
	localBB= CAABBox::transformAABBox(instanceMatrix.inverted(), shadowContext.ShadowWorldBB);
	static	std::vector<uint16>		triInQuadGrid;
	uint	numTrisInQuadGrid= _QuadGrid.select(localBB, triInQuadGrid);

	// no intersection at all? quit
	if(numTrisInQuadGrid==0)
		return;


	// **** prepare more precise Clip with shadow pyramid
	// enlarge temp flag array
	static	std::vector<uint8>	vertexFlags;
	if(vertexFlags.size()<_Vertices.size())
		vertexFlags.resize(_Vertices.size());
	// reset all to 0
	memset(&vertexFlags[0], 0, _Vertices.size()*sizeof(uint8));

	// Compute the "LocalToInstance" shadow Clip Volume
	static	std::vector<CPlane>		localClipPlanes;
	/*	We want to apply to plane this matrix: IM-1 * MCasterPos,
		where IM=instanceMatrix and MCasterPos= matrix translation of "shadowContext.CasterPos"
		BUT, since to transform a plane, we must do plane * M-1, then compute this matrix:
		localMat= MCasterPos-1 * IM
	*/
	CMatrix		localMat;
	localMat.setPos(-shadowContext.CasterPos);
	localMat*= instanceMatrix;
	// Allow max bits of planes clip.
	localClipPlanes.resize(min((uint)shadowContext.ShadowMap->LocalClipPlanes.size(), (uint)NL3D_VCM_SHADOW_NUM_CLIP_PLANE));
	// Transform into Mesh local space
	for(uint i=0;i<localClipPlanes.size();i++)
	{
		localClipPlanes[i]= shadowContext.ShadowMap->LocalClipPlanes[i] * localMat;
	}


	// **** Clip and fill the triangles
	uint	currentTriIdx= 0;
	// enlarge the index buffer as max of triangles possibly intersected
	shadowContext.IndexBuffer.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT);
	if(shadowContext.IndexBuffer.getNumIndexes()<numTrisInQuadGrid*3)
		shadowContext.IndexBuffer.setNumIndexes(numTrisInQuadGrid*3);

	// Start to clip and fill
	{
		CIndexBufferReadWrite	iba;
		shadowContext.IndexBuffer.lock(iba);
		if (iba.getFormat() == CIndexBuffer::Indices32)
		{
			uint32	*ibPtr= (uint32 *) iba.getPtr();
			// for all triangles selected with the quadgrid
			for(uint triq=0; triq<numTrisInQuadGrid;triq++)
			{
				uint			triId[3];
				triId[0]= _Triangles[uint(triInQuadGrid[triq])*3+0];
				triId[1]= _Triangles[uint(triInQuadGrid[triq])*3+1];
				triId[2]= _Triangles[uint(triInQuadGrid[triq])*3+2];
				uint			triFlag= NL3D_VCM_SHADOW_NUM_CLIP_PLANE_MASK;

				// for all vertices, clip them
				for(uint i=0;i<3;i++)
				{
					uint	vid= triId[i];
					uint	vf= vertexFlags[vid];

					// if this vertex is still not computed
					if(!vf)
					{
						// For all planes of the Clip Volume, clip this vertex.
						for(uint j=0;j<localClipPlanes.size();j++)
						{
							// out if in front
							bool	out= localClipPlanes[j]*_Vertices[vid] > 0;

							vf|= ((uint)out)<<j;
						}

						// add the bit flag to say "computed".
						vf|= NL3D_VCM_SHADOW_NUM_CLIP_PLANE_SHIFT;

						// store
						vertexFlags[vid]= vf;
					}

					// And all vertex bits.
					triFlag&= vf;
				}

				// if triangle not clipped, add the triangle
				if( (triFlag & NL3D_VCM_SHADOW_NUM_CLIP_PLANE_MASK)==0 )
				{
					// Add the 3 index to the index buffer.
					ibPtr[currentTriIdx++]= triId[0];
					ibPtr[currentTriIdx++]= triId[1];
					ibPtr[currentTriIdx++]= triId[2];
				}
			}
		}
		else
		{
			nlassert(iba.getFormat() == CIndexBuffer::Indices16);
			uint16	*ibPtr= (uint16 *) iba.getPtr();
			// for all triangles selected with the quadgrid
			for(uint triq=0; triq<numTrisInQuadGrid;triq++)
			{
				uint			triId[3];
				triId[0]= _Triangles[uint(triInQuadGrid[triq])*3+0];
				triId[1]= _Triangles[uint(triInQuadGrid[triq])*3+1];
				triId[2]= _Triangles[uint(triInQuadGrid[triq])*3+2];
				uint			triFlag= NL3D_VCM_SHADOW_NUM_CLIP_PLANE_MASK;

				// for all vertices, clip them
				for(uint i=0;i<3;i++)
				{
					uint	vid= triId[i];
					uint	vf= vertexFlags[vid];

					// if this vertex is still not computed
					if(!vf)
					{
						// For all planes of the Clip Volume, clip this vertex.
						for(uint j=0;j<localClipPlanes.size();j++)
						{
							// out if in front
							bool	out= localClipPlanes[j]*_Vertices[vid] > 0;

							vf|= ((uint)out)<<j;
						}

						// add the bit flag to say "computed".
						vf|= NL3D_VCM_SHADOW_NUM_CLIP_PLANE_SHIFT;

						// store
						vertexFlags[vid]= vf;
					}

					// And all vertex bits.
					triFlag&= vf;
				}

				// if triangle not clipped, add the triangle
				// if( (triFlag & NL3D_VCM_SHADOW_NUM_CLIP_PLANE_MASK)==0 )
				if (triFlag == 0) // previous line not useful due to init
				{
					// Add the 3 index to the index buffer.
					ibPtr[currentTriIdx++]= (uint16) triId[0];
					ibPtr[currentTriIdx++]= (uint16) triId[1];
					ibPtr[currentTriIdx++]= (uint16) triId[2];
				}
			}
		}
	}


	// **** Render
	// if some triangle to render
	if(currentTriIdx)
	{
		IDriver	*drv= shadowContext.Driver;
		// setup the collision instance matrix
		drv->setupModelMatrix(instanceMatrix);
		// update the material projection matrix, cause matrix changed
		shadowContext.ShadowMapProjector.applyToMaterial(instanceMatrix, shadowContext.ShadowMaterial);
		// render
		drv->activeVertexBuffer(*_VertexBuffer);
		drv->activeIndexBuffer(shadowContext.IndexBuffer);
		drv->renderTriangles(shadowContext.ShadowMaterial, 0, currentTriIdx/3);
		// TestYoyo. Show in Red triangles selected
		/*if(TESTYOYO_VCM_RedShadow)
		{
			static	CMaterial	tam;
			tam.initUnlit();
			tam.setColor(CRGBA(255,0,0,128));
			tam.setZFunc(CMaterial::always);
			tam.setZWrite(false);
			tam.setBlend(true);
			tam.setBlendFunc(CMaterial::srcalpha, CMaterial::invsrcalpha);
			tam.setDoubleSided(true);
			drv->renderTriangles(tam, 0, currentTriIdx/3);
		}*/
	}
}