/// <summary> /// Helper for ComputeBoundingBox(out Vector3 sceneMin, out Vector3 sceneMax) /// </summary> /// <param name="node"></param> /// <param name="min"></param> /// <param name="max"></param> /// <param name="trafo"></param> private void ComputeBoundingBox(Node node, ref Vector3 min, ref Vector3 max, ref Matrix4 trafo) { if (node.HasMeshes) { foreach (var mesh in node.MeshIndices.Select(index => _raw.Meshes[index])) { for (var i = 0; i < mesh.VertexCount; i++) { var tmp = AssimpToOpenTk.FromVector(mesh.Vertices[i]); Vector3.Transform(ref tmp, ref trafo, out tmp); min.X = Math.Min(min.X, tmp.X); min.Y = Math.Min(min.Y, tmp.Y); min.Z = Math.Min(min.Z, tmp.Z); max.X = Math.Max(max.X, tmp.X); max.Y = Math.Max(max.Y, tmp.Y); max.Z = Math.Max(max.Z, tmp.Z); } } } for (var i = 0; i < node.ChildCount; i++) { var prev = trafo; var mat = AssimpToOpenTk.FromMatrix(node.Children[i].Transform); mat.Transpose(); Matrix4.Mult(ref mat, ref prev, out prev); ComputeBoundingBox(node.Children[i], ref min, ref max, ref prev); } }
public static void DrawNormals(Node node, int meshIndex, Mesh mesh, CpuSkinningEvaluator skinner, float invGlobalScale, Matrix4 transform) { if (!mesh.HasNormals) { return; } // The normal directions are transformed using the transpose(inverse(transform)). // This ensures correct direction is used when non-uniform scaling is present. Matrix4 normalMatrix = transform; normalMatrix.Invert(); normalMatrix.Transpose(); // Scale by scene size because the scene will be resized to fit // the unit box, but the normals should have a fixed length. var scale = invGlobalScale * 0.05f; GL.Begin(BeginMode.Lines); GL.Disable(EnableCap.Lighting); GL.Disable(EnableCap.Texture2D); GL.Enable(EnableCap.ColorMaterial); GL.Color4(new Color4(0.0f, 1.0f, 0.0f, 1.0f)); for (uint i = 0; i < mesh.VertexCount; ++i) { Vector3 v; if (skinner != null && mesh.HasBones) { skinner.GetTransformedVertexPosition(node, mesh, i, out v); } else { v = AssimpToOpenTk.FromVector(mesh.Vertices[(int)i]); } v = Vector4.Transform(new Vector4(v, 1.0f), transform).Xyz; // Skip dividing by W component. It should always be 1, here. Vector3 n; if (skinner != null) { skinner.GetTransformedVertexNormal(node, mesh, i, out n); } else { n = AssimpToOpenTk.FromVector(mesh.Normals[(int)i]); } n = Vector4.Transform(new Vector4(n, 0.0f), normalMatrix).Xyz; // Toss the W component. It is non-sensical for normals. n.Normalize(); GL.Vertex3(v); GL.Vertex3(v + n * scale); } GL.End(); GL.Disable(EnableCap.ColorMaterial); }
public static void DrawNormals(Node node, int meshIndex, Mesh mesh, CpuSkinningEvaluator skinner, float invGlobalScale) { if (!mesh.HasNormals) { return; } // Scale by scene size because the scene will be resized to fit // the unit box but the normals should have a fixed length var scale = invGlobalScale * 0.05f; GL.Begin(BeginMode.Lines); GL.Disable(EnableCap.Lighting); GL.Disable(EnableCap.Texture2D); GL.Enable(EnableCap.ColorMaterial); GL.Color4(new Color4(0.0f, 1.0f, 0.0f, 1.0f)); for (uint i = 0; i < mesh.VertexCount; ++i) { Vector3 v; if (skinner != null && mesh.HasBones) { skinner.GetTransformedVertexPosition(node, meshIndex, i, out v); } else { v = AssimpToOpenTk.FromVector(mesh.Vertices[(int)i]); } Vector3 n; if (skinner != null) { skinner.GetTransformedVertexNormal(node, meshIndex, i, out n); } else { n = AssimpToOpenTk.FromVector(mesh.Normals[(int)i]); } GL.Vertex3(v); GL.Vertex3(v + n * scale); } GL.End(); GL.Disable(EnableCap.ColorMaterial); }
/// <summary> /// Internal method to (re-)cache all transformed vertex positions and normals /// </summary> private void Cache() { var boneMatrices = _scene.SceneAnimator.GetBoneMatricesForMesh(_lastNode, _source); // update entire mesh for (int i = 0; i < _cachedPositions.Length; ++i) { var v = AssimpToOpenTk.FromVector(_source.Vertices[i]); EvaluateBoneInfluences(ref v, (uint)i, boneMatrices, out _cachedPositions[i]); } for (int i = 0; i < _cachedNormals.Length; ++i) { var n = AssimpToOpenTk.FromVector(_source.Normals[i]); EvaluateBoneInfluences(ref n, (uint)i, boneMatrices, out _cachedNormals[i], true); } _dirty = false; }
/// <summary> /// Draw a mesh using either its given material or a transparent "ghost" material. /// </summary> /// <param name="node">Current node</param> /// <param name="animated">Specifies whether animations should be played</param> /// <param name="showGhost">Indicates whether to substitute the mesh' material with a /// "ghost" surrogate material that allows looking through the geometry.</param> /// <param name="index">Mesh index in the scene</param> /// <param name="mesh">Mesh instance</param> /// <param name="flags"> </param> /// <returns></returns> protected override bool InternDrawMesh(Node node, bool animated, bool showGhost, int index, Mesh mesh, RenderFlags flags) { if (showGhost) { Owner.MaterialMapper.ApplyGhostMaterial(mesh, Owner.Raw.Materials[mesh.MaterialIndex], flags.HasFlag(RenderFlags.Shaded), flags.HasFlag(RenderFlags.ForceTwoSidedLighting)); } else { Owner.MaterialMapper.ApplyMaterial(mesh, Owner.Raw.Materials[mesh.MaterialIndex], flags.HasFlag(RenderFlags.Textured), flags.HasFlag(RenderFlags.Shaded), flags.HasFlag(RenderFlags.ForceTwoSidedLighting)); } if (GraphicsSettings.Default.BackFaceCulling) { GL.FrontFace(FrontFaceDirection.Ccw); GL.CullFace(CullFaceMode.Back); GL.Enable(EnableCap.CullFace); } else { GL.Disable(EnableCap.CullFace); } var hasColors = mesh.HasVertexColors(0); var hasTexCoords = mesh.HasTextureCoords(0); var skinning = mesh.HasBones && animated; foreach (var face in mesh.Faces) { BeginMode faceMode; switch (face.IndexCount) { case 1: faceMode = BeginMode.Points; break; case 2: faceMode = BeginMode.Lines; break; case 3: faceMode = BeginMode.Triangles; break; default: faceMode = BeginMode.Polygon; break; } GL.Begin(faceMode); for (var i = 0; i < face.IndexCount; i++) { var indice = face.Indices[i]; if (hasColors) { var vertColor = AssimpToOpenTk.FromColor(mesh.VertexColorChannels[0][indice]); GL.Color4(vertColor); } if (mesh.HasNormals) { Vector3 normal; if (skinning) { Skinner.GetTransformedVertexNormal(node, mesh, (uint)indice, out normal); } else { normal = AssimpToOpenTk.FromVector(mesh.Normals[indice]); } GL.Normal3(normal); } if (hasTexCoords) { var uvw = AssimpToOpenTk.FromVector(mesh.TextureCoordinateChannels[0][indice]); GL.TexCoord2(uvw.X, 1 - uvw.Y); } Vector3 pos; if (skinning) { Skinner.GetTransformedVertexPosition(node, mesh, (uint)indice, out pos); } else { pos = AssimpToOpenTk.FromVector(mesh.Vertices[indice]); } GL.Vertex3(pos); } GL.End(); } GL.Disable(EnableCap.CullFace); return(skinning); }
public static void DrawBoundingBox(Node node, int meshIndex, Mesh mesh, CpuSkinningEvaluator skinner) { GL.Disable(EnableCap.Lighting); GL.Disable(EnableCap.Texture2D); GL.Enable(EnableCap.ColorMaterial); GL.Color4(new Color4(1.0f, 0.0f, 0.0f, 1.0f)); var min = new Vector3(1e10f, 1e10f, 1e10f); var max = new Vector3(-1e10f, -1e10f, -1e10f); for (uint i = 0; i < mesh.VertexCount; ++i) { Vector3 tmp; if (skinner != null && mesh.HasBones) { skinner.GetTransformedVertexPosition(node, mesh, i, out tmp); } else { tmp = AssimpToOpenTk.FromVector(mesh.Vertices[(int)i]); } min.X = Math.Min(min.X, tmp.X); min.Y = Math.Min(min.Y, tmp.Y); min.Z = Math.Min(min.Z, tmp.Z); max.X = Math.Max(max.X, tmp.X); max.Y = Math.Max(max.Y, tmp.Y); max.Z = Math.Max(max.Z, tmp.Z); } GL.Begin(BeginMode.LineLoop); GL.Vertex3(min); GL.Vertex3(new Vector3(min.X, max.Y, min.Z)); GL.Vertex3(new Vector3(min.X, max.Y, max.Z)); GL.Vertex3(new Vector3(min.X, min.Y, max.Z)); GL.End(); GL.Begin(BeginMode.LineLoop); GL.Vertex3(new Vector3(max.X, min.Y, min.Z)); GL.Vertex3(new Vector3(max.X, max.Y, min.Z)); GL.Vertex3(new Vector3(max.X, max.Y, max.Z)); GL.Vertex3(new Vector3(max.X, min.Y, max.Z)); GL.End(); GL.Begin(BeginMode.Lines); GL.Vertex3(min); GL.Vertex3(new Vector3(max.X, min.Y, min.Z)); GL.Vertex3(new Vector3(min.X, max.Y, min.Z)); GL.Vertex3(new Vector3(max.X, max.Y, min.Z)); GL.Vertex3(new Vector3(min.X, max.Y, max.Z)); GL.Vertex3(new Vector3(max.X, max.Y, max.Z)); GL.Vertex3(new Vector3(min.X, min.Y, max.Z)); GL.Vertex3(new Vector3(max.X, min.Y, max.Z)); GL.End(); GL.Disable(EnableCap.ColorMaterial); }