文章目录
- 渲染成果
- Assimp库准备:
- Mesh类修改:
- 透明贴图使用:
- 光源封装:
- 使用方式在如下测试环境中:
渲染成果
Assimp库准备:
从GitHub拉取源码,根据网络教程,借助CMake生成VS工程项目,并用VS将其编译为静态链接库(lib)或动态链接库(dll + lib)。最后将其库文件和工程内的include文件复制到图形工程下。
Mesh类修改:
在抽象Model,Mesh这些类时,我改动LearnOpenGL的最大的类是Mesh类,将其直接使用的GLAPI替换成了封装好的API,类如下。修改的数据结构在Model中修改相应的数据存放方法即可
//Mesh.h
#pragma once
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <vector>
#include "Shader.h"
#include "VertexArray.h"
#include "VertexBuffer.h"
#include "VertexBufferLayout.h"
#include "IndexBuffer.h"
#include "Texture.h"
using namespace std;
struct Vertex
{
glm::vec3 Position;
glm::vec3 Normal;
glm::vec2 TexCoords;
};
struct TextureData
{
string name;
Texture* texture;
};
class Mesh
{
public:
vector<Vertex> vertices;
vector<GLuint> indices;
vector<TextureData> textures;
Mesh(vector<Vertex> vertices, vector<GLuint> indices, vector<TextureData> textures);
void Draw(Renderer& renderer, Shader& shader);
private:
VertexArray VAO;
VertexBuffer VBO;
IndexBuffer EBO;
void setupMesh();
};
//Mesh.cpp
#include "Mesh.h"
Mesh::Mesh(vector<Vertex> vertices, vector<GLuint> indices, vector<TextureData> textures)
{
this->vertices = vertices;
this->indices = indices;
this->textures = textures;
this->setupMesh();
}
void Mesh::setupMesh()
{
VAO.Bind();
VBO.Init(&vertices[0], vertices.size() * sizeof(Vertex));
EBO.Init(&indices[0], indices.size());
VAO.AddVertexBuffer(VBO);
VAO.Unbind();
}
void Mesh::Draw(Renderer& renderer, Shader& shader)
{
for (int i = 0; i < textures.size(); i++)
{
textures[i].texture->Bind(i);
shader.SetUniform1i(textures[i].name, i);
}
renderer.Draw(VAO, EBO, shader);
}
透明贴图使用:
我所需要绘制的模型有半透明的面部贴图,因此需要使用透明度,这里需要注意的是,如果所有使用数据获取数据的地方都没有出错但仍没有透明效果,可以检查原始数据的问题,如图片本身的透明效果,在工程中加载图片时是否包含透明通道。
//shader
void main()
{
vec3 norm = normalize(Normal);
vec3 viewDir = normalize(viewPos - FragPos);
//透明测试
vec4 texColor = texture(texture_diffuse, TexCoords);
if(texColor.a < 0.2 && mixFactor == 0)
discard;
//光照着色
color = vec4(CalcPointLight(light, norm, FragPos, viewDir), 1);
}
光源封装:
每次使用光源需要大段的赋值语句,因此对其进行简单封装,目前只封装了点光源
//Light.h
#pragma once
#include <iostream>
#include <glm/glm.hpp>
#include "Shader.h"
using namespace std;
class Light
{
public:
Light(
glm::vec3 position = { 1.2f, 1.0f, 2.0f },
glm::vec3 ambient = { 0.4, 0.4, 0.4 },
glm::vec3 diffuse = { 1.2, 1.2, 1.2 },
glm::vec3 specular = { 0.1, 0.1, 0.1 },
float constant = 1,
float linear = 0.09,
float quadratic = 0.032);
void SetupShader(Shader& shader, string lightName);
private:
glm::vec3 m_Position;
glm::vec3 m_Ambient;
glm::vec3 m_Diffuse;
glm::vec3 m_Specular;
float m_Constant;
float m_Linear;
float m_Quadratic;
};
//Light.cpp
#include "Light.h"
Light::Light(glm::vec3 position, glm::vec3 ambient, glm::vec3 diffuse, glm::vec3 specular, float constant, float linear, float quadratic)
{
m_Position = position;
m_Ambient = ambient;
m_Diffuse = diffuse;
m_Specular = specular;
m_Constant = constant;
m_Linear = linear;
m_Quadratic = quadratic;
}
void Light::SetupShader(Shader& shader, std::string lightName)
{
shader.SetUniform3f(lightName + ".position", m_Position.x, m_Position.y, m_Position.z);
shader.SetUniform3f(lightName + ".ambient", m_Ambient.x, m_Ambient.y, m_Ambient.z);
shader.SetUniform3f(lightName + ".diffuse", m_Diffuse.x, m_Diffuse.y, m_Diffuse.z);
shader.SetUniform3f(lightName + ".specular", m_Specular.x, m_Specular.y, m_Specular.z);
shader.SetUniform1f(lightName + ".constant", m_Constant);
shader.SetUniform1f(lightName + ".linear", m_Linear);
shader.SetUniform1f(lightName + ".quadratic", m_Quadratic);
}
使用方式在如下测试环境中:
#pragma once
#include "RunBase.h"
#include "Model.h"
#include "Light.h"
#include <glm/gtc/type_ptr.hpp>
class AssimpTest : public RunBase
{
public:
Model* body, *blue, *ear, *eye, *mao, *mouth;
Shader diffuseShader;
Renderer renderer;
Light light;
AssimpTest() : RunBase()
{
diffuseShader.Init("res/shaders/AssimpTest.shader");
}
virtual void Init(GLFWwindow* window, float targetFrameTime) override
{
/*GLCall(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC1_ALPHA));
GLCall(glEnable(GL_BLEND));*/
body = new Model("res/models/jixuanyou/body.obj");
blue = new Model("res/models/jixuanyou/blue.obj");
ear = new Model("res/models/jixuanyou/ear.obj");
eye = new Model("res/models/jixuanyou/eye.obj");
mao = new Model("res/models/jixuanyou/mao.obj");
mouth = new Model("res/models/jixuanyou/mouth.obj");
}
virtual void RenderLoop(GLFWwindow* window, float targetFrameTime) override
{
renderer.Clear();
//绘制受光物体
diffuseShader.Bind();
//视图矩阵(透视参数)
glm::mat4 view(1), proj(1), model(1);
view = camera.GetViewMatrix();
proj = glm::perspective<GLfloat>(45, 640 / 480, .1f, 100.f);
//赋值透视
diffuseShader.SetUniformMat4f("view", glm::value_ptr(view));
diffuseShader.SetUniformMat4f("projection", glm::value_ptr(proj));
diffuseShader.SetUniformMat4f("model", glm::value_ptr(model));
//赋值光照
light.SetupShader(diffuseShader, "light");
//赋值视图位置
diffuseShader.SetUniform3f("viewPos", camera.Position.x, camera.Position.y, camera.Position.z);
diffuseShader.SetUniform1f("shininess", 4);
// 取消纯色
diffuseShader.SetUniform1f("mixFactor", 0);
//不透明物件
body->Draw(renderer, diffuseShader);
ear->Draw(renderer, diffuseShader);
eye->Draw(renderer, diffuseShader);
mouth->Draw(renderer, diffuseShader);
// 使用纯色
diffuseShader.SetUniform1f("mixFactor", 1);
// 浅蓝色
diffuseShader.SetUniform3f("diffuseColor", 0.50, 0.66, 0.81);
mao->Draw(renderer, diffuseShader);
// 深蓝色
diffuseShader.SetUniform3f("light.diffuse", 4, 4, 4);
diffuseShader.SetUniform3f("light.specular", 0.5, 0.5, 0.5);
diffuseShader.SetUniform3f("diffuseColor", 0.022, 0.06, 0.21);
blue->Draw(renderer, diffuseShader);
}
virtual bool UseCameraControl() override
{
return true;
}
};