refactor cloth

This commit is contained in:
Irlan
2018-05-24 05:35:16 -03:00
parent 47a2c12160
commit 4ae3b7cc79
17 changed files with 1993 additions and 2635 deletions

View File

@ -60,11 +60,10 @@
#include <testbed/tests/tumbler.h>
#include <testbed/tests/multiple_pendulum.h>
#include <testbed/tests/cloth_test.h>
#include <testbed/tests/spring_cloth_test.h>
#include <testbed/tests/table_cloth.h>
#include <testbed/tests/pinned_cloth.h>
#include <testbed/tests/shirt.h>
#include <testbed/tests/mass_types.h>
#include <testbed/tests/particle_types.h>
#include <testbed/tests/tension_mapping.h>
#include <testbed/tests/single_pendulum.h>
#include <testbed/tests/rope_test.h>
@ -113,11 +112,10 @@ TestEntry g_tests[] =
{ "Tumbler", &Tumbler::Create },
{ "Initial Overlap", &InitialOverlap::Create },
{ "Multiple Pendulum", &MultiplePendulum::Create },
{ "Cloth", &Cloth::Create },
{ "Table Cloth", &TableCloth::Create },
{ "Pinned Cloth", &PinnedCloth::Create },
{ "Shirt", &Shirt::Create },
{ "Mass Types", &MassTypes::Create },
{ "Particle Types", &ParticleTypes::Create },
{ "Tension Mapping", &TensionMapping::Create },
{ "Mass-Spring System", &MassSpring::Create },
{ "Single Pendulum", &SinglePendulum::Create },

View File

@ -16,52 +16,344 @@
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef CLOTH_H
#define CLOTH_H
#ifndef CLOTH_TESH_H
#define CLOTH_TESH_H
class Cloth : public Test
class ClothDragger
{
public:
Cloth()
ClothDragger(Ray3* ray, b3Cloth* cloth)
{
b3ClothDef def;
def.mesh = &m_clothMesh;
def.density = 0.2f;
def.gravity.Set(0.0f, -10.0f, 0.0f);
def.k1 = 0.2f;
def.k2 = 0.1f;
def.kd = 0.005f;
def.r = 1.0f;
m_ray = ray;
m_cloth = cloth;
m_isSelected = false;
}
m_cloth.Initialize(def);
~ClothDragger()
{
b3AABB3 aabb;
aabb.m_lower.Set(-5.0f, -1.0f, -6.0f);
aabb.m_upper.Set(5.0f, 1.0f, -4.0f);
}
b3Particle* vs = m_cloth.GetVertices();
for (u32 i = 0; i < m_cloth.GetVertexCount(); ++i)
bool IsSelected() const
{
return m_isSelected;
}
b3Vec3 GetPointA() const
{
B3_ASSERT(m_isSelected);
b3ClothMesh* m = m_cloth->GetMesh();
b3ClothMeshTriangle* t = m->triangles + m_selection;
b3Vec3 A = m->vertices[t->v1];
b3Vec3 B = m->vertices[t->v2];
b3Vec3 C = m->vertices[t->v3];
return m_u * A + m_v * B + (1.0f - m_u - m_v) * C;
}
b3Vec3 GetPointB() const
{
B3_ASSERT(m_isSelected);
return (1.0f - m_x) * m_ray->A() + m_x * m_ray->B();
}
bool StartDragging()
{
B3_ASSERT(m_isSelected == false);
if (Select(m_selection, m_x) == false)
{
if (aabb.Contains(vs[i].p))
return false;
}
m_isSelected = true;
b3ClothMesh* m = m_cloth->GetMesh();
b3ClothMeshTriangle* t = m->triangles + m_selection;
b3Particle* p1 = m_cloth->GetParticle(t->v1);
m_t1 = p1->type;
m_cloth->SetType(p1, e_staticParticle);
b3Particle* p2 = m_cloth->GetParticle(t->v2);
m_t2 = p2->type;
m_cloth->SetType(p2, e_staticParticle);
b3Particle* p3 = m_cloth->GetParticle(t->v3);
m_t3 = p3->type;
m_cloth->SetType(p3, e_staticParticle);
b3Vec3 v1 = p1->position;
b3Vec3 v2 = p2->position;
b3Vec3 v3 = p3->position;
b3Vec3 B = GetPointB();
float32 wABC[4];
b3BarycentricCoordinates(wABC, v1, v2, v3, B);
if (wABC[3] > B3_EPSILON)
{
m_u = wABC[0] / wABC[3];
m_v = wABC[1] / wABC[3];
}
else
{
m_u = m_v = 0.0f;
}
return true;
}
void Drag()
{
B3_ASSERT(m_isSelected);
b3ClothMesh* m = m_cloth->GetMesh();
b3ClothMeshTriangle* t = m->triangles + m_selection;
b3Vec3 A = GetPointA();
b3Vec3 B = GetPointB();
b3Vec3 dx = B - A;
b3Particle* p1 = m_cloth->GetParticle(t->v1);
m_cloth->Translate(p1, dx);
b3Particle* p2 = m_cloth->GetParticle(t->v2);
m_cloth->Translate(p2, dx);
b3Particle* p3 = m_cloth->GetParticle(t->v3);
m_cloth->Translate(p3, dx);
}
void StopDragging()
{
B3_ASSERT(m_isSelected);
m_isSelected = false;
b3ClothMesh* m = m_cloth->GetMesh();
b3ClothMeshTriangle* t = m->triangles + m_selection;
b3Particle* p1 = m_cloth->GetParticle(t->v1);
m_cloth->SetType(p1, m_t1);
b3Particle* p2 = m_cloth->GetParticle(t->v2);
m_cloth->SetType(p2, m_t2);
b3Particle* p3 = m_cloth->GetParticle(t->v3);
m_cloth->SetType(p3, m_t3);
}
private:
bool RayCast(b3RayCastOutput* output, u32 triangleIndex) const
{
b3ClothMesh* mesh = m_cloth->GetMesh();
B3_ASSERT(triangleIndex < mesh->triangleCount);
b3ClothMeshTriangle* triangle = mesh->triangles + triangleIndex;
b3Vec3 v1 = mesh->vertices[triangle->v1];
b3Vec3 v2 = mesh->vertices[triangle->v2];
b3Vec3 v3 = mesh->vertices[triangle->v3];
b3Vec3 p1 = m_ray->A();
b3Vec3 p2 = m_ray->B();
b3Vec3 d = p2 - p1;
float32 maxFraction = b3Length(d);
b3Vec3 n = b3Cross(v2 - v1, v3 - v1);
n.Normalize();
float32 numerator = b3Dot(n, v1 - p1);
float32 denominator = b3Dot(n, d);
if (denominator == 0.0f)
{
return false;
}
float32 t = numerator / denominator;
// Is the intersection not on the segment?
if (t < 0.0f || maxFraction < t)
{
return false;
}
b3Vec3 q = p1 + t * d;
// Barycentric coordinates for q
b3Vec3 Q = q;
b3Vec3 A = v1;
b3Vec3 B = v2;
b3Vec3 C = v3;
b3Vec3 AB = B - A;
b3Vec3 AC = C - A;
b3Vec3 QA = A - Q;
b3Vec3 QB = B - Q;
b3Vec3 QC = C - Q;
b3Vec3 QB_x_QC = b3Cross(QB, QC);
b3Vec3 QC_x_QA = b3Cross(QC, QA);
b3Vec3 QA_x_QB = b3Cross(QA, QB);
b3Vec3 AB_x_AC = b3Cross(AB, AC);
float32 u = b3Dot(QB_x_QC, AB_x_AC);
float32 v = b3Dot(QC_x_QA, AB_x_AC);
float32 w = b3Dot(QA_x_QB, AB_x_AC);
// This tolerance helps intersections lying on
// shared edges to not be missed.
const float32 kTol = -0.005f;
// Is the intersection on the triangle?
if (u > kTol && v > kTol && w > kTol)
{
output->fraction = t;
// Does the ray start from below or above the triangle?
if (numerator > 0.0f)
{
vs[i].im = 0.0f;
output->normal = -n;
}
else
{
output->normal = n;
}
return true;
}
return false;
}
bool Select(u32& selection, float32& fraction) const
{
b3ClothMesh* m = m_cloth->GetMesh();
b3RayCastInput input;
input.p1 = m_ray->A();
input.p2 = m_ray->B();
input.maxFraction = m_ray->fraction;
float32 minFraction = B3_MAX_FLOAT;
b3Vec3 minNormal(0.0f, 0.0f, 0.0f);
u32 minIndex = ~0;
for (u32 i = 0; i < m->triangleCount; ++i)
{
b3RayCastOutput subOutput;
if (RayCast(&subOutput, i) == true)
{
if (subOutput.fraction < minFraction)
{
minFraction = subOutput.fraction;
minNormal = subOutput.normal;
minIndex = i;
}
}
}
if (minIndex != ~0)
{
selection = minIndex;
fraction = minFraction;
return true;
}
return false;
}
bool m_isSelected;
Ray3* m_ray;
float32 m_x;
b3Cloth * m_cloth;
u32 m_selection;
float32 m_u, m_v;
b3ParticleType m_t1, m_t2, m_t3;
};
class ClothTest : public Test
{
public:
ClothTest() : m_clothDragger(&m_clothRay, &m_cloth)
{
m_cloth.SetGravity(b3Vec3(0.0f, -10.0f, 0.0f));
m_clothRay.origin.SetZero();
m_clothRay.direction.Set(0.0f, 0.0f, -1.0f);
m_clothRay.fraction = g_camera->m_zFar;
}
void Step()
{
m_cloth.Step(g_testSettings->inv_hertz, g_testSettings->positionIterations);
float32 dt = g_testSettings->inv_hertz;
m_cloth.Step(dt);
m_cloth.Apply();
b3Shape** shapes = m_cloth.GetShapeList();
for (u32 i = 0; i < m_cloth.GetShapeCount(); ++i)
{
b3Shape* s = shapes[i];
b3Transform xf;
xf.SetIdentity();
g_draw->DrawSolidShape(s, b3Color_white, xf);
}
m_cloth.Draw();
extern u32 b3_clothSolverIterations;
g_draw->DrawString(b3Color_white, "Iterations = %u", b3_clothSolverIterations);
float32 E = m_cloth.GetEnergy();
g_draw->DrawString(b3Color_white, "E = %f", E);
if (m_clothDragger.IsSelected() == true)
{
g_draw->DrawSegment(m_clothDragger.GetPointA(), m_clothDragger.GetPointB(), b3Color_white);
}
}
static Test* Create()
void MouseMove(const Ray3& pw)
{
return new Cloth();
m_clothRay = pw;
if (m_clothDragger.IsSelected() == true)
{
m_clothDragger.Drag();
}
}
b3GridMesh<10, 10> m_clothMesh;
void MouseLeftDown(const Ray3& pw)
{
if (m_clothDragger.IsSelected() == false)
{
m_clothDragger.StartDragging();
}
}
void MouseLeftUp(const Ray3& pw)
{
if (m_clothDragger.IsSelected() == true)
{
m_clothDragger.StopDragging();
}
}
Ray3 m_clothRay;
b3Cloth m_cloth;
ClothDragger m_clothDragger;
};
#endif

View File

@ -1,175 +0,0 @@
/*
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef MASS_TYPES_H
#define MASS_TYPES_H
class MassTypes : public PinnedCloth
{
public:
MassTypes()
{
}
void Step()
{
PinnedCloth::Step();
g_draw->DrawString(b3Color_white, "S - Static");
g_draw->DrawString(b3Color_white, "D - Dynamic");
g_draw->DrawString(b3Color_white, "K - Kinematic");
g_draw->DrawString(b3Color_white, "Arrows - Apply Force/Velocity/Position");
}
void SetClothType(b3MassType type)
{
for (u32 i = 0; i < m_cloth.GetMassCount(); ++i)
{
m_cloth.SetType(i, type);
}
}
void KeyDown(int button)
{
if (button == GLFW_KEY_S)
{
SetClothType(b3MassType::e_staticMass);
}
if (button == GLFW_KEY_K)
{
SetClothType(b3MassType::e_kinematicMass);
}
if (button == GLFW_KEY_D)
{
SetClothType(b3MassType::e_dynamicMass);
}
for (u32 i = 0; i < m_cloth.GetMassCount(); ++i)
{
if (m_cloth.GetType(i) == b3MassType::e_staticMass)
{
if (button == GLFW_KEY_LEFT)
{
b3Vec3 p = m_cloth.GetPosition(i);
p.x -= 1.0f;
m_cloth.SetPosition(i, p);
}
if (button == GLFW_KEY_RIGHT)
{
b3Vec3 p = m_cloth.GetPosition(i);
p.x += 1.0f;
m_cloth.SetPosition(i, p);
}
if (button == GLFW_KEY_UP)
{
b3Vec3 p = m_cloth.GetPosition(i);
p.z += 1.0f;
m_cloth.SetPosition(i, p);
}
if (button == GLFW_KEY_DOWN)
{
b3Vec3 p = m_cloth.GetPosition(i);
p.z -= 1.0f;
m_cloth.SetPosition(i, p);
}
}
if (m_cloth.GetType(i) == b3MassType::e_kinematicMass)
{
if (button == GLFW_KEY_LEFT)
{
b3Vec3 v = m_cloth.GetVelocity(i);
v.x -= 5.0f;
m_cloth.SetVelocity(i, v);
}
if (button == GLFW_KEY_RIGHT)
{
b3Vec3 v = m_cloth.GetVelocity(i);
v.x += 5.0f;
m_cloth.SetVelocity(i, v);
}
if (button == GLFW_KEY_UP)
{
b3Vec3 v = m_cloth.GetVelocity(i);
v.z -= 5.0f;
m_cloth.SetVelocity(i, v);
}
if (button == GLFW_KEY_DOWN)
{
b3Vec3 v = m_cloth.GetVelocity(i);
v.z += 5.0f;
m_cloth.SetVelocity(i, v);
}
}
if (m_cloth.GetType(i) == b3MassType::e_dynamicMass)
{
if (button == GLFW_KEY_LEFT)
{
m_cloth.ApplyForce(i, b3Vec3(-100.0f, 0.0f, 0.0f));
}
if (button == GLFW_KEY_RIGHT)
{
m_cloth.ApplyForce(i, b3Vec3(100.0f, 0.0f, 0.0f));
}
if (button == GLFW_KEY_UP)
{
m_cloth.ApplyForce(i, b3Vec3(0.0f, 0.0f, -100.0f));
}
if (button == GLFW_KEY_DOWN)
{
m_cloth.ApplyForce(i, b3Vec3(0.0f, 0.0f, 100.0f));
}
}
}
}
static Test* Create()
{
return new MassTypes();
}
};
#endif

View File

@ -0,0 +1,127 @@
/*
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef PARTICLE_TYPES_H
#define PARTICLE_TYPES_H
class ParticleTypes : public PinnedCloth
{
public:
ParticleTypes()
{
}
void Step()
{
PinnedCloth::Step();
g_draw->DrawString(b3Color_white, "S - Static");
g_draw->DrawString(b3Color_white, "D - Dynamic");
g_draw->DrawString(b3Color_white, "K - Kinematic");
g_draw->DrawString(b3Color_white, "Arrows - Apply Force/Velocity/Position");
}
void SetClothType(b3ParticleType type)
{
for (u32 i = 0; i < m_cloth.GetParticleCount(); ++i)
{
b3Particle* p = m_cloth.GetParticle(i);
m_cloth.SetType(p, type);
}
}
void KeyDown(int button)
{
if (button == GLFW_KEY_S)
{
SetClothType(e_staticParticle);
}
if (button == GLFW_KEY_K)
{
SetClothType(e_kinematicParticle);
}
if (button == GLFW_KEY_D)
{
SetClothType(e_dynamicParticle);
}
for (u32 i = 0; i < m_cloth.GetParticleCount(); ++i)
{
b3Particle* p = m_cloth.GetParticle(i);
b3Vec3 d;
d.SetZero();
if (button == GLFW_KEY_LEFT)
{
d.x = -1.0f;
}
if (button == GLFW_KEY_RIGHT)
{
d.x = 1.0f;
}
if (button == GLFW_KEY_UP)
{
d.y = 1.0f;
}
if (button == GLFW_KEY_DOWN)
{
d.y = -1.0f;
}
if (button == GLFW_KEY_LEFT ||
button == GLFW_KEY_RIGHT ||
button == GLFW_KEY_UP ||
button == GLFW_KEY_DOWN)
{
if (p->type == e_staticParticle)
{
m_cloth.Translate(p, d);
}
if (p->type == e_kinematicParticle)
{
b3Vec3 v = p->velocity;
v += 5.0f * d;
m_cloth.SetVelocity(p, d);
}
if (p->type == e_dynamicParticle)
{
b3Vec3 f = 100.0f * d;
m_cloth.ApplyForce(p, f);
}
}
}
}
static Test* Create()
{
return new ParticleTypes();
}
};
#endif

View File

@ -19,7 +19,7 @@
#ifndef PINNED_CLOTH_H
#define PINNED_CLOTH_H
class PinnedCloth : public SpringClothTest
class PinnedCloth : public ClothTest
{
public:
PinnedCloth()
@ -42,14 +42,12 @@ public:
m_gridClothMesh.sewingLineCount = 0;
m_gridClothMesh.sewingLines = nullptr;
b3SpringClothDef def;
def.allocator = &m_clothAllocator;
b3ClothDef def;
def.mesh = &m_gridClothMesh;
def.density = 0.2f;
def.ks = 10000.0f;
def.kd = 0.0f;
def.r = 0.05f;
def.gravity.Set(0.0f, -10.0f, 0.0f);
m_cloth.Initialize(def);
@ -57,11 +55,12 @@ public:
aabb.m_lower.Set(-5.0f, -1.0f, -6.0f);
aabb.m_upper.Set(5.0f, 1.0f, -4.0f);
for (u32 i = 0; i < m_cloth.GetMassCount(); ++i)
for (u32 i = 0; i < m_cloth.GetParticleCount(); ++i)
{
if (aabb.Contains(m_cloth.GetPosition(i)))
b3Particle* p = m_cloth.GetParticle(i);
if (aabb.Contains(p->position))
{
m_cloth.SetType(i, b3MassType::e_staticMass);
m_cloth.SetType(p, e_staticParticle);
}
}
}

View File

@ -23,7 +23,7 @@
#include <bounce/garment/sewing_pattern.h>
#include <bounce/garment/garment_mesh.h>
class Shirt : public SpringClothTest
class Shirt : public ClothTest
{
public:
Shirt()
@ -56,13 +56,11 @@ public:
}
// Create cloth
b3SpringClothDef def;
def.allocator = &m_clothAllocator;
b3ClothDef def;
def.mesh = &m_shirtClothMesh;
def.density = 0.2f;
def.ks = 10000.0f;
def.r = 0.2f;
def.gravity.Set(0.0f, -10.0f, 0.0f);
def.ks = 10000.0f;
m_cloth.Initialize(def);
}

View File

@ -1,356 +0,0 @@
/*
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SPRING_CLOTH_TESH_H
#define SPRING_CLOTH_TESH_H
class ClothDragger
{
public:
ClothDragger(Ray3* ray, b3SpringCloth* cloth)
{
m_ray = ray;
m_cloth = cloth;
m_isSelected = false;
}
~ClothDragger()
{
}
bool IsSelected() const
{
return m_isSelected;
}
b3Vec3 GetPointA() const
{
B3_ASSERT(m_isSelected);
b3ClothMesh* m = m_cloth->GetMesh();
b3ClothMeshTriangle* t = m->triangles + m_selection;
b3Vec3 A = m->vertices[t->v1];
b3Vec3 B = m->vertices[t->v2];
b3Vec3 C = m->vertices[t->v3];
return m_u * A + m_v * B + (1.0f - m_u - m_v) * C;
}
b3Vec3 GetPointB() const
{
B3_ASSERT(m_isSelected);
return (1.0f - m_x) * m_ray->A() + m_x * m_ray->B();
}
bool StartDragging()
{
B3_ASSERT(m_isSelected == false);
if (Select(m_selection, m_x) == false)
{
return false;
}
m_isSelected = true;
b3ClothMesh* m = m_cloth->GetMesh();
b3ClothMeshTriangle* t = m->triangles + m_selection;
m_t1 = m_cloth->GetType(t->v1);
m_cloth->SetType(t->v1, b3MassType::e_staticMass);
m_t2 = m_cloth->GetType(t->v2);
m_cloth->SetType(t->v2, b3MassType::e_staticMass);
m_t3 = m_cloth->GetType(t->v3);
m_cloth->SetType(t->v3, b3MassType::e_staticMass);
b3Vec3 v1 = m_cloth->GetPosition(t->v1);
b3Vec3 v2 = m_cloth->GetPosition(t->v2);
b3Vec3 v3 = m_cloth->GetPosition(t->v3);
b3Vec3 B = GetPointB();
float32 wABC[4];
b3BarycentricCoordinates(wABC, v1, v2, v3, B);
if (wABC[3] > B3_EPSILON)
{
m_u = wABC[0] / wABC[3];
m_v = wABC[1] / wABC[3];
}
else
{
m_u = m_v = 0.0f;
}
return true;
}
void Drag()
{
B3_ASSERT(m_isSelected);
b3ClothMesh* m = m_cloth->GetMesh();
b3ClothMeshTriangle* t = m->triangles + m_selection;
b3Vec3 A = GetPointA();
b3Vec3 B = GetPointB();
b3Vec3 dx = B - A;
b3Vec3 v1 = m_cloth->GetPosition(t->v1);
v1 += dx;
m_cloth->SetPosition(t->v1, v1);
b3Vec3 v2 = m_cloth->GetPosition(t->v2);
v2 += dx;
m_cloth->SetPosition(t->v2, v2);
b3Vec3 v3 = m_cloth->GetPosition(t->v3);
v3 += dx;
m_cloth->SetPosition(t->v3, v3);
}
void StopDragging()
{
B3_ASSERT(m_isSelected);
m_isSelected = false;
b3ClothMesh* m = m_cloth->GetMesh();
b3ClothMeshTriangle* t = m->triangles + m_selection;
m_cloth->SetType(t->v1, m_t1);
m_cloth->SetType(t->v2, m_t2);
m_cloth->SetType(t->v3, m_t3);
}
private:
bool RayCast(b3RayCastOutput* output, u32 triangleIndex) const
{
b3ClothMesh* mesh = m_cloth->GetMesh();
B3_ASSERT(triangleIndex < mesh->triangleCount);
b3ClothMeshTriangle* triangle = mesh->triangles + triangleIndex;
b3Vec3 v1 = mesh->vertices[triangle->v1];
b3Vec3 v2 = mesh->vertices[triangle->v2];
b3Vec3 v3 = mesh->vertices[triangle->v3];
b3Vec3 p1 = m_ray->A();
b3Vec3 p2 = m_ray->B();
b3Vec3 d = p2 - p1;
float32 maxFraction = b3Length(d);
b3Vec3 n = b3Cross(v2 - v1, v3 - v1);
n.Normalize();
float32 numerator = b3Dot(n, v1 - p1);
float32 denominator = b3Dot(n, d);
if (denominator == 0.0f)
{
return false;
}
float32 t = numerator / denominator;
// Is the intersection not on the segment?
if (t < 0.0f || maxFraction < t)
{
return false;
}
b3Vec3 q = p1 + t * d;
// Barycentric coordinates for q
b3Vec3 Q = q;
b3Vec3 A = v1;
b3Vec3 B = v2;
b3Vec3 C = v3;
b3Vec3 AB = B - A;
b3Vec3 AC = C - A;
b3Vec3 QA = A - Q;
b3Vec3 QB = B - Q;
b3Vec3 QC = C - Q;
b3Vec3 QB_x_QC = b3Cross(QB, QC);
b3Vec3 QC_x_QA = b3Cross(QC, QA);
b3Vec3 QA_x_QB = b3Cross(QA, QB);
b3Vec3 AB_x_AC = b3Cross(AB, AC);
float32 u = b3Dot(QB_x_QC, AB_x_AC);
float32 v = b3Dot(QC_x_QA, AB_x_AC);
float32 w = b3Dot(QA_x_QB, AB_x_AC);
// This tolerance helps intersections lying on
// shared edges to not be missed.
const float32 kTol = -0.005f;
// Is the intersection on the triangle?
if (u > kTol && v > kTol && w > kTol)
{
output->fraction = t;
// Does the ray start from below or above the triangle?
if (numerator > 0.0f)
{
output->normal = -n;
}
else
{
output->normal = n;
}
return true;
}
return false;
}
bool Select(u32& selection, float32& fraction) const
{
b3ClothMesh* m = m_cloth->GetMesh();
b3RayCastInput input;
input.p1 = m_ray->A();
input.p2 = m_ray->B();
input.maxFraction = m_ray->fraction;
float32 minFraction = B3_MAX_FLOAT;
b3Vec3 minNormal(0.0f, 0.0f, 0.0f);
u32 minIndex = ~0;
for (u32 i = 0; i < m->triangleCount; ++i)
{
b3RayCastOutput subOutput;
if (RayCast(&subOutput, i) == true)
{
if (subOutput.fraction < minFraction)
{
minFraction = subOutput.fraction;
minNormal = subOutput.normal;
minIndex = i;
}
}
}
if (minIndex != ~0)
{
selection = minIndex;
fraction = minFraction;
return true;
}
return false;
}
bool m_isSelected;
Ray3* m_ray;
float32 m_x;
b3SpringCloth * m_cloth;
u32 m_selection;
float32 m_u, m_v;
b3MassType m_t1, m_t2, m_t3;
};
class SpringClothTest : public Test
{
public:
SpringClothTest() : m_clothDragger(&m_clothRay, &m_cloth)
{
m_clothRay.origin.SetZero();
m_clothRay.direction.Set(0.0f, 0.0f, -1.0f);
m_clothRay.fraction = g_camera->m_zFar;
}
void Step()
{
float32 dt = g_testSettings->inv_hertz;
m_cloth.Step(dt);
m_cloth.Apply();
b3Shape** shapes = m_cloth.GetShapes();
for (u32 i = 0; i < m_cloth.GetShapeCount(); ++i)
{
b3Shape* s = shapes[i];
b3Transform xf;
xf.SetIdentity();
g_draw->DrawSolidShape(s, b3Color_white, xf);
}
m_cloth.Draw();
b3SpringClothStep step = m_cloth.GetStep();
g_draw->DrawString(b3Color_white, "Iterations = %u", step.iterations);
float32 E = m_cloth.GetEnergy();
g_draw->DrawString(b3Color_white, "E = %f", E);
if (m_clothDragger.IsSelected() == true)
{
g_draw->DrawSegment(m_clothDragger.GetPointA(), m_clothDragger.GetPointB(), b3Color_white);
}
}
void MouseMove(const Ray3& pw)
{
m_clothRay = pw;
if (m_clothDragger.IsSelected() == true)
{
m_clothDragger.Drag();
}
}
void MouseLeftDown(const Ray3& pw)
{
if (m_clothDragger.IsSelected() == false)
{
m_clothDragger.StartDragging();
}
}
void MouseLeftUp(const Ray3& pw)
{
if (m_clothDragger.IsSelected() == true)
{
m_clothDragger.StopDragging();
}
}
Ray3 m_clothRay;
b3StackAllocator m_clothAllocator;
b3SpringCloth m_cloth;
ClothDragger m_clothDragger;
};
#endif

View File

@ -19,7 +19,7 @@
#ifndef TABLE_CLOTH_H
#define TABLE_CLOTH_H
class TableCloth : public SpringClothTest
class TableCloth : public ClothTest
{
public:
TableCloth()
@ -48,14 +48,12 @@ public:
m_gridClothMesh.sewingLineCount = 0;
m_gridClothMesh.sewingLines = nullptr;
b3SpringClothDef def;
def.allocator = &m_clothAllocator;
b3ClothDef def;
def.mesh = &m_gridClothMesh;
def.density = 0.2f;
def.ks = 10000.0f;
def.kd = 0.0f;
def.r = 0.05f;
def.gravity.Set(0.0f, -10.0f, 0.0f);
m_cloth.Initialize(def);

View File

@ -55,7 +55,7 @@ static inline b3Color Color(float32 x, float32 a, float32 b)
return c;
}
class TensionMapping : public SpringClothTest
class TensionMapping : public ClothTest
{
public:
TensionMapping()
@ -78,14 +78,12 @@ public:
m_gridClothMesh.sewingLineCount = 0;
m_gridClothMesh.sewingLines = nullptr;
b3SpringClothDef def;
def.allocator = &m_clothAllocator;
b3ClothDef def;
def.mesh = &m_gridClothMesh;
def.density = 0.2f;
def.ks = 10000.0f;
def.kd = 0.0f;
def.r = 0.2f;
def.gravity.Set(0.0f, -10.0f, 0.0f);
m_cloth.Initialize(def);
@ -93,11 +91,12 @@ public:
aabb.m_lower.Set(-5.0f, -1.0f, -6.0f);
aabb.m_upper.Set(5.0f, 1.0f, -4.0f);
for (u32 i = 0; i < m_cloth.GetMassCount(); ++i)
for (u32 i = 0; i < m_cloth.GetParticleCount(); ++i)
{
if (aabb.Contains(m_cloth.GetPosition(i)))
b3Particle* p = m_cloth.GetParticle(i);
if (aabb.Contains(p->position))
{
m_cloth.SetType(i, b3MassType::e_staticMass);
m_cloth.SetType(p, e_staticParticle);
}
}
}
@ -108,29 +107,30 @@ public:
m_cloth.Step(dt);
m_cloth.Apply();
b3StackArray<b3Vec3, 100> T;
m_cloth.GetTension(T);
for (u32 i = 0; i < m_gridClothMesh.triangleCount; ++i)
{
b3ClothMeshTriangle* t = m_gridClothMesh.triangles + i;
b3Vec3 v1 = m_gridClothMesh.vertices[t->v1];
b3Vec3 v2 = m_gridClothMesh.vertices[t->v2];
b3Vec3 v3 = m_gridClothMesh.vertices[t->v3];
b3Particle* p1 = m_cloth.GetParticle(t->v1);
b3Particle* p2 = m_cloth.GetParticle(t->v2);
b3Particle* p3 = m_cloth.GetParticle(t->v3);
b3Vec3 v1 = p1->position;
b3Vec3 v2 = p2->position;
b3Vec3 v3 = p3->position;
b3Draw_draw->DrawSegment(v1, v2, b3Color_black);
b3Draw_draw->DrawSegment(v2, v3, b3Color_black);
b3Draw_draw->DrawSegment(v3, v1, b3Color_black);
b3Vec3 f1 = T[t->v1];
b3Vec3 f1 = p1->tension;
float32 L1 = b3Length(f1);
b3Vec3 f2 = T[t->v2];
b3Vec3 f2 = p2->tension;
float32 L2 = b3Length(f2);
b3Vec3 f3 = T[t->v3];
b3Vec3 f3 = p3->tension;
float32 L3 = b3Length(f3);
float32 L = (L1 + L2 + L3) / 3.0f;
@ -140,16 +140,14 @@ public:
b3Vec3 n1 = b3Cross(v2 - v1, v3 - v1);
n1.Normalize();
g_draw->DrawSolidTriangle(n1, v1, v2, v3, color);
b3Vec3 n2 = -n1;
g_draw->DrawSolidTriangle(n1, v1, v2, v3, color);
g_draw->DrawSolidTriangle(n2, v1, v3, v2, color);
}
b3SpringClothStep step = m_cloth.GetStep();
g_draw->DrawString(b3Color_white, "Iterations = %u", step.iterations);
extern u32 b3_clothSolverIterations;
g_draw->DrawString(b3Color_white, "Iterations = %u", b3_clothSolverIterations);
if (m_clothDragger.IsSelected() == true)
{