1.开发语言:C++语言
2.IDE:VS2022
3.开发用时:一周
4.本项目是OpenGL官方文档https://learnopengl.com中《入门》栏目的案例,素材和函数功能都可在官方文档找到。
5.源码已上传到我的GitHub,链接:https://github.com/2394799692/OpenGLpractice1 或点此跳转
以下是本篇文章正文内容,欢迎朋友们进行指正,一起探讨,共同进步。——来自读研路上的lwj。QQ:2394799692(请标明来意)
链接:https://pan.baidu.com/s/1dtXE22PZw14hif0ui3r2qA?pwd=z22g 提取码:z22g
定义源文件Camera.cpp中所使用到的函数和变量,这两个文件的作用是定义鼠标为摄像机的位置,从而实现在3维坐标中上下左右的移动
#pragma once#include
#include class Camera
{
public:Camera(glm::vec3 position, glm::vec3 target, glm::vec3 worldup);Camera(glm::vec3 position, float pitch, float yaw, glm::vec3 worldup);glm::vec3 Position;glm::vec3 Forward;glm::vec3 Right;glm::vec3 Up;glm::vec3 WorldUp;float Pitch;float Yaw;float SenseX = 0.001f;float SenseY = 0.001f;float speedZ = 0;glm::mat4 GetViewMatrix();void ProcessMouseMovement(float deltaX, float deltaY);void UpdateCameraPos();
private:void UpdateCameraVectors();
};
#include "Camera.h"Camera::Camera(glm::vec3 position, glm::vec3 target, glm::vec3 worldup)
{Position = position;WorldUp = worldup;Forward = glm::normalize(target - position);//转为单位向量Right = glm::normalize(glm::cross(Forward, WorldUp));//cross是叉乘的意思Up = glm::normalize(glm::cross(Forward, Right));
}
Camera::Camera(glm::vec3 position, float pitch, float yaw, glm::vec3 worldup)
{Position = position;WorldUp = worldup;Pitch = pitch;Yaw = yaw;Forward.x = glm::cos(Pitch) * glm::sin(Yaw);Forward.y = glm::sin(Pitch); Forward.z = glm::cos(Pitch) * glm::cos(Yaw);Right = glm::normalize(glm::cross(Forward, WorldUp));//cross是叉乘的意思Up = glm::normalize(glm::cross(Forward, Right));
}glm::mat4 Camera::GetViewMatrix()
{return glm::lookAt(Position, Position + Forward, WorldUp);
}
void Camera::UpdateCameraVectors()
{Forward.x = glm::cos(Pitch) * glm::sin(Yaw);Forward.y = glm::sin(Pitch);Forward.z = glm::cos(Pitch) * glm::cos(Yaw);Right = glm::normalize(glm::cross(Forward, WorldUp));//cross是叉乘的意思Up = glm::normalize(glm::cross(Forward, Right));
}
void Camera::ProcessMouseMovement(float deltaX, float deltaY)
{Pitch -= deltaY* SenseX;Yaw -= deltaX* SenseY;UpdateCameraVectors();
}
void Camera::UpdateCameraPos()
{Position += Forward*speedZ*0.01f;
}
结合shader.cpp和着色器资源实现渲染/着色功能
#pragma once
#include
using namespace std;
class Shader
{
public:Shader(const char* vertexPath,const char* fragmentPath);string vertexString;string fragmentString;const char* vertexSource;const char* fragmentSource;unsigned int ID;//shader program idvoid use();private:void checkCompileErrors(unsigned int ID, std::string type);
};
#include "Shader.h"
#include
#include
#include
#define GLEW_STATIC
#include
#include
using namespace std;
//shader命名空间下的shader方法
Shader::Shader(const char* vertexPath, const char* fragmentPath)
{ifstream vertexFile;ifstream fragmentFile;stringstream vertexSStream;stringstream fragmentSStream;vertexFile.open(vertexPath);fragmentFile.open(fragmentPath);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();vertexString = vertexSStream.str();fragmentString = fragmentSStream.str();vertexSource = vertexString.c_str();fragmentSource = fragmentString.c_str();unsigned int vertex, fragment;//承载gpu返还的shadervertex = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertex, 1, &vertexSource, NULL);glCompileShader(vertex);checkCompileErrors(vertex, "VERIEX");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::checkCompileErrors(unsigned int ID, string type)
{int success;char infoLog[512];if (type != "PROGRAM"){glGetShaderiv(ID, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(ID, 512, NULL, infoLog);cout << "shader compile error:" << infoLog << endl;}}else{glGetProgramiv(ID, GL_LINK_STATUS, &success);if (!success){glGetProgramInfoLog(ID, 512, NULL, infoLog);cout << "program link error:" << infoLog << endl;}}
}
#include
#define GLEW_STATIC
#include
#include#include "Shader.h"#include
#include
#include
#include "Camera.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
//float vertices[] = {
// // ---- 位置 ---- ---- 颜色 ---- - 纹理坐标 -
// 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 右上
// 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 右下
// -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // 左下
// -0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // 左上
//};
float vertices[] = {-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,0.5f, -0.5f, -0.5f, 1.0f, 0.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f,-0.5f, 0.5f, 0.5f, 0.0f, 1.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,-0.5f, 0.5f, -0.5f, 1.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,0.5f, -0.5f, -0.5f, 0.0f, 1.0f,0.5f, -0.5f, -0.5f, 0.0f, 1.0f,0.5f, -0.5f, 0.5f, 0.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,0.5f, -0.5f, -0.5f, 1.0f, 1.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,-0.5f, 0.5f, 0.5f, 0.0f, 0.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f
};
unsigned int indices[] = {0,1,2,2,3,0
}; 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)
};float lastX;
float lastY;
bool firstMouse = true;
//引入class类//Camera camera(glm::vec3(0,0,3.0f),glm::vec3(0,0,0),glm::vec3(0,1.0f,0));
Camera camera(glm::vec3(0, 0, 3.0f), glm::radians(15.0f), glm::radians(180.0f), glm::vec3(0, 1.0f, 0));
void processInput(GLFWwindow* window)
{if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS){glfwSetWindowShouldClose(window, true);}if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS){camera.speedZ=1.0f;}else if(glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS){camera.speedZ = -1.0f;}else {camera.speedZ = 0;}}
void mouse_callback(GLFWwindow* window, double xPos, double yPos)
{if (firstMouse == true){lastX = xPos;lastY = yPos;firstMouse = false;}float deltaX, deltaY;deltaX = xPos - lastX;deltaY = yPos - lastY;lastX = xPos;lastY = yPos;camera.ProcessMouseMovement(deltaX, deltaY);/*printf("%f \n", deltaX);*/
}
int main()
{glfwInit();//初始化glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//打开一个窗体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);//init glewglewExperimental = true;if (glewInit() != GLEW_OK){printf("Init GLEW failed.");glfwTerminate();return -1;}glViewport(0, 0, 800, 600);glEnable(GL_CULL_FACE);glCullFace(GL_BACK);//背面剔除,正面:GL_FRONT//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);//显示边框glEnable(GL_DEPTH_TEST);//做深度缓冲Shader* myShader = new Shader("vertexSource.txt", "fragmentSource.txt");unsigned int VAO;glGenVertexArrays(1, &VAO);glBindVertexArray(VAO); unsigned int VBO;glGenBuffers(1, &VBO);glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);unsigned int EBO;glGenBuffers(1, &EBO);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);/*glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));glEnableVertexAttribArray(1);*/glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));glEnableVertexAttribArray(2);unsigned int TexBufferA;glGenTextures(1, &TexBufferA);glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, TexBufferA);int width, height, nrChannel;stbi_set_flip_vertically_on_load(true);//图像翻转unsigned char* data = stbi_load("container.jpg", &width, &height, &nrChannel, 0);if (data){glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);glGenerateMipmap(GL_TEXTURE_2D);}else{printf("load image failed.");}stbi_image_free(data);unsigned int TexBufferB;//载入笑脸glGenTextures(1, &TexBufferB);glActiveTexture(GL_TEXTURE3);glBindTexture(GL_TEXTURE_2D, TexBufferB);unsigned char* data2 = stbi_load("awesomeface.png", &width, &height, &nrChannel, 0);if (data2){glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2);glGenerateMipmap(GL_TEXTURE_2D);}else{printf("load image failed.");}stbi_image_free(data2);glm::mat4 trans;//trans = glm::translate(trans, glm::vec3(-0.01f, 0, 0));//平移//trans = glm::rotate(trans,glm::radians(45.0f), glm::vec3(0, 0, 1.0f));//旋转45度//trans = glm::scale(trans, glm::vec3(2.0f, 2.0f, 2.0f));//缩放glm::mat4 modelMat;modelMat = glm::rotate(modelMat, glm::radians(-45.0f), glm::vec3(0, 1.0f, 1.0f));glm::mat4 viewMat;//viewMat = glm::translate(viewMat, glm::vec3(0, 0, -3.0f));//viewMat = camera.GetViewMatrix();glm::mat4 projMat;projMat = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f);while (!glfwWindowShouldClose(window)){/*glm::mat4 trans;//定义在里面每次重置角度不会转太快trans = glm::translate(trans, glm::vec3(0.5f, -0.5f, 0));trans = glm::rotate(trans, (float)glfwGetTime(), glm::vec3(0, 0, 1.0f));*/processInput(window);glClearColor(0.2f, 0.3f, 0.3f, 1.0f);/*glClear(GL_COLOR_BUFFER_BIT);*/glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//加了一个清除上一轮深度缓冲glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, TexBufferA);glActiveTexture(GL_TEXTURE3);glBindTexture(GL_TEXTURE_2D, TexBufferB);glBindVertexArray(VAO);//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);viewMat = camera.GetViewMatrix();for (int i = 0; i < 10; i++) {glm::mat4 modelMat2;modelMat2 = glm::translate(modelMat2, cubePositions[i]);myShader->use();glUniform1i(glGetUniformLocation(myShader->ID, "ourTexture"), 0);glUniform1i(glGetUniformLocation(myShader->ID, "ourFace"), 3);//glUniformMatrix4fv(glGetUniformLocation(myShader->ID, "transform"), 1, GL_FALSE, glm::value_ptr(trans));glUniformMatrix4fv(glGetUniformLocation(myShader->ID, "modelMat"), 1, GL_FALSE, glm::value_ptr(modelMat2));glUniformMatrix4fv(glGetUniformLocation(myShader->ID, "viewMat"), 1, GL_FALSE, glm::value_ptr(viewMat));glUniformMatrix4fv(glGetUniformLocation(myShader->ID, "projMat"), 1, GL_FALSE, glm::value_ptr(projMat));glDrawArrays(GL_TRIANGLES, 0, 36);//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);}glfwSwapBuffers(window);glfwPollEvents();camera.UpdateCameraPos();}glfwTerminate();return 0;
}
顶点着色器(Vertex Shader)是几个可编程着色器中的一个。如果我们打算做渲染的话,现代OpenGL需要我们至少设置一个顶点和一个片段着色器。
#version 330 core
layout (location=0) in vec3 aPos;
layout (location=1) in vec3 aColor;
layout (location=2) in vec2 aTexCoord; //uniform mat4 transform;
uniform mat4 modelMat;
uniform mat4 viewMat;
uniform mat4 projMat;out vec4 vertexColor;
out vec2 TexCoord;
void main(){ gl_Position=projMat*viewMat*modelMat*vec4(aPos.x,aPos.y,aPos.z,1.0f); vertexColor=vec4(aColor.x,aColor.y,aColor.z,1.0f);TexCoord=aTexCoord;
}
片段着色器(Fragment Shader)是第二个也是最后一个我们打算创建的用于渲染三角形的着色器。片段着色器所做的是计算像素最后的颜色输出。
#version 330 core
in vec4 vertexColor;
in vec2 TexCoord;uniform sampler2D ourTexture;
uniform sampler2D ourFace;out vec4 FragColor;
void main(){ FragColor = mix(texture(ourTexture,TexCoord),texture(ourFace,TexCoord), 0.2);//如果第三个值是0.0,它会返回第一个输入;如果是1.0,会返回第二个输入值。0.2会返回80%的第一个输入颜色和20%的第二个输入颜色,即返回两个纹理的混合色。
}
视频效果:
OpenGL入门demo