OpenGL + Cloth模拟物理不起作用

时间:2016-02-13 20:50:02

标签: c++ opengl

我正在尝试使用弹簧粒子系统来实现布料模拟,但是我的物理学并不完全正确。当我进行模拟时,布料按预期绘制,但随着时间的推移,重力将布料无限地向下拉。换句话说,由弹簧引起的力不能正确累积以克服重力的向下拉力,我最终得到了......: enter image description here

它继续无限下降。从我所做的所有调试中我所看到的是,当重力引起拉伸增加时,由附着在其上的所有弹簧引起的粒子上的力的累积不能正确地求和。我无法弄清楚我在物理学中忽略了什么。

我的布料使用此功能每次更新

void Cloth::updateGeometry(atlas::utils::Time const& t) {
    for (int i = 0; i < mSprings.size(); ++i) {
        mSprings[i].calculateForces();
    }

    for (int i = 0; i < mParticles.size(); ++i) {
        mParticles[i].updateGeometry(t);
    }
}

我的弹簧使用以下函数更新,其中p1和p2是指向此弹簧所连接的每个粒子的指针。

void Spring::calculateForces() {
    glm::vec3 springVector = normalize((p2->getCurrentPosition() - p1->getCurrentPosition()));
    GLfloat stretchLength = length(p2->getCurrentPosition(),  p1->getCurrentPosition());
    GLfloat displacementFromRest = restLength - stretchLength;
    glm::vec3 springForce = -k * displacementFromRest * normalize(springVector);
    //Multiply the displacements by the spring constant to get 
    //A vector which represents the force on each spring
    p1->addToSumOfSpringForces(springForce);
    p2->addToSumOfSpringForces(-springForce);
}

最后我的粒子使用。更新。

void Particle::updateGeometry(atlas::utils::Time const& t) {
    if (!stationary) {
        previousPosition = currentPosition;
        glm::vec3 forceOfGravity = mass * gravity;
        glm::vec3 totalForce = forceOfGravity + (mass * totalSpringForces) - velocity*Damping;
        acceleration = totalForce / mass;

        //Perform Euler Integration
        currentPosition += t.deltaTime * velocity;
        velocity += t.deltaTime * acceleration;

        //============== End Euler==============//

        //Reset the forces acting on the particle from all of the springs
        //So that a new accumulated total can be calculated.
        totalSpringForces = glm::vec3{ 0.0f, 0.0f, 0.0f };    
    }
}

totalSpringForces变量由弹簧更新功能中的addToSumOfSpringForces(springForce);调用更新。我们的想法是,每个弹簧首先根据每个粒子的当前位置进行评估,然后使用

每次迭代累积每个粒子的totalSpringForce变量。
void Particle::addToSumOfSpringForces(glm::vec3 force) {
    totalSpringForces += force;
}

只是为了补充说明,布料是根据this描述使用结构,弯曲和剪切弹簧构造的。这可能是不必要的,但我在下面包含了我的布料构造函数。

Cloth::Cloth(GLfloat width_, GLfloat height_, GLuint numParticlesWide_, GLuint numParticlesHigh_) :
    width(width_),
    height(height_),
    numParticlesHigh(numParticlesHigh_),
    numParticlesWide(numParticlesWide_),
    clothRotationVector{0.0f, 0.0f, 0.0f},
    clothPosition{ 0.0f, 5.0f, 0.0f },
    clothRotationAngle(0.0f)
{
    USING_ATLAS_MATH_NS;
    USING_ATLAS_GL_NS;
    glm::vec3 clothColour{1.0f, 0.5f, 0.2f};
    //Create Particles
    GLuint count = 0;
    restLength = (width * (1 / (float)numParticlesWide));
    for (GLuint y = 0; y < numParticlesHigh; ++y) {
        for (GLuint x = 0; x < numParticlesWide; ++x) {
            glm::vec3 pos = {(width * (x / (float)numParticlesWide)), (-height * (y / (float)numParticlesHigh)), 0.0f};
            mParticles.push_back(Particle(pos, count, clothColour));
            ++count;
        }
    }
    //Create Springs
    for (GLuint x = 0; x < numParticlesWide; ++x) {
        for (GLuint y = 0; y < numParticlesHigh; ++y) {

            //============ Structural springs ==========//
            //Connect to the particle to the immediate right of the current particle
            if (x < numParticlesWide - 1) mSprings.push_back(Spring(getParticle(x,y), getParticle(x+1,y)));

            //Connect to the particle that is immediately below the current particle
            if (y < numParticlesHigh - 1) mSprings.push_back(Spring(getParticle(x,y), getParticle(x,y+1)));

            //============ Shear Springs ================//
            //Connect the shear springs to make the X pattern
            if (x < numParticlesWide - 1 && y < numParticlesHigh - 1) {
                mSprings.push_back(Spring(getParticle(x, y), getParticle(x + 1, y + 1)));
                mSprings.push_back(Spring(getParticle(x+1, y), getParticle(x, y+1)));
            }

            //============ Bend Springs ===============//
            //Connect the current particle to the second particle over to the right
            if (x < numParticlesWide - 2) mSprings.push_back(Spring(getParticle(x,y), getParticle(x+2,y)));

            //Connect the current particle to the particle two below
            if (y < numParticlesHigh - 2) mSprings.push_back(Spring(getParticle(x,y), getParticle(x, y+2)));

            ////Create the X pattern 
            //if (x < numParticlesWide - 2 && y < numParticlesHigh - 2) {
            //  mSprings.push_back(Spring(getParticle(x, y), getParticle(x+2,y+2)));
            //  mSprings.push_back(Spring(getParticle(x+2,y), getParticle(x,y+2)));
            //};
        }
    }

    //Set the top left and right as stationary
    getParticle(0, 0)->makeStationary();
    getParticle(numParticlesWide - 1, 0)->makeStationary();

    //Make Indices for Particles
    for (GLuint row = 0; row < numParticlesWide - 1; ++row) {
        for (GLuint col = 0; col < numParticlesHigh - 1; ++col) {
            //Triangle one
            mParticleIndices.push_back(getParticle(row,col)->getIndex());
            mParticleIndices.push_back(getParticle(row,col+1)->getIndex());
            mParticleIndices.push_back(getParticle(row+1, col)->getIndex());

            //Triangle two
            mParticleIndices.push_back(getParticle(row, col+1)->getIndex());
            mParticleIndices.push_back(getParticle(row+1, col+1)->getIndex());
            mParticleIndices.push_back(getParticle(row+1, col)->getIndex());
        }
    }
    glGenBuffers(1, &clothVertexBufferID);
    glGenBuffers(1, &clothIndexBufferID);
    sendDataToGPU();
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, clothIndexBufferID);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, mParticleIndices.size() * sizeof(GLushort), &mParticleIndices[0], GL_STATIC_DRAW);
    defineVAO();

    std::string shaderDir = generated::ShaderPaths::getShaderDirectory();
    std::vector<ShaderInfo> shaders
    {
        { GL_VERTEX_SHADER, shaderDir + "Cloth.vs.glsl" },
        { GL_FRAGMENT_SHADER, shaderDir + "Cloth.fs.glsl" }
    };
    mModel = glm::translate(Matrix4(1.0f), clothPosition);
    mShaders.push_back(ShaderPointer(new Shader));
    mShaders[0]->compileShaders(shaders);
    mShaders[0]->linkShaders();
    mUniforms.insert(UniformKey("mvpMat",mShaders[0]->getUniformVariable("mvpMat")));
    mShaders[0]->disableShaders();
}

修改

我已经确认totalSpringForces变量确实在变化。我在粒子更新功能中添加了一个打印语句,您可以在下图中看到。仅选择totalSpringForces仅用于粒子#55,在这种情况下是粒子0下面的粒子,它是静止的并且不允许移动。打印输出也是在大约20-25次迭代之后。如您所见,y方向上的totalSpringForces具有0.7037的正值(即抵消重力)。我让它跑了半个小时,它只到了5。

目前我的常量是

k = 2.0f
mass = 0.1f
damping = 0.55f
gravity{ 0.0f, -9.81f, 0.0f },

enter image description here

0 个答案:

没有答案