LeeMcQueen / GameDemo

Demo
0 stars 0 forks source link

布料碰撞 地面&球体 #45

Closed LeeMcQueen closed 2 years ago

LeeMcQueen commented 2 years ago

这些是球类的信息,我们可以直接把玩家的位置传输进ballpos 不需要渲染,只需要碰撞

■变数设定 vec3 ballpos(0, 3, -2); int ballRadius = 1; glm::vec4 ballColor(0.6f, 0.5f, 0.8f, 1.0f); 这个球的结构体是关键 Ball ball(ballPos, ballRadius, ballColor);

BallRender ballRender(&ball);

ballRender.flush()

■主循环 ball(player.position.x, player.position.y, player.position.z, ballRadius, ballColor);

pragma region 布料主循环

    for (int i = 0; i < cloth.iterationFreq; i++) {
        cloth.computeForce(TIME_STEP, gravity);
        cloth.integrate(AIR_FRICTION, TIME_STEP);

        cloth.collisionResponse(&ball);

        cloth.addForce(normalForce);
    }
    cloth.computeNormal();
    clothRender.flush(camera);

pragma endregion

■只球体碰撞 其实可以加上地面 这样会比较有效果 void onlyBallCollisionResPonse(Ball *ball){

for(int i = 0; i < nodes.size(); i++){

Vec3 distVec = getWorldPos(nodes[i]) - ball -> center;
double disLen = distVec.length();
double safeDist = ball -> radius * 1.05;

if(distLen < safeDist){

    distVec.normalize();
    setWorldPos(nodes[i], distVec * safeDist + ball -> center);
    nodes[i] -> velocity = node[i] -> velocity * ball -> friction;
}

} }

■地面碰撞&球体碰撞 可以给碰撞加上地面的效果,实现的方法十分的简单 在每个循环当中加上高度地形的读取 配合每个点的XZ得当当前坐标的最低Y值 然后判断每个点的Y是否小于当前坐标的最低Y值 如果小于就对于当前的点进行重新设定

const float MAX_HEIGHT = 40.0f; const float MIN_HEIGHT = -40.0f; const float MAX_PIXEL_COLOUR = 256 256 256;

unsigned char *_image = stbiload("res/heightmap4.png", &width, &height, &colorChannels, 0);

float getHeight(int x, int z, unsigned char *data){

if (x < 0 || x > height_ || z < 0 || z > height_) {
    return 0;
}

float height = getRGBSum(x, z);
height /= (MAX_PIXEL_COLOUR / 2);
height -= 1.0;
height *= MAX_HEIGHT;

return height;

}

std::int32_t getRGBSum(int x, int y){

int addr = (y * width_ + x) * colorChannels_;
std::int32_t r = _image[addr];
std::int32_t g = _image[addr + 1];
std::int32_t b = _image[addr + 2];
return (r << 16) + (g << 8) + b;

}

地面摩擦 const double friction = 0.9;

Vec3 getWorldPos(Node n) { return clothPos + n -> position; } void setWorldPos(Node n, Vec pos) { n -> position = pos - clothPos; }

void collisionResponse(Ball *ball){

for(int i = 0; i < nodes.size(); i++){

    float height = getHeight(nodes[i].x, nodes[i].z, _image);

    if(getWorldPos(nodes[i].y < height)){

        nodes[i]->position.y = height - clothPos.y + 0.01;
        nodes[i]->velocity = nodes[i]->velocity * friction;
    }

    Vec3 distVec = getWorldPos(nodes[i]) - ball->center;
    double distLen = distVec.length();
    double safeDist = ball->radius*1.05;
    if (distLen < safeDist) {
        distVec.normalize();
        setWorldPos(nodes[i], distVec*safeDist+ball->center);
        nodes[i]->velocity = nodes[i]->velocity*ball->friction;
    }
}

}

LeeMcQueen commented 2 years ago

碰撞判定没有成功

完全没有进入碰撞的逻辑里面 是符合画面的反应的

碰撞判定在逻辑上是没有问题的 问题出现在getWorldPos函数上面

Vec3 getWorldPos(Node *n) { return clothPos + n->position; } 布料的起始坐标 + 每个node点的位置 逻辑上完全没有问题

clothPos 就是起始点 clothPos(140.0f, 35.0f, 50.0f);

vec3 distVec = getWorldPos(nodes[i]) - ball->center

ball的center就是球的起始坐标

vec3 checkPosition = getWorldPos(nodes[i]) 得到当前点的坐标 直接把clothPos设定成一个固定值 (140.0f, 35.0f, 50.0f)

分析了逻辑之后 可能性近乎就是值没有传好,在传值当中出现了错误

node结构体 mass isFixed texCoords normal position velocity force acceleration

最后的根本原因是因为TransformationMatrix里面的rotation和scale的变换导致坐标变化所以导致碰撞判定的坐标不是画面上直观显示的