基于OpenGL实现三维室内场景的方案
一、环境搭建与基础配置
1.1 开发环境配置
// Visual Studio 2022配置示例
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
// 初始化GLFW
if(!glfwInit()) {
std::cerr << "Failed to initialize GLFW" << std::endl;
return -1;
}
// 创建窗口
GLFWwindow* window = glfwCreateWindow(1280, 720, "室内场景", nullptr, nullptr);
glfwMakeContextCurrent(window);
// 初始化GLEW
glewExperimental = GL_TRUE;
if(glewInit() != GLEW_OK) {
std::cerr << "Failed to initialize GLEW" << std::endl;
return -1;
}
1.2 视口与投影矩阵
void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
glViewport(0, 0, width, height);
glm::mat4 projection = glm::perspective(glm::radians(45.0f),
(float)width/height,
0.1f, 100.0f);
// 传递投影矩阵到着色器
}
二、场景建模实现
2.1 基础几何体构建
// 墙体定义(使用VAO/VBO)
float walls[] = {
// 位置 // 法线 // UV坐标
-5.0f, 3.0f, -5.0f, 0.0f, 0.0f, 0.0f, 0.0f, // 左下前
5.0f, 3.0f, -5.0f, 0.0f, 0.0f, 1.0f, 0.0f, // 右下前
5.0f, 3.0f, 5.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 右上后
-5.0f, 3.0f, 5.0f, 0.0f, 0.0f, 0.0f, 1.0f // 左上后
};
GLuint VAO, VBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(walls), walls, GL_STATIC_DRAW);
// 顶点属性配置
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void*)(3*sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void*)(6*sizeof(float)));
glEnableVertexAttribArray(2);
2.2 复杂家具建模
// 沙发模型(使用OBJ加载器)
std::vector<float> sofa_vertices = loadOBJ("sofa.obj");
GLuint sofaVAO, sofaVBO;
glGenVertexArrays(1, &sofaVAO);
glGenBuffers(1, &sofaVBO);
glBindBuffer(GL_ARRAY_BUFFER, sofaVBO);
glBufferData(GL_ARRAY_BUFFER, sofa_vertices.size()*sizeof(float), &sofa_vertices[0], GL_STATIC_DRAW);
三、光照与材质系统
3.1 Phong光照模型
// 顶点着色器
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;
out vec3 FragPos;
out vec3 Normal;
out vec2 TexCoords;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main() {
FragPos = vec3(model * vec4(aPos, 1.0));
Normal = mat3(transpose(inverse(model))) * aNormal;
TexCoords = aTexCoords;
gl_Position = projection * view * model * vec4(aPos, 1.0);
}
// 片段着色器
#version 330 core
out vec4 FragColor;
in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoords;
uniform sampler2D texture1;
uniform vec3 lightPos;
uniform vec3 viewPos;
uniform vec3 lightColor;
void main() {
// 环境光
vec3 ambient = 0.1 * lightColor;
// 漫反射
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(lightPos - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * lightColor;
// 镜面反射
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
vec3 specular = 0.5 * spec * lightColor;
vec3 result = (ambient + diffuse + specular) * texture(texture1, TexCoords).rgb;
FragColor = vec4(result, 1.0);
}
3.2 材质属性设置
// 材质结构体
struct Material {
glm::vec3 ambient;
glm::vec3 diffuse;
glm::vec3 specular;
float shininess;
};
// 传递材质参数
glUniform3fv(glGetUniformLocation(shaderProgram, "material.ambient"), 1, &material.ambient[0]);
glUniform3fv(glGetUniformLocation(shaderProgram, "material.diffuse"), 1, &material.diffuse[0]);
glUniform3fv(glGetUniformLocation(shaderProgram, "material.specular"), 1, &material.specular[0]);
glUniform1f(glGetUniformLocation(shaderProgram, "material.shininess"), material.shininess);
四、纹理映射系统
4.1 纹理加载与绑定
// 使用stb_image加载纹理
GLuint loadTexture(const char* path) {
GLuint textureID;
glGenTextures(1, &textureID);
int width, height, nrChannels;
unsigned char *data = stbi_load(path, &width, &height, &nrChannels, 0);
if(data) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
stbi_image_free(data);
// 纹理参数设置
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
return textureID;
}
// 绑定纹理到着色器
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureID);
glUniform1i(glGetUniformLocation(shaderProgram, "texture1"), 0);
4.2 环境贴图实现
// 立方体贴图加载
GLuint loadCubemap(vector<std::string> faces) {
GLuint textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
int width, height, nrChannels;
for(uint i = 0; i < faces.size(); i++) {
unsigned char *data = stbi_load(faces[i].c_str(), &width, &height, &nrChannels, 0);
if(data) {
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
stbi_image_free(data);
}
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
return textureID;
}
参考代码 采用openGL实现的一个三维室内场景 www.youwenfan.com/contentcnh/56182.html
五、交互系统实现
5.1 第一人称视角控制
// 摄像机控制类
class Camera {
public:
glm::vec3 Position;
glm::vec3 Front;
glm::vec3 Up;
glm::vec3 Right;
glm::vec3 WorldUp;
float Yaw;
float Pitch;
Camera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 3.0f),
glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f),
float yaw = -90.0f, float pitch = 0.0f) {
Position = position;
WorldUp = up;
Yaw = yaw;
Pitch = pitch;
updateCameraVectors();
}
void ProcessMouseMovement(float xoffset, float yoffset) {
xoffset *= sensitivity;
yoffset *= sensitivity;
Yaw += xoffset;
Pitch += yoffset;
if(Pitch > 89.0f) Pitch = 89.0f;
if(Pitch < -89.0f) Pitch = -89.0f;
updateCameraVectors();
}
private:
void updateCameraVectors() {
glm::vec3 front;
front.x = cos(glm::radians(Yaw)) * cos(glm::radians(Pitch));
front.y = sin(glm::radians(Pitch));
front.z = sin(glm::radians(Yaw)) * cos(glm::radians(Pitch));
Front = glm::normalize(front);
}
};
5.2 物体交互系统
// 碰撞检测(AABB算法)
struct AABB {
glm::vec3 min;
glm::vec3 max;
};
bool CheckCollision(AABB a, AABB b) {
return (a.min.x <= b.max.x && a.max.x >= b.min.x) &&
(a.min.y <= b.max.y && a.max.y >= b.min.y) &&
(a.min.z <= b.max.z && a.max.z >= b.min.z);
}
// 物体移动控制
void moveObject(glm::vec3& position, glm::vec3 direction, float speed) {
if(!CheckCollision(objectAABB, cameraAABB)) {
position += direction * speed;
}
}

浙公网安备 33010602011771号