public void RenderWater(NativeArray <SPHSystem.WaterParticle> waterParticles) { float3 minPosition = cubeMarchineZone.bounds.min; float3 maxPosition = cubeMarchineZone.bounds.max; if (useBurst) { WaterMarchingCube.GenerateMeshBurst(waterParticles, waterParticles.Length, minPosition, maxPosition, marchingCubeResolution, ref mesh); } else { WaterMarchingCube.GenerateMesh(waterParticles, waterParticles.Length, minPosition, maxPosition, marchingCubeResolution, ref mesh); } waterMeshFilter.mesh = mesh; waterMeshFilter.transform.localScale = Vector3.one * cubeMarchineZone.size.x; waterMeshFilter.transform.localPosition = -Vector3.one * cubeMarchineZone.size.x * 0.5f; }
void UpdateInterWaterParticleCollision(float3 minPosition, float3 maxPosition) { //cache it int resolutionCube = marchingCubeResolution * marchingCubeResolution * marchingCubeResolution; if (waterParticleCountPerVoxel == null || waterParticleCountPerVoxel.Length != resolutionCube) { waterParticleCollisionTensor = new short[marchingCubeResolution, marchingCubeResolution, marchingCubeResolution, maxWaterParticlePerZone]; waterParticleCountPerVoxel = new byte[marchingCubeResolution, marchingCubeResolution, marchingCubeResolution]; particleIndicesInCollisionTensor = new int3[particleCount]; } else { Array.Clear(waterParticleCollisionTensor, 0, resolutionCube * maxWaterParticlePerZone); Array.Clear(waterParticleCountPerVoxel, 0, resolutionCube); Array.Clear(particleIndicesInCollisionTensor, 0, particleCount); } //float3 minPosition = cubeMarchineZone.bounds.min; //float3 maxPosition = cubeMarchineZone.bounds.max; float invResolution = 1f / marchingCubeResolution; float step = math.distance(minPosition, maxPosition) * invResolution; float invStep = 1f / step; //Broad phase for (int i = 0; i < particleCount; i++) { WaterParticle particle = waterParticles[i]; int3 index = WaterMarchingCube.GetPositionIndex(particle.position, minPosition, maxPosition, marchingCubeResolution, invStep); int numberOfParticleInVoxel = waterParticleCountPerVoxel[index.x, index.y, index.z]; if (numberOfParticleInVoxel < maxWaterParticlePerZone) { //Store the index of the particle in the grid particleIndicesInCollisionTensor[i] = index; waterParticleCollisionTensor[index.x, index.y, index.z, numberOfParticleInVoxel] = (short)i; waterParticleCountPerVoxel[index.x, index.y, index.z]++; } } //Narrow phase for (int i = 0; i < particleCount; i++) { //TODO check all 26 adjacent cells WaterParticle currentParticle = waterParticles[i]; int3 index = particleIndicesInCollisionTensor[i]; int numberOfParticleInVoxel = waterParticleCountPerVoxel[index.x, index.y, index.z]; for (int j = 0; j < numberOfParticleInVoxel; j++) { int otherParticleIndex = waterParticleCollisionTensor[index.x, index.y, index.z, j]; if (i == otherParticleIndex) { break; } WaterParticle otherParticle = waterParticles[otherParticleIndex]; float3 diff = otherParticle.position - currentParticle.position; //No collision if (math.lengthsq(diff) > particleRadius * particleRadius) { continue; } //TODO custom burstable functions //On collision vector keep they rejection, but swap projections float3 currentProjection = Vector3.Project(currentParticle.velocity, diff); float3 currentRejection = currentParticle.velocity - currentProjection; float3 otherProjection = Vector3.Project(otherParticle.velocity, diff); float3 otherRejection = currentParticle.velocity - otherProjection; //Swap currentParticle.velocity = (currentRejection + otherProjection) * elasticity; otherParticle.velocity = (otherRejection + currentProjection) * elasticity; //currentParticle.position -= diff * particleRadius; //otherParticle.position += diff * particleRadius; waterParticles[i] = currentParticle; waterParticles[otherParticleIndex] = otherParticle; } } }
public void Execute(int threadIndex) { int3 index = indices[threadIndex]; NativeArray <float> corners = new NativeArray <float>(8, Allocator.Temp); for (int j = 0; j < corners.Length; j++) { int3 corner = index + cornerTable[j]; int cornerFlat = WaterMarchingCube.GetFlatIndex(corner, resolution); corners[j] = map[cornerFlat]; } int configIndex = GetConfigIndex(corners); //empty config if (configIndex == 0 || configIndex == 255) { corners.Dispose(); return; } CubeTriangles cubeTriangle = new CubeTriangles(); int edgeIndex = 0; for (int i = 0; i < MAXEDGE; i++) { Triangle triangle = new Triangle(); bool addTriangle = true; for (int j = 0; j < MAXTRI; j++) { int triIndex = triangleTable[configIndex * MarchingCubeTables.TriangleWidth + edgeIndex]; ////No more triangles if (triIndex == -1) { addTriangle = false; break; } float3 vertex1 = index + edgeTable[triIndex * MarchingCubeTables.EdgeWidth]; float3 vertex2 = index + edgeTable[triIndex * MarchingCubeTables.EdgeWidth + 1]; //TODO Include smooth lerp float3 vertexPosition = math.lerp(vertex1, vertex2, 0.5f) * scaleFactor; //rofl switch (j) { case 0: triangle.vertex1 = vertexPosition; break; case 1: triangle.vertex2 = vertexPosition; break; case 2: triangle.vertex3 = vertexPosition; break; } edgeIndex++; } if (addTriangle) { cubeTriangle.AddTriangle(triangle); //generate unique hash index //const int separator = 4; //int hashIndex = triangleVertices.m_ThreadIndex * separator + i; //triangleVertices.Add(hashIndex, triangle); } } cubeTriangles[threadIndex] = cubeTriangle; corners.Dispose(); }