1. 程式人生 > >一步步寫水面渲染(三)

一步步寫水面渲染(三)

第九步:法線貼圖

為了使海面更加有真實感,我們還要為其新增法線貼圖,使其更具質感。為了保證法線方向的正確性,我們需要引入切線空間,並對於每一個三角面片計算其切線空間中的tangent和bitangent
程式碼如下:

void tangentandbitangent(GLint x)
{
    int x1, x2, x3;
    if (x % 2 == 0)//我繪製圖像的時候使用的是GL_TRIANGLE_STRIP
    {
        x1 = x - 2;
        x2 = x - 1;
        x3 = x;
    }
    else
    {
        x1 = x
- 1; x2 = x - 2; x3 = x; } vec3 pos1 = vec3(VBOdata[x1].vertex_data[0], VBOdata[x1].vertex_data[1], VBOdata[x1].vertex_data[2]); vec3 pos2 = vec3(VBOdata[x2].vertex_data[0], VBOdata[x2].vertex_data[1], VBOdata[x2].vertex_data[2]); vec3 pos3 = vec3(VBOdata[x3].vertex_data[0
], VBOdata[x3].vertex_data[1], VBOdata[x3].vertex_data[2]); vec2 uv1 = vec2(VBOdata[x1].texcoord_data[0], VBOdata[x1].texcoord_data[1]); vec2 uv2 = vec2(VBOdata[x2].texcoord_data[0], VBOdata[x2].texcoord_data[1]); vec2 uv3 = vec2(VBOdata[x3].texcoord_data[0], VBOdata[x3].texcoord_data[1]);
vec3 edge1 = pos2 - pos1; vec3 edge2 = pos3 - pos1; vec2 deltaUV1 = uv2 - uv1; vec2 deltaUV2 = uv3 - uv1; GLfloat f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y); vec3 tangent, bitangent; tangent.x = f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x); tangent.y = f * (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y); tangent.z = f * (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z); tangent = normalize(tangent); bitangent.x = f * (-deltaUV2.x * edge1.x + deltaUV1.x * edge2.x); bitangent.y = f * (-deltaUV2.x * edge1.y + deltaUV1.x * edge2.y); bitangent.z = f * (-deltaUV2.x * edge1.z + deltaUV1.x * edge2.z); bitangent = normalize(bitangent); VBOdata[x1].tangents[0] = VBOdata[x2].tangents[0] = VBOdata[x3].tangents[0] = tangent.x; VBOdata[x1].tangents[1] = VBOdata[x2].tangents[1] = VBOdata[x3].tangents[1] = tangent.y; VBOdata[x1].tangents[2] = VBOdata[x2].tangents[2] = VBOdata[x3].tangents[2] = tangent.z; VBOdata[x1].bitangents[0] = VBOdata[x2].bitangents[0] = VBOdata[x3].bitangents[0] = bitangent.x; VBOdata[x1].bitangents[1] = VBOdata[x2].bitangents[1] = VBOdata[x3].bitangents[1] = bitangent.y; VBOdata[x1].bitangents[2] = VBOdata[x2].bitangents[2] = VBOdata[x3].bitangents[2] = bitangent.z; }

我們需要稍微更新一下傳遞資料的程式碼:

void RenderWater()
{
    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(VBOdata), VBOdata, GL_STATIC_DRAW);

    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 14 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
    glEnableVertexAttribArray(3);
    glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(GLfloat), (GLvoid*)(8 * sizeof(GLfloat)));
    glEnableVertexAttribArray(4);
    glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(GLfloat), (GLvoid*)(11 * sizeof(GLfloat)));

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    glBindVertexArray(VAO);
    for (int c = 0; c<(STRIP_COUNT - 1); c++)
        glDrawArrays(GL_TRIANGLE_STRIP, STRIP_LENGTH * 2 * c, STRIP_LENGTH * 2);
    glBindVertexArray(0);
}

第十步:我們稍微更改一下紋理座標,使其具有流動的感覺

if (i == 0)
            VBOdata[index].texcoord_data[0] = (pt_strip[pt * 3 + i] + glfwGetTime() / 20.0) / 10.0;
else if(i == 2)
            VBOdata[index].texcoord_data[1] = (pt_strip[pt * 3 + i] + glfwGetTime() / 20.0) / 10.0;

第十一步:更改片斷著色器,使用ward各向異性光照模型(phong—blinn模型會有點屎)

#version 330 core

out vec4 FragColor;

in VS_OUT
{
    vec3 FragPos;
    vec2 TexCoords;
    vec3 TangentLightPos;
    vec3 TangentViewPos;
    vec3 TangentFragPos;
}fs_in;

uniform sampler2D diffuseMap;
uniform sampler2D normalMap;

uniform vec4 materAmbient, materSpecular;
uniform vec4 lightDiffuse, lightAmbient, lightSpecular;
uniform vec4 envirAmbient;

void main()
{
    vec3 normal = texture(normalMap, fs_in.TexCoords).rgb;
    normal = normalize(normal * 2.0 - 1.0);                                 

    vec3 color = texture(diffuseMap, fs_in.TexCoords).rgb;

    //vec3 ambient = 0.1 * color;

    vec3 lightDir = normalize(fs_in.TangentLightPos - fs_in.TangentFragPos); 
    //float diff = max(dot(lightDir, normal), 0.0);                            
    //vec3 diffuse = diff * color;

    vec3 viewDir = normalize(fs_in.TangentViewPos - fs_in.TangentFragPos);   
    vec3 reflectDir = normalize(reflect(-lightDir, normal));                 
    vec3 halfwayDir = normalize(lightDir + viewDir);                         
    //float spec = pow(max(dot(normal, halfwayDir), 0.0), 16.0);               
    //vec3 specular = vec3(0.2) * spec;


    //上面被註釋的程式碼是phong-blinn光照模型,效果非常屎,下面的則是ward各向異性光照模型
    vec4 diffuse, ambient, globalAmt;
    vec4 specular;
    float NdotL, NdotH, NdotR, S, temp, delta;
    float alpha = 0.4;

    NdotL = max(dot(normal, lightDir), 0.0);
    NdotH = max(dot(normal, halfwayDir), 0.0);
    NdotR = max(dot(normal, reflectDir), 0.0);

    delta = acos(NdotH);
    temp = -1.0 * tan(delta) * tan(delta) / alpha / alpha;
    S = pow(2.71828, temp) / 4.0 / 3.14159 / alpha / alpha / pow(NdotL * NdotR, 0.5);

    diffuse = texture2D(diffuseMap, fs_in.TexCoords) * lightDiffuse;
    globalAmt = envirAmbient * materAmbient;
    ambient = envirAmbient * lightAmbient;
    specular = materSpecular * lightSpecular;

    FragColor = NdotL * (diffuse + specular * S) + globalAmt;
}

最終結果

這裡寫圖片描述
這裡寫圖片描述

雖然效果還是有點屎,但是終於稍微有點海面的樣子了,然而這些還是遠遠不夠。。。。。比如水面倒影、水面折射、水面反射這些還沒有進行新增,所以這隻能算是我第一個半脫離教程的OpenGL程式碼,還需要繼續努力啊。。。。。