该文档中的代码实现了立方体贴图(Cube Mapping)以实现反射和天空盒的功能。以下是相关的代码段:
### 1. 加载纹理和立方体贴图
在 `renderer.cpp` 文件中,加载了各种纹理和立方体贴图:
```cpp
#include "Renderer.h"
#include "../nclgl/Light.h"
#include "../nclgl/HeightMap.h"
#include "../nclgl/Shader.h"
#include "../nclgl/Camera.h"
Renderer::Renderer(Window& parent)
: OGLRenderer(parent) {
quad = Mesh::GenerateQuad();
heightMap = new HeightMap(TEXTURED_DIR "noise.png");
waterTex = SOIL_load_OGL_texture(
TEXTURED_DIR "water.TGA",
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID,
SOIL_FLAG_MIPMAPS
);
earthTex = SOIL_load_OGL_texture(
TEXTURED_DIR "Barren Reds.JPG",
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID,
SOIL_FLAG_MIPMAPS
);
earthBump = SOIL_load_OGL_texture(
TEXTURED_DIR "Barren RedsDOT3.JPG",
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID,
SOIL_FLAG_MIPMAPS
);
cubeMap = SOIL_load_OGL_cubemap(
TEXTURED_DIR "rusted_west.jpg",
TEXTURED_DIR "rusted_east.jpg",
TEXTURED_DIR "rusted_up.jpg",
TEXTURED_DIR "rusted_down.jpg",
TEXTURED_DIR "rusted_south.jpg",
TEXTURED_DIR "rusted_north.jpg",
SOIL_LOAD_RGB,
SOIL_CREATE_NEW_ID,
0
);
if (!earthTex || !earthBump || !cubeMap || !waterTex) {
return;
}
SetTextureRepeating(earthTex, true);
SetTextureRepeating(earthBump, true);
SetTextureRepeating(waterTex, true);
}
reflectShader = new Shader(
"reflectVertex.glsl",
"reflectFragment.glsl"
);
skyboxShader = new Shader(
"skyboxVertex.glsl",
"skyboxFragment.glsl"
);
lightShader = new Shader(
"PerPixelVertex.glsl",
"PerPixelFragment.glsl"
);
if (!reflectShader->LoadSuccess() ||
!skyboxShader->LoadSuccess() ||
!lightShader->LoadSuccess()) {
return;
}
Vector3 heightMapSize = heightMap->GetHeightmapSize();
camera = new Camera(-45.0f, 0.0f,
heightMapSize * Vector3(0.5f, 5.0f, 0.5f));
light = new Light(heightMapSize * Vector3(0.5f, 1.5f, 0.5f),
Vector4(1, 1, 1, 1), heightMapSize.x);
projMatrix = Matrix4::Perspective(1.0f, 15000.0f,
(float)width / (float)height, 45.0f);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
waterRotate = 0.0f;
waterCycle = 0.0f;
init = true;
```
### 2. 更新场景
在 `UpdateScene` 函数中,更新水纹动画参数:
```cpp
void Renderer::UpdateScene(float dt) {
camera->UpdateCamera(dt);
viewMatrix = camera->BuildViewMatrix();
waterRotate += dt * 2.0f; // 2 degrees per second
waterCycle += dt * 0.25f; // 10 units per second
}
```
### 3. 渲染场景
在 `RenderScene` 函数中,调用绘制天空盒、地形高度图和水面的函数:
```cpp
void Renderer::RenderScene() {
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
DrawSkybox();
DrawHeightmap();
DrawWater();
}
```
### 4. 绘制天空盒
在 `DrawSkybox` 函数中,使用全屏四边形投影立方体贴图作为背景天空盒:
```cpp
void Renderer::DrawSkybox() {
glDepthMask(GL_FALSE);
BindShader(skyboxShader);
UpdateShaderMatrices();
quad->Draw();
glDepthMask(GL_TRUE);
}
```
### 5. 绘制地形高度图
在 `DrawHeightmap` 函数中,启用光照着色器并绘制地形高度图:
```cpp
void Renderer::DrawHeightmap() {
BindShader(lightShader);
SetShaderLight(*light);
glUniform3fv(glGetUniformLocation(lightShader->GetProgram(),
"cameraPos"), 1, (float*)&camera->GetPosition());
glUniform1i(glGetUniformLocation(
lightShader->GetProgram(), "diffuseTex"), 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, earthTex);
glUniform1i(glGetUniformLocation(
lightShader->GetProgram(), "bumpTex"), 1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, earthBump);
modelMatrix.ToIdentity();
textureMatrix.ToIdentity();
UpdateShaderMatrices();
heightMap->Draw();
}
```
### 6. 绘制水面
在 `DrawWater` 函数中,启用反射着色器并绘制水面:
```cpp
void Renderer::DrawWater() {
BindShader(reflectShader);
glUniform3fv(glGetUniformLocation(reflectShader->GetProgram(),
"cameraPos"), 1, (float*)&camera->GetPosition());
glUniform1i(glGetUniformLocation(
reflectShader->GetProgram(), "diffuseTex"), 0);
glUniform1i(glGetUniformLocation(
reflectShader->GetProgram(), "cubeTex"), 2);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, waterTex);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubeMap);
Vector3 hSize = heightMap->GetHeightmapSize();
modelMatrix =
Matrix4::Translation(hSize * 0.5f) *
Matrix4::Scale(hSize * 0.5f) *
Matrix4::Rotation(90, Vector3(1, 0, 0));
textureMatrix =
Matrix4::Translation(Vector3(waterCycle, 0.0f, waterCycle)) *
Matrix4::Scale(Vector3(10, 10, 10)) *
Matrix4::Rotation(waterRotate, Vector3(0, 0, 1));
UpdateShaderMatrices();
// SetShaderLight(*light); // No lighting in this shader!
quad->Draw();
}
```
### 7. 顶点着色器
在 `reflectVertex.glsl` 和 `skyboxVertex.glsl` 中,定义了顶点着色器:
#### 反射顶点着色器
```glsl
#version 330 core
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projMatrix;
uniform mat4 textureMatrix;
in vec3 position;
in vec3 normal;
in vec2 texCoord;
out Vertex {
vec3 colour;
vec2 texCoord;
vec3 normal;
vec3 worldPos;
} OUT;
void main(void) {
mat3 normalMatrix = transpose(inverse(mat3(modelMatrix)));
OUT.texCoord = (textureMatrix * vec4(texCoord, 0.0, 1.0)).xy;
OUT.normal = normalize(normalMatrix * normalize(normal));
vec4 worldPos = (modelMatrix * vec4(position, 1));
OUT.worldPos = worldPos.xyz;
gl_Position = (projMatrix * viewMatrix) * worldPos;
}
```
#### 天空盒顶点着色器
```glsl
#version 330 core
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projMatrix;
in vec3 position;
out Vertex {
vec3 viewDir;
} OUT;
void main(void) {
vec3 pos = position;
mat4 invProj = inverse(projMatrix);
pos.xy *= vec2(invProj[0][0], invProj[1][1]);
pos.z = -1.0f;
OUT.viewDir = transpose(mat3(viewMatrix)) * normalize(pos);
gl_Position = vec4(position, 1.0);
}
```
### 8. 片段着色器
在 `reflectFragment.glsl` 和 `skyboxFragment.glsl` 中,定义了片段着色器:
#### 反射片段着色器
```glsl
#version 330 core
uniform sampler2D diffuseTex;
uniform samplerCube cubeTex;
uniform vec3 cameraPos;
in Vertex {
vec4 colour;
vec2 texCoord;
vec3 normal;
vec3 worldPos;
} IN;
out vec4 fragColour;
void main(void) {
vec4 diffuse = texture(diffuseTex, IN.texCoord);
vec3 viewDir = normalize(cameraPos - IN.worldPos);
vec3 reflectDir = reflect(-viewDir, normalize(IN.normal));
vec4 reflectTex = texture(cubeTex, reflectDir);
fragColour = reflectTex + (diffuse * 0.25f);
}
```
#### 天空盒片段着色器
```glsl
#version 330 core
uniform samplerCube cubeTex;
in Vertex {
vec3 viewDir;
} IN;
out vec4 fragColour;
void main(void) {
fragColour = texture(cubeTex, normalize(IN.viewDir));
}
```
这些代码共同实现了立方体贴图用于反射和天空盒的效果。