/// <summary> /// /// </summary> public override void FrameUpdate() { long currentTime = mWindTimer.Milliseconds; long elapsedTime = currentTime - mLastTime; mLastTime = currentTime; float elapsed = elapsedTime / 1000.0f; //Update the vertex shader parameters foreach (GrassLayer it in mLayerList) { GrassLayer layer = it; layer.UpdateShaders(); GpuProgramParameters gparams = layer.Material.GetTechnique(0).GetPass(0).VertexProgramParameters; if (layer.IsAnimationEnabled) { //Increment animation frame layer.WaveCount += elapsed * (float)(layer.SwaySpeed * System.Math.PI); if (layer.WaveCount > System.Math.PI * 2) { layer.WaveCount -= (float)System.Math.PI * 2; } //Set vertex shader parameters gparams.SetNamedConstant("time", layer.WaveCount); gparams.SetNamedConstant("frequency", layer.SwayDistribution); Vector3 direction = mWindDir * layer.SwayLength; gparams.SetNamedConstant("direction", new Vector4(direction.x, direction.y, direction.z, 0)); } } }
/// <summary> /// /// </summary> /// <param name="material"></param> /// <returns></returns> public GrassLayer AddLayer(string material) { GrassLayer layer = new GrassLayer(mGeom, this); layer.MaterialName = material; mLayerList.Add(layer); return(layer); }
/// <summary> /// /// </summary> /// <param name="page"></param> /// <param name="layer"></param> /// <param name="grassPostions"></param> /// <param name="grassCount"></param> /// <returns></returns> private Mesh GenerateGrassSprite(PageInfo page, GrassLayer layer, IntPtr grassPostions, int grassCount) { //Calculate the number of quads to be added int quadCount = grassCount; //Create manual mesh to store grass quads Mesh mesh = (Mesh)MeshManager.Instance.CreateManual(GetUniqueID(), ResourceGroupManager.DefaultResourceGroupName, null); SubMesh subMesh = mesh.CreateSubMesh(); subMesh.useSharedVertices = false; //Setup vertex format information subMesh.vertexData = new VertexData(); subMesh.vertexData.vertexStart = 0; subMesh.vertexData.vertexCount = 4 * quadCount; VertexDeclaration dcl = subMesh.vertexData.vertexDeclaration; int offset = 0; dcl.AddElement(0, offset, VertexElementType.Float3, VertexElementSemantic.Position); offset += VertexElement.GetTypeSize(VertexElementType.Float3); dcl.AddElement(0, offset, VertexElementType.Float4, VertexElementSemantic.Normal); offset += VertexElement.GetTypeSize(VertexElementType.Float4); dcl.AddElement(0, offset, VertexElementType.Color, VertexElementSemantic.Diffuse); offset += VertexElement.GetTypeSize(VertexElementType.Color); dcl.AddElement(0, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords); offset += VertexElement.GetTypeSize(VertexElementType.Float2); //Populate a new vertex buffer with grass HardwareVertexBuffer vbuf = HardwareBufferManager.Instance.CreateVertexBuffer( /*offset*/dcl, subMesh.vertexData.vertexCount, BufferUsage.DynamicWriteOnly, false); unsafe { float* pReal = (float*)vbuf.Lock(BufferLocking.Discard); //Calculate size variance float rndWidth = layer.mMaxWidth - layer.mMinWidth; float rndHeight = layer.mMaxHeight - layer.mMinHeight; float minY = float.PositiveInfinity, maxY = float.NegativeInfinity; float* posPtr = (float*)grassPostions; //Position array "iterator" for (int i = 0; i < grassCount; i++) { //Get the x and z positions from the position array float x = *posPtr++; float z = *posPtr++; //Calculate height float y = 0; if (mHeightFunction != null) { y = mHeightFunction.GetHeightAt(x, z, mHeightFunctionUserData); } else { y = 0; } float x1 = (x - page.CenterPoint.x); float z1 = (z - page.CenterPoint.z); //Get the color at the grass position uint color = 0; if (layer.ColorMap != null) color = layer.ColorMap.GetColorAt(x, z); else color = 0xFFFFFFFF; //Calculate size float rnd = MogreLibMath.Utility.UnitRandom();//The same rnd value is used for width and height to maintain aspect ratio float halfXScale = (layer.mMinWidth + rndWidth * rnd) * 0.5f; float scaleY = (layer.mMinWidth + rndHeight * rnd); //Randomly mirror grass textures float uvLeft, uvRight; if (MogreLibMath.Utility.UnitRandom() > 0.5f) { uvLeft = 0; uvRight = 1; } else { uvLeft = 1; uvRight = 0; } //Add vertices *pReal++ = x1; *pReal++ = y; *pReal++ = z1; //center position *pReal++ = -halfXScale; *pReal++ = scaleY; *pReal++ = 0; *pReal++ = 0; //normal (used to store relative corner positions) *((uint*)pReal++) = color; //color *pReal++ = uvLeft; *pReal++ = 0; //uv *pReal++ = x1; *pReal++ = y; *pReal++ = z1; //center position *pReal++ = +halfXScale; *pReal++ = scaleY; *pReal++ = 0; *pReal++ = 0; //normal (used to store relative corner positions) *((uint*)pReal++) = color; //color *pReal++ = uvRight; *pReal++ = 0; //uv *pReal++ = x1; *pReal++ = y; *pReal++ = z1; //center position *pReal++ = -halfXScale; *pReal++ = 0.0f; *pReal++ = 0; *pReal++ = 0; //normal (used to store relative corner positions) *((uint*)pReal++) = color; //color *pReal++ = uvLeft; *pReal++ = 1; //uv *pReal++ = x1; *pReal++ = y; *pReal++ = z1; //center position *pReal++ = +halfXScale; *pReal++ = 0.0f; *pReal++ = 0; *pReal++ = 0; //normal (used to store relative corner positions) *((uint*)pReal++) = color; //color *pReal++ = uvRight; *pReal++ = 1; //uv //Update bounds if (y < minY) minY = y; if (y + scaleY > maxY) maxY = y + scaleY; } vbuf.Unlock(); subMesh.vertexData.vertexBufferBinding.SetBinding(0, vbuf); //Populate index buffer subMesh.indexData.indexStart = 0; subMesh.indexData.indexCount = 6 * quadCount; subMesh.indexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size16, subMesh.indexData.indexCount, BufferUsage.DynamicWriteOnly); ushort* pI = (ushort*)subMesh.indexData.indexBuffer.Lock(BufferLocking.Discard); for (ushort i = 0; i < quadCount; i++) { ushort ofset = (ushort)(i * 4); *pI++ = (ushort)(0 + ofset); *pI++ = (ushort)(2 + ofset); *pI++ = (ushort)(1 + ofset); *pI++ = (ushort)(1 + ofset); *pI++ = (ushort)(2 + ofset); *pI++ = (ushort)(3 + ofset); } subMesh.indexData.indexBuffer.Unlock(); //Finish up mesh AxisAlignedBox bounds = new AxisAlignedBox( new Vector3(page.Bounds.Left - page.CenterPoint.x, minY, page.Bounds.Top - page.CenterPoint.z), new Vector3(page.Bounds.Right - page.CenterPoint.x, maxY, page.Bounds.Bottom - page.CenterPoint.z)); mesh.BoundingBox = bounds; Vector3 tmp = bounds.Maximum - bounds.Minimum; mesh.BoundingSphereRadius = tmp.Length * 0.5f; mesh.Load(); //Apply grass material to mesh subMesh.MaterialName = layer.Material.Name; //Return the mesh return mesh; } }
/// <summary> /// /// </summary> /// <param name="page"></param> /// <param name="layer"></param> /// <param name="grassPostions"></param> /// <param name="grassCount"></param> /// <returns></returns> private Mesh GenerateGrassCrossQuads(PageInfo page, GrassLayer layer, IntPtr grassPostions, int grassCount) { //Calculate the number of quads to be added int quadCount = grassCount * 2; //Create manual mesh to store grass quads Mesh mesh = (Mesh)MeshManager.Instance.CreateManual(GetUniqueID(), ResourceGroupManager.DefaultResourceGroupName, null); SubMesh subMesh = mesh.CreateSubMesh(); subMesh.useSharedVertices = false; //Setup vertex format information subMesh.vertexData = new VertexData(); subMesh.vertexData.vertexStart = 0; subMesh.vertexData.vertexCount = 4 * quadCount; VertexDeclaration dcl = subMesh.vertexData.vertexDeclaration; int offset = 0; dcl.AddElement(0, offset, VertexElementType.Float3, VertexElementSemantic.Position); offset += VertexElement.GetTypeSize(VertexElementType.Float3); dcl.AddElement(0, offset, VertexElementType.Color, VertexElementSemantic.Diffuse); offset += VertexElement.GetTypeSize(VertexElementType.Color); dcl.AddElement(0, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords); offset += VertexElement.GetTypeSize(VertexElementType.Float2); //Populate a new vertex buffer with grass HardwareVertexBuffer vbuf = HardwareBufferManager.Instance.CreateVertexBuffer( /*offset*/dcl, subMesh.vertexData.vertexCount, BufferUsage.DynamicWriteOnly, false); unsafe { float* pReal = (float*)vbuf.Lock(BufferLocking.Discard); //Calculate size variance float rndWidth = layer.mMaxWidth - layer.mMinWidth; float rndHeight = layer.mMaxHeight - layer.mMinHeight; float minY = float.PositiveInfinity, maxY = float.NegativeInfinity; float* posPtr = (float*)grassPostions; //Position array "iterator" for (int i = 0; i < grassCount; i++) { //Get the x and z positions from the position array float x = *posPtr++; float z = *posPtr++; //Get the color at the grass position uint color = 0; if (layer.ColorMap != null) color = layer.ColorMap.GetColorAt(x, z); else color = 0xFFFFFFFF; //Calculate size float rnd = MogreLibMath.Utility.UnitRandom();//The same rnd value is used for width and height to maintain aspect ratio float halfXScale = (layer.mMinWidth + rndWidth * rnd) * 0.5f; float scaleY = (layer.mMinWidth + rndHeight * rnd); //Calculate rotation float angle = MogreLibMath.Utility.RangeRandom(0, MogreLibMath.Utility.TWO_PI); float xTrans = MogreLibMath.Utility.Cos(angle) * halfXScale; float zTrans = MogreLibMath.Utility.Sin(angle) * halfXScale; //Calculate heights and edge positions float x1 = x - xTrans, z1 = z - zTrans; float x2 = x + xTrans, z2 = z + zTrans; float y1, y2; if (mHeightFunction != null) { y1 = mHeightFunction.GetHeightAt(x1, z1, mHeightFunctionUserData); y2 = mHeightFunction.GetHeightAt(x2, z2, mHeightFunctionUserData); } else { y1 = 0; y2 = 0; } //Add vertices *pReal++ = (x1 - page.CenterPoint.x); *pReal++ = (y1 + scaleY); *pReal++ = (z1 - page.CenterPoint.z); //pos *((uint*)pReal++) = color; //color *pReal++ = 0; *pReal++ = 0; //uv *pReal++ = (x2 - page.CenterPoint.x); *pReal++ = (y2 + scaleY); *pReal++ = (z2 - page.CenterPoint.z); //pos *((uint*)pReal++) = color; //color *pReal++ = 1; *pReal++ = 0; //uv *pReal++ = (x1 - page.CenterPoint.x); *pReal++ = (y1); *pReal++ = (z1 - page.CenterPoint.z); //pos *((uint*)pReal++) = color; //color *pReal++ = 0; *pReal++ = 1; //uv *pReal++ = (x2 - page.CenterPoint.x); *pReal++ = (y2); *pReal++ = (z2 - page.CenterPoint.z); //pos *((uint*)pReal++) = color; //color *pReal++ = 1; *pReal++ = 1; //uv //Update bounds if (y1 < minY) minY = y1; if (y2 < minY) minY = y2; if (y1 + scaleY > maxY) maxY = y1 + scaleY; if (y2 + scaleY > maxY) maxY = y2 + scaleY; //Calculate heights and edge positions float x3 = x + zTrans, z3 = z - xTrans; float x4 = x - zTrans, z4 = z + xTrans; float y3, y4; if (mHeightFunction != null) { y3 = mHeightFunction.GetHeightAt(x3, z3, mHeightFunctionUserData); y4 = mHeightFunction.GetHeightAt(x4, z4, mHeightFunctionUserData); } else { y3 = 0; y4 = 0; } //Add vertices *pReal++ = (x3 - page.CenterPoint.x); *pReal++ = (y3 + scaleY); *pReal++ = (z3 - page.CenterPoint.z); //pos *((uint*)pReal++) = color; //color *pReal++ = 0; *pReal++ = 0; //uv *pReal++ = (x4 - page.CenterPoint.x); *pReal++ = (y4 + scaleY); *pReal++ = (z4 - page.CenterPoint.z); //pos *((uint*)pReal++) = color; //color *pReal++ = 1; *pReal++ = 0; //uv *pReal++ = (x3 - page.CenterPoint.x); *pReal++ = (y3); *pReal++ = (z3 - page.CenterPoint.z); //pos *((uint*)pReal++) = color; //color *pReal++ = 0; *pReal++ = 1; //uv *pReal++ = (x4 - page.CenterPoint.x); *pReal++ = (y4); *pReal++ = (z4 - page.CenterPoint.z); //pos *((uint*)pReal++) = color; //color *pReal++ = 1; *pReal++ = 1; //uv //Update bounds if (y3 < minY) minY = y1; if (y4 < minY) minY = y2; if (y3 + scaleY > maxY) maxY = y3 + scaleY; if (y4 + scaleY > maxY) maxY = y4 + scaleY; } vbuf.Unlock(); subMesh.vertexData.vertexBufferBinding.SetBinding(0, vbuf); //Populate index buffer subMesh.indexData.indexStart = 0; subMesh.indexData.indexCount = 6 * quadCount; subMesh.indexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size16, subMesh.indexData.indexCount, BufferUsage.DynamicWriteOnly); ushort* pI = (ushort*)subMesh.indexData.indexBuffer.Lock(BufferLocking.Discard); for (ushort i = 0; i < quadCount; i++) { ushort ofset = (ushort)(i * 4); *pI++ = (ushort)(0 + ofset); *pI++ = (ushort)(2 + ofset); *pI++ = (ushort)(1 + ofset); *pI++ = (ushort)(1 + ofset); *pI++ = (ushort)(2 + ofset); *pI++ = (ushort)(3 + ofset); } subMesh.indexData.indexBuffer.Unlock(); //Finish up mesh AxisAlignedBox bounds = new AxisAlignedBox( new Vector3(page.Bounds.Left - page.CenterPoint.x, minY, page.Bounds.Top - page.CenterPoint.z), new Vector3(page.Bounds.Right - page.CenterPoint.x, maxY, page.Bounds.Bottom - page.CenterPoint.z)); mesh.BoundingBox = bounds; Vector3 tmp = bounds.Maximum - bounds.Minimum; mesh.BoundingSphereRadius = tmp.Length * 0.5f; mesh.Load(); //Apply grass material to mesh subMesh.MaterialName = layer.Material.Name; //Return the mesh return mesh; } }
/// <summary> /// /// </summary> /// <param name="layer"></param> public void DeleteLayer(ref GrassLayer layer) { mLayerList.Remove(layer); layer = null; }
/// <summary> /// /// </summary> /// <param name="material"></param> /// <returns></returns> public GrassLayer AddLayer(string material) { GrassLayer layer = new GrassLayer(mGeom, this); layer.MaterialName = material; mLayerList.Add(layer); return layer; }
/// <summary> /// /// </summary> /// <param name="page"></param> /// <param name="layer"></param> /// <param name="grassPostions"></param> /// <param name="grassCount"></param> /// <returns></returns> private Mesh GenerateGrassSprite(PageInfo page, GrassLayer layer, IntPtr grassPostions, int grassCount) { //Calculate the number of quads to be added int quadCount = grassCount; //Create manual mesh to store grass quads Mesh mesh = (Mesh)MeshManager.Instance.CreateManual(GetUniqueID(), ResourceGroupManager.DefaultResourceGroupName, null); SubMesh subMesh = mesh.CreateSubMesh(); subMesh.useSharedVertices = false; //Setup vertex format information subMesh.vertexData = new VertexData(); subMesh.vertexData.vertexStart = 0; subMesh.vertexData.vertexCount = 4 * quadCount; VertexDeclaration dcl = subMesh.vertexData.vertexDeclaration; int offset = 0; dcl.AddElement(0, offset, VertexElementType.Float3, VertexElementSemantic.Position); offset += VertexElement.GetTypeSize(VertexElementType.Float3); dcl.AddElement(0, offset, VertexElementType.Float4, VertexElementSemantic.Normal); offset += VertexElement.GetTypeSize(VertexElementType.Float4); dcl.AddElement(0, offset, VertexElementType.Color, VertexElementSemantic.Diffuse); offset += VertexElement.GetTypeSize(VertexElementType.Color); dcl.AddElement(0, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords); offset += VertexElement.GetTypeSize(VertexElementType.Float2); //Populate a new vertex buffer with grass HardwareVertexBuffer vbuf = HardwareBufferManager.Instance.CreateVertexBuffer( /*offset*/ dcl, subMesh.vertexData.vertexCount, BufferUsage.DynamicWriteOnly, false); unsafe { float *pReal = (float *)vbuf.Lock(BufferLocking.Discard); //Calculate size variance float rndWidth = layer.mMaxWidth - layer.mMinWidth; float rndHeight = layer.mMaxHeight - layer.mMinHeight; float minY = float.PositiveInfinity, maxY = float.NegativeInfinity; float *posPtr = (float *)grassPostions; //Position array "iterator" for (int i = 0; i < grassCount; i++) { //Get the x and z positions from the position array float x = *posPtr++; float z = *posPtr++; //Calculate height float y = 0; if (mHeightFunction != null) { y = mHeightFunction.GetHeightAt(x, z, mHeightFunctionUserData); } else { y = 0; } float x1 = (x - page.CenterPoint.x); float z1 = (z - page.CenterPoint.z); //Get the color at the grass position uint color = 0; if (layer.ColorMap != null) { color = layer.ColorMap.GetColorAt(x, z); } else { color = 0xFFFFFFFF; } //Calculate size float rnd = MogreLibMath.Utility.UnitRandom();//The same rnd value is used for width and height to maintain aspect ratio float halfXScale = (layer.mMinWidth + rndWidth * rnd) * 0.5f; float scaleY = (layer.mMinWidth + rndHeight * rnd); //Randomly mirror grass textures float uvLeft, uvRight; if (MogreLibMath.Utility.UnitRandom() > 0.5f) { uvLeft = 0; uvRight = 1; } else { uvLeft = 1; uvRight = 0; } //Add vertices *pReal++ = x1; *pReal++ = y; *pReal++ = z1; //center position *pReal++ = -halfXScale; *pReal++ = scaleY; *pReal++ = 0; *pReal++ = 0; //normal (used to store relative corner positions) *((uint *)pReal++) = color; //color *pReal++ = uvLeft; *pReal++ = 0; //uv *pReal++ = x1; *pReal++ = y; *pReal++ = z1; //center position *pReal++ = +halfXScale; *pReal++ = scaleY; *pReal++ = 0; *pReal++ = 0; //normal (used to store relative corner positions) *((uint *)pReal++) = color; //color *pReal++ = uvRight; *pReal++ = 0; //uv *pReal++ = x1; *pReal++ = y; *pReal++ = z1; //center position *pReal++ = -halfXScale; *pReal++ = 0.0f; *pReal++ = 0; *pReal++ = 0; //normal (used to store relative corner positions) *((uint *)pReal++) = color; //color *pReal++ = uvLeft; *pReal++ = 1; //uv *pReal++ = x1; *pReal++ = y; *pReal++ = z1; //center position *pReal++ = +halfXScale; *pReal++ = 0.0f; *pReal++ = 0; *pReal++ = 0; //normal (used to store relative corner positions) *((uint *)pReal++) = color; //color *pReal++ = uvRight; *pReal++ = 1; //uv //Update bounds if (y < minY) { minY = y; } if (y + scaleY > maxY) { maxY = y + scaleY; } } vbuf.Unlock(); subMesh.vertexData.vertexBufferBinding.SetBinding(0, vbuf); //Populate index buffer subMesh.indexData.indexStart = 0; subMesh.indexData.indexCount = 6 * quadCount; subMesh.indexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size16, subMesh.indexData.indexCount, BufferUsage.DynamicWriteOnly); ushort *pI = (ushort *)subMesh.indexData.indexBuffer.Lock(BufferLocking.Discard); for (ushort i = 0; i < quadCount; i++) { ushort ofset = (ushort)(i * 4); * pI++ = (ushort)(0 + ofset); * pI++ = (ushort)(2 + ofset); * pI++ = (ushort)(1 + ofset); *pI++ = (ushort)(1 + ofset); *pI++ = (ushort)(2 + ofset); *pI++ = (ushort)(3 + ofset); } subMesh.indexData.indexBuffer.Unlock(); //Finish up mesh AxisAlignedBox bounds = new AxisAlignedBox( new Vector3(page.Bounds.Left - page.CenterPoint.x, minY, page.Bounds.Top - page.CenterPoint.z), new Vector3(page.Bounds.Right - page.CenterPoint.x, maxY, page.Bounds.Bottom - page.CenterPoint.z)); mesh.BoundingBox = bounds; Vector3 tmp = bounds.Maximum - bounds.Minimum; mesh.BoundingSphereRadius = tmp.Length * 0.5f; mesh.Load(); //Apply grass material to mesh subMesh.MaterialName = layer.Material.Name; //Return the mesh return(mesh); } }
/// <summary> /// /// </summary> /// <param name="page"></param> /// <param name="layer"></param> /// <param name="grassPostions"></param> /// <param name="grassCount"></param> /// <returns></returns> private Mesh GenerateGrassCrossQuads(PageInfo page, GrassLayer layer, IntPtr grassPostions, int grassCount) { //Calculate the number of quads to be added int quadCount = grassCount * 2; //Create manual mesh to store grass quads Mesh mesh = (Mesh)MeshManager.Instance.CreateManual(GetUniqueID(), ResourceGroupManager.DefaultResourceGroupName, null); SubMesh subMesh = mesh.CreateSubMesh(); subMesh.useSharedVertices = false; //Setup vertex format information subMesh.vertexData = new VertexData(); subMesh.vertexData.vertexStart = 0; subMesh.vertexData.vertexCount = 4 * quadCount; VertexDeclaration dcl = subMesh.vertexData.vertexDeclaration; int offset = 0; dcl.AddElement(0, offset, VertexElementType.Float3, VertexElementSemantic.Position); offset += VertexElement.GetTypeSize(VertexElementType.Float3); dcl.AddElement(0, offset, VertexElementType.Color, VertexElementSemantic.Diffuse); offset += VertexElement.GetTypeSize(VertexElementType.Color); dcl.AddElement(0, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords); offset += VertexElement.GetTypeSize(VertexElementType.Float2); //Populate a new vertex buffer with grass HardwareVertexBuffer vbuf = HardwareBufferManager.Instance.CreateVertexBuffer( /*offset*/ dcl, subMesh.vertexData.vertexCount, BufferUsage.DynamicWriteOnly, false); unsafe { float *pReal = (float *)vbuf.Lock(BufferLocking.Discard); //Calculate size variance float rndWidth = layer.mMaxWidth - layer.mMinWidth; float rndHeight = layer.mMaxHeight - layer.mMinHeight; float minY = float.PositiveInfinity, maxY = float.NegativeInfinity; float *posPtr = (float *)grassPostions; //Position array "iterator" for (int i = 0; i < grassCount; i++) { //Get the x and z positions from the position array float x = *posPtr++; float z = *posPtr++; //Get the color at the grass position uint color = 0; if (layer.ColorMap != null) { color = layer.ColorMap.GetColorAt(x, z); } else { color = 0xFFFFFFFF; } //Calculate size float rnd = MogreLibMath.Utility.UnitRandom();//The same rnd value is used for width and height to maintain aspect ratio float halfXScale = (layer.mMinWidth + rndWidth * rnd) * 0.5f; float scaleY = (layer.mMinWidth + rndHeight * rnd); //Calculate rotation float angle = MogreLibMath.Utility.RangeRandom(0, MogreLibMath.Utility.TWO_PI); float xTrans = MogreLibMath.Utility.Cos(angle) * halfXScale; float zTrans = MogreLibMath.Utility.Sin(angle) * halfXScale; //Calculate heights and edge positions float x1 = x - xTrans, z1 = z - zTrans; float x2 = x + xTrans, z2 = z + zTrans; float y1, y2; if (mHeightFunction != null) { y1 = mHeightFunction.GetHeightAt(x1, z1, mHeightFunctionUserData); y2 = mHeightFunction.GetHeightAt(x2, z2, mHeightFunctionUserData); } else { y1 = 0; y2 = 0; } //Add vertices *pReal++ = (x1 - page.CenterPoint.x); *pReal++ = (y1 + scaleY); *pReal++ = (z1 - page.CenterPoint.z); //pos *((uint *)pReal++) = color; //color *pReal++ = 0; *pReal++ = 0; //uv *pReal++ = (x2 - page.CenterPoint.x); *pReal++ = (y2 + scaleY); *pReal++ = (z2 - page.CenterPoint.z); //pos *((uint *)pReal++) = color; //color *pReal++ = 1; *pReal++ = 0; //uv *pReal++ = (x1 - page.CenterPoint.x); *pReal++ = (y1); *pReal++ = (z1 - page.CenterPoint.z); //pos *((uint *)pReal++) = color; //color *pReal++ = 0; *pReal++ = 1; //uv *pReal++ = (x2 - page.CenterPoint.x); *pReal++ = (y2); *pReal++ = (z2 - page.CenterPoint.z); //pos *((uint *)pReal++) = color; //color *pReal++ = 1; *pReal++ = 1; //uv //Update bounds if (y1 < minY) { minY = y1; } if (y2 < minY) { minY = y2; } if (y1 + scaleY > maxY) { maxY = y1 + scaleY; } if (y2 + scaleY > maxY) { maxY = y2 + scaleY; } //Calculate heights and edge positions float x3 = x + zTrans, z3 = z - xTrans; float x4 = x - zTrans, z4 = z + xTrans; float y3, y4; if (mHeightFunction != null) { y3 = mHeightFunction.GetHeightAt(x3, z3, mHeightFunctionUserData); y4 = mHeightFunction.GetHeightAt(x4, z4, mHeightFunctionUserData); } else { y3 = 0; y4 = 0; } //Add vertices *pReal++ = (x3 - page.CenterPoint.x); *pReal++ = (y3 + scaleY); *pReal++ = (z3 - page.CenterPoint.z); //pos *((uint *)pReal++) = color; //color *pReal++ = 0; *pReal++ = 0; //uv *pReal++ = (x4 - page.CenterPoint.x); *pReal++ = (y4 + scaleY); *pReal++ = (z4 - page.CenterPoint.z); //pos *((uint *)pReal++) = color; //color *pReal++ = 1; *pReal++ = 0; //uv *pReal++ = (x3 - page.CenterPoint.x); *pReal++ = (y3); *pReal++ = (z3 - page.CenterPoint.z); //pos *((uint *)pReal++) = color; //color *pReal++ = 0; *pReal++ = 1; //uv *pReal++ = (x4 - page.CenterPoint.x); *pReal++ = (y4); *pReal++ = (z4 - page.CenterPoint.z); //pos *((uint *)pReal++) = color; //color *pReal++ = 1; *pReal++ = 1; //uv //Update bounds if (y3 < minY) { minY = y1; } if (y4 < minY) { minY = y2; } if (y3 + scaleY > maxY) { maxY = y3 + scaleY; } if (y4 + scaleY > maxY) { maxY = y4 + scaleY; } } vbuf.Unlock(); subMesh.vertexData.vertexBufferBinding.SetBinding(0, vbuf); //Populate index buffer subMesh.indexData.indexStart = 0; subMesh.indexData.indexCount = 6 * quadCount; subMesh.indexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size16, subMesh.indexData.indexCount, BufferUsage.DynamicWriteOnly); ushort *pI = (ushort *)subMesh.indexData.indexBuffer.Lock(BufferLocking.Discard); for (ushort i = 0; i < quadCount; i++) { ushort ofset = (ushort)(i * 4); * pI++ = (ushort)(0 + ofset); * pI++ = (ushort)(2 + ofset); * pI++ = (ushort)(1 + ofset); *pI++ = (ushort)(1 + ofset); *pI++ = (ushort)(2 + ofset); *pI++ = (ushort)(3 + ofset); } subMesh.indexData.indexBuffer.Unlock(); //Finish up mesh AxisAlignedBox bounds = new AxisAlignedBox( new Vector3(page.Bounds.Left - page.CenterPoint.x, minY, page.Bounds.Top - page.CenterPoint.z), new Vector3(page.Bounds.Right - page.CenterPoint.x, maxY, page.Bounds.Bottom - page.CenterPoint.z)); mesh.BoundingBox = bounds; Vector3 tmp = bounds.Maximum - bounds.Minimum; mesh.BoundingSphereRadius = tmp.Length * 0.5f; mesh.Load(); //Apply grass material to mesh subMesh.MaterialName = layer.Material.Name; //Return the mesh return(mesh); } }
/// <summary> /// /// </summary> /// <param name="page"></param> public override void LoadPage(PageInfo page) { //Seed random number generator based on page indexes ushort xSeed = (ushort)(page.XIndex % 0xFFFF); ushort zSeed = (ushort)(page.ZIndex % 0xFFFF); uint seed = (uint)(xSeed << 16) | zSeed; seed = (uint)new Random((int)seed).Next(); //Keep a list of a generated meshes List <Mesh> meshList = new List <Mesh>(); page.UserData = (object)meshList; //Generate meshes foreach (GrassLayer it in mLayerList) { GrassLayer layer = it; //Calculate how much grass needs to be added float volume = page.Bounds.Width * page.Bounds.Height; int grassCount = (int)(layer.Density * DensityFactor * volume); //The vertex buffer can't be allocated until the exact number of polygons is known, //so the locations of all grasses in this page must be precalculated. //Precompute grass locations into an array of floats. A plain array is used for speed; //there's no need to use a dynamic sized array since a maximum size is known. float[] position = new float[grassCount * 2]; IntPtr posBuff = Memory.PinObject(position); if (layer.DensityMap != null) { if (layer.DensityMap.Filter == MapFilter.None) { grassCount = (int)layer.PopulateGrassListUnfilteredDM(page, posBuff, grassCount); } else if (layer.DensityMap.Filter == MapFilter.Bilinear) { grassCount = (int)layer.PopulateGrassListBilenearDM(page, posBuff, grassCount); } } else { grassCount = (int)layer.PopulateGrassListUniform(page, posBuff, grassCount); } //Don't build a mesh unless it contains something if (grassCount != 0) { Mesh mesh = null; switch (layer.RenderTechnique) { case GrassTechnique.Quad: mesh = GenerateGrassQuad(page, layer, posBuff, grassCount); break; case GrassTechnique.CrossQuads: mesh = GenerateGrassCrossQuads(page, layer, posBuff, grassCount); break; case GrassTechnique.Sprite: mesh = GenerateGrassSprite(page, layer, posBuff, grassCount); break; } Debug.Assert(mesh != null); //Add the mesh to PagedGeometry Entity entity = mGeom.Camera.SceneManager.CreateEntity(GetUniqueID(), mesh.Name); entity.RenderQueueGroup = mRenderQueue; entity.CastShadows = false; AddEntity(entity, page.CenterPoint, Quaternion.Identity, Vector3.UnitScale); mGeom.SceneManager.RemoveEntity(entity); //Store the mesh pointer meshList.Add(mesh); } //Delete the position list //Memory.UnpinObject(posBuff); position = null; } }
/// <summary> /// /// </summary> /// <param name="layer"></param> public void DeleteLayer(ref GrassLayer layer) { mLayerList.Remove(layer); layer = null; }