public MyDecalsForVoxelsTriangleBuffer GetTrianglesBuffer(MyVoxelMap voxelMap, ref MyMwcVector3Int renderCellCoord, MyDecalTexturesEnum decalTexture, ref BoundingBox renderCellBoundingBox) { MyDecalsForVoxelsDictionaryKey key = new MyDecalsForVoxelsDictionaryKey(voxelMap.VoxelMapId, ref renderCellCoord, decalTexture); MyDecalsForVoxelsTriangleBuffer outValue; if (m_triangleBuffersByKey.TryGetValue(key, out outValue) == true) { // Combination of cell/texture was found in dictionary, so we can return in right now return(outValue); } else { if (m_triangleBuffersByKey.Count >= m_capacity) { // We are full, can't place decal on a new cell/texture. Need to wait for next CheckBufferFull. return(null); } else { // This is first time we want to place decal to this cell/texture, so here we allocate and initialize buffer MyDecalsForVoxelsTriangleBuffer newBuffer = m_freeTriangleBuffers.Pop(); m_triangleBuffersByKey.Add(key, newBuffer); m_usedTriangleBuffers.Enqueue(newBuffer); newBuffer.Start(voxelMap, ref renderCellCoord, decalTexture, ref renderCellBoundingBox); return(newBuffer); } } }
// Add decal and all surounding triangles for voxel intersection static void AddDecalVoxel(MyDecalTexturesEnum decalTexture, float decalSize, float decalScale, Vector4 color, bool alphaBlendByAngle, ref MyIntersectionResultLineTriangleEx intersection, ref MyPlane rightPlane, ref MyPlane upPlane, float lightSize, float emissivity, float decalNormalOffset) { MyVoxelMap voxelMap = (MyVoxelMap)intersection.Entity; MyMwcVector3Int renderCellCoord = voxelMap.GetVoxelRenderCellCoordinateFromMeters(ref intersection.IntersectionPointInWorldSpace); BoundingSphere decalBoundingSphere = new BoundingSphere(intersection.IntersectionPointInWorldSpace, decalSize); // If whole decal can't fit inside of render cell, we won't add any of its triangles. This is because // when hiding/removing triangles after explosion, it is easier to check only one render cell. BoundingBox renderCellBoundingBox; voxelMap.GetRenderCellBoundingBox(ref renderCellCoord, out renderCellBoundingBox); // TODO simon - commented as an experiment. If there are bugs with decals on voxels, remove the comment below //if (renderCellBoundingBox.Contains(decalBoundingSphere) != ContainmentType.Contains) return; // If we get null, buffer is full so no new decals can't be placed MyDecalsForVoxelsTriangleBuffer decalsBuffer = m_decalsForVoxels.GetTrianglesBuffer(voxelMap, ref renderCellCoord, decalTexture, ref renderCellBoundingBox); if (decalsBuffer == null) { return; } // We need to create decals on neighborhood triangles too, so we check all triangles if they fall in decal's sphere and if yes, we place decal on them. // We check triangles from same voxelmap or model only. m_neighbourTriangles.Clear(); //intersection.VoxelMap.GetTrianglesIntersectingSphere(ref decalBoundingSphere, intersection.TriangleHelperIndex, m_neighbourTriangles, decalsBuffer.MaxNeighbourTriangles); voxelMap.GetTrianglesIntersectingSphere(ref decalBoundingSphere, m_neighbourTriangles, decalsBuffer.MaxNeighbourTriangles, false); int trianglesToAdd = m_neighbourTriangles.Count;// +1; if (trianglesToAdd == 0) { return; } if (decalsBuffer.CanAddTriangles(trianglesToAdd) == true) { var normalSum = CalculateDominantNormal(m_neighbourTriangles); normalSum *= decalNormalOffset; // Create decal for every neighbour triangleVertexes for (int i = 0; i < m_neighbourTriangles.Count; i++) { trianglesToAdd--; var triangle = m_neighbourTriangles[i]; triangle.Vertexes.Vertex0 += normalSum; triangle.Vertexes.Vertex1 += normalSum; triangle.Vertexes.Vertex2 += normalSum; m_neighbourTriangles[i] = triangle; decalsBuffer.Add(m_neighbourTriangles[i], intersection.NormalInWorldSpace, ref rightPlane, ref upPlane, decalScale, trianglesToAdd, color, alphaBlendByAngle, lightSize, intersection.IntersectionPointInWorldSpace, emissivity); } } }
public MyDecalsForVoxels(int capacity) { m_status = MyDecalForVoxelsState.READY; m_capacity = capacity; m_fadingOutStartLimit = (int)(m_capacity * MyDecalsConstants.TEXTURE_LARGE_FADING_OUT_START_LIMIT_PERCENT); m_fadingOutBuffersCount = (int)(m_capacity * MyDecalsConstants.TEXTURE_LARGE_FADING_OUT_MINIMAL_TRIANGLE_COUNT_PERCENT); m_sortTriangleBuffersByTexture = new List <MyDecalsForVoxelsTriangleBuffer>(m_capacity); m_triangleBuffersByKey = new Dictionary <MyDecalsForVoxelsDictionaryKey, MyDecalsForVoxelsTriangleBuffer>(m_capacity); m_freeTriangleBuffers = new Stack <MyDecalsForVoxelsTriangleBuffer>(m_capacity); m_usedTriangleBuffers = new Queue <MyDecalsForVoxelsTriangleBuffer>(m_capacity); m_triangleBuffers = new MyDecalsForVoxelsTriangleBuffer[m_capacity]; for (int i = 0; i < m_capacity; i++) { m_triangleBuffers[i] = new MyDecalsForVoxelsTriangleBuffer(MyDecalsConstants.MAX_DECAL_TRIANGLES_IN_BUFFER); m_freeTriangleBuffers.Push(m_triangleBuffers[i]); } }
public void CheckIfBufferIsFull() { if (m_status == MyDecalForVoxelsState.FADING_OUT) { if ((MyMinerGame.TotalGamePlayTimeInMilliseconds - m_fadingOutStartTime) > MyDecalsConstants.DECALS_FADE_OUT_INTERVAL_MILISECONDS) { // If fading-out phase finished, we change state and remove faded-out buffers for (int i = 0; i < m_fadingOutBuffersCount; i++) { MyDecalsForVoxelsTriangleBuffer releasedBuffer = m_usedTriangleBuffers.Dequeue(); releasedBuffer.Clear(); m_freeTriangleBuffers.Push(releasedBuffer); m_triangleBuffersByKey.Remove(new MyDecalsForVoxelsDictionaryKey(releasedBuffer.VoxelMap.VoxelMapId, ref releasedBuffer.RenderCellCoord, releasedBuffer.DecalTexture)); } m_status = MyDecalForVoxelsState.READY; } } else { if (m_triangleBuffersByKey.Count >= m_fadingOutStartLimit) { int i = 0; foreach (MyDecalsForVoxelsTriangleBuffer buffer in m_usedTriangleBuffers) { if (i < m_fadingOutBuffersCount) { buffer.FadeOutAll(); } i++; } m_status = MyDecalForVoxelsState.FADING_OUT; m_fadingOutStartTime = MyMinerGame.TotalGamePlayTimeInMilliseconds; } } }
public void Draw(MyVertexFormatDecal[] vertices, Effects.MyEffectDecals effect, MyTexture2D[] texturesDiffuse, MyTexture2D[] texturesNormalMap) { CheckIfBufferIsFull(); // Sort buffers by texture m_sortTriangleBuffersByTexture.Clear(); foreach (MyDecalsForVoxelsTriangleBuffer buffer in m_usedTriangleBuffers) { // Check if render cell is close enought and visible in the view frustum if (//(buffer.VoxelMap.GetSmallestDistanceFromCameraToRenderCell(ref buffer.RenderCellCoord) <= (MyDecals.GetMaxDistanceForDrawingDecals())) && (MyCamera.IsInFrustum(ref buffer.RenderCellBoundingBox) == true)) { float fadeoutDistance = MyDecals.GetMaxDistanceForDrawingDecals(); if (buffer.DecalTexture == MyDecalTexturesEnum.ExplosionSmut) { fadeoutDistance *= MyDecalsConstants.DISTANCE_MULTIPLIER_FOR_LARGE_DECALS; } if (buffer.VoxelMap.GetSmallestDistanceFromCameraToRenderCell(ref buffer.RenderCellCoord) <= fadeoutDistance) { m_sortTriangleBuffersByTexture.Add(buffer); } } } m_sortTriangleBuffersByTexture.Sort(); if (m_sortTriangleBuffersByTexture.Count <= 0) { return; } // Draw decals - sorted by texture MyDecalTexturesEnum?lastDecalTexture = null; for (int i = 0; i < m_sortTriangleBuffersByTexture.Count; i++) { MyDecalsForVoxelsTriangleBuffer buffer = m_sortTriangleBuffersByTexture[i]; int trianglesCount = buffer.CopyDecalsToVertexBuffer(vertices); if (trianglesCount <= 0) { continue; } // Switch texture only if different than previous one if ((lastDecalTexture == null) || (lastDecalTexture != buffer.DecalTexture)) { int textureIndex = (int)buffer.DecalTexture; effect.SetDecalDiffuseTexture(texturesDiffuse[textureIndex]); effect.SetDecalNormalMapTexture(texturesNormalMap[textureIndex]); lastDecalTexture = buffer.DecalTexture; } // This will move all voxel maps back to position [0,0,0] effect.SetVoxelMapPosition(buffer.VoxelMap.PositionLeftBottomCorner - MyCamera.Position); effect.SetViewProjectionMatrix(MyCamera.ViewProjectionMatrixAtZero); // Set fadeout distance float fadeoutDistance = MyDecals.GetMaxDistanceForDrawingDecals(); if (buffer.DecalTexture == MyDecalTexturesEnum.ExplosionSmut) { fadeoutDistance *= MyDecalsConstants.DISTANCE_MULTIPLIER_FOR_LARGE_DECALS; } effect.SetFadeoutDistance(fadeoutDistance); if (!MyRenderConstants.RenderQualityProfile.ForwardRender) { effect.SetTechnique(Effects.MyEffectDecals.Technique.Voxels); } else { effect.SetTechnique(Effects.MyEffectDecals.Technique.VoxelsForward); } MyMinerGame.Static.GraphicsDevice.VertexDeclaration = MyVertexFormatDecal.VertexDeclaration; effect.Begin(); MyMinerGame.Static.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, 0, trianglesCount, vertices); effect.End(); MyPerformanceCounter.PerCameraDraw.DecalsForVoxelsInFrustum += trianglesCount; } }
// For sorting buffers by texture public int CompareTo(object compareToObject) { MyDecalsForVoxelsTriangleBuffer compareToBuffer = (MyDecalsForVoxelsTriangleBuffer)compareToObject; return(((int)compareToBuffer.DecalTexture).CompareTo((int)this.DecalTexture)); }