第九步:法线贴图
为了使海面更加有真实感,我们还要为其添加法线贴图,使其更具质感。为了保证法线方向的正确性,我们需要引入切线空间,并对于每一个三角面片计算其切线空间中的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代码,还需要继续努力啊。。。。。
PS:http://download.csdn.net/detail/xiewenzhao123/9770840 整个工程文件