LearnOpenGL学习笔记—模型加载:复习与总结

【项目地址:点击这里这里这里

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;
}
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值