private static void ProcessMeshes(Scene scene, ref GeoModel model) { model.MeshHitboxes = new List <GeoMeshHitbox>(); string currentMeshName = null; GeoMeshHitbox meshHitBox = null; float minX = float.MaxValue, minY = float.MaxValue, minZ = float.MaxValue; float maxX = float.MinValue, maxY = float.MinValue, maxZ = float.MinValue; Matrix4 nodeTransform = Matrix4.Identity; Mesh mesh = null; for (int m = 0; m < scene.MeshCount; m++) { mesh = scene.Meshes[m]; bool isNewMesh = currentMeshName != null && mesh.Name != currentMeshName && model.Filename != "kwcube6.obj"; if (mesh.PrimitiveType != PrimitiveType.Triangle) { throw new Exception("Model's primitive type is not set to 'triangles'. Cannot import model."); } if (isNewMesh) { if (currentMeshName != null) { // Generate hitbox for the previous mesh: meshHitBox = new GeoMeshHitbox(maxX, maxY, maxZ, minX, minY, minZ, currentMeshName.ToLower().Contains("_fullhitbox") ? mesh : null); meshHitBox.Model = model; meshHitBox.Name = currentMeshName; meshHitBox.Transform = nodeTransform; meshHitBox.IsActive = !currentMeshName.ToLower().Contains("_nohitbox"); model.MeshHitboxes.Add(meshHitBox); } minX = float.MaxValue; minY = float.MaxValue; minZ = float.MaxValue; maxX = float.MinValue; maxY = float.MinValue; maxZ = float.MinValue; } currentMeshName = mesh.Name; GeoMesh geoMesh = new GeoMesh(); Matrix4 parentTransform = Matrix4.Identity; bool transformFound = FindTransformForMesh(scene, scene.RootNode, mesh, ref nodeTransform, out string nodeName, ref parentTransform); geoMesh.Transform = nodeTransform; geoMesh.Terrain = null; geoMesh.BoneTranslationMatrixCount = mesh.BoneCount; geoMesh.Name = mesh.Name + " #" + m.ToString().PadLeft(4, '0') + " (Node: " + nodeName + ")"; geoMesh.NameOrg = mesh.Name; geoMesh.Vertices = new GeoVertex[mesh.VertexCount]; geoMesh.Primitive = OpenTK.Graphics.OpenGL4.PrimitiveType.Triangles; geoMesh.VAOGenerateAndBind(); for (int i = 0; i < mesh.VertexCount; i++) { Vector3D vertex = mesh.Vertices[i]; if (vertex.X > maxX) { maxX = vertex.X; } if (vertex.Y > maxY) { maxY = vertex.Y; } if (vertex.Z > maxZ) { maxZ = vertex.Z; } if (vertex.X < minX) { minX = vertex.X; } if (vertex.Y < minY) { minY = vertex.Y; } if (vertex.Z < minZ) { minZ = vertex.Z; } GeoVertex geoVertex = new GeoVertex(i, vertex.X, vertex.Y, vertex.Z); geoMesh.Vertices[i] = geoVertex; } geoMesh.Indices = mesh.GetUnsignedIndices(); if (model.HasBones) { for (int i = 0; i < mesh.BoneCount; i++) { Bone bone = mesh.Bones[i]; geoMesh.BoneNames.Add(bone.Name); geoMesh.BoneIndices.Add(i); geoMesh.BoneOffset.Add(HelperMatrix.ConvertAssimpToOpenTKMatrix(bone.OffsetMatrix)); foreach (VertexWeight vw in bone.VertexWeights) { int weightIndexToBeSet = geoMesh.Vertices[vw.VertexID].WeightSet; if (weightIndexToBeSet >= KWEngine.MAX_BONE_WEIGHTS) { throw new Exception("Model's bones have more than three weights per vertex. Cannot import model."); } //Debug.WriteLine("Setting Vertex " + vw.VertexID + " with BoneID " + i + " and Weight: " + vw.Weight + " to Slot #" + weightIndexToBeSet); geoMesh.Vertices[vw.VertexID].Weights[weightIndexToBeSet] = vw.Weight; geoMesh.Vertices[vw.VertexID].BoneIDs[weightIndexToBeSet] = i; geoMesh.Vertices[vw.VertexID].WeightSet++; } } } geoMesh.VBOGenerateIndices(); geoMesh.VBOGenerateVerticesAndBones(model.HasBones); geoMesh.VBOGenerateNormals(mesh); geoMesh.VBOGenerateTangents(mesh); if (model.Filename == "kwcube.obj") { geoMesh.VBOGenerateTextureCoords1(mesh, scene, 1); } else if (model.Filename == "kwcube6.obj") { geoMesh.VBOGenerateTextureCoords1(mesh, scene, 6); } else if (model.Filename == "kwsphere.obj") { geoMesh.VBOGenerateTextureCoords1(mesh, scene, 2); } else { geoMesh.VBOGenerateTextureCoords1(mesh, scene); } geoMesh.VBOGenerateTextureCoords2(mesh); ProcessMaterialsForMesh(scene, mesh, ref model, ref geoMesh, model.Filename == "kwcube.obj" || model.Filename == "kwcube6.obj"); geoMesh.VAOUnbind(); model.Meshes.Add(geoMesh.Name, geoMesh); } // Generate hitbox for the last mesh: if (currentMeshName != null) { meshHitBox = new GeoMeshHitbox(maxX, maxY, maxZ, minX, minY, minZ, currentMeshName.ToLower().Contains("_fullhitbox") ? mesh : null); meshHitBox.Model = model; meshHitBox.Name = model.Filename == "kwcube6.obj" ? "KWCube6" : currentMeshName; meshHitBox.Transform = nodeTransform; meshHitBox.IsActive = !currentMeshName.ToLower().Contains("_nohitbox"); model.MeshHitboxes.Add(meshHitBox); } foreach (GeoMeshHitbox hitbox in model.MeshHitboxes) { foreach (GeoMesh m in model.Meshes.Values) { if (m.NameOrg == hitbox.Name) { hitbox.Mesh = m; break; } } } }
internal GeoMesh BuildTerrain(Vector3 position, string heightMap, float width, float height, float depth, float texRepeatX = 1, float texRepeatY = 1, bool isFile = true) { GeoMesh mmp; try { Assembly a = Assembly.GetEntryAssembly(); using (Stream s = isFile ? File.Open(heightMap, FileMode.Open) : a.GetManifestResourceStream(a.GetName().Name + "." + heightMap)) { using (Bitmap image = new Bitmap(s)) { mDots = image.Width * image.Height; mWidth = width; mDepth = depth; mScaleFactor = height > 0 ? height : 1; mTexX = texRepeatX > 0 ? texRepeatX : 1; mTexY = texRepeatY > 0 ? texRepeatY : 1; if (image.Width < 4 || image.Height < 4 || image.Height > 256 || image.Width > 256) { throw new Exception("Image size too small or too big: width and height need to be >= 4 and <= 256 pixels."); } Debug.WriteLine("Generating terrain from height map: " + heightMap); double mp = Math.Round(mDots / 1000000.0, 3); if (mDots > 1000) { Debug.WriteLine("\tImage pixel count:\t\t" + mp + " megapixel"); if (mp >= 0.5) { Debug.WriteLine("(WARNING: pixel count > 0.5 megapixel! You will experience SERIOUS performance issues with this terrain mapping.)"); } } else { Debug.WriteLine("\tImage pixel count:\t\t" + mDots); } long start = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; mSectorSize = image.Width < image.Height ? (int)Math.Sqrt(image.Width) : (int)Math.Sqrt(image.Height); while (mSectorSize % 4 != 0) { mSectorSize++; } mSectorSizeCoarse = mSectorSize / 4; if (mSectorSize > 144) { mSectorSize = 144; mSectorSizeCoarse = 12; } mSectorWidth = mWidth / mSectorSize; mSectorDepth = mDepth / mSectorSize; mSectorDiameter = (float)Math.Sqrt(mSectorWidth * mSectorWidth + mSectorDepth * mSectorDepth); mSectorWidthCoarse = mWidth / mSectorSizeCoarse; mSectorDepthCoarse = mDepth / mSectorSizeCoarse; for (int i = 0; i < mSectorSizeCoarse; i++) { for (int j = 0; j < mSectorSizeCoarse; j++) { Sector sec = new Sector( (position.X - mWidth / 2) + i * mSectorWidthCoarse, (position.X - mWidth / 2) + (i + 1) * mSectorWidthCoarse, (position.Z + mDepth / 2) - (j + 1) * mSectorDepthCoarse, (position.Z + mDepth / 2) - j * mSectorDepthCoarse ); mSectorsCoarse.Add(sec); mSectorCoarseMap.Add(sec, new List <Sector>()); } } for (int i = 0; i < mSectorSize; i++) { for (int j = 0; j < mSectorSize; j++) { Sector sec = new Sector( (position.X - mWidth / 2) + i * mSectorWidth, (position.X - mWidth / 2) + (i + 1) * mSectorWidth, (position.Z + mDepth / 2) - (j + 1) * mSectorDepth, (position.Z + mDepth / 2) - j * mSectorDepth ); sec.ID = mSectors.Count; mSectors.Add(sec); Sector coarseSector = GetSectorCoarseForSector(sec); mSectorCoarseMap[coarseSector].Add(sec); mSectorTriangleMap.Add(mSectors.Count - 1, new List <GeoTerrainTriangle>()); } } float[,] mHeightMap = new float[image.Width, image.Height]; mCompleteDiameter = (float)Math.Sqrt(mWidth * mWidth + mDepth * mDepth + mScaleFactor * mScaleFactor); float stepWidth = mWidth / (image.Width - 1); float stepDepth = mDepth / (image.Height - 1); Vector3[] points = new Vector3[mDots]; int c = 0; int cFBuffer = 0; int cFBufferUV = 0; float[] VBOVerticesBuffer = new float[mDots * 3]; float[] VBONormalsBuffer = new float[mDots * 3]; float[] VBOUVBuffer = new float[mDots * 2]; float[] VBOTangentBuffer = new float[mDots * 3]; float[] VBOBiTangentBuffer = new float[mDots * 3]; Dictionary <int, Vector3> normalMapping = new Dictionary <int, Vector3>(); Dictionary <int, Vector3> tangentMapping = new Dictionary <int, Vector3>(); Dictionary <int, Vector3> bitangentMapping = new Dictionary <int, Vector3>(); Dictionary <int, int> normalMappingCount = new Dictionary <int, int>(); for (int i = 0; i < image.Width; i++) { for (int j = 0; j < image.Height; j++) { Color tmpColor = image.GetPixel(i, j); float normalizedRGB = ((tmpColor.R + tmpColor.G + tmpColor.B) / 3f) / 255f; mHeightMap[i, j] = normalizedRGB; Vector3 tmp = new Vector3( position.X + i * stepWidth - mWidth / 2, position.Y + mScaleFactor * normalizedRGB, position.Z - mDepth / 2 + j * stepDepth ); points[c] = tmp; VBOVerticesBuffer[cFBuffer + 0] = points[c].X; VBOVerticesBuffer[cFBuffer + 1] = points[c].Y; VBOVerticesBuffer[cFBuffer + 2] = points[c].Z; VBOUVBuffer[cFBufferUV + 0] = i * (1f / (image.Width - 1)); //* mTexX; VBOUVBuffer[cFBufferUV + 1] = j * (1f / (image.Height - 1)); // * mTexY; normalMapping.Add(c, new Vector3(0, 0, 0)); tangentMapping.Add(c, new Vector3(0, 0, 0)); bitangentMapping.Add(c, new Vector3(0, 0, 0)); normalMappingCount.Add(c, 0); //increase counter: c++; cFBuffer += 3; cFBufferUV += 2; } } mmp = new GeoMesh(); mmp.Name = heightMap; // Build indices and triangles: mmp.VAO = GL.GenVertexArray(); GL.BindVertexArray(mmp.VAO); int triangles = 0; List <uint> mIndices = new List <uint>(); int imageHeight = image.Height; Vector3 normalT1 = new Vector3(0, 0, 0); Vector3 normalT2 = new Vector3(0, 0, 0); float deltaU1 = 0; float deltaV1 = 0; float deltaU2 = 0; float deltaV2 = 0; float f = 1.0f; Vector3 tangent = new Vector3(0, 0, 0); Vector3 bitangent = new Vector3(0, 0, 0); for (int i = 0; i < points.Length - imageHeight - 1; i++) { Vector3 tmp; if ((i + 1) % imageHeight == 0) { continue; } // Generate Indices: mIndices.Add((uint)(i + imageHeight + 1)); mIndices.Add((uint)(i + imageHeight)); mIndices.Add((uint)(i)); mIndices.Add((uint)(i)); mIndices.Add((uint)(i + 1)); mIndices.Add((uint)(i + imageHeight + 1)); // Generate Triangle objects: // T1: Vector3 v1 = new Vector3(points[i + imageHeight + 1]); Vector3 v2 = new Vector3(points[i + imageHeight]); Vector3 v3 = new Vector3(points[i]); GeoTerrainTriangle t123 = new GeoTerrainTriangle(v1, v2, v3); normalT1 = t123.Normal; List <int> sectorIds = GetSectorsForGeoTriangle(t123); foreach (int sID in sectorIds) { mSectorTriangleMap[sID].Add(t123); } // tangents and bitangent generation deltaU1 = VBOUVBuffer[(i + imageHeight) * 2] - VBOUVBuffer[(i + imageHeight + 1) * 2]; deltaV1 = VBOUVBuffer[(i + imageHeight) * 2 + 1] - VBOUVBuffer[(i + imageHeight + 1) * 2 + 1]; deltaU2 = VBOUVBuffer[(i + 0) * 2] - VBOUVBuffer[(i + imageHeight + 1) * 2]; deltaV2 = VBOUVBuffer[(i + 0) * 2 + 1] - VBOUVBuffer[(i + imageHeight + 1) * 2 + 1]; f = 1.0f / (deltaU1 * deltaV2 - deltaU2 * deltaV1); tangent.X = f * (deltaV2 * t123.edge1.X - deltaV1 * t123.edge2.X); tangent.Y = f * (deltaV2 * t123.edge1.Y - deltaV1 * t123.edge2.Y); tangent.Z = f * (deltaV2 * t123.edge1.Z - deltaV1 * t123.edge2.Z); bitangent.X = f * (-deltaU2 * t123.edge1.X - deltaU1 * t123.edge2.X); bitangent.Y = f * (-deltaU2 * t123.edge1.Y - deltaU1 * t123.edge2.Y); bitangent.Z = f * (-deltaU2 * t123.edge1.Z - deltaU1 * t123.edge2.Z); // Generate their normals for VBO: normalMapping.TryGetValue(i, out tmp); tmp += normalT1; normalMapping[i] = tmp; normalMappingCount[i]++; normalMapping.TryGetValue(i + imageHeight, out tmp); tmp += normalT1; normalMapping[i + imageHeight] = tmp; normalMappingCount[i + imageHeight]++; normalMapping.TryGetValue(i + imageHeight + 1, out tmp); tmp += normalT1; normalMapping[i + imageHeight + 1] = tmp; normalMappingCount[i + imageHeight + 1]++; // map tangents & bitangent here: tangentMapping.TryGetValue(i, out tmp); tmp += tangent; tangentMapping[i] = tmp; tangentMapping.TryGetValue(i + imageHeight, out tmp); tmp += tangent; tangentMapping[i + imageHeight] = tmp; tangentMapping.TryGetValue(i + imageHeight + 1, out tmp); tmp += tangent; tangentMapping[i + imageHeight + 1] = tmp; bitangentMapping.TryGetValue(i, out tmp); tmp += bitangent; bitangentMapping[i] = tmp; bitangentMapping.TryGetValue(i + imageHeight, out tmp); tmp += bitangent; bitangentMapping[i + imageHeight] = tmp; bitangentMapping.TryGetValue(i + imageHeight + 1, out tmp); tmp += bitangent; bitangentMapping[i + imageHeight + 1] = tmp; // ============================ T2 ====================== Vector3 v4 = new Vector3(points[i]); Vector3 v5 = new Vector3(points[i + 1]); Vector3 v6 = new Vector3(points[i + imageHeight + 1]); GeoTerrainTriangle t456 = new GeoTerrainTriangle(v4, v5, v6); normalT2 = t456.Normal; sectorIds.Clear(); sectorIds = GetSectorsForGeoTriangle(t456); foreach (int sID in sectorIds) { mSectorTriangleMap[sID].Add(t456); } // tangents and bitangent generation deltaU1 = VBOUVBuffer[(i + 1) * 2] - VBOUVBuffer[(i) * 2]; deltaV1 = VBOUVBuffer[(i + 1) * 2 + 1] - VBOUVBuffer[(i) * 2 + 1]; deltaU2 = VBOUVBuffer[(i + imageHeight + 1) * 2] - VBOUVBuffer[(i) * 2]; deltaV2 = VBOUVBuffer[(i + imageHeight + 1) * 2 + 1] - VBOUVBuffer[(i) * 2 + 1]; f = 1.0f / (deltaU1 * deltaV2 - deltaU2 * deltaV1); tangent.X = f * (deltaV2 * t456.edge1.X - deltaV1 * t456.edge2.X); tangent.Y = f * (deltaV2 * t456.edge1.Y - deltaV1 * t456.edge2.Y); tangent.Z = f * (deltaV2 * t456.edge1.Z - deltaV1 * t456.edge2.Z); bitangent.X = f * (-deltaU2 * t456.edge1.X - deltaU1 * t456.edge2.X); bitangent.Y = f * (-deltaU2 * t456.edge1.Y - deltaU1 * t456.edge2.Y); bitangent.Z = f * (-deltaU2 * t456.edge1.Z - deltaU1 * t456.edge2.Z); normalMapping.TryGetValue(i + imageHeight + 1, out tmp); tmp += normalT2; normalMapping[i + imageHeight + 1] = tmp; normalMappingCount[i + imageHeight + 1]++; normalMapping.TryGetValue(i + 1, out tmp); tmp += normalT2; normalMapping[i + 1] = tmp; normalMappingCount[i + 1]++; normalMapping.TryGetValue(i, out tmp); tmp += normalT2; normalMapping[i] = tmp; normalMappingCount[i]++; // map tangents & bitangent here: tangentMapping.TryGetValue(i + imageHeight + 1, out tmp); tmp += tangent; tangentMapping[i + imageHeight + 1] = tmp; tangentMapping.TryGetValue(i + 1, out tmp); tmp += tangent; tangentMapping[i + 1] = tmp; tangentMapping.TryGetValue(i, out tmp); tmp += tangent; tangentMapping[i] = tmp; bitangentMapping.TryGetValue(i + imageHeight + 1, out tmp); tmp += bitangent; bitangentMapping[i + imageHeight + 1] = tmp; bitangentMapping.TryGetValue(i + 1, out tmp); tmp += bitangent; bitangentMapping[i + 1] = tmp; bitangentMapping.TryGetValue(i, out tmp); tmp += bitangent; bitangentMapping[i] = tmp; triangles += 2; } Debug.WriteLine("\tGenerated triangles:\t" + triangles); cFBuffer = 0; for (int i = 0; i < points.Length; i++) { // Interpolate normals: Vector3 tmp = new Vector3(normalMapping[i].X / normalMappingCount[i], normalMapping[i].Y / normalMappingCount[i], normalMapping[i].Z / normalMappingCount[i]); tmp.Normalize(); Vector3 tTemp = new Vector3(tangentMapping[i].X / normalMappingCount[i], tangentMapping[i].Y / normalMappingCount[i], tangentMapping[i].Z / normalMappingCount[i]); tTemp.Normalize(); Vector3 btTemp = new Vector3(bitangentMapping[i].X / normalMappingCount[i], bitangentMapping[i].Y / normalMappingCount[i], bitangentMapping[i].Z / normalMappingCount[i]); btTemp.Normalize(); VBONormalsBuffer[cFBuffer + 0] = tmp.X; VBONormalsBuffer[cFBuffer + 1] = tmp.Y; VBONormalsBuffer[cFBuffer + 2] = tmp.Z; // tangents and bitangents: VBOTangentBuffer[cFBuffer + 0] = tTemp.X; VBOTangentBuffer[cFBuffer + 1] = tTemp.Y; VBOTangentBuffer[cFBuffer + 2] = tTemp.Z; // tangents and bitangents: VBOBiTangentBuffer[cFBuffer + 0] = btTemp.X; VBOBiTangentBuffer[cFBuffer + 1] = btTemp.Y; VBOBiTangentBuffer[cFBuffer + 2] = btTemp.Z; cFBuffer += 3; } // Generate VBOs: mmp.VBOPosition = GL.GenBuffer(); mmp.VBONormal = GL.GenBuffer(); mmp.VBOTexture1 = GL.GenBuffer(); mmp.VBOTangent = GL.GenBuffer(); mmp.VBOBiTangent = GL.GenBuffer(); mmp.VBOIndex = GL.GenBuffer(); // Vertices: GL.BindBuffer(BufferTarget.ArrayBuffer, mmp.VBOPosition); GL.BufferData(BufferTarget.ArrayBuffer, VBOVerticesBuffer.Length * 4, VBOVerticesBuffer, BufferUsageHint.StaticDraw); GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, 0); GL.EnableVertexAttribArray(0); GL.BindBuffer(BufferTarget.ArrayBuffer, 0); // Normals GL.BindBuffer(BufferTarget.ArrayBuffer, mmp.VBONormal); GL.BufferData(BufferTarget.ArrayBuffer, VBONormalsBuffer.Length * 4, VBONormalsBuffer, BufferUsageHint.StaticDraw); GL.VertexAttribPointer(1, 3, VertexAttribPointerType.Float, false, 0, 0); GL.EnableVertexAttribArray(1); GL.BindBuffer(BufferTarget.ArrayBuffer, 0); // UVs GL.BindBuffer(BufferTarget.ArrayBuffer, mmp.VBOTexture1); GL.BufferData(BufferTarget.ArrayBuffer, VBOUVBuffer.Length * 4, VBOUVBuffer, BufferUsageHint.StaticDraw); GL.VertexAttribPointer(2, 2, VertexAttribPointerType.Float, false, 0, 0); GL.EnableVertexAttribArray(2); GL.BindBuffer(BufferTarget.ArrayBuffer, 0); // Tangents GL.BindBuffer(BufferTarget.ArrayBuffer, mmp.VBOTangent); GL.BufferData(BufferTarget.ArrayBuffer, VBOTangentBuffer.Length * 4, VBOTangentBuffer, BufferUsageHint.StaticDraw); GL.VertexAttribPointer(4, 3, VertexAttribPointerType.Float, false, 0, 0); GL.EnableVertexAttribArray(4); GL.BindBuffer(BufferTarget.ArrayBuffer, 0); // Bitangents GL.BindBuffer(BufferTarget.ArrayBuffer, mmp.VBOBiTangent); GL.BufferData(BufferTarget.ArrayBuffer, VBOBiTangentBuffer.Length * 4, VBOBiTangentBuffer, BufferUsageHint.StaticDraw); GL.VertexAttribPointer(5, 3, VertexAttribPointerType.Float, false, 0, 0); GL.EnableVertexAttribArray(5); GL.BindBuffer(BufferTarget.ArrayBuffer, 0); mmp.Indices = mIndices.ToArray(); // Indices: GL.BindBuffer(BufferTarget.ElementArrayBuffer, mmp.VBOIndex); GL.BufferData(BufferTarget.ElementArrayBuffer, mIndices.Count * 4, mmp.Indices, BufferUsageHint.StaticDraw); GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0); mmp.Transform = Matrix4.Identity; GL.BindVertexArray(0); long diff = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - start; Debug.WriteLine("\t...done (" + Math.Round(diff / 1000f, 2) + " seconds)"); } } } catch (Exception ex) { throw new Exception("Terrain could not be created: " + ex.Message); } finally { GLWindow.StartGarbageCollection(); } mmp.Primitive = PrimitiveType.Triangles; return(mmp); }
private static void ProcessMaterialsForMesh(Scene scene, Mesh mesh, ref GeoModel model, ref GeoMesh geoMesh, bool isKWCube = false) { GeoMaterial geoMaterial = new GeoMaterial(); Material material = null; if (isKWCube) { if (mesh.MaterialIndex >= 0) { material = scene.Materials[mesh.MaterialIndex]; geoMaterial.Name = model.Filename == "kwcube.obj" ? "KWCube" : material.Name; geoMaterial.BlendMode = material.BlendMode == BlendMode.Default ? OpenTK.Graphics.OpenGL4.BlendingFactor.OneMinusSrcAlpha : OpenTK.Graphics.OpenGL4.BlendingFactor.One; // TODO: Check if this is correct! geoMaterial.ColorDiffuse = new Vector4(1, 1, 1, 1); geoMaterial.ColorEmissive = new Vector4(0, 0, 0, 1); } else { geoMaterial.Name = "kw-undefined."; geoMaterial.BlendMode = OpenTK.Graphics.OpenGL4.BlendingFactor.OneMinusSrcAlpha; geoMaterial.ColorDiffuse = new Vector4(1, 1, 1, 1); geoMaterial.ColorEmissive = new Vector4(0, 0, 0, 1); } geoMaterial.SpecularArea = 1024; geoMaterial.SpecularPower = 0; } else { if (mesh.MaterialIndex >= 0) { material = scene.Materials[mesh.MaterialIndex]; geoMaterial.Name = material.Name; if (material.Name == "DefaultMaterial") { geoMaterial.BlendMode = OpenTK.Graphics.OpenGL4.BlendingFactor.OneMinusSrcAlpha; geoMaterial.ColorDiffuse = new Vector4(1, 1, 1, 1); geoMaterial.ColorEmissive = new Vector4(0, 0, 0, 1); geoMaterial.SpecularPower = 0; geoMaterial.SpecularArea = 1024; geoMaterial.TextureSpecularIsRoughness = false; if (mesh.Name != null && mesh.Name.ToLower().Contains("_invisible")) { geoMaterial.Opacity = 0; } } else { geoMaterial.BlendMode = material.BlendMode == BlendMode.Default ? OpenTK.Graphics.OpenGL4.BlendingFactor.OneMinusSrcAlpha : OpenTK.Graphics.OpenGL4.BlendingFactor.One; // TODO: Check if this is correct! if (model.AssemblyMode == AssemblyMode.Internal && material.Name == "System") { geoMaterial.ColorDiffuse = new Vector4(1, 1, 1, 1); } else if (model.AssemblyMode == AssemblyMode.Internal && material.Name == "X") { geoMaterial.ColorDiffuse = new Vector4(1, 0, 0, 1); } else if (model.AssemblyMode == AssemblyMode.Internal && material.Name == "Y") { geoMaterial.ColorDiffuse = new Vector4(0, 1, 0, 1); } else if (model.AssemblyMode == AssemblyMode.Internal && material.Name == "Z") { geoMaterial.ColorDiffuse = new Vector4(0, 0, 1, 1); } else { geoMaterial.ColorDiffuse = material.HasColorDiffuse ? new Vector4(material.ColorDiffuse.R, material.ColorDiffuse.G, material.ColorDiffuse.B, material.ColorDiffuse.A) : new Vector4(1, 1, 1, 1); } geoMaterial.ColorEmissive = material.HasColorEmissive ? new Vector4(material.ColorEmissive.R, material.ColorEmissive.G, material.ColorEmissive.B, material.ColorEmissive.A) : new Vector4(0, 0, 0, 1); geoMaterial.SpecularPower = material.ShininessStrength; geoMaterial.SpecularArea = material.Shininess; geoMaterial.TextureSpecularIsRoughness = false; geoMaterial.Opacity = material.HasOpacity ? material.Opacity : 1; if (mesh.Name != null && mesh.Name.ToLower().Contains("_invisible")) { geoMaterial.Opacity = 0; } } } else { geoMaterial.Name = "kw-undefined."; geoMaterial.BlendMode = OpenTK.Graphics.OpenGL4.BlendingFactor.OneMinusSrcAlpha; geoMaterial.ColorDiffuse = new Vector4(1, 1, 1, 1); geoMaterial.ColorEmissive = new Vector4(0, 0, 0, 1); geoMaterial.SpecularArea = 1024; geoMaterial.SpecularPower = 0; geoMaterial.TextureSpecularIsRoughness = false; if (mesh.Name != null && mesh.Name.ToLower().Contains("_invisible")) { geoMaterial.Opacity = 0; } } } // Process Textures: if (material != null) { bool roughnessUsed = false; TextureSlot[] texturesOfMaterial = material.GetAllMaterialTextures(); foreach (TextureSlot slot in texturesOfMaterial) { if (slot.TextureType == TextureType.Shininess) // this is PBR Roughness { GeoTexture tex = new GeoTexture(); tex.UVTransform = new OpenTK.Vector2(1, 1); tex.Filename = slot.FilePath; tex.UVMapIndex = slot.UVIndex; if (model.Textures.ContainsKey(tex.Filename)) { tex.OpenGLID = model.Textures[tex.Filename].OpenGLID; } else { if (model.AssemblyMode == AssemblyMode.File) { tex.OpenGLID = HelperTexture.LoadTextureForModelExternal( FindTextureInSubs(StripPathFromFile(tex.Filename), model.PathAbsolute), true ); } else { string path = StripFileNameFromAssemblyPath(model.PathAbsolute).Substring(model.PathAbsolute.IndexOf('.') + 1) + StripPathFromFile(tex.Filename); tex.OpenGLID = HelperTexture.LoadTextureForModelInternal(path, true); } if (tex.OpenGLID > 0) { tex.Type = GeoTexture.TexType.Specular; model.Textures.Add(tex.Filename, tex); geoMaterial.TextureSpecular = tex; geoMaterial.TextureSpecularIsRoughness = true; roughnessUsed = true; } else { geoMaterial.TextureSpecular = tex; geoMaterial.TextureSpecularIsRoughness = false; tex.OpenGLID = KWEngine.TextureBlack; } } break; } } // Diffuse texture if (material.HasTextureDiffuse) { GeoTexture tex = new GeoTexture(); tex.UVTransform = new OpenTK.Vector2(1, 1); tex.Filename = material.TextureDiffuse.FilePath; tex.UVMapIndex = material.TextureDiffuse.UVIndex; tex.Type = GeoTexture.TexType.Diffuse; if (model.Textures.ContainsKey(tex.Filename)) { tex.OpenGLID = model.Textures[tex.Filename].OpenGLID; geoMaterial.TextureDiffuse = tex; } else if (CheckIfOtherModelsShareTexture(tex.Filename, model.Path, out GeoTexture sharedTexture)) { geoMaterial.TextureDiffuse = sharedTexture; } else { if (model.AssemblyMode == AssemblyMode.File) { tex.OpenGLID = HelperTexture.LoadTextureForModelExternal( FindTextureInSubs(StripPathFromFile(tex.Filename), model.PathAbsolute) ); } else { string path = StripFileNameFromAssemblyPath(model.PathAbsolute).Substring(model.PathAbsolute.IndexOf('.') + 1) + StripPathFromFile(tex.Filename); tex.OpenGLID = HelperTexture.LoadTextureForModelInternal(path, true); } if (tex.OpenGLID > 0) { geoMaterial.TextureDiffuse = tex; model.Textures.Add(tex.Filename, tex); } else { tex.OpenGLID = KWEngine.TextureDefault; geoMaterial.TextureDiffuse = tex; } } } // Normal map texture if (material.HasTextureNormal) { GeoTexture tex = new GeoTexture(); tex.UVTransform = new OpenTK.Vector2(1, 1); tex.Filename = material.TextureNormal.FilePath; tex.UVMapIndex = material.TextureNormal.UVIndex; tex.Type = GeoTexture.TexType.Normal; if (model.Textures.ContainsKey(tex.Filename)) { tex.OpenGLID = model.Textures[tex.Filename].OpenGLID; geoMaterial.TextureNormal = tex; } else if (CheckIfOtherModelsShareTexture(tex.Filename, model.Path, out GeoTexture sharedTexture)) { geoMaterial.TextureNormal = sharedTexture; } else { if (model.AssemblyMode == AssemblyMode.File) { tex.OpenGLID = HelperTexture.LoadTextureForModelExternal( FindTextureInSubs(StripPathFromFile(tex.Filename), model.PathAbsolute) ); } else { string path = StripFileNameFromAssemblyPath(model.PathAbsolute).Substring(model.PathAbsolute.IndexOf('.') + 1) + StripPathFromFile(tex.Filename); tex.OpenGLID = HelperTexture.LoadTextureForModelInternal(path, true); } if (tex.OpenGLID > 0) { model.Textures.Add(tex.Filename, tex); geoMaterial.TextureNormal = tex; } else { tex.OpenGLID = KWEngine.TextureBlack; //geoMaterial.TextureNormal = tex; } } } // Specular map texture if (material.HasTextureSpecular && roughnessUsed == false) { GeoTexture tex = new GeoTexture(); tex.UVTransform = new OpenTK.Vector2(1, 1); tex.Filename = material.TextureSpecular.FilePath; tex.UVMapIndex = material.TextureSpecular.UVIndex; tex.Type = GeoTexture.TexType.Specular; if (model.Textures.ContainsKey(tex.Filename)) { tex.OpenGLID = model.Textures[tex.Filename].OpenGLID; geoMaterial.TextureSpecular = tex; } else if (CheckIfOtherModelsShareTexture(tex.Filename, model.Path, out GeoTexture sharedTexture)) { geoMaterial.TextureSpecular = sharedTexture; } else { if (model.AssemblyMode == AssemblyMode.File) { tex.OpenGLID = HelperTexture.LoadTextureForModelExternal( FindTextureInSubs(StripPathFromFile(tex.Filename), model.PathAbsolute) ); } else { string path = StripFileNameFromAssemblyPath(model.PathAbsolute).Substring(model.PathAbsolute.IndexOf('.') + 1) + StripPathFromFile(tex.Filename); tex.OpenGLID = HelperTexture.LoadTextureForModelInternal(path, true); } if (tex.OpenGLID > 0) { geoMaterial.TextureSpecular = tex; model.Textures.Add(tex.Filename, tex); } else { tex.OpenGLID = KWEngine.TextureBlack; geoMaterial.TextureSpecular = tex; } } } else { if (material.HasTextureSpecular && roughnessUsed) { Debug.WriteLine("Skipping specular texture for " + model.Filename + " because roughness texture was found."); } } // Emissive map texture if (material.HasTextureEmissive) { GeoTexture tex = new GeoTexture(); tex.UVTransform = new OpenTK.Vector2(1, 1); tex.Filename = material.TextureEmissive.FilePath; tex.UVMapIndex = material.TextureEmissive.UVIndex; tex.Type = GeoTexture.TexType.Emissive; if (model.Textures.ContainsKey(tex.Filename)) { tex.OpenGLID = model.Textures[tex.Filename].OpenGLID; geoMaterial.TextureEmissive = tex; } else if (CheckIfOtherModelsShareTexture(tex.Filename, model.Path, out GeoTexture sharedTexture)) { geoMaterial.TextureEmissive = sharedTexture; } else { if (model.AssemblyMode == AssemblyMode.File) { tex.OpenGLID = HelperTexture.LoadTextureForModelExternal( FindTextureInSubs(StripPathFromFile(tex.Filename), model.PathAbsolute) ); } else { string path = StripFileNameFromAssemblyPath(model.PathAbsolute).Substring(model.PathAbsolute.IndexOf('.') + 1) + StripPathFromFile(tex.Filename); tex.OpenGLID = HelperTexture.LoadTextureForModelInternal(path, true); } if (tex.OpenGLID > 0) { geoMaterial.TextureEmissive = tex; model.Textures.Add(tex.Filename, tex); } else { tex.OpenGLID = KWEngine.TextureBlack; geoMaterial.TextureEmissive = tex; } } } // Light map texture if (material.HasTextureLightMap) { GeoTexture tex = new GeoTexture(); tex.UVTransform = new OpenTK.Vector2(1, 1); tex.Filename = material.TextureLightMap.FilePath; tex.UVMapIndex = material.TextureLightMap.UVIndex; tex.Type = GeoTexture.TexType.Light; if (model.Textures.ContainsKey(tex.Filename)) { tex.OpenGLID = model.Textures[tex.Filename].OpenGLID; geoMaterial.TextureLight = tex; } else if (CheckIfOtherModelsShareTexture(tex.Filename, model.Path, out GeoTexture sharedTexture)) { geoMaterial.TextureLight = sharedTexture; } else { if (model.AssemblyMode == AssemblyMode.File) { tex.OpenGLID = HelperTexture.LoadTextureForModelExternal( FindTextureInSubs(StripPathFromFile(tex.Filename), model.PathAbsolute) ); } else { string path = StripFileNameFromAssemblyPath(model.PathAbsolute).Substring(model.PathAbsolute.IndexOf('.') + 1) + StripPathFromFile(tex.Filename); tex.OpenGLID = HelperTexture.LoadTextureForModelInternal(path, true); } if (tex.OpenGLID > 0) { model.Textures.Add(tex.Filename, tex); geoMaterial.TextureLight = tex; } else { tex.OpenGLID = KWEngine.TextureBlack; //geoMaterial.TextureLight = tex; } } } } geoMesh.Material = geoMaterial; }