一步步写水面渲染(一)

第一步:了解Gerstner波

这里写图片描述
上述即为Gerstner波的方程,下面我们来说一下这个方程当中各个变量的含义:
1、x:水面静止时,某个顶点的x轴坐标。
2、y:水面静止时,某个顶点的y轴坐标。
3、Qi:用于控制波浪平滑度的变量,当Qi为0的时候,波浪就是一个正弦函数的波形。当Qi为1/(wi*Ai)时,波峰的形状最尖,波底较为平滑,若Qi继续增大则波峰会变成环状,另外要注意的是,因为最后我们要将各个波形叠加,有可能会导致其值变得太大,所以我们一般用Qi = Q/(wi Ai x numWaves)。
4、Ai:单个波的振幅
5、Di:波矢量,即波的传递方向,用一个二维向量表示
6、wi:单个波的角速度

第二步:初始化水面

void initWave()
{
    //1.用结构体存储每一个波纹的基本参数
    waves.time = 0.0;
    for (int i = 0; i<numberofwaves; i++)
    {
        waves[i].phi= 初相;
        waves[i].height = 振幅;
        waves[i].dirx = 传播方向x坐标;
        waves[i].diry = 传播方向y坐标;
        waves[i].w = 角速度;
    }
    //2.先将要构建的水面的顶点数据求出
    int index= 0;
    for (int i = 0; i<waterwide; i++)
    {
        for (int j = 0; j<waterlength; j++)
        {
            pt_strip[index] = -1.0f + i * 0.02f;
            pt_strip[index + 1] = -1.0f + j * 0.02f;
            pt_strip[index + 2] = 0.0f;
            //把数据再额外存储一份,用来备用
            pt_strip2[index] = -1.0f + i * 0.02f;
            pt_strip2[index + 1] = -1.0f + j * 0.02f;
            pt_strip2[index + 2] = 0.0f;
            index += 3;
        }
    }
}

第三步:将初始数据带入Gerstner方程计算

int index = 0;
for (int i = 0; i<waterwide; i++)
{
    for (int j = 0; j<waterlength; j++)//枚举各个顶点
    {
        vec2 offset = vec2(0.0f, 0.0f);
        GLfloat height = 0.0f;
        for (int k = 0; k < 3; k++)//枚举波形
        {
            vec2 K = vec2(waves[k].dirx, waves[k].diry);
            GLfloat Qi = 1 / (waves[k].height * waves[k].w) * 0.3;
            GLfloat p = waves[k].w * dot(K, vec2(pt_strip2[index], pt_strip2[index + 1])) + glfwGetTime() * waves[k].phi;

            offset.x += Qi * waves[k].height * K.x*cos(p);
            offset.y += Qi * waves[k].height * K.y*cos(p);
            height += wave_para2[k][1] * sin(p);
        }
        pt_strip[index] = pt_strip2[index] + offset.x;
        pt_strip[index + 1] = pt_strip2[index + 1] + offset.y;
        pt_strip[index + 2] = -height;
        index += 3;
    }
}

第四部:将计算好的数据进行排序,便于绘制网格

int pt;
for (int c = 0; c<(waterwide- 1); c++)
{
    for (int l = 0; l<2 * waterlength; l++)
    {
        if (l % 2 == 1)
        {
            pt = c*waterlength + l / 2;
        }
        else
        {
            pt = c*waterlength + l / 2 + waterlength;
        }
        index = waterlength * 2 * c + l;
        for (int i = 0; i<3; i++)
        {
            vertex_data[index * 3 + i] = pt_strip[pt * 3 + i];
            normal_data[index * 3 + i] = pt_normal[pt * 3 + i];
        }
    }
}

第五步:传递数据并进行绘制

while (!glfwWindowShouldClose(window))
{
    GLfloat currentFrame = glfwGetTime();
    deltaTime = currentFrame - lastFrame;
    lastFrame = currentFrame;

    glfwPollEvents();
    Do_Movement();

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    values.time = currentFrame;
    calcuWave2();

    mat4 projection = perspective(radians(camera.Zoom), (GLfloat)screenWidth / (GLfloat)screenHeight, 0.1f, 100.0f);
    mat4 view = camera.GetViewMatrix();
    mat4 model;
    model = rotate(model, radians(90.0f), vec3(1.0f, 0.0f, 0.0f));
    model = scale(model, vec3(10.0f, 10.0f, 10.0f));
    GLfloat time = glfwGetTime();
    shader.Use();
    glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, value_ptr(projection));
    glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, value_ptr(view));
    glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, value_ptr(model));
    RenderWater();

    glfwSwapBuffers(window);
}

以上仅仅是计算波形的顶点位置,如果没有问题的话,将会得到一下结果:
这里写图片描述
这里写图片描述

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值