public void Execute(int i) { // Is hair movable? if (HairMovability.IsMovable(i, movability)) { bool wasModified = false; float3 v = vertices[i]; for (int j = 0; j < colliderCount; j++) { // Read collider var c = colliders[j]; // Intersection? float3 dir = (v - c.center); float sqMag = math.lengthsq(dir); if (sqMag <= c.radiusSq) // if (Vector3.Distance(v, c.center) <= c.radius) { // Intersection! push the vertex out float d = math.sqrt(sqMag); // dir.magnitude; v += (dir / d) * (c.radius - d); wasModified = true; } } if (wasModified) { vertices[i] = v; // Sync } } }
protected override void _SimulationStep(float timestep) { HairStrand[] strands = this.instance.strands.cpuReference; Vector3[] vertices = this.instance.vertices.cpuReference; uint[] movability = this.instance.movability.cpuReference; for (int s = 0; s < strands.Length; s++) { HairStrand strand = strands[s]; for (int j = strand.firstVertex + 1; j <= strand.lastVertex; j++) { if (!HairMovability.IsMovable(j, movability)) { continue; } float nDist = this.lengths[j]; Vector3 p = vertices[j], pPrev = vertices[j - 1], pDir = (p - pPrev); float dist = pDir.magnitude; float distDiff = (nDist - dist); vertices[j] = p + ((pDir / dist) * (distDiff * this.stiffness * timestep)); } } this.instance.vertices.SetGPUDirty(); }
public void Execute(int index) { HairStrand strand = this.strands[index]; quaternion rotGlobal = this.globalTransform[strand.firstVertex]; for (int j = strand.firstVertex + 1; j < strand.lastVertex - 1; j++) { quaternion rotGlobalWorld = math.mul(rotation, rotGlobal); float3 p1 = vertices[j], p2 = vertices[j + 1]; float3 orgP2 = math.mul(rotGlobalWorld, this.referenceVectors[j + 1]) + p1; float3 delta = stiffness * (orgP2 - p2); if (HairMovability.IsMovable(j, movability)) { p1 -= delta; } if (HairMovability.IsMovable(j + 1, movability)) { p2 += delta; } float3 vec = (p2 - p1); rotGlobal = math.mul(rotGlobal, quaternion.LookRotation(math.normalize(math.mul(math.inverse(rotGlobalWorld), vec)), new float3(0, 1, 0))); vertices[j] = p1; vertices[j + 1] = p2; } }
protected override void _SimulationStep(float timestep) { NativeArray <float3> vertices = this.instance.vertices.CpuReference; NativeArray <uint> movability = this.instance.movability.CpuReference; NativeArray <HairStrand> strands = this.instance.strands.CpuReference; Matrix4x4 matrix = this.transform.localToWorldMatrix; for (int j = 0; j < strands.Length; j++) { HairStrand strand = strands[j]; int target = Mathf.Min(strand.firstVertex + this.vertexRange, strand.lastVertex); for (int i = strand.firstVertex; i <= target; i++) { if (!HairMovability.IsMovable(i, movability)) { continue; } Vector3 iV = this.simulation.initialVertices[i], v = vertices[i]; iV = matrix.MultiplyPoint3x4(iV); Vector3 delta = (iV - v); vertices[i] = v + (delta * this.stiffness * timestep); } } this.instance.vertices.SetGPUDirty(); }
protected override void _SimulationStep(float timestep) { List <CollisionSphere> colliders = ListPool <CollisionSphere> .Get(); for (int i = 0; i < this.colliders.Length; i++) { colliders.Add(new CollisionSphere() { center = this.colliders[i].transform.TransformPoint(this.colliders[i].center), radius = this.colliders[i].radius, radiusSq = this.colliders[i].radius * this.colliders[i].radius }); } int colliderCount = colliders.Count; NativeArray <float3> vertices = this.instance.vertices.CpuReference; NativeArray <uint> movability = this.instance.movability.CpuReference; bool wasAnythingModified = false; for (int i = 0; i < vertices.Length; i++) { // Is hair movable? if (HairMovability.IsMovable(i, movability)) { bool wasModified = false; Vector3 v = vertices[i]; for (int j = 0; j < colliderCount; j++) { // Read collider var c = colliders[j]; // Intersection? Vector3 dir = (v - c.center); float sqrMag = dir.sqrMagnitude; if (sqrMag <= c.radiusSq) // if (Vector3.Distance(v, c.center) <= c.radius) { // Intersection! push the vertex out float d = Mathf.Sqrt(sqrMag); // dir.magnitude; v += (dir / d) * (c.radius - d); wasModified = true; } } if (wasModified) { vertices[i] = v; // Sync } wasAnythingModified |= wasModified; } } if (wasAnythingModified) { this.instance.vertices.SetGPUDirty(); } ListPool <CollisionSphere> .Return(colliders); }
public void Execute(int i) { if (!HairMovability.IsMovable(i, movability)) { return; } vertices[i] = vertices[i] + force; }
protected override void _SimulationStep(float timestep) { // TODO: Damping Matrix4x4 matrix = this.transform.localToWorldMatrix; Matrix4x4 invPrevMatrix = this.simulation.prevFrameMatrix.inverse; // Read vertices and strands NativeArray <HairStrand> strands = this.instance.strands.CpuReference; NativeArray <float3> vertices = this.instance.vertices.CpuReference; NativeArray <uint> movability = this.instance.movability.CpuReference; Vector3 gravity = Physics.gravity * this.gravityStrength; HairStrand strand; Vector3 lastFramePosWS, lastFramePosOS, posWS, newPos; lastFramePosOS = lastFramePosWS = posWS = newPos = new Vector3(); float timestepSqr = timestep * timestep; for (int j = 0; j < strands.Length; j++) { strand = strands[j]; // First vertex is immovable vertices[strand.firstVertex] = matrix.MultiplyPoint3x4(this.simulation.initialVertices[strand.firstVertex]); for (int i = strand.firstVertex; i <= strand.lastVertex; i++) { if (!HairMovability.IsMovable(i, movability)) { continue; } lastFramePosWS = vertices[i]; lastFramePosOS = invPrevMatrix.MultiplyPoint3x4(lastFramePosWS); posWS = matrix.MultiplyPoint3x4(lastFramePosOS); // Unoptimized: // newPos = posWS + (lastFramePosWS - posWS) + (gravity * (timestep * timestep)); // Optimized version: newPos.x = posWS.x + (lastFramePosWS.x - posWS.x) + (gravity.x * timestepSqr); newPos.y = posWS.y + (lastFramePosWS.y - posWS.y) + (gravity.y * timestepSqr); newPos.z = posWS.z + (lastFramePosWS.z - posWS.z) + (gravity.z * timestepSqr); vertices[i] = newPos; } } // Set dirty this.instance.vertices.SetGPUDirty(); }
protected override void _SimulationStep(float timestep) { // TODO: Spherical wind zones Vector3[] vertices = this.instance.vertices.cpuReference; uint[] movability = this.instance.movability.cpuReference; Vector3 f = this.windZone.transform.forward * Mathf.Abs(Mathf.Sin(Time.time) * this.windZone.windMain); for (int i = 0; i < vertices.Length; i++) { if (!HairMovability.IsMovable(i, movability)) { continue; } vertices[i] = vertices[i] + (f * timestep); } }
protected override void _SimulationStep(float timestep) { float stiffness = .5f * Mathf.Min(this.stiffness * timestep, .95f); HairStrand[] strands = this.instance.strands.cpuReference; Vector3[] vertices = this.instance.vertices.cpuReference; uint[] movability = this.instance.movability.cpuReference; Quaternion rotation = this.transform.rotation; // Apply local shape constraint for (int i = 0; i < strands.Length; i++) { HairStrand strand = strands[i]; Quaternion rotGlobal = this.globalTransform[strand.firstVertex]; realtimeDebug[strand.firstVertex] = rotGlobal; for (int j = strand.firstVertex + 1; j < strand.lastVertex - 1; j++) { Quaternion rotGlobalWorld = rotation * rotGlobal; Vector3 p1 = vertices[j], p2 = vertices[j + 1]; Vector3 orgP2 = rotGlobalWorld * this.referenceVectors[j + 1] + p1; Vector3 delta = stiffness * (orgP2 - p2); if (HairMovability.IsMovable(j, movability)) { p1 -= delta; } if (HairMovability.IsMovable(j + 1, movability)) { p2 += delta; } Vector3 vec = (p2 - p1); rotGlobal = rotGlobal * Quaternion.LookRotation((Quaternion.Inverse(rotGlobalWorld) * vec).normalized); vertices[j] = p1; vertices[j + 1] = p2; realtimeDebug[j] = rotGlobal; } realtimeDebug[strand.lastVertex] = rotGlobal; } this.instance.vertices.SetGPUDirty(); }
public void Execute(int index) { HairStrand strand = this.strands[index]; for (int j = strand.firstVertex + 1; j <= strand.lastVertex; j++) { if (!HairMovability.IsMovable(j, movability)) { continue; } float nDist = this.lengths[j]; float3 p = vertices[j], pPrev = vertices[j - 1], pDir = (p - pPrev); float dist = math.length(pDir); float distDiff = (nDist - dist); vertices[j] = p + ((pDir / dist) * (distDiff * this.stiffness * timestep)); } }
public void Execute(int j) { HairStrand strand = strands[j]; int target = Mathf.Min(strand.firstVertex + this.vertexRange, strand.lastVertex); for (int i = strand.firstVertex; i <= target; i++) { if (!HairMovability.IsMovable(i, movability)) { continue; } float3 iV = initialVertices[i], v = vertices[i]; float4 iV4 = new float4(iV.x, iV.y, iV.z, 1); iV = math.mul(matrix, iV4).xyz; float3 delta = (iV - v); vertices[i] = v + (delta * this.stiffness * timestep); } }
public void Execute(int index) { HairStrand strand = this.strands[index]; float3 lastFramePosWS, lastFramePosOS, posWS, newPos; lastFramePosOS = lastFramePosWS = posWS = newPos = new float3(); // First vertex is immovable float3 initialPos = initialVertices[strand.firstVertex]; vertices[strand.firstVertex] = math.mul(matrix, new float4(initialPos.x, initialPos.y, initialPos.z, 1)).xyz; for (int i = strand.firstVertex; i <= strand.lastVertex; i++) { if (!HairMovability.IsMovable(i, movability)) { continue; } lastFramePosWS = vertices[i]; float4 lastFramePosWS4 = new float4(lastFramePosWS.x, lastFramePosWS.y, lastFramePosWS.z, 1); lastFramePosOS = math.mul(invPrevMatrix, lastFramePosWS4).xyz; float4 lastFramePosOS4 = new float4(lastFramePosOS.x, lastFramePosOS.y, lastFramePosOS.z, 1); posWS = math.mul(matrix, lastFramePosOS4).xyz; // Unoptimized: // newPos = posWS + (lastFramePosWS - posWS) + (gravity * (timestep * timestep)); // Optimized version: newPos.x = posWS.x + (lastFramePosWS.x - posWS.x) + (gravity.x * timestepSqr); newPos.y = posWS.y + (lastFramePosWS.y - posWS.y) + (gravity.y * timestepSqr); newPos.z = posWS.z + (lastFramePosWS.z - posWS.z) + (gravity.z * timestepSqr); vertices[i] = newPos; } }
public void Execute(int i) { // Is hair movable? if (HairMovability.IsMovable(i, movability)) { bool wasModified = false; float3 v = vertices[i]; for (int j = 0; j < colliderCount; j++) { // Read collider var c = colliders[j]; // Test sphere 1 float3 dir = (v - c.sphere1Pos); float sqMag = math.lengthsq(dir); if (sqMag <= c.radiusSq) { // Intersection! push the vertex out float d = math.sqrt(sqMag); v += (dir / d) * (c.radius - d); wasModified = true; } else { // Test sphere 2 dir = (v - c.sphere2Pos); sqMag = math.lengthsq(dir); if (sqMag <= c.radiusSq) { // Intersection! push the vertex out float d = math.sqrt(sqMag); v += (dir / d) * (c.radius - d); wasModified = true; } else { // Test cylinder float3 d = c.sphere2Pos - c.sphere1Pos; float3 pd = v - c.sphere1Pos; float dot = math.dot(d, pd); if (dot >= 0 && dot <= c.lengthSq) { float dist = math.lengthsq(pd) - (dot * dot / c.lengthSq); if (dist <= c.radiusSq) { // Get closest point to vertex on cylinder axis float3 dNorm = d / c.length; float dotP = math.dot(v - c.sphere1Pos, dNorm); float3 axisPoint = c.sphere1Pos + dNorm * dotP; // Construct ray through vertex from axis point and get cylinder body exit point v = axisPoint + (math.normalizesafe(v - axisPoint) * c.radius); wasModified = true; } } } } } if (wasModified) { vertices[i] = v; // Sync } } }