/// <summary> /// Calculates the resulting force on this skin vertex based on /// the gravity and the spring forces of all edges starting in this skin vertex. /// This value will be cached and used in the associated 'ApplyAcceleration()' method. /// </summary> public void CalculateResultingForce() { _resultingForce = Mathf.Atan(currentPosition.y) * Physics.gravity * 0.05f * _skinMesh.gravityMultiplier + addedForces; Vector3 skinEdgesResultingForce = Vector3.zero; foreach (SkinEdge skinEdge in edges) { skinEdge.ShuffleVertexIndices(vertexIndex); SkinVertex otherSkinVertex = _skinMesh.GetSkinVertex(skinEdge.vertex1Index); skinEdgesResultingForce += skinEdge.cachedSpringForce * (otherSkinVertex.currentPosition - currentPosition).normalized; } if (threads.Count == 0) { _resultingForce += skinEdgesResultingForce; } else { Vector3 threadsResultingForce = Vector3.zero; foreach (Thread thread in threads) { thread.ShuffleVertexIndices(vertexIndex); SkinVertex otherSkinVertex = _skinMesh.GetSkinVertex(thread.vertex1Index); threadsResultingForce += thread.cachedSpringForce * (otherSkinVertex.currentPosition - currentPosition).normalized; } _resultingForce += skinEdgesResultingForce + threadsResultingForce; } }
/// <summary> /// Update is called every frame, if the MonoBehaviour is enabled. /// </summary> public void Update() { if (!Input.GetKey(KeyCode.LeftControl) && !Input.GetKey(KeyCode.RightControl)) { threadStart = null; } if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) { //we are using the scalpel return; } if (Input.GetMouseButtonDown(0) && (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl))) { if (threadStart == null) { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); threadStart = _skinMesh.GetClosestSkinVertexToLineSgement(ray.origin, ray.GetPoint(10f), _skin.snapDistance); } else { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); SkinVertex skinVertex = _skinMesh.GetClosestSkinVertexToLineSgement(ray.origin, ray.GetPoint(10f), _skin.snapDistance); if (skinVertex != null) { _skinMesh.AddThread(threadStart.vertexIndex, skinVertex.vertexIndex); threadStart = skinVertex; } } } }
/// <summary> /// Update is called every frame, if the MonoBehaviour is enabled. /// </summary> public void Update() { if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)) { //we are using the needle return; } if (Input.GetMouseButton(0) && (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))) { if (cutStart == null) { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); cutStart = _skinMesh.GetClosestSkinVertexToLineSgement(ray.origin, ray.GetPoint(10f), _skin.snapDistance); } else { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); SkinVertex cutEnd = _skinMesh.GetClosestSkinVertexToLineSgement(ray.origin, ray.GetPoint(10f), _skin.snapDistance); _skinMesh.Cut(cutStart, cutEnd, _skin.snapDistance, cutDepth); cutStart = cutEnd; } } else { _cutStart = null; } }
/// <summary> /// Update is called every frame, if the MonoBehaviour is enabled. /// </summary> public void Update() { if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)) { //we are using the needle return; } if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) { //we are using the scalpel return; } if (Input.GetMouseButton(0)) { if (dragSkinVertex == null) { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); dragSkinVertex = _skinMesh.GetClosestSkinVertexToLineSgement(ray.origin, ray.GetPoint(10f), _skin.snapDistance); if (dragSkinVertex != null) { originalVertexHeight = dragSkinVertex.currentPosition.y; } _draggingHeight = 0f; } else { if (_draggingHeight < maxHeight) { _draggingHeight = Mathf.Min(maxHeight, _draggingHeight + Time.deltaTime * maxHeight); //1 second to get to the max height } Vector3 newPosition = Camera.main.ScreenToWorldPoint( new Vector3(Input.mousePosition.x, Input.mousePosition.y, Camera.main.transform.position.y - (originalVertexHeight + _draggingHeight))); Vector3 skinVertexForce = dragSkinVertex.resultingForce; Vector3 skinVertexForceNormalized = skinVertexForce.normalized; Vector3 newForce = newPosition - dragSkinVertex.currentPosition; //The size of the projection of the new force on the normalized skin vertex force. float newForceProjectedMagnitude = Vector3.Dot(newForce, skinVertexForceNormalized); if (newForceProjectedMagnitude < 0.0f) { float multiplier = Mathf.Clamp01(0.5f - 0.33f * Mathf.Atan(skinVertexForce.magnitude - maximumPullForce)); newPosition = dragSkinVertex.currentPosition + newForce * multiplier; } dragSkinVertex.currentPosition = newPosition; } } else { _dragSkinVertex = null; } }
public ClumpBuffers(ITagContainer diContainer, RWClump clump) { var device = diContainer.GetTag <GraphicsDevice>(); var atomic = clump.FindChildById(SectionId.Atomic, recursive: false) as RWAtomic; var geometry = clump.FindChildById(SectionId.Geometry, true) as RWGeometry; var materialList = geometry?.FindChildById(SectionId.MaterialList, false) as RWMaterialList; var materials = materialList?.children.Where(s => s is RWMaterial).Cast <RWMaterial>().ToArray(); var morphTarget = geometry?.morphTargets[0]; // TODO: morph support for the one model that uses it? if (geometry == null || morphTarget == null || materials == null || atomic == null) { throw new InvalidDataException("Could not find valid section structure in clump"); } RWGeometry = geometry; BSphereCenter = morphTarget.bsphereCenter; BSphereRadius = morphTarget.bsphereRadius; IsSolid = atomic.flags.HasFlag(AtomicFlags.CollisionTest); var vertices = new ModelStandardVertex[morphTarget.vertices.Length]; var bounds = new Box(morphTarget.vertices.First(), Vector3.Zero); for (int i = 0; i < vertices.Length; i++) { vertices[i].pos = morphTarget.vertices[i]; vertices[i].color = geometry.colors.Length > 0 ? geometry.colors[i] : new IColor(255); vertices[i].tex = geometry.texCoords.Length > 0 ? geometry.texCoords[0][i] : Vector2.Zero; bounds = bounds.Union(vertices[i].pos); } Bounds = bounds; vertexBuffer = device.ResourceFactory.CreateBuffer(new BufferDescription((uint)vertices.Length * ModelStandardVertex.Stride, BufferUsage.VertexBuffer)); device.UpdateBuffer(vertexBuffer, 0, vertices); // TODO: might have to correlate to the materialIndices member of materialList var trianglesByMatIdx = geometry.triangles.GroupBy(t => t.m).Where(g => g.Count() > 0); var indices = trianglesByMatIdx.SelectMany( g => g.SelectMany(t => new[] { t.v1, t.v2, t.v3 }) ).ToArray(); subMeshes = new SubMesh[trianglesByMatIdx.Count()]; int nextIndexPtr = 0; foreach (var(group, idx) in trianglesByMatIdx.Indexed()) { subMeshes[idx] = new SubMesh(nextIndexPtr, group.Count() * 3, materials[group.Key]); nextIndexPtr += subMeshes[idx].IndexCount; } indexBuffer = device.ResourceFactory.CreateBuffer(new BufferDescription((uint)indices.Length * 2, BufferUsage.IndexBuffer)); device.UpdateBuffer(indexBuffer, 0, indices); Skin = clump.FindChildById(SectionId.SkinPLG, true) as RWSkinPLG; if (Skin != null) { if (vertices.Length != Skin.vertexWeights.GetLength(0)) { throw new InvalidDataException("Vertex count in skin is not equal to geometry"); } var skinVertices = new SkinVertex[vertices.Length]; for (int i = 0; i < skinVertices.Length; i++) { skinVertices[i].bone0 = Skin.vertexIndices[i, 0]; skinVertices[i].bone1 = Skin.vertexIndices[i, 1]; skinVertices[i].bone2 = Skin.vertexIndices[i, 2]; skinVertices[i].bone3 = Skin.vertexIndices[i, 3]; skinVertices[i].weights.X = Skin.vertexWeights[i, 0]; skinVertices[i].weights.Y = Skin.vertexWeights[i, 1]; skinVertices[i].weights.Z = Skin.vertexWeights[i, 2]; skinVertices[i].weights.W = Skin.vertexWeights[i, 3]; } skinBuffer = device.ResourceFactory.CreateBuffer(new BufferDescription((uint)skinVertices.Length * SkinVertex.Stride, BufferUsage.VertexBuffer)); device.UpdateBuffer(skinBuffer, 0, skinVertices); } }
private SkelletalMesh GetMesh(GMeshContainer meshContainer, Bone root, VertexDescriptor vd) { SlimDX.Direct3D9.Mesh d3dMesh = meshContainer.Mesh; var adjacency = meshContainer.GetAdjacency(); var meshMaterials = meshContainer.GetMaterials(); List <MeshMaterial> materials = new List <MeshMaterial>(); for (int i = 0; i < meshMaterials.Length; i++) { var matd3d = meshMaterials[i].MaterialD3D; string textureFilename = meshMaterials[i].TextureFileName; if (textureFilename != null && !Path.IsPathRooted(textureFilename)) { textureFilename = Path.Combine(Path.GetDirectoryName(xFile), textureFilename); } materials.Add(new MeshMaterial() { Name = root.Name + "_material" + i, Alpha = matd3d.Diffuse.Alpha, Diffuse = matd3d.Diffuse.ToVector3(), Specular = matd3d.Specular.ToVector3(), SpecularPower = Math.Max(1, matd3d.Power), Reflectivity = 0, Refractitity = 0, EmissiveColor = matd3d.Emissive.ToVector3(), DiffuseMap = textureFilename }); } SkelletalMesh mesh = new SkelletalMesh(vd); mesh.Adjacency = adjacency; SkinVertex[] vertexes = new SkinVertex[d3dMesh.VertexCount]; Array indices; if (d3dMesh.IndexBuffer.Description.Format == Format.Index16) { indices = new ushort[d3dMesh.FaceCount * 3]; } else { indices = new uint[d3dMesh.FaceCount * 3]; } VertexDescriptor meshVD = new VertexDescriptor(d3dMesh.GetDeclaration()); int positionOffset = meshVD.GetOffset(DeclarationUsage.Position, 0); int normalOffset = meshVD.GetOffset(DeclarationUsage.Normal, 0); int texCoordOffset = meshVD.GetOffset(DeclarationUsage.TextureCoordinate, 0); int blendIndicesOffset = meshVD.GetOffset(DeclarationUsage.BlendIndices, 0); int blendIndicesSize = meshVD.SizeOfElement(DeclarationUsage.BlendIndices, 0); int blendWeightsOffset = meshVD.GetOffset(DeclarationUsage.BlendWeight, 0); int blendWeightSize = meshVD.SizeOfElement(DeclarationUsage.BlendWeight, 0); byte[] buffer; unsafe { DataStream vertexStream = d3dMesh.LockVertexBuffer(0); buffer = new byte[vertexStream.Length]; vertexStream.Read(buffer, 0, (int)vertexStream.Length); fixed(byte *_pter = buffer) { fixed(SkinVertex *pVertexes = vertexes) { byte *pter = _pter; int j = 0; for (int i = 0; i < d3dMesh.VertexCount; i++) { pVertexes[i].Position = *((Vector3 *)(pter + positionOffset)); if (normalOffset >= 0) { pVertexes[i].Normal = *((Vector3 *)(pter + normalOffset)); } if (texCoordOffset >= 0) { pVertexes[i].TexCoord = *((Vector2 *)(pter + texCoordOffset)); } if (blendIndicesOffset >= 0) { byte *indicesPter = (pter + blendIndicesOffset); uint *pDest = (uint *)&(pVertexes[i].BlendIndices); for (j = 0; j < blendIndicesSize; j++) { *(((byte *)pDest) + j) = *(indicesPter + j); } } if (blendWeightsOffset >= 0) { byte * weightsPter = (pter + blendWeightsOffset); Vector4 *pDest = &(pVertexes[i].BlendWeights); for (j = 0; j < blendWeightSize; j++) { *(((byte *)pDest) + j) = *(weightsPter + j); } } pter += d3dMesh.BytesPerVertex; } } } d3dMesh.UnlockVertexBuffer(); DataStream indexStream = d3dMesh.LockIndexBuffer(0); GCHandle handler = GCHandle.Alloc(indices, GCHandleType.Pinned); IntPtr indexPter = Marshal.UnsafeAddrOfPinnedArrayElement(indices, 0); buffer = new byte[indexStream.Length]; indexStream.Read(buffer, 0, (int)indexStream.Length); Marshal.Copy(buffer, 0, indexPter, buffer.Length); handler.Free(); d3dMesh.UnlockIndexBuffer(); } mesh.CreateVertexBuffer(vertexes); if (d3dMesh.IndexBuffer.Description.Format == Format.Index16) { mesh.CreateIndexBuffer((ushort[])indices); } else { mesh.CreateIndexBuffer((uint[])indices); } List <MeshLayer> layers = new List <MeshLayer>(); if (meshContainer.BoneCombinations == null || meshContainer.BoneCombinations.Length == 0) { MeshLayer component = new MeshLayer(); materials.Add(MeshMaterial.CreateDefaultMaterial(meshContainer.Name + "_default")); component.materialIndex = 0; component.primitiveCount = mesh.FaceCount; component.startIndex = 0; component.startVertex = 0; component.vertexCount = mesh.VertexCount; layers.Add(component); } else { for (int i = 0; i < meshContainer.BoneCombinations.Length; i++) { BoneCombination comb = meshContainer.BoneCombinations[i]; MeshLayer component = new MeshLayer(); component.materialIndex = comb.AttributeId; component.primitiveCount = comb.FaceCount; component.startIndex = comb.FaceStart * 3; component.startVertex = comb.VertexStart; component.vertexCount = comb.VertexCount; layers.Add(component); } } var layerArray = layers.ToArray(); mesh.Materials = materials.ToArray(); mesh.SetLayers(layerArray); var skinInfo = meshContainer.SkinInfo; mesh.MaxVertexInfluences = skinInfo.MaximumVertexInfluences; var bones = new Bone[skinInfo.BoneCount]; var boneOffsetMatrices = new Matrix[bones.Length]; for (int i = 0; i < bones.Length; i++) { bones[i] = root.FindChild(skinInfo.GetBoneName(i)); boneOffsetMatrices[i] = skinInfo.GetBoneOffsetMatrix(i); } mesh.Bones = bones; mesh.BoneBindingMatrices = boneOffsetMatrices; if (meshContainer.BoneCombinations != null && meshContainer.BoneCombinations.Length > 0) { for (int layerIndex = 0; layerIndex < layerArray.Length; layerIndex++) { mesh.SetLayerBones(layerIndex, meshContainer.BoneCombinations[layerIndex].BoneIds); } } mesh.LockVertexBuffer(); int[] vertices; float[] weights; for (int i = 0; i < mesh.bones.Length; i++) { skinInfo.GetBoneInfluence(i, out vertices, out weights); VertexStreamView <Vector3> positions = mesh.GetVertexViewStream <Vector3>(DeclarationUsage.Position, 0, vertices); } mesh.UnlockVertexBuffer(); meshVD.Dispose(); if (normalOffset < 0) { mesh.ComputeNormals(); } if (texCoordOffset < 0) { mesh.ComputeTextureCoords(CoordMappingType.Spherical); } mesh.ComputeTangents(); return(mesh); }