public override void ApplyLight(bool innerLayer = true) { var modifiedBatchKey = BatchKey; switch (dataSource) { case LevelEntity_Polygon.DataSources.Floor: modifiedBatchKey.sourceLight = polygonEntity.ParentLevel.Lights[polygonEntity.NativeObject.FloorLight]; lastLightIndex = polygonEntity.NativeObject.FloorLight; break; case LevelEntity_Polygon.DataSources.Ceiling: modifiedBatchKey.sourceLight = polygonEntity.ParentLevel.Lights[polygonEntity.NativeObject.CeilingLight]; lastLightIndex = polygonEntity.NativeObject.CeilingLight; break; case LevelEntity_Polygon.DataSources.Media: modifiedBatchKey.sourceLight = polygonEntity.ParentLevel.Lights[polygonEntity.NativeObject.MediaLight]; lastLightIndex = polygonEntity.NativeObject.MediaLight; break; default: throw new NotImplementedException($"DataSource '{dataSource}' is not implemented."); } var UVs = SurfaceMesh.uv.Select(uv => new Vector4(uv.x, uv.y, lastLightIndex, lastTextureIndex)).ToArray(); SurfaceMesh.SetUVs(0, UVs); BatchKey = modifiedBatchKey; }
public override void ApplyTransferMode(bool innerLayer = true) { Color vertexColor; switch (dataSource) { case LevelEntity_Polygon.DataSources.Floor: vertexColor = GetTransferModeVertexColor(polygonEntity.NativeObject.FloorTransferMode); break; case LevelEntity_Polygon.DataSources.Ceiling: vertexColor = GetTransferModeVertexColor(polygonEntity.NativeObject.CeilingTransferMode); break; case LevelEntity_Polygon.DataSources.Media: // Medias don't have transfer modes return; default: throw new NotImplementedException($"DataSource '{dataSource}' is not implemented."); } var vertexColors = new Color[polygonEntity.NativeObject.VertexCount]; for (var i = 0; i < polygonEntity.NativeObject.VertexCount; i++) { vertexColors[i] = vertexColor; } SurfaceMesh.SetColors(vertexColors); }
public override void ApplyLight(bool innerLayer) { var modifiedBatchKey = BatchKey; if (sideEntity.NativeObject == null) { modifiedBatchKey.sourceLight = null; modifiedBatchKey.layeredTransparentSideSourceLight = null; } else if (innerLayer) { switch (dataSource) { case LevelEntity_Side.DataSources.Primary: modifiedBatchKey.sourceLight = sideEntity.ParentLevel.Lights[sideEntity.NativeObject.PrimaryLightsourceIndex]; lastLightIndex = sideEntity.NativeObject.PrimaryLightsourceIndex; break; case LevelEntity_Side.DataSources.Secondary: modifiedBatchKey.sourceLight = sideEntity.ParentLevel.Lights[sideEntity.NativeObject.SecondaryLightsourceIndex]; lastLightIndex = sideEntity.NativeObject.SecondaryLightsourceIndex; break; case LevelEntity_Side.DataSources.Transparent: modifiedBatchKey.sourceLight = sideEntity.ParentLevel.Lights[sideEntity.NativeObject.TransparentLightsourceIndex]; lastLightIndex = sideEntity.NativeObject.TransparentLightsourceIndex; break; default: throw new NotImplementedException($"DataSource '{dataSource}' is not implemented."); } } else { modifiedBatchKey.layeredTransparentSideSourceLight = sideEntity.ParentLevel.Lights[sideEntity.NativeObject.TransparentLightsourceIndex]; lastLayeredTransparentSideLightIndex = sideEntity.NativeObject.TransparentLightsourceIndex; } if (innerLayer) { var UVs = SurfaceMesh.uv.Select(uv => new Vector4(uv.x, uv.y, lastLightIndex, lastTextureIndex)).ToArray(); SurfaceMesh.SetUVs(0, UVs); } else { var UVs = SurfaceMesh.uv.Select(uv => new Vector4(uv.x, uv.y, lastLayeredTransparentSideLightIndex, lastLayeredTransparentSideTextureIndex)).ToArray(); SurfaceMesh.SetUVs(1, UVs); } BatchKey = modifiedBatchKey; }
private void StepUWP() { // Mesh updates need to be on the main thread. There are plans to // make this unnecessary in the future. for (int i = 0; i < queuedUpdates.Count; i++) { SpatialSurfaceMesh s = queuedUpdates[i]; SurfaceMesh mesh = meshes.Find(m => m.id == s.SurfaceInfo.Id); UpdateMesh(ref mesh.mesh, s); mesh.localTransform = s.CoordinateSystem.TryGetTransformTo(frame.CoordinateSystem) ?? Matrix.Identity; mesh.transform = mesh.localTransform * root; } queuedUpdates.Clear(); }
public override void InitWorld() { Light(100, 150, -150, White / 10); Light(-100, 300, -150, White); var floor = DefaultFloor(); floor.Material.Reflective = 0; floor.Material.Ambient = 0; floor.Material.Specular = 0; var wall = new Plane().Rotate(rx: Pi / 2 - 0.175).Translate(tz: 2); wall.Material = new Material(White, reflective: 1); Add(wall); var mesh = new SurfaceMesh(60, 60); // thanks to TJ Wei ( https://www.youtube.com/channel/UCLA68RSY6peX50b-Dw8mEpQ) // cf https://www.youtube.com/watch?v=vUz4kov3K1c // Surface[cos(s) + sgn(s - π / 2) (abs(sin(s)) - 1), 2sin(s), cos(s) - sgn(s - π / 2) (abs(sin(s)) - 1) + d, s, (-π) / 2, π + π / 2, d, 0.5, 3] double Interp(double t, double t0, double t1) => t0 + (t1 - t0) * t; double FuncD(double t) => Interp(t, 0.5, 3); double FuncS(double t) => Interp(t, -Pi / 2, 3 * Pi / 2); double FuncX(double u, double v) => Math.Cos(FuncS(u)) + Math.Sign(FuncS(u) - Pi / 2) * (Math.Abs(Math.Sin(FuncS(u))) - 1); double FuncZ(double u, double v) => 2 * Math.Sin(FuncS(u)); double FuncY(double u, double v) => Math.Cos(FuncS(u)) - Math.Sign(FuncS(u) - Pi / 2) * (Math.Abs(Math.Sin(FuncS(u))) - 1) + FuncD(v); mesh.Build(FuncX, FuncY, FuncZ); var factory = new TriangleMeshFactory(); var surf = factory.Build(mesh); surf.HasShadow = false; Add(surf.Rotate(ry: Pi / 2 + 0.0).Translate(tz: -2)); Add(new Cube { Material = new Material(Blue) }.Scale(sx: 2).Rotate(ry: Pi / 4).Translate(tx: -4.5, tz: -2)); Add(new Sphere { Material = new Material(Red) }.Scale(sx: 2).Rotate(ry: -Pi / 4).Translate(tx: 4.5, tz: -2)); }
public override void ApplyTextureOffset(bool innerLayer) { Vector4[] UVs; var lastLight = innerLayer ? lastLightIndex : lastLayeredTransparentSideLightIndex; var lastTexture = innerLayer ? lastTextureIndex : lastLayeredTransparentSideTextureIndex; if (sideEntity.NativeObject == null) { UVs = BuildUVs(0, 0, lastLight, lastTexture); SurfaceMesh.SetUVs(channel: 0, UVs); } else if (innerLayer) { switch (dataSource) { case LevelEntity_Side.DataSources.Primary: UVs = BuildUVs(sideEntity.NativeObject.Primary.X, (short)(sideEntity.NativeObject.Primary.Y - textureOffsetFromFacingCeilingPlatform), lastLight, lastTexture); break; case LevelEntity_Side.DataSources.Secondary: UVs = BuildUVs(sideEntity.NativeObject.Secondary.X, (short)(sideEntity.NativeObject.Secondary.Y - textureOffsetFromFacingCeilingPlatform), lastLight, lastTexture); break; case LevelEntity_Side.DataSources.Transparent: UVs = BuildUVs(sideEntity.NativeObject.Transparent.X, (short)(sideEntity.NativeObject.Transparent.Y - textureOffsetFromFacingCeilingPlatform), lastLight, lastTexture); break; default: throw new NotImplementedException($"DataSource '{dataSource}' is not implemented."); } SurfaceMesh.SetUVs(channel: 0, UVs); } else { UVs = BuildUVs(sideEntity.NativeObject.Transparent.X, (short)(sideEntity.NativeObject.Transparent.Y + textureOffsetFromFacingCeilingPlatform), lastLight, lastTexture); SurfaceMesh.SetUVs(channel: 1, UVs); } }
public override void ApplyPositionsAndTriangles() { var line = sideEntity.ParentLevel.Level.Lines[sideEntity.ParentLineIndex]; var endpointIndexA = sideEntity.IsClockwise ? line.EndpointIndexes[0] : line.EndpointIndexes[1]; var endpointIndexB = sideEntity.IsClockwise ? line.EndpointIndexes[1] : line.EndpointIndexes[0]; var bottomPosition = (short)(LowElevation - HighElevation); var positions = new Vector3[] { GeometryUtilities.GetMeshVertex(sideEntity.ParentLevel.Level, endpointIndexA, bottomPosition), GeometryUtilities.GetMeshVertex(sideEntity.ParentLevel.Level, endpointIndexA), GeometryUtilities.GetMeshVertex(sideEntity.ParentLevel.Level, endpointIndexB), GeometryUtilities.GetMeshVertex(sideEntity.ParentLevel.Level, endpointIndexB, bottomPosition) }; var triangles = new int[6]; triangles[0] = 0; triangles[1] = 1; triangles[2] = 2; triangles[3] = 2; triangles[4] = 3; triangles[5] = 0; SurfaceMesh.SetVertices(positions); SurfaceMesh.SetTriangles(triangles, submesh: 0); SurfaceMesh.RecalculateNormals(MeshUpdateFlags.DontNotifyMeshUsers | MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontResetBoneBounds); SurfaceMesh.RecalculateTangents(MeshUpdateFlags.DontNotifyMeshUsers | MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontResetBoneBounds); }
public static Scene Mesh() { Scene scene = new Scene(new Color(200, 200, 255)); Mesh mesh = OBJ.ParseFile(@"..\..\monkey.obj"); LightGroup lightGroup = new LightGroup(); lightGroup.addLight(new LightDirectional(new Color(255, 255, 255), new Vector3(0.2, -0.2, 1), scene)); SurfaceGeometry geometry = new SurfaceMesh(mesh, Vector3.Forward * 10, new Vector3(0, Math.PI, 0), SurfaceMesh.NormalMode.PER_VERTEX); SurfaceMaterial diffuse = new SurfaceDiffuse(new Color(200, 212, 180), lightGroup); SurfaceMaterial specular = new SurfaceSpecular(new Color(255, 255, 255), 150, lightGroup); SurfaceMaterial material = new SurfaceMaterialSum(diffuse, specular); Surface monkey = new Surface(geometry, material); //We enclose the monkey in a bounding sphere, which speeds up the rendering over 7 times Surface boundedMonkey = new Surface(new SurfaceBoundingVolume(new SurfaceSphere(Vector3.Forward * 10, 2.5), monkey), null); scene.addSurface(boundedMonkey); return(scene); }
public override void ApplyTextureOffset(bool innerLayer = true) { Vector4[] UVs; switch (dataSource) { case LevelEntity_Polygon.DataSources.Floor: UVs = BuildUVs(polygonEntity.NativeObject.FloorOrigin.X, polygonEntity.NativeObject.FloorOrigin.Y); break; case LevelEntity_Polygon.DataSources.Ceiling: UVs = BuildUVs(polygonEntity.NativeObject.CeilingOrigin.X, polygonEntity.NativeObject.CeilingOrigin.Y); break; case LevelEntity_Polygon.DataSources.Media: UVs = BuildUVs(0, 0); break; default: throw new NotImplementedException($"DataSource '{dataSource}' is not implemented."); } SurfaceMesh.SetUVs(channel: 0, UVs); }
private void OnSurfaceUpdate(SpatialSurfaceObserver observer, object args) { var surfaceDict = observer.GetObservedSurfaces(); foreach (var surface in surfaceDict) { // Find or add a surface mesh for this surface SurfaceMesh mesh = meshes.Find(m => m.id == surface.Key); if (mesh == null) { mesh = new SurfaceMesh { mesh = new Mesh(), id = surface.Key, lastUpdate = new DateTimeOffset() }; meshes.Add(mesh); } // Ask for an update to the mesh data, if it's old if (surface.Value.UpdateTime > mesh.lastUpdate) { mesh.lastUpdate = surface.Value.UpdateTime; SpatialSurfaceMeshOptions opts = new SpatialSurfaceMeshOptions(); opts.IncludeVertexNormals = false; opts.TriangleIndexFormat = Windows.Graphics.DirectX.DirectXPixelFormat.R32UInt; opts.VertexPositionFormat = Windows.Graphics.DirectX.DirectXPixelFormat.R32G32B32A32Float; surface.Value.TryComputeLatestMeshAsync(trisPerMeter, opts).Completed = (info, state) => { // Send update to the main thread for upload to GPU if (state == Windows.Foundation.AsyncStatus.Completed) { queuedUpdates.Add(info.GetResults()); } }; } } }
public override void ApplyBatchKeyMaterial(bool innerLayer) { DecrementTextureUsage(); var modifiedBatchKey = BatchKey; if (sideEntity.NativeObject == null) { modifiedBatchKey.sourceMaterial = MaterialGeneration_Geometry.GetMaterial(ShapeDescriptor.Empty, transferMode: 0, isOpaqueSurface: true, MaterialGeneration_Geometry.SurfaceTypes.Normal, incrementUsageCounter: false); } else if (innerLayer) { switch (dataSource) { case LevelEntity_Side.DataSources.Primary: #if USE_TEXTURE_ARRAYS modifiedBatchKey.sourceShapeDescriptor = sideEntity.NativeObject.Primary.Texture; #endif modifiedBatchKey.sourceMaterial = MaterialGeneration_Geometry.GetMaterial(sideEntity.NativeObject.Primary.Texture, sideEntity.NativeObject.PrimaryTransferMode, sideEntity.NativeObject.SurfaceShouldBeOpaque(dataSource, sideEntity.ParentLevel.Level), MaterialGeneration_Geometry.SurfaceTypes.Normal, incrementUsageCounter: true); #if USE_TEXTURE_ARRAYS lastTextureIndex = MaterialGeneration_Geometry.GetTextureArrayIndex( sideEntity.NativeObject.Primary.Texture, sideEntity.NativeObject.PrimaryTransferMode, sideEntity.NativeObject.SurfaceShouldBeOpaque(dataSource, sideEntity.ParentLevel.Level), MaterialGeneration_Geometry.SurfaceTypes.Normal); #endif break; case LevelEntity_Side.DataSources.Secondary: #if USE_TEXTURE_ARRAYS modifiedBatchKey.sourceShapeDescriptor = sideEntity.NativeObject.Secondary.Texture; #endif modifiedBatchKey.sourceMaterial = MaterialGeneration_Geometry.GetMaterial(sideEntity.NativeObject.Secondary.Texture, sideEntity.NativeObject.SecondaryTransferMode, sideEntity.NativeObject.SurfaceShouldBeOpaque(dataSource, sideEntity.ParentLevel.Level), MaterialGeneration_Geometry.SurfaceTypes.Normal, incrementUsageCounter: true); #if USE_TEXTURE_ARRAYS lastTextureIndex = MaterialGeneration_Geometry.GetTextureArrayIndex( sideEntity.NativeObject.Secondary.Texture, sideEntity.NativeObject.SecondaryTransferMode, sideEntity.NativeObject.SurfaceShouldBeOpaque(dataSource, sideEntity.ParentLevel.Level), MaterialGeneration_Geometry.SurfaceTypes.Normal); #endif break; case LevelEntity_Side.DataSources.Transparent: #if USE_TEXTURE_ARRAYS modifiedBatchKey.sourceShapeDescriptor = sideEntity.NativeObject.Transparent.Texture; #endif modifiedBatchKey.sourceMaterial = MaterialGeneration_Geometry.GetMaterial(sideEntity.NativeObject.Transparent.Texture, sideEntity.NativeObject.TransparentTransferMode, sideEntity.NativeObject.SurfaceShouldBeOpaque(dataSource, sideEntity.ParentLevel.Level), MaterialGeneration_Geometry.SurfaceTypes.Normal, incrementUsageCounter: true); #if USE_TEXTURE_ARRAYS lastTextureIndex = MaterialGeneration_Geometry.GetTextureArrayIndex( sideEntity.NativeObject.Transparent.Texture, sideEntity.NativeObject.TransparentTransferMode, sideEntity.NativeObject.SurfaceShouldBeOpaque(dataSource, sideEntity.ParentLevel.Level), MaterialGeneration_Geometry.SurfaceTypes.Normal); #endif break; default: throw new NotImplementedException($"DataSource '{dataSource}' is not implemented."); } } else { #if USE_TEXTURE_ARRAYS modifiedBatchKey.layeredTransparentSideShapeDescriptor = sideEntity.NativeObject.Transparent.Texture; #endif modifiedBatchKey.layeredTransparentSideSourceMaterial = MaterialGeneration_Geometry.GetMaterial(sideEntity.NativeObject.Transparent.Texture, sideEntity.NativeObject.TransparentTransferMode, sideEntity.NativeObject.SurfaceShouldBeOpaque(dataSource, sideEntity.ParentLevel.Level), MaterialGeneration_Geometry.SurfaceTypes.LayeredTransparentOuter, incrementUsageCounter: true); #if USE_TEXTURE_ARRAYS lastLayeredTransparentSideTextureIndex = MaterialGeneration_Geometry.GetTextureArrayIndex( sideEntity.NativeObject.Transparent.Texture, sideEntity.NativeObject.TransparentTransferMode, sideEntity.NativeObject.SurfaceShouldBeOpaque(dataSource, sideEntity.ParentLevel.Level), MaterialGeneration_Geometry.SurfaceTypes.LayeredTransparentOuter); #endif } if (innerLayer) { var UVs = SurfaceMesh.uv.Select(uv => new Vector4(uv.x, uv.y, lastLightIndex, lastTextureIndex)).ToArray(); SurfaceMesh.SetUVs(0, UVs); } else { var UVs = SurfaceMesh.uv.Select(uv => new Vector4(uv.x, uv.y, lastLayeredTransparentSideLightIndex, lastLayeredTransparentSideTextureIndex)).ToArray(); SurfaceMesh.SetUVs(1, UVs); } BatchKey = modifiedBatchKey; }
public override void ApplyTransferMode(bool innerLayer) { if (sideEntity.NativeObject == null) { var vertexColors = new Color[4]; for (var i = 0; i < 4; i++) { vertexColors[i] = Color.black; } SurfaceMesh.SetColors(vertexColors); return; } if (innerLayer) { Color vertexColor; switch (dataSource) { case LevelEntity_Side.DataSources.Primary: vertexColor = GetTransferModeVertexColor(sideEntity.NativeObject.PrimaryTransferMode); break; case LevelEntity_Side.DataSources.Secondary: vertexColor = GetTransferModeVertexColor(sideEntity.NativeObject.SecondaryTransferMode); break; case LevelEntity_Side.DataSources.Transparent: vertexColor = GetTransferModeVertexColor(sideEntity.NativeObject.TransparentTransferMode); break; default: throw new NotImplementedException($"DataSource '{dataSource}' is not implemented."); } var vertexColors = new Color[4]; for (var i = 0; i < 4; i++) { vertexColors[i] = vertexColor; } SurfaceMesh.SetColors(vertexColors); } else { var vertexColor = GetTransferModeVertexColor(sideEntity.NativeObject.TransparentTransferMode); var uv2 = new Vector4[4]; for (var i = 0; i < 4; i++) { uv2[i].x = vertexColor.r; uv2[i].y = vertexColor.g; uv2[i].z = vertexColor.b; uv2[i].w = vertexColor.a; } SurfaceMesh.SetUVs(channel: 2, uvs: uv2); } }
public override void ApplyPositionsAndTriangles() { var positions = new Vector3[polygonEntity.NativeObject.VertexCount]; var triangles = new int[(polygonEntity.NativeObject.VertexCount - 2) * (dataSource == LevelEntity_Polygon.DataSources.Media ? 6 : 3)]; // Using Collapsing Convex-Polygon Traversal for speediness reasons for (int earlyVertexIndex = 0, lateVertexIndex = polygonEntity.NativeObject.VertexCount - 1, currentTriangleIndex = 0; earlyVertexIndex <= lateVertexIndex; earlyVertexIndex++, lateVertexIndex--) { AssignVertexPosition(earlyVertexIndex, polygonEntity.NativeObject, positions); if (earlyVertexIndex < lateVertexIndex) { // Vertex-traversal has not intersected, so continue AssignVertexPosition(lateVertexIndex, polygonEntity.NativeObject, positions); // Note: only need to rebuild triangles if the vertex count changed if (polygonEntity.NativeObject.VertexCount != SurfaceMesh.vertexCount && earlyVertexIndex + 1 < lateVertexIndex) { // Vertex-traversal is not on the final vertices, so continue AssignTriangle(earlyVertexIndex, lateVertexIndex, currentTriangleIndex, triangles, reverseOrder: dataSource == LevelEntity_Polygon.DataSources.Ceiling); currentTriangleIndex += 3; if (dataSource == LevelEntity_Polygon.DataSources.Media) { // Backside triangles for media AssignTriangle(earlyVertexIndex, lateVertexIndex, currentTriangleIndex, triangles, reverseOrder: true); currentTriangleIndex += 3; } if (earlyVertexIndex + 1 < lateVertexIndex - 1) { // Vertex traversal is not about to intersect, so continue AssignTriangle(earlyVertexIndex, lateVertexIndex, currentTriangleIndex, triangles, isLateTriangle: true, reverseOrder: dataSource == LevelEntity_Polygon.DataSources.Ceiling); currentTriangleIndex += 3; if (dataSource == LevelEntity_Polygon.DataSources.Media) { // Backside triangles for media AssignTriangle(earlyVertexIndex, lateVertexIndex, currentTriangleIndex, triangles, isLateTriangle: true, reverseOrder: true); currentTriangleIndex += 3; } } } } } var vertexCountChanged = polygonEntity.NativeObject.VertexCount != SurfaceMesh.vertexCount; SurfaceMesh.SetVertices(positions); if (vertexCountChanged) { SurfaceMesh.SetTriangles(triangles, submesh: 0); ApplyTextureOffset(); ApplyTransferMode(); } SurfaceMesh.RecalculateNormals(MeshUpdateFlags.DontNotifyMeshUsers | MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontResetBoneBounds); SurfaceMesh.RecalculateTangents(MeshUpdateFlags.DontNotifyMeshUsers | MeshUpdateFlags.DontRecalculateBounds | MeshUpdateFlags.DontResetBoneBounds); }
public override void ApplyBatchKeyMaterial(bool innerLayer = true) { DecrementTextureUsage(); var modifiedBatchKey = BatchKey; switch (dataSource) { case LevelEntity_Polygon.DataSources.Floor: #if USE_TEXTURE_ARRAYS modifiedBatchKey.sourceShapeDescriptor = polygonEntity.NativeObject.FloorTexture; #endif modifiedBatchKey.sourceMaterial = MaterialGeneration_Geometry.GetMaterial( polygonEntity.NativeObject.FloorTexture, polygonEntity.NativeObject.FloorTransferMode, isOpaqueSurface: true, MaterialGeneration_Geometry.SurfaceTypes.Normal, incrementUsageCounter: true); #if USE_TEXTURE_ARRAYS lastTextureIndex = MaterialGeneration_Geometry.GetTextureArrayIndex( polygonEntity.NativeObject.FloorTexture, polygonEntity.NativeObject.FloorTransferMode, isOpaqueSurface: true, MaterialGeneration_Geometry.SurfaceTypes.Normal); #endif break; case LevelEntity_Polygon.DataSources.Ceiling: #if USE_TEXTURE_ARRAYS modifiedBatchKey.sourceShapeDescriptor = polygonEntity.NativeObject.CeilingTexture; #endif modifiedBatchKey.sourceMaterial = MaterialGeneration_Geometry.GetMaterial( polygonEntity.NativeObject.CeilingTexture, polygonEntity.NativeObject.CeilingTransferMode, isOpaqueSurface: true, MaterialGeneration_Geometry.SurfaceTypes.Normal, incrementUsageCounter: true); #if USE_TEXTURE_ARRAYS lastTextureIndex = MaterialGeneration_Geometry.GetTextureArrayIndex( polygonEntity.NativeObject.CeilingTexture, polygonEntity.NativeObject.CeilingTransferMode, isOpaqueSurface: true, MaterialGeneration_Geometry.SurfaceTypes.Normal); #endif break; case LevelEntity_Polygon.DataSources.Media: var mediaShapeDescriptor = new ShapeDescriptor((ushort)polygonEntity.NativeObject.FloorTexture); switch (BatchKey.sourceMedia.NativeObject.Type) { case MediaType.Water: mediaShapeDescriptor.Collection = 17; mediaShapeDescriptor.Bitmap = 19; break; case MediaType.Lava: mediaShapeDescriptor.Collection = 18; mediaShapeDescriptor.Bitmap = 12; break; case MediaType.Goo: mediaShapeDescriptor.Collection = 21; mediaShapeDescriptor.Bitmap = 5; break; case MediaType.Sewage: mediaShapeDescriptor.Collection = 19; mediaShapeDescriptor.Bitmap = 13; break; case MediaType.Jjaro: mediaShapeDescriptor.Collection = 20; mediaShapeDescriptor.Bitmap = 13; break; } #if USE_TEXTURE_ARRAYS modifiedBatchKey.sourceShapeDescriptor = mediaShapeDescriptor; #endif modifiedBatchKey.sourceMaterial = MaterialGeneration_Geometry.GetMaterial( mediaShapeDescriptor, (short)TransferModes.Normal, isOpaqueSurface: true, MaterialGeneration_Geometry.SurfaceTypes.Media, incrementUsageCounter: false); #if USE_TEXTURE_ARRAYS lastTextureIndex = MaterialGeneration_Geometry.GetTextureArrayIndex( mediaShapeDescriptor, (short)TransferModes.Normal, isOpaqueSurface: true, MaterialGeneration_Geometry.SurfaceTypes.Media); #endif break; default: throw new NotImplementedException($"DataSource '{dataSource}' is not implemented."); } var UVs = SurfaceMesh.uv.Select(uv => new Vector4(uv.x, uv.y, lastLightIndex, lastTextureIndex)).ToArray(); SurfaceMesh.SetUVs(0, UVs); BatchKey = modifiedBatchKey; }