/// <summary> /// /// </summary> /// <param name="position"></param> /// <param name="xScale"></param> /// <param name="yScale"></param> /// <param name="color"></param> /// <param name="texcoordIndexU"></param> /// <param name="texcoordsIndexV"></param> public void CreateBillboard(Vector3 position, float xScale, float yScale, ColorEx color, short texcoordIndexU, short texcoordsIndexV) { if (mRenderMethod == BillboardMethod.Accelerated) { StaticBillboard bb = new StaticBillboard(); bb.Position = position; bb.XScale = xScale; bb.YScale = yScale; bb.TextCoordIndexU = texcoordIndexU; bb.TextCoordIndexV = texcoordsIndexV; uint packedColor = (uint)Root.Singleton.RenderSystem.ConvertColor(color); bb.Color = packedColor; mBillboardBuffer.Add(bb); } else { Billboard bb = mFallbackSet.CreateBillboard(position); bb.SetDimensions(xScale, yScale); bb.TexcoordRect = new RectangleF( texcoordIndexU * mUFactor, texcoordsIndexV * mVFactor, (texcoordIndexU + 1) * mUFactor, (texcoordsIndexV + 1) * mVFactor); bb.Color = color; } }
/// <summary> /// /// </summary> public void Build() { if (mRenderMethod == BillboardMethod.Accelerated) { Clear(); //If there are no billboards to create, exit if (mBillboardBuffer.Count == 0) { return; } //Create manual mesh to store billboard quads mMesh = MeshManager.Instance.CreateManual(GetUniqueID("SBSMesh"), ResourceGroupManager.DefaultResourceGroupName, null); mSubMesh = mMesh.CreateSubMesh(); mSubMesh.useSharedVertices = false; //Setup vertex format information mSubMesh.vertexData = new VertexData(); mSubMesh.vertexData.vertexStart = 0; mSubMesh.vertexData.vertexCount = 4 * mBillboardBuffer.Count; VertexDeclaration dcl = mSubMesh.vertexData.vertexDeclaration; int offset = 0; dcl.AddElement(0, offset, VertexElementType.Float3, VertexElementSemantic.Position); offset += VertexElement.GetTypeSize(VertexElementType.Float3); dcl.AddElement(0, offset, VertexElementType.Float3, VertexElementSemantic.Normal); offset += VertexElement.GetTypeSize(VertexElementType.Float3); dcl.AddElement(0, offset, VertexElementType.Float3, VertexElementSemantic.Diffuse); offset += VertexElement.GetTypeSize(VertexElementType.Color); dcl.AddElement(0, offset, VertexElementType.Float3, VertexElementSemantic.TexCoords); offset += VertexElement.GetTypeSize(VertexElementType.Float2); //Populate a new vertex buffer HardwareVertexBuffer vbuf = HardwareBufferManager.Instance.CreateVertexBuffer( /*offset*/ dcl, mSubMesh.vertexData.vertexCount, BufferUsage.StaticWriteOnly, false); unsafe { float *pReal = (float *)vbuf.Lock(BufferLocking.Discard); float minX = float.PositiveInfinity; float maxX = float.NegativeInfinity; float minY = float.PositiveInfinity; float maxY = float.NegativeInfinity; float minZ = float.PositiveInfinity; float maxZ = float.NegativeInfinity; foreach (StaticBillboard it in mBillboardBuffer) { StaticBillboard bb = it; float halfXScale = bb.XScale * 0.5f; float halfYScale = bb.YScale * 0.5f; // position *pReal++ = bb.Position.x; *pReal++ = bb.Position.y; *pReal++ = bb.Position.z; // normals (actually used as scale / translate info for vertex shader) *pReal++ = halfXScale; *pReal++ = halfYScale; *pReal++ = 0.0f; // color *((uint *)pReal++) = bb.Color; // uv *pReal++ = (float)(bb.TextCoordIndexU * mUFactor); *pReal++ = (float)(bb.TextCoordIndexV * mVFactor); // position *pReal++ = bb.Position.x; *pReal++ = bb.Position.y; *pReal++ = bb.Position.z; // normals (actually used as scale / translate info for vertex shader) *pReal++ = halfXScale; *pReal++ = halfYScale; *pReal++ = 1.0f; // color *((uint *)pReal++) = bb.Color; // uv *pReal++ = (float)((bb.TextCoordIndexU + 1) * mUFactor); *pReal++ = (float)(bb.TextCoordIndexV * mVFactor); // position *pReal++ = bb.Position.x; *pReal++ = bb.Position.y; *pReal++ = bb.Position.z; // normals (actually used as scale / translate info for vertex shader) *pReal++ = halfXScale; *pReal++ = halfYScale; *pReal++ = 2.0f; // color *((uint *)pReal++) = bb.Color; // uv *pReal++ = (float)(bb.TextCoordIndexU * mUFactor); *pReal++ = (float)((bb.TextCoordIndexV + 1) * mVFactor); // position *pReal++ = bb.Position.x; *pReal++ = bb.Position.y; *pReal++ = bb.Position.z; // normals (actually used as scale / translate info for vertex shader) *pReal++ = halfXScale; *pReal++ = halfYScale; *pReal++ = 3.0f; // color *((uint *)pReal++) = bb.Color; // uv *pReal++ = (float)((bb.TextCoordIndexU + 1) * mUFactor); *pReal++ = (float)((bb.TextCoordIndexV + 1) * mVFactor); //Update bounding box if (bb.Position.x - halfXScale < minX) { minX = bb.Position.x - halfXScale; } if (bb.Position.x + halfXScale > maxX) { maxX = bb.Position.x + halfXScale; } if (bb.Position.y - halfYScale < minY) { minY = bb.Position.y - halfYScale; } if (bb.Position.y + halfYScale > maxY) { maxY = bb.Position.y + halfYScale; } if (bb.Position.z - halfXScale < minZ) { minZ = bb.Position.z - halfXScale; } if (bb.Position.z + halfXScale > maxZ) { maxZ = bb.Position.z + halfXScale; } } AxisAlignedBox bounds = new AxisAlignedBox( new Vector3(minX, minY, minZ), new Vector3(maxX, maxY, maxZ)); vbuf.Unlock(); mSubMesh.vertexData.vertexBufferBinding.SetBinding(0, vbuf); //Populate index buffer mSubMesh.indexData.indexStart = 0; mSubMesh.indexData.indexCount = 6 * mBillboardBuffer.Count; mSubMesh.indexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size16, mSubMesh.indexData.indexCount, BufferUsage.StaticWriteOnly); ushort *pI = (ushort *)mSubMesh.indexData.indexBuffer.Lock(BufferLocking.Discard); for (ushort i = 0; i < mBillboardBuffer.Count; 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); } mSubMesh.indexData.indexBuffer.Unlock(); //Finish up mesh mMesh.BoundingBox = bounds; Vector3 tmp = bounds.Maximum - bounds.Minimum; mMesh.BoundingSphereRadius = tmp.Length * 0.5f; LoggingLevel lvl = LogManager.Instance.LogDetail; LogManager.Instance.LogDetail = LoggingLevel.Low; mMesh.Load(); LogManager.Instance.LogDetail = lvl; //Empty the billboardBuffer now, because all billboards have been built mBillboardBuffer.Clear(); //Create an entity for the mesh mEntity = mSceneMgr.CreateEntity(mEntityName, mMesh.Name); mEntity.CastShadows = false; //Apply texture if (mFadeEnabled) { Debug.Assert(mFadeMaterial != null); mEntity.MaterialName = mFadeMaterial.Name; } else { Debug.Assert(mMaterial != null); mEntity.MaterialName = mMaterial.Name; } //Add to scene mNode.AttachObject(mEntity); mEntity.IsVisible = mVisible; } } }