布料类

来源:互联网 发布:ps4pro优化游戏 编辑:程序博客网 时间:2024/03/28 16:25

#ifndef _CLOTH_H_
#define _CLOTH_H_

//#include "ClothNew.h"

class Cloth : public Ogre::SimpleRenderable
{
public:

    Cloth(int w = 20, int h = 20);
    ~Cloth();

    void update(float delta_time);

    virtual void getRenderOperation(Ogre::RenderOperation& rend);

    //重载renderable及Moveable方法
    Ogre::Real getBoundingRadius() const;

    Ogre::Real getSquaredViewDepth(const Ogre::Camera* cam) const;

protected:
   
    class Particle;

    class Spring
    {
    public:
        float RestLength;
        Particle *a, *b;

        void ApplyConstraints();
    };

    class Particle {
    public:
        Ogre::Vector3 OldPosition;
        Ogre::Vector3 Position;
        Ogre::Vector3 Force;
        bool          Fixed;
    };
   
    int mWidth;
    int mHeight;

    // 所有质点
    std::vector<std::vector<Particle> >mParticles;

    // 所有弹簧
    std::vector<Spring> mSprings;

    //ClothImpl mImpl;

    // 渲染相关
    Ogre::HardwareVertexBufferSharedPtr mPositionBuffer;
    Ogre::HardwareVertexBufferSharedPtr mUvBuffer;

    Ogre::HardwareIndexBufferSharedPtr mIndexBuffer;
};

#endif
#include "stdafx.h"
#include "Cloth.h"
using namespace Ogre;

Cloth::Cloth(int w, int h)
    :mWidth(w),
     mHeight(h)
{
    mParticles.resize(h);
    for (int i = 0; i < h; ++i)
        mParticles[i].resize(w);

    for (int i = 0; i < h; ++i)
    {
        for (int j = 0; j < w; ++ j)
        {
            mParticles[i][j].Position = mParticles[i][j].OldPosition = Vector3(j, -i, 0);
            if (i == 0)
                mParticles[i][j].Fixed = 1;
            else mParticles[i][j].Fixed = 0;
        }
    }
   
    mRenderOp.indexData = new Ogre::IndexData;
    mRenderOp.vertexData = new Ogre::VertexData;

    mRenderOp.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST;

    mRenderOp.useIndexes = true;

    mRenderOp.vertexData->vertexCount = w * h;
    mRenderOp.vertexData->vertexStart = 0;
    Ogre::VertexDeclaration* decl = mRenderOp.vertexData->vertexDeclaration;
    decl->addElement(0, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
    decl->addElement(1, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES);

    HardwareBufferManager& mgr = HardwareBufferManager::getSingleton();

    mIndexBuffer  = mgr.createIndexBuffer(HardwareIndexBuffer::IT_32BIT, 6 * (h - 1) * (w - 1), HardwareBuffer::HBU_STATIC_WRITE_ONLY);
    mPositionBuffer = mgr.createVertexBuffer( sizeof(Vector3), w * h,  HardwareBuffer::HBU_STATIC_WRITE_ONLY);
    mUvBuffer = mgr.createVertexBuffer( sizeof(Vector2), h * w, HardwareBuffer::HBU_STATIC_WRITE_ONLY);

    mRenderOp.indexData->indexCount = 6 * (h - 1) * (w - 1);
    mRenderOp.indexData->indexStart = 0;
    mRenderOp.indexData->indexBuffer = mIndexBuffer;

    mRenderOp.vertexData->vertexBufferBinding->setBinding(0, mPositionBuffer);
    mRenderOp.vertexData->vertexBufferBinding->setBinding(1, mUvBuffer);

    Vector2* pUv = (Vector2*)mUvBuffer->lock(HardwareBuffer::HBL_NORMAL);
    for (int i = 0; i < h; ++i)
    {
        for (int j = 0; j < w; ++ j)
        {
            *pUv++ = Vector2(j / (float)w, i / (float)h);
        }
    }
    mUvBuffer->unlock();

    mBox.setNull();
    mBox.merge(Vector3(0, 0, 0));
    mBox.merge(Vector3(w - 1, h - 1, 0));

    uint32 *pIndex = (uint32*) mIndexBuffer->lock(HardwareBuffer::HBL_NORMAL);
    for (int i = 0; i < h - 1; ++i)
    {
        for (int j = 0; j < w - 1; ++ j)
        {
            *pIndex++ = i * w + j;
            *pIndex++ = i * w + w + j;
            *pIndex++ = i * w + w + j + 1;

            *pIndex++ = i * w + j;
            *pIndex++ = i * w + w + j + 1;
            *pIndex++ = i * w + j + 1;
        }
    }
    mIndexBuffer->unlock();

    Vector3* pPos = (Vector3*)mPositionBuffer->lock(HardwareBuffer::HBL_NORMAL);
    for (int i = 0; i < h; ++i)
    {
        for (int j = 0; j < w; ++ j)
        {
            *pPos++ = mParticles[i][j].Position;
        }
    }
    mPositionBuffer->unlock();

    for (int i = 0; i < mHeight - 1; ++i)
    {
        for (int j = 0; j < mWidth - 1; ++ j)
        {
            Spring s;
            s.a = &mParticles[i][j];
            s.b = &mParticles[i][j+1];
            s.RestLength = 1;
            mSprings.push_back(s);

            s.b = &mParticles[i+1][j];
            mSprings.push_back(s);

            s.b = &mParticles[i+1][j+1];
            s.RestLength = sqrt(2.0f);
            mSprings.push_back(s);

            if (j > 0)
            {
                s.b = &mParticles[i+1][j-1];
                mSprings.push_back(s);
            }
        }
    }
}

Cloth::~Cloth()
{
    delete mRenderOp.indexData;
    delete mRenderOp.vertexData;
}

void Cloth::getRenderOperation(RenderOperation& rend)
{
    rend = mRenderOp;
}

Ogre::Real Cloth::getSquaredViewDepth(const Camera* cam) const
{
    return mParentNode->getSquaredViewDepth( cam );
}

Ogre::Real Cloth::getBoundingRadius() const
{
    return mBox.getHalfSize().length();
}

void Cloth::update(float delta_time)
{
    static float mass = 1.0f;

    // 应用重力
    for (int i = 0; i < mHeight; ++i)
    {
        for (int j = 0; j < mWidth; ++ j)
        {
            Particle &p = mParticles[i][j];
            if (!p.Fixed)
                p.Force = Vector3(0, -1.8, 0);
        }
    }

    // 应用弹簧
    std::vector<Spring>::iterator it, iend = mSprings.end();
    for (it = mSprings.begin(); it != iend; ++it)
    {
        it->ApplyConstraints();
    }

    // 计算新位置
    for (int i = 0; i < mHeight; ++i)
    {
        for (int j = 0; j < mWidth; ++ j)
        {
            Particle &p = mParticles[i][j];
            if (p.Fixed) continue;
            Vector3 tmp = p.Position;
            p.Position = p.Position + (p.Position - p.OldPosition) * 0.99 + p.Force / mass * delta_time;

            p.OldPosition = tmp;
        }
    }
    Vector3* pPos = (Vector3*)mPositionBuffer->lock(HardwareBuffer::HBL_NORMAL);
    for (int i = 0; i < mHeight; ++i)
    {
        for (int j = 0; j < mWidth; ++ j)
        {
            *pPos++ = mParticles[i][j].Position;
        }
    }
    mPositionBuffer->unlock();

    //static float timeStored = 0.0f;
    //if (timeStored > TIME_STEPSIZE2)
    //{
    //    timeStored -= TIME_STEPSIZE2;
    //    mImpl.addForce(Vector3(0, -2.8, 0));

    //    // 随机风向
    //    Vector3 wind(Math::UnitRandom(), Math::UnitRandom(), Math::UnitRandom());
    //    wind.normalise();
    //    wind *= Math::UnitRandom() * 0.3;
    //    mImpl.windForce(wind);

    //    mImpl.timeStep();

    //    Vector3* pPos = (Vector3*)mPositionBuffer->lock(HardwareBuffer::HBL_NORMAL);
    //    for (int i = 0; i < mHeight; ++i)
    //    {
    //        for (int j = 0; j < mWidth; ++ j)
    //        {
    //            *pPos++ = mImpl.getParticle(i,j)->getPos();
    //        }
    //    }
    //    mPositionBuffer->unlock();
    //}
    //timeStored += delta_time;
}




void Cloth::Spring::ApplyConstraints()
{
    assert(a && b);
    Vector3 vec = b->Position - a->Position;
    float len = vec.length();
   
    Vector3 correctionVec = vec * ( 1 - RestLength / len );
    if (! a->Fixed)
        a->Position += 0.5 * correctionVec;
    if (! b->Fixed)
        b->Position -= 0.5 * correctionVec;
}