Cubemap 中 6 个 View Matrix 的制作方法

本文介绍了Cubemap的基本概念及其在环境映射和ShadowMap中的应用。详细阐述了如何生成Cubemap的6个View Matrix,重点讨论了从+Z Face开始,通过旋转生成其他五个Face的View Matrix的过程,强调了正确处理Camera旋转和Cube变换的顺序对于正确渲染的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、简述 Cubemap

 二、制作 View Matrix

1. 制作 +Z 的 View Matrix

2. 制作其他方向的 View Matrix 

3. 其他


一、简述 Cubemap

        Cubemap 是一种自从 Direct3D 7 开始就存在的古老技术,其一般用于环境映射贴图、点光源的 ShadowMap 等技术场景。

        Cubemap 工作原理大体就是先把 Cubemap 当成 RenderTarget ,把场景渲染到 Cube 的 6 个面上,然后再把 Cubemap 当成 Texture 等待被使用。其中把场景渲染到 Cubemap 的步骤实际上就是把场景中需要渲染的每个物体分别渲染到 Cube 的 6 个 Face 上,这样每一个 Cube Face 都相当于是一个 Camera ,渲染物体的时候都需要变换到对应的 Camera 中, 也就是乘以其对应 View Matrix。今天我们就来说说这 6 个 View Matrix 的制作。

        首先说明一下 Cubemap 6 个 Face 的顺序是 +X/-X /+Y/-Y/+Z/-Z,其中 XYZ 的方向和 D3D 的坐标轴一样(如图)。

 二、制作 View Matrix

 1. 制作 +Z 的 View Matrix

        我们仔细观察可以发现选择 Cubemap 中任意一个面,通过旋转都可以变换成其他的 5 个面&#x

该文档中的代码实现了立方体贴图(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)); } ``` 这些代码共同实现了立方体贴图用于反射和天空盒的效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值