diff options
Diffstat (limited to 'NvCloth/samples/SampleBase/utils/MeshGenerator.cpp')
| -rw-r--r-- | NvCloth/samples/SampleBase/utils/MeshGenerator.cpp | 353 |
1 files changed, 301 insertions, 52 deletions
diff --git a/NvCloth/samples/SampleBase/utils/MeshGenerator.cpp b/NvCloth/samples/SampleBase/utils/MeshGenerator.cpp index 5541cc3..ccb3bf3 100644 --- a/NvCloth/samples/SampleBase/utils/MeshGenerator.cpp +++ b/NvCloth/samples/SampleBase/utils/MeshGenerator.cpp @@ -387,56 +387,28 @@ Mesh generateCone(physx::PxVec4 a, physx::PxVec4 b, int segments, float grow, bo //sphere a with smaller radius float cRadius = aRadius - bRadius; - physx::PxVec3 cCenter = aCenter; - - //sphere in between the a and b - physx::PxVec3 dCenter = (aCenter+bCenter)*0.5f; - float dRadius = (aCenter - bCenter).magnitude()*0.5f; - - //intersection between c and d to get tangent point - float iRadius; - physx::PxVec3 iCenter = IntersectSpheres(&iRadius, dCenter, dRadius, cCenter, cRadius); - physx::PxVec3 iPoint = iCenter + basis[0] * iRadius; //tangent point on c - physx::PxVec3 offset = (iPoint - aCenter).getNormalized(); //offset direction - - physx::PxVec3 aPoint = aCenter + offset*aRadius; - aCenter = (aPoint - aCenter).dot(basis[2])*basis[2] + aCenter; - aRadius = (aPoint - aCenter).magnitude(); - physx::PxVec3 bPoint = bCenter + offset*bRadius; - bCenter = (bPoint - aCenter).dot(basis[2])*basis[2] + aCenter; - bRadius = (bPoint - bCenter).magnitude(); - - - } - - //old code, probably wrong - /* - physx::PxVec3 pa = aCenter + aRadius*basis[0]; - physx::PxVec3 pb = bCenter + bRadius*basis[0]; - physx::PxVec3 dir = pb - pa; - - //construct plane containing pa and pb, with normal perpendicular to basis[0] - physx::PxVec3 n = basis[2].cross(dir); - physx::PxVec3 n2 = dir.cross(n); - - //line plane intersection - physx::PxVec3 focusPoint = aCenter + ((pa - aCenter).dot(n2)) / basis[2].dot(n2) * basis[2]; - - { - float focusDistance = (focusPoint - aCenter).magnitude(); - //make circle with center in mid point between focusPoint and aCenter - physx::PxVec3 cCenter = (focusPoint + aCenter)*0.5f; - float cRadius = focusDistance*0.5f; - - aCenter = IntersectSpheres(&aRadius, aCenter, aRadius, cCenter, cRadius); + if(cRadius > 0.00001) + { + physx::PxVec3 cCenter = aCenter; + + //sphere in between the a and b + physx::PxVec3 dCenter = (aCenter + bCenter)*0.5f; + float dRadius = (aCenter - bCenter).magnitude()*0.5f; + + //intersection between c and d to get tangent point + float iRadius; + physx::PxVec3 iCenter = IntersectSpheres(&iRadius, dCenter, dRadius, cCenter, cRadius); + physx::PxVec3 iPoint = iCenter + basis[0] * iRadius; //tangent point on c + physx::PxVec3 offset = (iPoint - aCenter).getNormalized(); //offset direction + + physx::PxVec3 aPoint = aCenter + offset*aRadius; + aCenter = (aPoint - aCenter).dot(basis[2])*basis[2] + aCenter; + aRadius = (aPoint - aCenter).magnitude(); + physx::PxVec3 bPoint = bCenter + offset*bRadius; + bCenter = (bPoint - aCenter).dot(basis[2])*basis[2] + aCenter; + bRadius = (bPoint - bCenter).magnitude(); + } } - - { - float focusDistance = (focusPoint - bCenter).magnitude(); - physx::PxVec3 cCenter = (focusPoint + bCenter)*0.5f; - float cRadius = focusDistance*0.5f; - bCenter = IntersectSpheres(&bRadius, bCenter, bRadius, cCenter, cRadius); - }*/ } @@ -491,7 +463,7 @@ Mesh generateCollisionCapsules(physx::PxVec4* spheres, int sphereCount, uint32_t Mesh finalMesh; for(int i = 0; i < sphereCount; i++) { - Mesh sphere = generateIcosahedron(spheres[i].w+ grow, 4); + Mesh sphere = generateIcosahedron(spheres[i].w+ grow, 2); sphere.applyTransfom(physx::PxTransform(spheres[i].getXYZ())); finalMesh.merge(sphere); } @@ -504,6 +476,272 @@ Mesh generateCollisionCapsules(physx::PxVec4* spheres, int sphereCount, uint32_t return finalMesh; } +::SimpleMesh generateFastSphere(int segmentsX, int segmentY, physx::PxMat44 transform) +{ + SimpleMesh mesh; + const int xSegments = segmentsX; + const int ySegments = segmentY; + + { + //bottom + SimpleMesh::Vertex v; + v.position = physx::PxVec3(0.0f, -1.0f, 0.0f); + v.normal = transform.rotate(physx::PxVec4(v.position, 0.0f)).getXYZ(); + v.position = transform.transform(v.position); + v.uv = physx::PxVec2(0.0f, 0.0f); + mesh.vertices.push_back(v); + } + + //middle + for(int y = 1; y < ySegments; y++) + { + for(int x = 0; x < xSegments; x++) + { + float xf = (float)x / (xSegments - 1.0f); + float yaw = xf*physx::PxTwoPi; + float yf = (float)y / (ySegments); + float pitch = (yf - 0.5f)*physx::PxPi; + + SimpleMesh::Vertex v; + v.position = physx::PxVec3(cos(yaw)*cos(pitch), sin(pitch), sin(yaw)*cos(pitch)); + v.uv = physx::PxVec2(xf, yf); + v.normal = transform.rotate(physx::PxVec4(v.position, 0.0f)).getXYZ(); + v.position = transform.transform(v.position); + mesh.vertices.push_back(v); + } + } + + { + //top + SimpleMesh::Vertex v; + v.position = physx::PxVec3(0.0f, 1.0f, 0.0f); + v.normal = transform.rotate(physx::PxVec4(v.position,0.0f)).getXYZ(); + v.position = transform.transform(v.position); + v.uv = physx::PxVec2(0.0f, 1.0f); + mesh.vertices.push_back(v); + } + + //bottom cap + for(int x = 0; x < xSegments; x++) + { + mesh.indices.push_back(0); + mesh.indices.push_back(1 + x); + mesh.indices.push_back(1 + (x + 1) % xSegments); + } + + const auto RingVertex = [xSegments, ySegments](int x, int y) + { + return 1 + y*xSegments + x%xSegments; + }; + + //middle + for(int y = 0; y < ySegments - 2; y++) + { + for(int x = 0; x < xSegments; x++) + { + mesh.indices.push_back(RingVertex(x, y)); + mesh.indices.push_back(RingVertex(x + 1, y)); + mesh.indices.push_back(RingVertex(x, y + 1)); + + mesh.indices.push_back(RingVertex(x + 1, y)); + mesh.indices.push_back(RingVertex(x + 1, y + 1)); + mesh.indices.push_back(RingVertex(x, y + 1)); + } + } + + //bottom cap + for(int x = 0; x < xSegments; x++) + { + mesh.indices.push_back((uint16_t)mesh.vertices.size() - 1); + mesh.indices.push_back(RingVertex(x, ySegments - 2)); + mesh.indices.push_back(RingVertex(x + 1, ySegments - 2)); + } + + return mesh; +} + +::SimpleMesh generateFastCylinder(int segmentsX, int segmentY, physx::PxMat44 transform) +{ + SimpleMesh mesh; + const int xSegments = segmentsX; + const int ySegments = segmentY; + + + //middle + for(int y = 0; y < ySegments+1; y++) + { + for(int x = 0; x < xSegments; x++) + { + float xf = (float)x / (xSegments - 1.0f); + float yaw = xf*physx::PxTwoPi; + float yf = (float)y / (ySegments) * 2.0f - 1.0f; + + SimpleMesh::Vertex v; + v.position = physx::PxVec3(cos(yaw), yf, sin(yaw)); + v.uv = physx::PxVec2(xf, yf); + v.normal = transform.rotate(physx::PxVec4(physx::PxVec3(cos(yaw), 0.0f, sin(yaw)), 0.0f)).getXYZ(); + v.position = transform.transform(v.position); + mesh.vertices.push_back(v); + } + } + + + const auto RingVertex = [xSegments, ySegments](int x, int y) + { + return y*xSegments + x%xSegments; + }; + + //middle + for(int y = 0; y < ySegments; y++) + { + for(int x = 0; x < xSegments; x++) + { + mesh.indices.push_back(RingVertex(x, y)); + mesh.indices.push_back(RingVertex(x + 1, y)); + mesh.indices.push_back(RingVertex(x, y + 1)); + + mesh.indices.push_back(RingVertex(x + 1, y)); + mesh.indices.push_back(RingVertex(x + 1, y + 1)); + mesh.indices.push_back(RingVertex(x, y + 1)); + } + } + + return mesh; +} + +::SimpleMesh generateCollisionCapsulesFast(physx::PxVec4* spheres, int sphereCount, uint32_t* indices, int indexCount, float grow) +{ + static ::SimpleMesh sphere = generateFastSphere(24,12,physx::PxTransform(physx::PxVec3(0.0f, 0.0f, 0.0f), physx::PxQuat(0.0f, physx::PxVec3(0.0f, 1.0f, 0.0f)))); + static ::SimpleMesh cylinder = generateFastCylinder(24, 1, physx::PxTransform(physx::PxVec3(0.0f, 1.0f, 0.0f), physx::PxQuat(0.0f, physx::PxVec3(0.0f, 1.0f, 0.0f)))); + + ::SimpleMesh mesh; + mesh.vertices.resize(sphere.vertices.size()*sphereCount + cylinder.vertices.size()*(indexCount / 2)); + mesh.indices.resize(sphere.indices.size()*sphereCount + cylinder.indices.size()*(indexCount / 2)); + + int nextVertex = 0; + int nextIndex = 0; + for(int i = 0; i < sphereCount; i++) + { + int baseIndex = nextVertex; + physx::PxMat44 transform = + physx::PxMat44(physx::PxMat33(physx::PxIdentity), spheres[i].getXYZ()) + * physx::PxMat44(PxVec4(spheres[i].w + grow, spheres[i].w + grow, spheres[i].w + grow, 1.0f)); + + for(int vi = 0; vi<(int)sphere.vertices.size(); vi++) + { + SimpleMesh::Vertex v = sphere.vertices[vi]; + v.normal = transform.rotate(physx::PxVec4(v.normal, 0.0f)).getXYZ(); + v.position = transform.transform(v.position); + mesh.vertices[nextVertex++] = v; + } + + for(int ii = 0; ii < (int)sphere.indices.size(); ii++) + { + mesh.indices[nextIndex++] = sphere.indices[ii]+ baseIndex; + } + } + + for(int i = 0; i < indexCount; i+=2) + { + int baseIndex = nextVertex; + + physx::PxVec3 spherePosA = spheres[indices[i]].getXYZ(); + physx::PxVec3 spherePosB = spheres[indices[i+1]].getXYZ(); + float sphereRadiusA = spheres[indices[i]].w + grow; + float sphereRadiusB = spheres[indices[i + 1]].w + grow; + + if(sphereRadiusA < sphereRadiusB) + { + std::swap(sphereRadiusA, sphereRadiusB); + std::swap(spherePosA, spherePosB); + } + + { + //http://jwilson.coe.uga.edu/emt669/Student.Folders/Kertscher.Jeff/Essay.3/Tangents.html + + //sphere a with smaller radius + float cRadius = sphereRadiusA - sphereRadiusB; + if(cRadius > 0.00001) + { + physx::PxVec3 basis[3]; + basis[2] = spherePosB - spherePosA; + basis[2].normalize(); + computeBasis(basis[2], &basis[0], &basis[1]); + + physx::PxVec3 cCenter = spherePosA; + + //sphere in between the a and b + physx::PxVec3 dCenter = (spherePosA + spherePosB)*0.5f; + float dRadius = (spherePosA - spherePosB).magnitude()*0.5f; + + //intersection between c and d to get tangent point + float iRadius; + physx::PxVec3 iCenter = IntersectSpheres(&iRadius, dCenter, dRadius, cCenter, cRadius); + physx::PxVec3 iPoint = iCenter + basis[0] * iRadius; //tangent point on c + physx::PxVec3 offset = (iPoint - spherePosA).getNormalized(); //offset direction + + physx::PxVec3 aPoint = spherePosA + offset*sphereRadiusA; + spherePosA = (aPoint - spherePosA).dot(basis[2])*basis[2] + spherePosA; + sphereRadiusA = (aPoint - spherePosA).magnitude(); + physx::PxVec3 bPoint = spherePosB + offset*sphereRadiusB; + spherePosB = (bPoint - spherePosA).dot(basis[2])*basis[2] + spherePosA; + sphereRadiusB = (bPoint - spherePosB).magnitude(); + } + } + + float length = (spherePosB - spherePosA).magnitude(); + + + physx::PxMat44 scaleA = physx::PxMat44(PxVec4(sphereRadiusA, length/2.0f, sphereRadiusA+grow, 1.0f)); + physx::PxMat44 scaleB = physx::PxMat44(PxVec4(sphereRadiusB, length/2.0f, sphereRadiusB, 1.0f)); + + physx::PxQuat orientation; + { + physx::PxVec3 u = physx::PxVec3(0.0f, 1.0f, 0.0f); + physx::PxVec3 v = spherePosB - spherePosA; + v.normalize(); + + if(u.dot(v) < -0.9999) + orientation = physx::PxQuat(physx::PxTwoPi, physx::PxVec3(1.0f, 0.0f, 0.0f)); + else if(u.dot(v) > 0.9999) + orientation = physx::PxQuat(0.0f, physx::PxVec3(1.0f, 0.0f, 0.0f)); + else + { + physx::PxVec3 half = u + v; + half.normalize(); + physx::PxVec3 imaginary = u.cross(half); + orientation = physx::PxQuat(imaginary.x, imaginary.y, imaginary.z, u.dot(half)); + } + } + + physx::PxMat44 transform = physx::PxMat44(physx::PxTransform(spherePosA, orientation))*scaleA; + + int firstRing = (int)cylinder.vertices.size() / 2; + for(int vi = 0; vi<firstRing; vi++) + { + SimpleMesh::Vertex v = cylinder.vertices[vi]; + v.normal = transform.rotate(physx::PxVec4(v.normal, 0.0f)).getXYZ(); + v.position = transform.transform(v.position); + mesh.vertices[nextVertex++] = v; + } + transform = physx::PxMat44(physx::PxTransform(spherePosA, orientation))*scaleB; + for(int vi = firstRing; vi<(int)cylinder.vertices.size(); vi++) + { + SimpleMesh::Vertex v = cylinder.vertices[vi]; + v.normal = transform.rotate(physx::PxVec4(v.normal, 0.0f)).getXYZ(); + v.position = transform.transform(v.position); + mesh.vertices[nextVertex++] = v; + } + + for(int ii = 0; ii < (int)cylinder.indices.size(); ii++) + { + mesh.indices[nextIndex++] = cylinder.indices[ii] + baseIndex; + } + } + + return mesh; +} + uint32_t generateConvexPolyhedronPlanes(int segmentsX, int segmentsY, physx::PxVec3 center, float radius, std::vector<physx::PxVec4>* planes) { int offset = 0; @@ -546,7 +784,7 @@ MeshGeneratorRenderMesh::MeshGeneratorRenderMesh(const Mesh mesh) layout.push_back({"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}); layout.push_back({"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}); - initialize(vertices, (uint32_t)vertexCount, sizeof(RenderVertex), layout, indices, indexCount); + initialize(vertices, (uint32_t)vertexCount, sizeof(RenderVertex), layout, indices, indexCount, 0); delete vertices; delete indices; @@ -567,11 +805,22 @@ MeshGeneratorRenderMeshSmooth::MeshGeneratorRenderMeshSmooth(const Mesh mesh) layout.push_back({"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}); layout.push_back({"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}); - initialize(vertices, (uint32_t)vertexCount, sizeof(RenderVertex), layout, indices, indexCount); + initialize(vertices, (uint32_t)vertexCount, sizeof(RenderVertex), layout, indices, indexCount, 0); delete vertices; delete indices; } + +MeshGeneratorRenderMeshSmooth::MeshGeneratorRenderMeshSmooth(const ::SimpleMesh mesh, int flags) +{ + std::vector<D3D11_INPUT_ELEMENT_DESC> layout; + layout.push_back({"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}); + layout.push_back({"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}); + layout.push_back({"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0}); + + initialize(mesh.vertices.data(), (uint32_t)mesh.vertices.size(), sizeof(::SimpleMesh::Vertex), layout, mesh.indices.data(), (uint32_t)mesh.indices.size(), flags); +} + MeshGeneratorRenderMeshSmooth::~MeshGeneratorRenderMeshSmooth() { |