public GLModelViewer(VrfGuiContext guiContext, PhysAggregateData phys) : base(guiContext, Frustum.CreateEmpty()) { this.phys = phys; }
protected override void LoadScene() { if (model != null) { modelSceneNode = new ModelSceneNode(Scene, model); SetAvailableAnimations(modelSceneNode.GetSupportedAnimationNames()); Scene.Add(modelSceneNode, false); phys = model.GetEmbeddedPhys(); if (phys == null) { var refPhysicsPaths = model.GetReferencedPhysNames(); if (refPhysicsPaths.Any()) { //TODO are there any models with more than one vphys? if (refPhysicsPaths.Count() != 1) { Console.WriteLine($"Model has more than 1 vphys ({refPhysicsPaths.Count()})." + " Please report this on https://github.com/SteamDatabase/ValveResourceFormat and provide the file that caused this."); } var newResource = Scene.GuiContext.LoadFileByAnyMeansNecessary(refPhysicsPaths.First() + "_c"); if (newResource != null) { phys = (PhysAggregateData)newResource.DataBlock; } } } var meshGroups = modelSceneNode.GetMeshGroups(); if (meshGroups.Count() > 1) { meshGroupListBox = ViewerControl.AddMultiSelection("Mesh Group", selectedGroups => { modelSceneNode.SetActiveMeshGroups(selectedGroups); }); meshGroupListBox.Items.AddRange(modelSceneNode.GetMeshGroups().ToArray <object>()); foreach (var group in modelSceneNode.GetActiveMeshGroups()) { meshGroupListBox.SetItemChecked(meshGroupListBox.FindStringExact(group), true); } } var materialGroups = model.GetMaterialGroups(); if (materialGroups.Count() > 1) { materialGroupListBox = ViewerControl.AddSelection("Material Group", (selectedGroup, _) => { modelSceneNode?.SetSkin(selectedGroup); }); materialGroupListBox.Items.AddRange(materialGroups.ToArray <object>()); materialGroupListBox.SelectedIndex = 0; } modelSceneNode.AnimationController.RegisterUpdateHandler((animation, frame) => { if (animationTrackBar.TrackBar.Value != frame) { animationTrackBar.UpdateValueSilently(frame); } var maximum = animation == null ? 1 : animation.FrameCount - 1; if (animationTrackBar.TrackBar.Maximum != maximum) { animationTrackBar.TrackBar.Maximum = maximum; } animationTrackBar.Enabled = animation != null; animationPlayPause.Enabled = animation != null; }); } else { SetAvailableAnimations(Enumerable.Empty <string>()); } if (mesh != null) { meshSceneNode = new MeshSceneNode(Scene, mesh); Scene.Add(meshSceneNode, false); } if (phys != null) { physSceneNode = new PhysSceneNode(Scene, phys); Scene.Add(physSceneNode, false); //disabled by default. Enable if viewing only phys or model without meshes physSceneNode.Enabled = (modelSceneNode == null || !modelSceneNode.RenderableMeshes.Any()); ViewerControl.AddCheckBox("Show Physics", physSceneNode.Enabled, (v) => { physSceneNode.Enabled = v; }); } }
public PhysSceneNode(Scene scene, PhysAggregateData phys) : base(scene) { this.phys = phys; var verts = new List <float>(); var inds = new List <int>(); var bindPose = phys.Data.GetArray("m_bindPose") .Select(v => Matrix4x4FromArray(v .Select(m => Convert.ToSingle(m.Value)) .ToArray())) .ToArray(); if (bindPose.Length == 0) { bindPose = new Matrix4x4[] { Matrix4x4.Identity }; } //m_boneParents bool firstBbox = true; var parts = phys.Data.GetArray("m_parts"); for (int p = 0; p < parts.Length; p++) { var shape = parts[p].GetSubCollection("m_rnShape"); var spheres = shape.GetArray("m_spheres"); foreach (var s in spheres) { var sphere = s.GetSubCollection("m_Sphere"); var center = sphere.GetSubCollection("m_vCenter").ToVector3(); var radius = sphere.GetFloatProperty("m_flRadius"); if (bindPose.Any()) { center = Vector3.Transform(center, bindPose[p]); } AddSphere(verts, inds, center, radius); AABB bbox = new AABB(center + new Vector3(radius), center - new Vector3(radius)); LocalBoundingBox = firstBbox ? bbox : LocalBoundingBox.Union(bbox); firstBbox = false; } var capsules = shape.GetArray("m_capsules"); foreach (var c in capsules) { var capsule = c.GetSubCollection("m_Capsule"); var center = capsule.GetArray("m_vCenter").Select(v => v.ToVector3()).ToArray(); var radius = capsule.GetFloatProperty("m_flRadius"); center[0] = Vector3.Transform(center[0], bindPose[p]); center[1] = Vector3.Transform(center[1], bindPose[p]); AddCapsule(verts, inds, center[0], center[1], radius); foreach (var cn in center) { AABB bbox = new AABB(cn + new Vector3(radius), cn - new Vector3(radius)); LocalBoundingBox = firstBbox ? bbox : LocalBoundingBox.Union(bbox); firstBbox = false; } } var hulls = shape.GetArray("m_hulls"); foreach (var h in hulls) { var hull = h.GetSubCollection("m_Hull"); //m_vCentroid //m_flMaxAngularRadius //m_Vertices var vertices = hull.GetArray("m_Vertices"); var vertOffset = verts.Count / 7; foreach (var v in vertices) { var vec = v.ToVector3(); if (bindPose.Any()) { vec = Vector3.Transform(vec, bindPose[p]); } verts.Add(vec.X); verts.Add(vec.Y); verts.Add(vec.Z); //color red verts.Add(1); verts.Add(0); verts.Add(0); verts.Add(1); } //m_Planes var edges = hull.GetArray("m_Edges"); foreach (var e in edges) { inds.Add((int)(vertOffset + e.GetIntegerProperty("m_nOrigin"))); var next = edges[e.GetIntegerProperty("m_nNext")]; inds.Add((int)(vertOffset + next.GetIntegerProperty("m_nOrigin"))); } //m_Faces var bounds = hull.GetSubCollection("m_Bounds"); AABB bbox = new AABB(bounds.GetSubCollection("m_vMinBounds").ToVector3(), bounds.GetSubCollection("m_vMaxBounds").ToVector3()); LocalBoundingBox = firstBbox ? bbox : LocalBoundingBox.Union(bbox); firstBbox = false; } var meshes = shape.GetArray("m_meshes"); foreach (var m in meshes) { var mesh = m.GetSubCollection("m_Mesh"); //m_Nodes var vertOffset = verts.Count / 7; Vector3[] vertices = null; if (mesh is NTROStruct) { //NTRO has vertices as array of structs var verticesArr = mesh.GetArray("m_Vertices"); vertices = verticesArr.Select(v => v.ToVector3()).ToArray(); } else { //KV3 has vertices as blob var verticesBlob = mesh.GetArray <byte>("m_Vertices"); vertices = Enumerable.Range(0, verticesBlob.Length / 12) .Select(i => new Vector3(BitConverter.ToSingle(verticesBlob, i * 12), BitConverter.ToSingle(verticesBlob, (i * 12) + 4), BitConverter.ToSingle(verticesBlob, (i * 12) + 8))) .ToArray(); } foreach (var vec in vertices) { var v = vec; if (bindPose.Any()) { v = Vector3.Transform(vec, bindPose[p]); } verts.Add(v.X); verts.Add(v.Y); verts.Add(v.Z); //color green verts.Add(0); verts.Add(1); verts.Add(0); verts.Add(1); } int[] triangles = null; if (mesh is NTROStruct) { //NTRO and SOME KV3 has triangles as array of structs var trianglesArr = mesh.GetArray("m_Triangles"); triangles = trianglesArr.SelectMany(t => t.GetArray <object>("m_nIndex"). Select(Convert.ToInt32)).ToArray(); } else { //some KV3 has triangles as blob var trianglesBlob = mesh.GetArray <byte>("m_Triangles"); triangles = new int[trianglesBlob.Length / 4]; System.Buffer.BlockCopy(trianglesBlob, 0, triangles, 0, trianglesBlob.Length); } for (int i = 0; i < triangles.Length; i += 3) { inds.Add(vertOffset + triangles[i]); inds.Add(vertOffset + triangles[i + 1]); inds.Add(vertOffset + triangles[i + 1]); inds.Add(vertOffset + triangles[i + 2]); inds.Add(vertOffset + triangles[i + 2]); inds.Add(vertOffset + triangles[i]); } AABB bbox = new AABB(mesh.GetSubCollection("m_vMin").ToVector3(), mesh.GetSubCollection("m_vMax").ToVector3()); LocalBoundingBox = firstBbox ? bbox : LocalBoundingBox.Union(bbox); firstBbox = false; } //m_CollisionAttributeIndices //Console.WriteLine($"Phys mesh verts {verts.Count} inds {inds.Count}"); } shader = Scene.GuiContext.ShaderLoader.LoadShader("vrf.grid", new Dictionary <string, bool>()); GL.UseProgram(shader.Program); vaoHandle = GL.GenVertexArray(); GL.BindVertexArray(vaoHandle); vboHandle = GL.GenBuffer(); GL.BindBuffer(BufferTarget.ArrayBuffer, vboHandle); GL.BufferData(BufferTarget.ArrayBuffer, verts.Count * sizeof(float), verts.ToArray(), BufferUsageHint.StaticDraw); iboHandle = GL.GenBuffer(); indexCount = inds.Count; GL.BindBuffer(BufferTarget.ElementArrayBuffer, iboHandle); GL.BufferData(BufferTarget.ElementArrayBuffer, inds.Count * sizeof(int), inds.ToArray(), BufferUsageHint.StaticDraw); const int stride = sizeof(float) * 7; var positionAttributeLocation = GL.GetAttribLocation(shader.Program, "aVertexPosition"); GL.EnableVertexAttribArray(positionAttributeLocation); GL.VertexAttribPointer(positionAttributeLocation, 3, VertexAttribPointerType.Float, false, stride, 0); var colorAttributeLocation = GL.GetAttribLocation(shader.Program, "aVertexColor"); GL.EnableVertexAttribArray(colorAttributeLocation); GL.VertexAttribPointer(colorAttributeLocation, 4, VertexAttribPointerType.Float, false, stride, sizeof(float) * 3); GL.BindVertexArray(0); }