视图变换
代码实验
#include <glad/glad.h>//glad必须在glfw头文件之前包含
#include <GLFW/glfw3.h>
#include <iostream>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
//GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/string_cast.hpp>
void frameBufferSizeCallbakc(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
void glfwKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
}
GLuint program = 0;
GLuint vao = 0;
GLuint texture = 0;
glm::mat4 transform(1.0f);//4×4单位矩阵
glm::mat4 viewMatrix(1.0f);
void prepareCamera()
{
//lookat:生成一个viewMatrix
//eye:当前摄像机所在的位置
//center:当前摄像机看向的那个点
//up:穹顶向量
viewMatrix = glm::lookAt(glm::vec3(0.5f, 0.0f, 0.5f), glm::vec3(0.5f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
}
void prepareVAO()
{
//positions
float positions[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f,
};
//颜色
float colors[] = {
1.0f, 0.0f,0.0f,
0.0f, 1.0f,0.0f,
0.0f, 0.0f,1.0f
};
//索引
unsigned int indices[] = {
0, 1, 2,
};
//uv坐标
float uvs[] = {
0.0f, 0.0f,
1.0f, 0.0f,
0.5f, 1.0f,
};
//2 VBO创建
GLuint posVbo = 0;
GLuint colorVbo = 0;
GLuint uvVbo = 0;
glGenBuffers(1, &posVbo);
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
glGenBuffers(1, &colorVbo);
glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
glGenBuffers(1, &uvVbo);
glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(uvs), uvs, GL_STATIC_DRAW);
//3 EBO创建
GLuint ebo = 0;
glGenBuffers(1, &ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
//4 VAO创建
vao = 0;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
//5 绑定vbo ebo 加入属性描述信息
//5.1 加入位置属性描述信息
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
//5.2 加入颜色属性描述信息
glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
//5.3 加入uv属性描述数据
glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
//5.2 加入ebo到当前的vao
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBindVertexArray(0);
}
void prepareShader() {
//1 完成vs与fs的源代码,并且装入字符串
//aPos作为attribute(属性)传入shader不允许更改的
const char* vertexShaderSource =
"#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec3 aColor;\n"
"layout (location = 2) in vec2 aUV;\n"
"out vec3 color;\n"
"out vec2 uv;\n"
"uniform mat4 transform;\n"
"uniform mat4 viewMatrix;\n"
"void main()\n"
"{\n"
" vec4 position = vec4(aPos, 1.0);\n"
" position = viewMatrix * transform * position;\n"
" gl_Position = position;\n"
" color = aColor;\n"
" uv = aUV;\n"
"}\0";
const char* fragmentShaderSource =
"#version 330 core\n"
"out vec4 FragColor;\n"
"in vec3 color;\n"
"in vec2 uv;\n"
"uniform sampler2D sampler;\n"
"void main()\n"
"{\n"
" FragColor = texture(sampler, uv);\n"
"}\n\0";
//2 创建Shader程序(vs、fs)
GLuint vertex, fragment;
vertex = glCreateShader(GL_VERTEX_SHADER);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
//3 为shader程序输入shader代码
glShaderSource(vertex, 1, &vertexShaderSource, NULL);
glShaderSource(fragment, 1, &fragmentShaderSource, NULL);
int success = 0;
char infoLog[1024];
//4 执行shader代码编译
glCompileShader(vertex);
//检查vertex编译结果
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertex, 1024, NULL, infoLog);
std::cout << "Error: SHADER COMPILE ERROR --VERTEX" << "\n" << infoLog << std::endl;
}
glCompileShader(fragment);
//检查fragment编译结果
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragment, 1024, NULL, infoLog);
std::cout << "Error: SHADER COMPILE ERROR --FRAGMENT" << "\n" << infoLog << std::endl;
}
//5 创建一个Program壳子
program = glCreateProgram();
//6 将vs与fs编译好的结果放到program这个壳子里
glAttachShader(program, vertex);
glAttachShader(program, fragment);
//7 执行program的链接操作,形成最终可执行shader程序
glLinkProgram(program);
//检查链接错误
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(program, 1024, NULL, infoLog);
std::cout << "Error: SHADER LINK ERROR " << "\n" << infoLog << std::endl;
}
//清理
glDeleteShader(vertex);
glDeleteShader(fragment);
}
void prepareTextrue()
{
//1 stbImage 读取图片
int width, height, channels;
//--反转y轴
stbi_set_flip_vertically_on_load(true);
unsigned char* data = stbi_load("goku.jpg", &width, &height, &channels, STBI_rgb_alpha);
//2 生成纹理并且激活单元绑定
glGenTextures(1, &texture);
//--激活纹理单元--
glActiveTexture(GL_TEXTURE0);
//--绑定纹理对象--
glBindTexture(GL_TEXTURE_2D, texture);
//3 传输纹理数据,开辟显存
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
//***释放数据
stbi_image_free(data);
//4 设置纹理的过滤方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
//5 设置纹理的包裹方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);//u
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);//v
}
void render()
{
//执行opengl画布清理操作
glClear(GL_COLOR_BUFFER_BIT);
//1.绑定当前的program
glUseProgram(program);
//2 更新Uniform的时候,一定要先UserProgram
//2.1 通过名称拿到Uniform变量的位置Location
GLint location = glGetUniformLocation(program, "sampler");
//2.2 通过Location更新Uniform变量的值
glUniform1f(location, 0);
GLint locationTransform = glGetUniformLocation(program, "transform");
//transpose参数:表示是否对传输进去的矩阵数据进行转置
glUniformMatrix4fv(locationTransform, 1, GL_FALSE, glm::value_ptr(transform));
GLint locationviewMatrix = glGetUniformLocation(program, "viewMatrix");
//transpose参数:表示是否对传输进去的矩阵数据进行转置
glUniformMatrix4fv(locationviewMatrix, 1, GL_FALSE, glm::value_ptr(viewMatrix));
//3 绑定当前的vao
glBindVertexArray(vao);
//4 发出绘制指令
//glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);
}
int main()
{
//初始化glfw环境
glfwInit();
//设置opengl主版本号
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
//设置opengl次版本号
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
//设置opengl启用核心模式
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//创建窗体对象
GLFWwindow* window = glfwCreateWindow(800, 600, "lenarnOpenGL", nullptr, nullptr);
//设置当前窗体对象为opengl的绘制舞台
glfwMakeContextCurrent(window);
//窗体大小回调
glfwSetFramebufferSizeCallback(window, frameBufferSizeCallbakc);
//键盘相应回调
glfwSetKeyCallback(window, glfwKeyCallback);
//使用glad加载所有当前版本opengl的函数
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "初始化glad失败" << std::endl;
return -1;
}
;
//设置opengl视口大小和清理颜色
glViewport(0, 0, 800, 600);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
//shader
prepareShader();
//vao
prepareVAO();
//texture
prepareTextrue();
prepareCamera();
//执行窗体循环
while (!glfwWindowShouldClose(window))
{
//接受并分发窗体消息
//检查消息队列是否有需要处理的鼠标、键盘等消息
//如果有的话就将消息批量处理,清空队列
glfwPollEvents();
//渲染操作
render();
//切换双缓存
glfwSwapBuffers(window);
}
//推出程序前做相关清理
glfwTerminate();
return 0;
}
glm中的lookat参数可以生成视图变换矩阵,设置给VS即可。
正交投影
总结
案例分析
#include <glad/glad.h>//glad必须在glfw头文件之前包含
#include <GLFW/glfw3.h>
#include <iostream>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
//GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/string_cast.hpp>
void frameBufferSizeCallbakc(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
void glfwKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
}
GLuint program = 0;
GLuint vao = 0;
GLuint texture = 0;
glm::mat4 transform(1.0f);//4×4单位矩阵
glm::mat4 viewMatrix(1.0f);
glm::mat4 orthoMatrix(1.0f);
void prepareCamera()
{
//lookat:生成一个viewMatrix
//eye:当前摄像机所在的位置
//center:当前摄像机看向的那个点
//up:穹顶向量
viewMatrix = glm::lookAt(glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
}
void prepareOrtho()
{
//参数为盒体上下左右远近
orthoMatrix = glm::ortho(-2.0f, 2.0f, -2.0f, 2.0f, 2.0f, -2.0f);
}
void prepareVAO()
{
//positions
float positions[] = {
-1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
//颜色
float colors[] = {
1.0f, 0.0f,0.0f,
0.0f, 1.0f,0.0f,
0.0f, 0.0f,1.0f
};
//索引
unsigned int indices[] = {
0, 1, 2,
};
//uv坐标
float uvs[] = {
0.0f, 0.0f,
1.0f, 0.0f,
0.5f, 1.0f,
};
//2 VBO创建
GLuint posVbo = 0;
GLuint colorVbo = 0;
GLuint uvVbo = 0;
glGenBuffers(1, &posVbo);
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
glGenBuffers(1, &colorVbo);
glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
glGenBuffers(1, &uvVbo);
glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(uvs), uvs, GL_STATIC_DRAW);
//3 EBO创建
GLuint ebo = 0;
glGenBuffers(1, &ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
//4 VAO创建
vao = 0;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
//5 绑定vbo ebo 加入属性描述信息
//5.1 加入位置属性描述信息
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
//5.2 加入颜色属性描述信息
glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
//5.3 加入uv属性描述数据
glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
//5.2 加入ebo到当前的vao
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBindVertexArray(0);
}
void prepareShader() {
//1 完成vs与fs的源代码,并且装入字符串
//aPos作为attribute(属性)传入shader不允许更改的
const char* vertexShaderSource =
"#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec3 aColor;\n"
"layout (location = 2) in vec2 aUV;\n"
"out vec3 color;\n"
"out vec2 uv;\n"
"uniform mat4 transform;\n"
"uniform mat4 viewMatrix;\n"
"uniform mat4 orthoMatrix;\n"
"void main()\n"
"{\n"
" vec4 position = vec4(aPos, 1.0);\n"
" position = orthoMatrix * viewMatrix * transform * position;\n"
" gl_Position = position;\n"
" color = aColor;\n"
" uv = aUV;\n"
"}\0";
const char* fragmentShaderSource =
"#version 330 core\n"
"out vec4 FragColor;\n"
"in vec3 color;\n"
"in vec2 uv;\n"
"uniform sampler2D sampler;\n"
"void main()\n"
"{\n"
" FragColor = texture(sampler, uv);\n"
"}\n\0";
//2 创建Shader程序(vs、fs)
GLuint vertex, fragment;
vertex = glCreateShader(GL_VERTEX_SHADER);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
//3 为shader程序输入shader代码
glShaderSource(vertex, 1, &vertexShaderSource, NULL);
glShaderSource(fragment, 1, &fragmentShaderSource, NULL);
int success = 0;
char infoLog[1024];
//4 执行shader代码编译
glCompileShader(vertex);
//检查vertex编译结果
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertex, 1024, NULL, infoLog);
std::cout << "Error: SHADER COMPILE ERROR --VERTEX" << "\n" << infoLog << std::endl;
}
glCompileShader(fragment);
//检查fragment编译结果
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragment, 1024, NULL, infoLog);
std::cout << "Error: SHADER COMPILE ERROR --FRAGMENT" << "\n" << infoLog << std::endl;
}
//5 创建一个Program壳子
program = glCreateProgram();
//6 将vs与fs编译好的结果放到program这个壳子里
glAttachShader(program, vertex);
glAttachShader(program, fragment);
//7 执行program的链接操作,形成最终可执行shader程序
glLinkProgram(program);
//检查链接错误
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(program, 1024, NULL, infoLog);
std::cout << "Error: SHADER LINK ERROR " << "\n" << infoLog << std::endl;
}
//清理
glDeleteShader(vertex);
glDeleteShader(fragment);
}
void prepareTextrue()
{
//1 stbImage 读取图片
int width, height, channels;
//--反转y轴
stbi_set_flip_vertically_on_load(true);
unsigned char* data = stbi_load("goku.jpg", &width, &height, &channels, STBI_rgb_alpha);
//2 生成纹理并且激活单元绑定
glGenTextures(1, &texture);
//--激活纹理单元--
glActiveTexture(GL_TEXTURE0);
//--绑定纹理对象--
glBindTexture(GL_TEXTURE_2D, texture);
//3 传输纹理数据,开辟显存
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
//***释放数据
stbi_image_free(data);
//4 设置纹理的过滤方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
//5 设置纹理的包裹方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);//u
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);//v
}
void render()
{
//执行opengl画布清理操作
glClear(GL_COLOR_BUFFER_BIT);
//1.绑定当前的program
glUseProgram(program);
//2 更新Uniform的时候,一定要先UserProgram
//2.1 通过名称拿到Uniform变量的位置Location
GLint location = glGetUniformLocation(program, "sampler");
//2.2 通过Location更新Uniform变量的值
glUniform1f(location, 0);
GLint locationTransform = glGetUniformLocation(program, "transform");
//transpose参数:表示是否对传输进去的矩阵数据进行转置
glUniformMatrix4fv(locationTransform, 1, GL_FALSE, glm::value_ptr(transform));
GLint locationviewMatrix = glGetUniformLocation(program, "viewMatrix");
glUniformMatrix4fv(locationviewMatrix, 1, GL_FALSE, glm::value_ptr(viewMatrix));
GLint locationorthoMatrix = glGetUniformLocation(program, "orthoMatrix");
glUniformMatrix4fv(locationorthoMatrix, 1, GL_FALSE, glm::value_ptr(orthoMatrix));
//3 绑定当前的vao
glBindVertexArray(vao);
//4 发出绘制指令
//glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);
}
int main()
{
//初始化glfw环境
glfwInit();
//设置opengl主版本号
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
//设置opengl次版本号
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
//设置opengl启用核心模式
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//创建窗体对象
GLFWwindow* window = glfwCreateWindow(800, 600, "lenarnOpenGL", nullptr, nullptr);
//设置当前窗体对象为opengl的绘制舞台
glfwMakeContextCurrent(window);
//窗体大小回调
glfwSetFramebufferSizeCallback(window, frameBufferSizeCallbakc);
//键盘相应回调
glfwSetKeyCallback(window, glfwKeyCallback);
//使用glad加载所有当前版本opengl的函数
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "初始化glad失败" << std::endl;
return -1;
}
;
//设置opengl视口大小和清理颜色
glViewport(0, 0, 800, 600);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
//shader
prepareShader();
//vao
prepareVAO();
//texture
prepareTextrue();
prepareCamera();
prepareOrtho();
//执行窗体循环
while (!glfwWindowShouldClose(window))
{
//接受并分发窗体消息
//检查消息队列是否有需要处理的鼠标、键盘等消息
//如果有的话就将消息批量处理,清空队列
glfwPollEvents();
//渲染操作
render();
//切换双缓存
glfwSwapBuffers(window);
}
//推出程序前做相关清理
glfwTerminate();
return 0;
}
在vao中给入模型坐标,模型坐标经过变换后转换成世界坐标,世界坐标经过视图变换矩阵变换为相机坐标,相机坐标经过正交投影变换为NDC坐标。
在构造正交投影矩阵过程中,传入的参数为盒体的大小,只有在盒体范围内的坐标点才会保留,范围外的将会被裁剪。
透视投影
例子
#include <glad/glad.h>//glad必须在glfw头文件之前包含
#include <GLFW/glfw3.h>
#include <iostream>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
//GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/string_cast.hpp>
void frameBufferSizeCallbakc(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
void glfwKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
}
GLuint program = 0;
GLuint vao = 0;
GLuint texture = 0;
glm::mat4 transform(1.0f);//4×4单位矩阵
glm::mat4 viewMatrix(1.0f);
glm::mat4 orthoMatrix(1.0f);
glm::mat4 perspectiveMatrix(1.0f);
void prepareCamera()
{
//lookat:生成一个viewMatrix
//eye:当前摄像机所在的位置
//center:当前摄像机看向的那个点
//up:穹顶向量
viewMatrix = glm::lookAt(glm::vec3(0.0f, 0.0f, 5.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
}
void prepareOrtho()
{
//参数为盒体上下左右远近
orthoMatrix = glm::ortho(-2.0f, 2.0f, -2.0f, 2.0f, 2.0f, -2.0f);
}
void preparePerspective()
{
//fovy:y轴方向的视张角,弧度单位
//aspect:近平面的横纵百分比
//near:近平面距离
//far:远平面距离
perspectiveMatrix = glm::perspective(glm::radians(60.0f), 800.0f / 600, 0.1f, 1000.0f);
}
void prepareVAO()
{
//positions
float positions[] = {
-1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
//颜色
float colors[] = {
-1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
//索引
unsigned int indices[] = {
0, 1, 2,
};
//uv坐标
float uvs[] = {
0.0f, 0.0f,
1.0f, 0.0f,
0.5f, 1.0f,
};
//2 VBO创建
GLuint posVbo = 0;
GLuint colorVbo = 0;
GLuint uvVbo = 0;
glGenBuffers(1, &posVbo);
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
glGenBuffers(1, &colorVbo);
glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
glGenBuffers(1, &uvVbo);
glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(uvs), uvs, GL_STATIC_DRAW);
//3 EBO创建
GLuint ebo = 0;
glGenBuffers(1, &ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
//4 VAO创建
vao = 0;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
//5 绑定vbo ebo 加入属性描述信息
//5.1 加入位置属性描述信息
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
//5.2 加入颜色属性描述信息
glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
//5.3 加入uv属性描述数据
glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
//5.2 加入ebo到当前的vao
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBindVertexArray(0);
}
void prepareShader() {
//1 完成vs与fs的源代码,并且装入字符串
//aPos作为attribute(属性)传入shader不允许更改的
const char* vertexShaderSource =
"#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec3 aColor;\n"
"layout (location = 2) in vec2 aUV;\n"
"out vec3 color;\n"
"out vec2 uv;\n"
"uniform mat4 transform;\n"
"uniform mat4 viewMatrix;\n"
"uniform mat4 perspectiveMatrix;\n"
"void main()\n"
"{\n"
" vec4 position = vec4(aPos, 1.0);\n"
" position = perspectiveMatrix * viewMatrix * transform * position;\n"
" gl_Position = position;\n"
" color = aColor;\n"
" uv = aUV;\n"
"}\0";
const char* fragmentShaderSource =
"#version 330 core\n"
"out vec4 FragColor;\n"
"in vec3 color;\n"
"in vec2 uv;\n"
"uniform sampler2D sampler;\n"
"void main()\n"
"{\n"
" FragColor = texture(sampler, uv);\n"
"}\n\0";
//2 创建Shader程序(vs、fs)
GLuint vertex, fragment;
vertex = glCreateShader(GL_VERTEX_SHADER);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
//3 为shader程序输入shader代码
glShaderSource(vertex, 1, &vertexShaderSource, NULL);
glShaderSource(fragment, 1, &fragmentShaderSource, NULL);
int success = 0;
char infoLog[1024];
//4 执行shader代码编译
glCompileShader(vertex);
//检查vertex编译结果
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertex, 1024, NULL, infoLog);
std::cout << "Error: SHADER COMPILE ERROR --VERTEX" << "\n" << infoLog << std::endl;
}
glCompileShader(fragment);
//检查fragment编译结果
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragment, 1024, NULL, infoLog);
std::cout << "Error: SHADER COMPILE ERROR --FRAGMENT" << "\n" << infoLog << std::endl;
}
//5 创建一个Program壳子
program = glCreateProgram();
//6 将vs与fs编译好的结果放到program这个壳子里
glAttachShader(program, vertex);
glAttachShader(program, fragment);
//7 执行program的链接操作,形成最终可执行shader程序
glLinkProgram(program);
//检查链接错误
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(program, 1024, NULL, infoLog);
std::cout << "Error: SHADER LINK ERROR " << "\n" << infoLog << std::endl;
}
//清理
glDeleteShader(vertex);
glDeleteShader(fragment);
}
void prepareTextrue()
{
//1 stbImage 读取图片
int width, height, channels;
//--反转y轴
stbi_set_flip_vertically_on_load(true);
unsigned char* data = stbi_load("goku.jpg", &width, &height, &channels, STBI_rgb_alpha);
//2 生成纹理并且激活单元绑定
glGenTextures(1, &texture);
//--激活纹理单元--
glActiveTexture(GL_TEXTURE0);
//--绑定纹理对象--
glBindTexture(GL_TEXTURE_2D, texture);
//3 传输纹理数据,开辟显存
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
//***释放数据
stbi_image_free(data);
//4 设置纹理的过滤方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
//5 设置纹理的包裹方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);//u
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);//v
}
void render()
{
//执行opengl画布清理操作
glClear(GL_COLOR_BUFFER_BIT);
//1.绑定当前的program
glUseProgram(program);
//2 更新Uniform的时候,一定要先UserProgram
//2.1 通过名称拿到Uniform变量的位置Location
GLint location = glGetUniformLocation(program, "sampler");
//2.2 通过Location更新Uniform变量的值
glUniform1f(location, 0);
GLint locationTransform = glGetUniformLocation(program, "transform");
//transpose参数:表示是否对传输进去的矩阵数据进行转置
glUniformMatrix4fv(locationTransform, 1, GL_FALSE, glm::value_ptr(transform));
GLint locationviewMatrix = glGetUniformLocation(program, "viewMatrix");
glUniformMatrix4fv(locationviewMatrix, 1, GL_FALSE, glm::value_ptr(viewMatrix));
GLint locationperspectiveMatrix = glGetUniformLocation(program, "perspectiveMatrix");
glUniformMatrix4fv(locationperspectiveMatrix, 1, GL_FALSE, glm::value_ptr(perspectiveMatrix));
//3 绑定当前的vao
glBindVertexArray(vao);
//4 发出绘制指令
//glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);
}
int main()
{
//初始化glfw环境
glfwInit();
//设置opengl主版本号
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
//设置opengl次版本号
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
//设置opengl启用核心模式
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//创建窗体对象
GLFWwindow* window = glfwCreateWindow(800, 600, "lenarnOpenGL", nullptr, nullptr);
//设置当前窗体对象为opengl的绘制舞台
glfwMakeContextCurrent(window);
//窗体大小回调
glfwSetFramebufferSizeCallback(window, frameBufferSizeCallbakc);
//键盘相应回调
glfwSetKeyCallback(window, glfwKeyCallback);
//使用glad加载所有当前版本opengl的函数
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "初始化glad失败" << std::endl;
return -1;
}
;
//设置opengl视口大小和清理颜色
glViewport(0, 0, 800, 600);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
//shader
prepareShader();
//vao
prepareVAO();
//texture
prepareTextrue();
prepareCamera();
preparePerspective();
//执行窗体循环
while (!glfwWindowShouldClose(window))
{
//接受并分发窗体消息
//检查消息队列是否有需要处理的鼠标、键盘等消息
//如果有的话就将消息批量处理,清空队列
glfwPollEvents();
//渲染操作
render();
//切换双缓存
glfwSwapBuffers(window);
}
//推出程序前做相关清理
glfwTerminate();
return 0;
}