LearnOpenGL学习笔记—模型加载:复习与总结
- 0 前言
- 1 逻辑梳理
- 2 完整代码
- 2.1 main.cpp
- 2.2 Shader.h
- 2.3 Shader.cpp
- 2.4 Camera.h
- 2.5 Camera.cpp
- 2.6 vertexSource.vert
- 2.7 fragmentSource.frag
- 2.8 Material.h
- 2.9 Material.cpp
- 2.10 Mesh.h
- 2.11 Mesh.cpp
- 2.12 Model.h
- 2.13 Model.cpp
- 2.14 LightSpot.h
- 2.15 LightSpot.cpp
- 2.16 LightPoint.h
- 2.17 LightPoint.cpp
- 2.18 LightDirectional.h
- 2.19 LightDirectional.cpp
【项目地址:点击这里这里这里】
0 前言
在模型加载01中我们导入了assimp库。
在模型加载02中我们定义了一个我们自己的网格类,并经过简单测试。
在模型加载03中我们接触Assimp并创建实际的加载和转换代码,通过创建另一个类来完整地表示一个模型,或者说是包含多个网格,甚至是多个物体的模型,但我们并没有进行展示。
这一节我们来对代码进行梳理和展示,并复习前面的内容。
我们最后会得到这么一个成果:
1 逻辑梳理
1.1 main
在main文件中,我们按照渲染管线的要求实现逻辑(大部分是渲染管线的杂活):
- 正方体数据的准备—Model Data
- 相机的建立——Camera Declare
- 光源的建立——Light Declare
- 准备键鼠控制的方法——Input Declare
- 准备正方体材质图片传入GPU的方法——unsigned int LoadImageToGPU(…)
- main函数:
-开窗初始化——Open a Window
-Shader建立——Init Shader Program
-正方体的材质建立——Init Material
-正方体的网格建立,纳米机器人模型建立——Init and Load Models to VAO,VBO
-材质导入设置——Init and Load Textures
-准备MVP矩阵——Prepare MVP matrices
-渲染循环——While:
– 获取输入——Process Input
– 清缓存——Clear Screen
– 开始绘制:
— mvp矩阵单独操作
— Shader使用
— Uniforms设置
— Draw
–双缓冲,计时,为下一个循环准备
-退出
1.2 light
平行光,点光,聚光如何设置的思考,可以在之前的光照笔记中了解到。
有所改动的就只有以下几点(之前建构函数中有些偷懒没改)
- 平行光与光源位置无关
- 点光与光源旋转无关
然后不同光源根据其特点设置建构函数就好
1.3 shader
shader的建构以及vertexSource与fragmentSource基本没有改动,也可参照之前的笔记
只是针对光源的不同,把设置的一些用不到的位置和旋转量去掉了。
shader逻辑大致概括的话
- 顶点着色器负责接收 顶点位置,法向,uv变量,mvp矩阵,
然后将顶点位置,法向,uv变量等在变换后的结果传出去 - 片元着色器接收着色点,法向,uv变量
然后根据一些uniform变量,把材质和光照条件通过特定的计算方法来计算得到该着色点的颜色。
1.4 Material
这个类定义了材质,将光照贴图和对应的Shader进行了整合
1.5 Camera
这个类用来键鼠控制相机,内含一些坐标变换的方法
1.6 Mesh
网格类将模型的网格数据进行统一
这次有通过画数组得到的正方体,也有画EBO得到的机器人,所以设置不同的方法来建构和绘制
这里有个让我理解了好久需要注意的点(即有次出现了,方块用到机器人的材质来画的诡异局面)
- 对于材质传给缓存然后传给Shader的过程
我们之前在把图片传给GPU的过程中
用了glGenTextures这个用来生成纹理的函数 - glGenTextures(GLsizei n, GLuint *textures)
n:用来生成纹理的数量
textures:存储纹理索引的第一个元素指针
函数根据纹理参数返回n个纹理索引
然后我们就得到了当前材质的纹理索引
然后为当前纹理索引绑定的纹理对象设置环绕、过滤方式 - 也就是说到此为止,我们都还没有去激活来用纹理,只是在缓存中操作
- 在我们的案例中,便是3个箱子的纹理索引存到了Material的对应属性,加上11个机器人的纹理索引,我们获得了14个纹理索引
- 在纹理使用的过程中
我们用glActiveTexture激活对应的纹理单元
然后使用glBindTexture,将所用纹理的类型与纹理索引绑定到这个纹理单元上
然后将shader的所需要的Uniform通过SetUniform,从这个纹理单元上拿
也就是说,外面的纹理索引和里面的Shader,通过过纹理单元这个管道连在一起,让uniform采样器对应着正确的纹理单元,拿到正确的纹理索引。
至于其他VAO,VBO,EBO的设置同理老生常谈了。
1.7 Model
这个类通过模型路径获得模型数据,利用assimp的数据结构载入到我们的网格之中
载入模型首先经过检查,没问题后存到根节点的场景节点中
然后把每个节点进行对应的网格处理
从数据中处理顶点位置、法线,纹理坐标,索引,并且将材质的图片生成我们能用的纹理
将这几项分门别类的存储,方便我们使用
对应的绘制用Mesh的绘制方法即可
2 完整代码
这是完整的项目目录
正方体的材质文件可以去光照的复习笔记中获取
模型文件可以去模型加载02的笔记中获取
stb_image库可以去入门的复习笔记中获取
2.1 main.cpp
#include <iostream>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "Shader.h"
#include "Camera.h"
#include "Material.h"
#include "LightDirectional.h"
#include "LightPoint.h"
#include "LightSpot.h"
#include "Mesh.h"
#include "Model.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
//发光正方体的数据
#pragma region Model Data
float vertices[] = {
//position //normal //TexCoord
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
};
glm::vec3 cubePositions[] = {
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(2.0f, 5.0f, -15.0f),
glm::vec3(-1.5f, -2.2f, -2.5f),
glm::vec3(-3.8f, -2.0f, -12.3f),
glm::vec3(2.4f, -0.4f, -3.5f),
glm::vec3(-1.7f, 3.0f, -7.5f),
glm::vec3(1.3f, -2.0f, -2.5f),
glm::vec3(1.5f, 2.0f, -2.5f),
glm::vec3(1.5f, 0.2f, -1.5f),
glm::vec3(-1.3f, 1.0f, -1.5f)
};
#pragma endregion
#pragma region Camera Declare
//建立camera
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);
glm::vec3 cameraTarget = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
Camera camera(cameraPos, cameraTarget, cameraUp);
#pragma endregion
#pragma region Light Declare
//position angle color
LightDirectional lightD (
glm::vec3(135.0f, 0,0),
glm::vec3(0.5f, 0.5f, 0.5f));
LightPoint lightP0 (glm::vec3(1.0f, 0,0),
glm::vec3(1.0f, 0, 0));
LightPoint lightP1 (glm::vec3(0, 1.0f, 0),
glm::vec3(0, 1.0f, 0));
LightPoint lightP2 (glm::vec3(0, 0, 1.0f),
glm::vec3(0, 0, 1.0f));
LightPoint lightP3 (glm::vec3(1.0f, 1.0f, 1.0f),
glm::vec3(1.0f, 0, 1.0f));
LightSpot lightS (glm::vec3(0, 8.0f,0.0f),
glm::vec3(135.0f, 0, 0),
glm::vec3(0, 0,1.5f));
#pragma endregion
#pragma region Input Declare
//移动用
float deltaTime = 0.0f; // 当前帧与上一帧的时间差
float lastFrame = 0.0f; // 上一帧的时间
void processInput(GLFWwindow* window) {
//看是不是按下esc键 然后退出
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(window, true);
}
//更流畅点的摄像机系统
if (deltaTime != 0) {
camera.cameraPosSpeed = 5 * deltaTime;
}
//camera前后左右根据镜头方向移动
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
camera.PosUpdateForward();
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
camera.PosUpdateBackward();
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
camera.PosUpdateLeft();
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
camera.PosUpdateRight();
if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS)
camera.PosUpdateUp();
if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS)
camera.PosUpdateDown();
}
float lastX;
float lastY;
bool firstMouse = true;
//鼠标控制镜头方向
void mouse_callback(GLFWwindow* window, double xpos, double ypos) {
if (firstMouse == true)
{
lastX = xpos;
lastY = ypos;
firstMouse = false;
}
float deltaX, deltaY;
float sensitivity = 0.05f;
deltaX = (xpos - lastX)*sensitivity;
deltaY = (ypos - lastY)*sensitivity;
lastX = xpos;
lastY = ypos;
camera.ProcessMouseMovement(deltaX, deltaY);
};
//缩放
float fov = 45.0f;
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
if (fov >= 1.0f && fov <= 45.0f)
fov -= yoffset;
if (fov <= 1.0f)
fov = 1.0f;
if (fov >= 45.0f)
fov = 45.0f;
}
#pragma endregion
unsigned int LoadImageToGPU(const char* filename, GLint internalFormat, GLenum format) {
unsigned int TexBuffer;
glGenTextures(1, &TexBuffer);
glBindTexture(GL_TEXTURE_2D, TexBuffer);
// 为当前绑定的纹理对象设置环绕、过滤方式
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);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
// 加载并生成纹理
int width, height, nrChannel;
unsigned char *data = stbi_load(filename, &width, &height, &nrChannel, 0);
if (data) {
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
printf("Failed to load texture");
}
stbi_image_free(data);
return TexBuffer;
}
int main(int argc, char* argv[]) {
std::string exePath = argv[0];
#pragma region Open a Window
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//Open GLFW Window
GLFWwindow* window = glfwCreateWindow(800,600,"My OpenGL Game",NULL,NULL);
if(window == NULL)
{
printf("Open window failed.");
glfwTerminate();
return - 1;
}
glfwMakeContextCurrent(window);
//关闭鼠标显示
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
//回调函数监听鼠标
glfwSetCursorPosCallback(window, mouse_callback);
//回调函数监听滚轮
glfwSetScrollCallback(window, scroll_callback);
//Init GLEW
glewExperimental = true;
if (glewInit() != GLEW_OK)
{
printf("Init GLEW failed.");
glfwTerminate();
return -1;
}
glViewport(0, 0, 800, 600);
glEnable(GL_DEPTH_TEST);
#pragma endregion
#pragma region Init Shader Program
Shader* myShader = new Shader("vertexSource.vert", "fragmentSource.frag");
#pragma endregion
#pragma region Init Material
Material * myMaterial = new Material(myShader,
LoadImageToGPU("container2.png", GL_RGBA, GL_RGBA),
LoadImageToGPU("container2_specular.png", GL_RGBA, GL_RGBA),
LoadImageToGPU("matrix.jpg", GL_RGB, GL_RGB),
glm::vec3 (1.0f, 1.0f, 1.0f),
150.0f);
#pragma endregion
#pragma region Init and Load Models to VAO,VBO
Mesh cube(vertices);
Model model(exePath.substr(0, exePath.find_last_of('\\')) + "\\model\\nanosuit.obj");
#pragma endregion
#pragma region Init and Load Textures
//坐标翻转
stbi_set_flip_vertically_on_load(true);
#pragma endregion
#pragma region Prepare MVP matrices
//model
glm::mat4 modelMat;
//view
glm::mat4 viewMat;
//projection
glm::mat4 projMat;
#pragma endregion
while (!glfwWindowShouldClose(window))
{
//Process Input
processInput(window);
//Clear Screen
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//方块 10代表模型
for (unsigned int i = 0; i < 11; i++)
{
if (i != 10) {
//Set Model matrix
modelMat = glm::translate(glm::mat4(1.0f), cubePositions[i]);
float angle = 20.0f * (i);
//float angle = 20.0f * i + 50*glfwGetTime();
modelMat = glm::rotate(modelMat, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
}
else {
modelMat = glm::translate(glm::mat4(1.0f), { 0,-10,-5 });
}
//Set view matrix
viewMat = camera.GetViewMatrix();
//Set projection matrix
projMat = glm::perspective(glm::radians(fov), 800.0f / 600.0f, 0.1f, 100.0f);
//Set Material -> Shader Program
myShader->use();
//Set Material -> Uniforms
#pragma region Uniform
glUniformMatrix4fv(glGetUniformLocation(myShader->ID, "modelMat"), 1, GL_FALSE, glm::value_ptr(modelMat));
glUniformMatrix4fv(glGetUniformLocation(myShader->ID, "viewMat"), 1, GL_FALSE, glm::value_ptr(viewMat));
glUniformMatrix4fv(glGetUniformLocation(myShader->ID, "projMat"), 1, GL_FALSE, glm::value_ptr(projMat));
glUniform3f(glGetUniformLocation(myShader->ID, "cameraPos"), camera.Position.x, camera.Position.y, camera.Position.z);
glUniform1f(glGetUniformLocation(myShader->ID, "time"), glfwGetTime());
glUniform3f(glGetUniformLocation(myShader->ID, "objColor"), 1.0f, 1.0f, 1.0f);
glUniform3f(glGetUniformLocation(myShader->ID, "ambientColor"), 0.1f, 0.1f, 0.1f);
glUniform3f(glGetUniformLocation(myShader->ID, "lightD.color"), lightD.color.x, lightD.color.y, lightD.color.z);
glUniform3f(glGetUniformLocation(myShader->ID, "lightD.dirToLight"), lightD.direction.x, lightD.direction.y, lightD.direction.z);
glUniform3f(glGetUniformLocation(myShader->ID, "lightP0.pos"), lightP0.position.x, lightP0.position.y, lightP0.position.z);
glUniform3f(glGetUniformLocation(myShader->ID, "lightP0.color"), lightP0.color.x, lightP0.color.y, lightP0.color.z);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP0.constant"), lightP0.constant);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP0.linear"), lightP0.linear);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP0.quadratic"), lightP0.quadratic);
glUniform3f(glGetUniformLocation(myShader->ID, "lightP1.pos"), lightP1.position.x, lightP1.position.y, lightP1.position.z);
glUniform3f(glGetUniformLocation(myShader->ID, "lightP1.color"), lightP1.color.x, lightP1.color.y, lightP1.color.z);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP1.constant"), lightP1.constant);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP1.linear"), lightP1.linear);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP1.quadratic"), lightP1.quadratic);
glUniform3f(glGetUniformLocation(myShader->ID, "lightP2.pos"), lightP2.position.x, lightP2.position.y, lightP2.position.z);
glUniform3f(glGetUniformLocation(myShader->ID, "lightP2.color"), lightP2.color.x, lightP2.color.y, lightP2.color.z);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP2.constant"), lightP2.constant);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP2.linear"), lightP2.linear);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP2.quadratic"), lightP2.quadratic);
glUniform3f(glGetUniformLocation(myShader->ID, "lightP3.pos"), lightP3.position.x, lightP3.position.y, lightP3.position.z);
glUniform3f(glGetUniformLocation(myShader->ID, "lightP3.color"), lightP3.color.x, lightP3.color.y, lightP3.color.z);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP3.constant"), lightP3.constant);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP3.linear"), lightP3.linear);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP3.quadratic"), lightP3.quadratic);
glUniform3f(glGetUniformLocation(myShader->ID, "lightS.pos"), lightS.position.x, lightS.position.y, lightS.position.z);
glUniform3f(glGetUniformLocation(myShader->ID, "lightS.color"), lightS.color.x, lightS.color.y, lightS.color.z);
glUniform3f(glGetUniformLocation(myShader->ID, "lightS.dirToLight"), lightS.direction.x, lightS.direction.y, lightS.direction.z);
glUniform1f(glGetUniformLocation(myShader->ID, "lightS.constant"), lightS.constant);
glUniform1f(glGetUniformLocation(myShader->ID, "lightS.linear"), lightS.linear);
glUniform1f(glGetUniformLocation(myShader->ID, "lightS.quadratic"), lightS.quadratic);
glUniform1f(glGetUniformLocation(myShader->ID, "lightS.cosPhyInner"), lightS.cosPhyInner);
glUniform1f(glGetUniformLocation(myShader->ID, "lightS.cosPhyOuter"), lightS.cosPhyOuter);
#pragma endregion
myMaterial->shader->SetUniform3f("material.ambient", myMaterial->ambient);
myMaterial->shader->SetUniform1f("material.shininess", myMaterial->shininess);
if (i == 10) {
model.Draw(myShader);
}
else {
cube.DrawArray(myMaterial->shader, myMaterial->diffuse, myMaterial->specular, myMaterial->emission);
}
}
//Clean up prepare for next render loop
glfwSwapBuffers(window);
glfwPollEvents();
//Recording the time
float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
}
//Exit program
glfwTerminate();
return 0;
}
2.2 Shader.h
#pragma once
#include <string>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
class Shader
{
public:
Shader(const char* vertexPath, const char* fragmentPath);
std::string vertexString;
std::string fragmentString;
const char* vertexSource;
const char* fragmentSource;
unsigned int ID; //Shader Program ID
void use();
void SetUniform3f(const char* paraNameString,glm::vec3 param);
void SetUniform1f(const char* paraNameString, float param);
void SetUniform1i(const char* paraNameString, int slot);
//~Shader();
private:
void checkCompileErrors(unsigned int ID, std::string type);
};
2.3 Shader.cpp
#include "Shader.h"
#include <iostream>
#include <fstream>
#include <SStream>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
using namespace std;
Shader::Shader(const char* vertexPath, const char* fragmentPath)
{
//从文件路径中获取顶点/片段着色器
ifstream vertexFile;
ifstream fragmentFile;
stringstream vertexSStream;
stringstream fragmentSStream;
//打开文件
vertexFile.open(vertexPath);
fragmentFile.open(fragmentPath);
//保证ifstream对象可以抛出异常:
vertexFile.exceptions(ifstream::failbit || ifstream::badbit);
fragmentFile.exceptions(ifstream::failbit || ifstream::badbit);
try
{
if (!vertexFile.is_open() || !fragmentFile.is_open())
{
throw exception("open file error");
}
//读取文件缓冲内容到数据流
vertexSStream << vertexFile.rdbuf();
fragmentSStream << fragmentFile.rdbuf();
//转换数据流到string
vertexString = vertexSStream.str();
fragmentString = fragmentSStream.str();
vertexSource = vertexString.c_str();
fragmentSource = fragmentString.c_str();
// 编译着色器
unsigned int vertex, fragment;
// 顶点着色器
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vertexSource, NULL);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");
// 片段着色器
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fragmentSource, NULL);
glCompileShader(fragment);
checkCompileErrors(fragment, "FRAGMENT");
// 着色器程序
ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
glLinkProgram(ID);
checkCompileErrors(ID, "PROGRAM");
// 删除着色器,它们已经链接到我们的程序中了,已经不再需要了
glDeleteShader(vertex);
glDeleteShader(fragment);
}
catch (const std::exception& ex)
{
printf(ex.what());
}
}
void Shader::use()
{
glUseProgram(ID);
}
void Shader::SetUniform3f(const char * paraNameString, glm::vec3 param)
{
glUniform3f(glGetUniformLocation(ID, paraNameString), param.x, param.y, param.z);
}
void Shader::SetUniform1f(const char * paraNameString, float param)
{
glUniform1f(glGetUniformLocation(ID, paraNameString), param);
}
void Shader::SetUniform1i(const char * paraNameString, int slot)
{
glUniform1i(glGetUniformLocation(ID, paraNameString), slot);
}
void Shader::checkCompileErrors(unsigned int ID, std::string type) {
int sucess;
char infolog[512];
if (type != "PROGRAM")
{
glGetShaderiv(ID, GL_COMPILE_STATUS, &sucess);
if (!sucess)
{
glGetShaderInfoLog(ID, 512, NULL, infolog);
cout << "shader compile error:" << infolog << endl;
}
}
else
{
glGetProgramiv(ID, GL_LINK_STATUS, &sucess);
if (!sucess)
{
glGetProgramInfoLog(ID, 512, NULL, infolog);
cout << "program linking error:" << infolog << endl;
}
}
}
2.4 Camera.h
#pragma once
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
class Camera
{
public:
~Camera();
//position 相机所在位置 target 相机指向的位置 worldup 世界向上的向量
Camera(glm::vec3 position, glm::vec3 target, glm::vec3 worldup);
//pitch俯仰角和yaw偏航角
Camera(glm::vec3 position, float pitch, float yaw, glm::vec3 worldup);
//摄影机位置
glm::vec3 Position;
//Forward 摄影机的“方向”(一个和朝向相反的向量)
glm::vec3 Forward;
glm::vec3 Right;
//摄影机的上方向
glm::vec3 Up;
//世界的上方向
glm::vec3 WorldUp;
float Pitch;
float Yaw;
float cameraPosSpeed;
glm::mat4 GetViewMatrix();
void ProcessMouseMovement(float deltaX, float deltaY);
void PosUpdateForward();
void PosUpdateBackward();
void PosUpdateLeft();
void PosUpdateRight();
void PosUpdateUp();
void PosUpdateDown();
private:
void UpdateCameraVectors();
};
2.5 Camera.cpp
#include "Camera.h"
Camera::Camera(glm::vec3 position, glm::vec3 target, glm::vec3 worldup)
{
Position = position;
WorldUp = worldup;
//normalize 归一化变成单位向量
//Forward 摄影机的“方向”(一个和朝向相反的向量)
Forward = glm::normalize(position - target);
//Right 它代表Camera的右方,用世界的上方向与摄影机朝向叉乘
Right = glm::normalize(glm::cross(WorldUp, Forward));
//UP 摄像机的上方向
Up = glm::cross(Forward, Right);
}
glm::mat4 Camera::GetViewMatrix()
{
//glm::LookAt函数需要一个摄像机位置、一个目标位置和表示世界空间中的上向量的向量。
//它会创建一个观察矩阵。
return glm::lookAt(Position, Position - Forward, WorldUp);
}
Camera::Camera(glm::vec3 position, float pitch, float yaw, glm::vec3 worldup)
{
Position = position;
WorldUp = worldup;
Pitch = pitch;
Yaw = yaw;
Forward.x = cos(glm::radians(Pitch)) * sin(glm::radians(Yaw));
Forward.y = sin(glm::radians(Pitch));
Forward.z = cos(glm::radians(Pitch)) * cos(glm::radians(Yaw));
Forward = glm::normalize(Forward);
//Right 它代表摄像机空间的x轴的正方向
Right = glm::normalize(glm::cross(WorldUp, Forward));
//UP 一个指向摄像机的正y轴向量
Up = glm::cross(Forward, Right);
}
void Camera::ProcessMouseMovement(float deltaX, float deltaY)
{
Pitch += deltaY;
Yaw -= deltaX;
UpdateCameraVectors();
if (Pitch > 89.0f)
Pitch = 89.0f;
if (Pitch < -89.0f)
Pitch = -89.0f;
}
//-Forward是当前相机的朝向
//朝前
void Camera::PosUpdateForward()
{
Position += cameraPosSpeed * -Forward;
}
//朝后
void Camera::PosUpdateBackward()
{
Position -= cameraPosSpeed * -Forward;
}
//朝上
void Camera::PosUpdateUp()
{
Position += cameraPosSpeed * WorldUp;
}
//朝下
void Camera::PosUpdateDown()
{
Position -= cameraPosSpeed * WorldUp;
//左边
void Camera::PosUpdateLeft()
{
Position -= glm::normalize(glm::cross(-Forward, Up)) * cameraPosSpeed;
}
//右边
void Camera::PosUpdateRight()
{
Position += glm::normalize(glm::cross(-Forward, Up)) * cameraPosSpeed;
}
void Camera::UpdateCameraVectors()
{
Forward.x = cos(glm::radians(Pitch)) * sin(glm::radians(Yaw));
Forward.y = sin(glm::radians(Pitch));
Forward.z = cos(glm::radians(Pitch)) * cos(glm::radians(Yaw));
Forward = glm::normalize(Forward);
//Right 它代表摄像机空间的x轴的正方向
Right = glm::normalize(glm::cross(WorldUp, Forward));
//UP 一个指向摄像机的正y轴向量
Up = glm::cross(Forward, Right);
}
Camera::~Camera()
{
}
2.6 vertexSource.vert
#version 330 core
layout(location = 0) in vec3 aPos; // 位置变量的属性位置值为 0
layout(location = 1) in vec3 aNormal; // 法向量的属性位置值为 1
layout(location = 2) in vec2 aTexCoord; // uv变量的属性位置值为 2
//out vec4 vertexColor;
out vec2 TexCoord;
//着色点和法向
out vec3 FragPos;
out vec3 Normal;
//uniform mat4 transform;
uniform mat4 modelMat;
uniform mat4 viewMat;
uniform mat4 projMat;
void main(){
gl_Position = projMat * viewMat * modelMat * vec4(aPos.xyz,1.0);
Normal =mat3(transpose(inverse(modelMat)))*aNormal;
FragPos=(modelMat * vec4(aPos.xyz,1.0)).xyz;
//vertexColor = vec4(aColor,1.0);
//TexCoord = aTexCoord;
TexCoord=aTexCoord;
}
2.7 fragmentSource.frag
#version 330 core
//着色点和法向
in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoord;
struct Material {
vec3 ambient;
sampler2D diffuse;
sampler2D specular;
sampler2D emission;
float shininess;
};
uniform Material material;
struct LightDirectional{
vec3 dirToLight;
vec3 color;
};
uniform LightDirectional lightD;
struct LightPoint{
vec3 pos;
vec3 color;
float constant;
float linear;
float quadratic;
};
uniform LightPoint lightP0;
uniform LightPoint lightP1;
uniform LightPoint lightP2;
uniform LightPoint lightP3;
struct LightSpot{
vec3 pos;
vec3 color;
float constant;
float linear;
float quadratic;
vec3 dirToLight;
float cosPhyInner;
float cosPhyOuter;
};
uniform LightSpot lightS;
out vec4 FragColor;
uniform vec3 objColor;
uniform vec3 ambientColor;
uniform vec3 cameraPos;
uniform float time;
vec3 CalcLightDirectional(LightDirectional light, vec3 uNormal, vec3 dirToCamera){
//diffuse
float diffIntensity = max(dot(uNormal, light.dirToLight), 0.0);
vec3 diffuseColor = diffIntensity * texture(material.diffuse,TexCoord).rgb * light.color;
//Blinn-Phong specular
vec3 halfwarDir = normalize(light.dirToLight + dirToCamera);
float specularAmount = pow(max(dot(uNormal, halfwarDir), 0.0),material.shininess);
vec3 specularColor = texture(material.specular,TexCoord).rgb * specularAmount * light.color;
vec3 result = diffuseColor+specularColor;
return result;
}
vec3 CalcLightPoint(LightPoint light, vec3 uNormal, vec3 dirToCamera){
//attenuation
vec3 dirToLight=light.pos-FragPos;
float dist =length(dirToLight);
float attenuation= 1.0 / (light.constant + light.linear * dist + light.quadratic * (dist * dist));
//diffuse
float diffIntensity = max(dot(uNormal, normalize(dirToLight)), 0.0);
vec3 diffuseColor = diffIntensity * texture(material.diffuse,TexCoord).rgb * light.color;
//Blinn-Phong specular
vec3 halfwarDir = normalize(dirToLight + dirToCamera);
float specularAmount = pow(max(dot(uNormal, halfwarDir), 0.0),material.shininess);
vec3 specularColor = texture(material.specular,TexCoord).rgb * specularAmount * light.color;
vec3 result = (diffuseColor+specularColor)*attenuation;
return result;
}
vec3 CalcLightSpot(LightSpot light, vec3 uNormal, vec3 dirToCamera){
//attenuation
vec3 dirToLight=light.pos-FragPos;
float dist =length(dirToLight);
float attenuation= 1.0 / (light.constant + light.linear * dist + light.quadratic * (dist * dist));
//diffuse
float diffIntensity = max(dot(uNormal, normalize(dirToLight)), 0.0);
vec3 diffuseColor = diffIntensity * texture(material.diffuse,TexCoord).rgb * light.color;
//Blinn-Phong specular
vec3 halfwarDir = normalize(dirToLight + dirToCamera);
float specularAmount = pow(max(dot(uNormal, halfwarDir), 0.0),material.shininess);
vec3 specularColor = texture(material.specular,TexCoord).rgb * specularAmount * light.color;
//spot
float spotRatio;
float cosTheta = dot( normalize(-1*dirToLight) , -1*light.dirToLight );
if(cosTheta > light.cosPhyInner){
//inside
spotRatio=1;
}else if(cosTheta > light.cosPhyOuter){
//middle
spotRatio=(cosTheta-light.cosPhyOuter)/(light.cosPhyInner-light.cosPhyOuter);
}else{
//outside
spotRatio=0;
}
vec3 result=(diffuseColor+specularColor)*attenuation*spotRatio;
return result;
}
void main(){
vec3 finalResult = vec3(0,0,0);
vec3 uNormal = normalize(Normal);
vec3 dirToCamera = normalize(cameraPos - FragPos);
//emission 32 distance
float eDistance = length(cameraPos-FragPos);
float eCoefficient= 1.0 / (1.0f + 0.14f * eDistance + 0.07f * (eDistance * eDistance));
vec3 emission;
if( texture(material.specular,TexCoord).rgb== vec3(0,0,0) ){
emission= texture(material.emission,TexCoord).rgb;
//fun
emission = texture(material.emission,TexCoord + vec2(0.0,time/2)).rgb;//moving
emission = emission * (sin(time) * 0.5 + 0.5) * 2.0 * eCoefficient;//fading
}
//ambient
vec3 ambient= material.ambient * ambientColor * texture(material.diffuse,TexCoord).rgb;
finalResult += CalcLightDirectional(lightD, uNormal, dirToCamera);
finalResult += CalcLightPoint(lightP0, uNormal, dirToCamera);
finalResult += CalcLightPoint(lightP1, uNormal, dirToCamera);
finalResult += CalcLightPoint(lightP2, uNormal, dirToCamera);
finalResult += CalcLightPoint(lightP3, uNormal, dirToCamera);
finalResult += CalcLightSpot(lightS, uNormal, dirToCamera);
finalResult += emission+ambient;
FragColor=vec4(finalResult,1.0);
//FragColor=vec4(1.0,1.0,1.0,1.0);
}
2.8 Material.h
#pragma once
#include "Shader.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
class Material
{
public:
Shader * shader;
unsigned int diffuse;
unsigned int specular;
unsigned int emission;
glm::vec3 ambient;
float shininess;
Material(Shader* _shader, unsigned int _diffuse, unsigned int _specular, unsigned int _emission, glm::vec3 _ambient, float _shininess);
~Material();
};
2.9 Material.cpp
#pragma once
#include "Shader.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
class Material
{
public:
Shader * shader;
unsigned int diffuse;
unsigned int specular;
unsigned int emission;
glm::vec3 ambient;
float shininess;
Material(Shader* _shader, unsigned int _diffuse, unsigned int _specular, unsigned int _emission, glm::vec3 _ambient, float _shininess);
~Material();
};
2.10 Mesh.h
#pragma once
#include <glm/glm.hpp>
#include <string>
#include <vector>
#include "Shader.h"
#include <GL/glew.h>
#include <iostream>
struct Vertex {
glm::vec3 Position;
glm::vec3 Normal;
glm::vec2 TexCoords;
};
struct Texture {
unsigned int id;
std::string type;
std::string path;
};
class Mesh
{
public:
/* 网格数据 */
std::vector<Vertex> vertices;
std::vector<unsigned int> indices;
std::vector<Texture> textures;
/* 函数 */
Mesh(std::vector<Vertex> vertices, std::vector<unsigned int> indices, std::vector<Texture> textures);
void DrawArray(Shader* shader,int diffuse , int specular , int emission);
void DrawElements(Shader* shader);
/* 测试 */
Mesh(float vertices[]);
private:
/* 渲染数据 */
unsigned int VAO, VBO, EBO;
/* 函数 */
void setupElementsMesh();
void setupArrayMesh();
};
2.11 Mesh.cpp
#include "Mesh.h"
Mesh::Mesh(std::vector<Vertex> vertices, std::vector<unsigned int> indices, std::vector<Texture> textures)
{
this->vertices = vertices;
this->indices = indices;
this->textures = textures;
setupElementsMesh();
}
void Mesh::DrawArray(Shader * shader, int diffuse, int specular, int emission)
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, diffuse);
shader->SetUniform1i("material.diffuse", 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, specular);
shader->SetUniform1i("material.specular", 1);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, emission);
shader->SetUniform1i("material.emission", 2);
// 绘制网格
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
glActiveTexture(GL_TEXTURE0);
}
void Mesh::DrawElements(Shader * shader)
{
for (unsigned int i = 0; i < textures.size(); i++)
{
if (textures[i].type == "texture_diffuse") {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[i].id);
shader->SetUniform1i("material.diffuse", i);
}
else if (textures[i].type == "texture_specular")
{
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textures[i].id);
shader->SetUniform1i("material.specular",i);
}
}
// 绘制网格
glBindVertexArray(VAO);
//glDrawArrays(GL_TRIANGLES, 0, 36);
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glActiveTexture(GL_TEXTURE0);
}
Mesh::Mesh(float vertices[])
{
this->vertices.resize(36);
memcpy(&(this->vertices[0]), vertices, 36 * 8 * sizeof(float));
setupArrayMesh();
}
void Mesh::setupElementsMesh()
{
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
// 顶点位置
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
// 顶点法线
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));
// 顶点纹理坐标
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords));
glBindVertexArray(0);
}
void Mesh::setupArrayMesh()
{
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);
// 顶点位置
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
// 顶点法线
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));
// 顶点纹理坐标
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords));
glBindVertexArray(0);
}
2.12 Model.h
#pragma once
#include <vector>
#include <string>
#include "Mesh.h"
#include <iostream>
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include "stb_image.h"
class Model
{
public:
/* 函数 */
Model(std::string path);
void Draw(Shader * shader);
private:
/* 模型数据 */
std::vector<Mesh> meshes;
std::string directory;
std::vector<Texture> textures_loaded;
/* 函数 */
void loadModel(std::string path);
void processNode(aiNode* node, const aiScene* scene);
Mesh processMesh(aiMesh* mesh, const aiScene* scene);
std::vector<Texture> loadMaterialTextures(aiMaterial* mat, aiTextureType type,std::string typeName);
unsigned int TextureFromFile(const char *path, const std::string &directory);
};
2.13 Model.cpp
#include "Model.h"
Model::Model(std::string path)
{
loadModel(path);
}
void Model::loadModel(std::string path)
{
Assimp::Importer import;
const aiScene* scene = import.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_CalcTangentSpace);
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
{
std::cout << "ERROR::ASSIMP::" << import.GetErrorString() << std::endl;
return;
}
directory = path.substr(0, path.find_last_of('\\'));
//std::cout << "Success!" << directory << std::endl;
processNode(scene->mRootNode, scene);
}
void Model::processNode(aiNode* node, const aiScene* scene)
{
// 处理节点所有的网格
for (unsigned int i = 0; i < node->mNumMeshes; i++)
{
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
meshes.push_back(processMesh(mesh, scene));
}
// 接下来对它的子节点重复这一过程
for (unsigned int i = 0; i < node->mNumChildren; i++)
{
processNode(node->mChildren[i], scene);
}
}
Mesh Model::processMesh(aiMesh *mesh, const aiScene *scene)
{
std::vector<Vertex> vertices;
std::vector<unsigned int> indices;
std::vector<Texture> textures;
// 处理顶点位置、法线和纹理坐标
for (unsigned int i = 0; i < mesh->mNumVertices; i++)
{
Vertex vertex;
glm::vec3 vector;
// 位置
vector.x = mesh->mVertices[i].x;
vector.y = mesh->mVertices[i].y;
vector.z = mesh->mVertices[i].z;
vertex.Position = vector;
// 法向
vector.x = mesh->mNormals[i].x;
vector.y = mesh->mNormals[i].y;
vector.z = mesh->mNormals[i].z;
vertex.Normal = vector;
// 纹理坐标
if (mesh->mTextureCoords[0]) // 是否存在
{
glm::vec2 vec;
// Assimp允许一个模型在一个顶点上有最多8个不同的纹理坐标,
// 我们不会用到那么多,我们只关心第一组纹理坐标。
vec.x = mesh->mTextureCoords[0][i].x;
vec.y = mesh->mTextureCoords[0][i].y;
vertex.TexCoords = vec;
}
else
{
vertex.TexCoords = glm::vec2(0.0f, 0.0f);
}
vertices.push_back(vertex);
}
// 处理索引
for (unsigned int i = 0; i < mesh->mNumFaces; i++)
{
aiFace face = mesh->mFaces[i];
for (unsigned int j = 0; j < face.mNumIndices; j++)
indices.push_back(face.mIndices[j]);
}
// 处理材质
if (mesh->mMaterialIndex >= 0)
{
aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex];
std::vector<Texture> diffuseMaps = loadMaterialTextures(material,
aiTextureType_DIFFUSE, "texture_diffuse");
textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
std::vector<Texture> specularMaps = loadMaterialTextures(material,
aiTextureType_SPECULAR, "texture_specular");
textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
}
// return a mesh object created from the extracted mesh data
return Mesh(vertices, indices, textures);
}
std::vector<Texture> Model::loadMaterialTextures(aiMaterial * mat, aiTextureType type, std::string typeName)
{
std::vector<Texture> textures;
for (unsigned int i = 0; i < mat->GetTextureCount(type); i++)
{
aiString str;
mat->GetTexture(type, i, &str);
bool skip = false;
for (unsigned int j = 0; j < textures_loaded.size(); j++)
{
if (std::strcmp(textures_loaded[j].path.data(), str.C_Str()) == 0)
{
textures.push_back(textures_loaded[j]);
skip = true;
break;
}
}
if (!skip)
{ // 如果纹理还没有被加载,则加载它
Texture texture;
texture.id = TextureFromFile(str.C_Str(), directory);
texture.type = typeName;
texture.path = str.C_Str();
textures.push_back(texture);
textures_loaded.push_back(texture); // 添加到已加载的纹理中
}
}
return textures;
}
unsigned int Model::TextureFromFile(const char *path, const std::string &directory)
{
std::string filename = std::string(path);
filename = directory + '\\' + filename;
unsigned int textureID;
glGenTextures(1, &textureID);
int width, height, nrComponents;
unsigned char *data = stbi_load(filename.c_str(), &width, &height, &nrComponents, 0);
if (data)
{
GLenum format;
if (nrComponents == 1)
format = GL_RED;
else if (nrComponents == 3)
format = GL_RGB;
else if (nrComponents == 4)
format = GL_RGBA;
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
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);
stbi_image_free(data);
}
else
{
std::cout << "Texture failed to load at path: " << path << std::endl;
stbi_image_free(data);
}
return textureID;
}
void Model::Draw(Shader * shader)
{
for (unsigned int i = 0; i < meshes.size(); i++)
meshes[i].DrawElements(shader);
}
2.14 LightSpot.h
#pragma once
#include <glm/glm.hpp>
#include <glm/gtx/rotate_vector.hpp>
class LightSpot
{
public:
LightSpot(glm::vec3 _position, glm::vec3 _angles, glm::vec3 _color = glm::vec3(1.0f, 1.0f, 1.0f));
glm::vec3 position;
glm::vec3 angles;
glm::vec3 direction = glm::vec3(0, 0, 1.0f);
glm::vec3 color;
float cosPhyInner =0.9f;
float cosPhyOuter = 0.85f;
float constant;
float linear;
float quadratic;
void UpdateDiection();
};
2.15 LightSpot.cpp
#include "LightSpot.h"
LightSpot::LightSpot(glm::vec3 _position, glm::vec3 _angles, glm::vec3 _color):
position(_position),
angles(_angles),
color(_color)
{
constant = 1.0f;
linear = 0.09f;
quadratic = 0.032f;
UpdateDiection();
}
void LightSpot::UpdateDiection()
{
direction = glm::vec3(0, 0, 1.0f);//pointing to Z
direction = glm::rotateZ(direction, glm::radians(angles.z));
direction = glm::rotateX(direction, glm::radians(angles.x));
direction = glm::rotateY(direction, glm::radians(angles.y));
direction *= -1.0f;
}
2.16 LightPoint.h
#pragma once
#include <glm/glm.hpp>
#include <glm/gtx/rotate_vector.hpp>
class LightPoint
{
public:
LightPoint(glm::vec3 _position, glm::vec3 _color = glm::vec3(1.0f, 1.0f, 1.0f));
glm::vec3 position;
glm::vec3 color;
float constant;
float linear;
float quadratic;
};
2.17 LightPoint.cpp
#include "LightPoint.h"
LightPoint::LightPoint(glm::vec3 _position, glm::vec3 _color):
position(_position),
color(_color)
{
constant = 1.0f;
linear = 0.09f;
quadratic = 0.032f;
}
2.18 LightDirectional.h
#pragma once
#include <glm/glm.hpp>
#include <glm/gtx/rotate_vector.hpp>
class LightDirectional
{
public:
LightDirectional(glm::vec3 _angles, glm::vec3 _color = glm::vec3(1.0f,1.0f,1.0f));
glm::vec3 angles;
glm::vec3 direction=glm::vec3(0,0,1.0f);
glm::vec3 color;
void UpdateDiection();
};
2.19 LightDirectional.cpp
#include "LightDirectional.h"
LightDirectional::LightDirectional(glm::vec3 _angles, glm::vec3 _color):
angles(_angles),
color(_color)
{
UpdateDiection();
}
void LightDirectional::UpdateDiection() {
direction = glm::vec3(0, 0, 1.0f);//这是光线方向
direction = glm::rotateZ(direction, glm::radians(angles.z));
direction = glm::rotateX(direction, glm::radians(angles.x));
direction = glm::rotateY(direction, glm::radians(angles.y));
//这是指向光的方向(与光线相反)
direction *= -1.0f;
}