1.当片段着色器处理完一个片段之后,模板测试(stencil test)会开始执行,和深度测试一样,它也可能会丢弃片段,接下来,被保留的片段会进入深度测试
2.每个窗口库都需要为你配置一个模板缓冲,但是GLFW这个窗口库会自动做这件事,所以不用告诉GLFW来创建一个模板缓冲
3.场景中的片段将只会在片段的模板值为1的时候被渲染,其他的都被丢弃了
启用模板缓冲的写入
渲染物体,更新模板缓冲的内容
禁用模板缓冲的写入
渲染其他物体,这次根据模板缓冲的内容丢弃特定的片段


用来配置模板缓冲的两个函数,glStencilFunc和glStencilOp
glStencilFunc(GLenum func, GLint ref, GLuint mash)一共包含三个参数:
func:设置模板测试函数(Stencil Test Function),这个测试函数将会应用到已存储的的模板值上和GLstenciFunc函数的ref值上,
可用的选项有:GL_NEVER/ GL_LESS/ GL_LEQUAL / GL_GREATER / GL_AEAUAL / GL_EQUAL / GL_NOTEQUAL和 GL_ALWAYS
ref:设置了模板测试的参考值(Reference Value), 模板缓冲的内容将会与这个值进行比较
mask:设置一个掩码,它将会与参考值和村初值在测试比较他们之前进行与(and)运算,初识情况下所有为都为1


但是glStencilFunc只描述了OpenGL应该对模板缓冲内容做什么,而不是我们应该如何更新缓冲,所以就需要glStencilOp这个函数了
glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass)一共包含三个选项,我们能够设置每个选项应该采取的行为
sfail:模板测试失败是采取的行为
dpfail:模板测试通过,但深度测试失败采取的行为
dppass:模板测试和深度测试都通过时采取的行为


  1 /**
* glBlendFunc混合两种颜色的函数
*glBlendFunc(GLenum sfactor, GLenum dfactor)函数接受两个参数,来设置源和目标因子
*常数颜色向量Cconstan可以通过glBlendColor函数来另外设置*
*glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
*也可以使用glBlendFuncSeparate为RGB和alpha通道分别设置不同的选项
* glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_GL_ZERO);
*glBlendEquation(GLenum mode)允许我们设置运算符
*GL_FUNC_ADD:默认选项,将两个分量相加,Cr = S + D
*GL_FUNC_SUBTRACT = S - D
*GL_FUNC_REVERSE_SUBTRACT,将两个分量向减,但顺序相反*/ /**
*当绘制一个有不透明和透明物体的场景的时候,大体的原则如下:
*1.先绘制所有不透明的物体。
*2.对所有透明的物体排序。
*3.按顺序绘制所有透明的物体。**/ #include <iostream>
#include <vector>
#include <map> using namespace std;
#define GLEW_STATIC #include <GL/glew.h>
#include <GLFW/glfw3.h> #include "stb_image.h" #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp> #include "Shader.h"
#include "camera.h"
//#include "Model.h" void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void processInput(GLFWwindow* window);
unsigned int loadTexture(const char *path); //setting
const unsigned int SCR_WIDTH = ;
const unsigned int SCR_HEIGHT = ; //camera
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
float lastX = (float)SCR_WIDTH / ;
float lastY = (float)SCR_HEIGHT / ;
bool firstMouse = true; //timing
float deltaTime = 0.0f;
float lastFrame = 0.0f; int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, );
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, );
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LEARNOPENGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create window!" << std::endl;
glfwTerminate();
return -;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback); //tell GLFW to capture our mouse
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK)
{
std::cout << "Failed to initialize GLEW!" << std::endl;
return -;
} ////configure global opengl state
//glEnable(GL_DEPTH_TEST); //启用深度测试,默认情况下是禁用的
//glDepthFunc(GL_LESS); //always pass the depth test(same effect as glDisable(GL_DEPTH_TEST)//禁用深度测试,永远都通过深度测试
////glDepthMask(GL_FALSE); //深度掩码,可以禁用深度缓冲的写入 //glEnable(GL_STENCIL_TEST);
////glStencilMask(0x00); //位掩码, 每个模板值都为0, 每一位在写入模板缓冲时都会变成0(禁用写入)
//glStencilMask(0xff); //每个模板值都为1,每一位写入模板缓冲时都保持原样 //glStencilFunc(GL_EQUAL, 1, 0xFF); //只要一个片段的模板值等于参考值1,片段将会通过测试并被绘制,否则会被被丢弃
//glStencilOp(GL_INCR_WRAP, GL_INCR_WRAP, GL_INCR_WRAP);//默认情况下,glStencilOp是设置为这样的,所以不论任何测试的结果是如何,模板缓冲都会保留它的值
////默认的行为不会更新模板缓冲,所以如果你想写入模板缓冲的话,至少对其中一个选项设置不同的值
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glEnable(GL_BLEND); //启用混合
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //build and compile shaders
Shader shader("E:\\C++\\HigherOpenGL\\1.2.1ver1.txt", "E:\\C++\\HigherOpenGL\\1.3.2Frag1.txt"); float cubeVertices[] = {
//position //texture Coords
-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
}; float floorVertices[] = {
5.0f, -0.5f, 5.0f, 2.0f, 0.0f,
-5.0f, -0.5f, 5.0f, 0.0f, 0.0f,
-5.0f, -0.5f, -5.0f, 0.0f, 2.0f, 5.0f, -0.5f, 5.0f, 2.0f, 0.0f,
-5.0f, -0.5f, -5.0f, 0.0f, 2.0f,
5.0f, -0.5f, -5.0f, 2.0f, 2.0f
}; float grassVertices[] = {
1.0f, -0.5f, 0.0f, 1.0f, 0.0f,
0.0f, -0.5f, 0.0f, 0.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f, 1.0f,
1.0f, -0.5f, 0.0f, 1.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f, 1.0f,
1.0f, 0.5f, 0.0f, 1.0f, 1.0f
}; vector<glm::vec3> vegetation;
vegetation.push_back(glm::vec3(-1.5f, 0.0f, -0.48f));
vegetation.push_back(glm::vec3(1.5f, 0.0f, 0.51f));
vegetation.push_back(glm::vec3(0.0f, 0.0f, 0.7f));
vegetation.push_back(glm::vec3(-0.3f, 0.0f, -2.3f));
vegetation.push_back(glm::vec3(0.5f, 0.0f, -0.6f)); //cube VAO
unsigned int cubeVAO, cubeVBO;
glGenVertexArrays(, &cubeVAO);
glGenBuffers(, &cubeVBO);
glBindVertexArray(cubeVAO);
glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), cubeVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray();
glVertexAttribPointer(, , GL_FLOAT, GL_FALSE, * sizeof(float), (void*));
glEnableVertexAttribArray();
glVertexAttribPointer(, , GL_FLOAT, GL_FALSE, * sizeof(float), (void*)( * sizeof(float)));
glBindVertexArray(); //floor VAO
unsigned int floorVAO, floorVBO;
glGenVertexArrays(, &floorVAO);
glGenBuffers(, &floorVBO);
glBindVertexArray(floorVAO);
glBindBuffer(GL_ARRAY_BUFFER, floorVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(floorVertices), floorVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray();
glVertexAttribPointer(, , GL_FLOAT, GL_FALSE, * sizeof(float), (void*));
glEnableVertexAttribArray();
glVertexAttribPointer(, , GL_FLOAT, GL_FALSE, * sizeof(float), (void*)( * sizeof(float)));
glBindVertexArray(); unsigned grassVAO, grassVBO;
glGenVertexArrays(, &grassVAO);
glGenBuffers(, &grassVBO);
glBindVertexArray(grassVAO);
glBindBuffer(GL_ARRAY_BUFFER, grassVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(grassVertices), grassVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray();
glVertexAttribPointer(, , GL_FLOAT, GL_FALSE, * sizeof(float), (void*));
glEnableVertexAttribArray();
glVertexAttribPointer(, , GL_FLOAT, GL_FALSE, * sizeof(float), (void*)( * sizeof(float))); //load textures
stbi_set_flip_vertically_on_load(true);
unsigned int cubeTexture = loadTexture("greenWall.jpg");
unsigned int floorTexture = loadTexture("floor.jpg");
unsigned int grassTexture = loadTexture("glass.png"); shader.use();
glUniform1i(glGetUniformLocation(shader.ID, "texture1"), ); //render loop
while (!glfwWindowShouldClose(window))
{
//per-frame time logic
float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame; //input
processInput(window); //render
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); shader.use();
glm::mat4 model;
glm::mat4 view = camera.GetViewMatrix();
glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
shader.setMat4("view", view);
glUniformMatrix4fv(glGetUniformLocation(shader.ID, "projection"), , GL_FALSE, glm::value_ptr(projection)); //floor
glBindVertexArray(floorVAO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, floorTexture);
shader.setMat4("model", glm::mat4());
glDrawArrays(GL_TRIANGLES, , );
//glBindVertexArray(0); //cube
glBindVertexArray(cubeVAO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, cubeTexture);
model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f));
glUniformMatrix4fv(glGetUniformLocation(shader.ID, "model"), , GL_FALSE, glm::value_ptr(model));
glDrawArrays(GL_TRIANGLES, , );
model = glm::mat4();
model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f)); //the second cube
shader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, , ); //我们把距离和它对应的位置向量存储到一个STL库的map数据结构中,map会自动根据健值(key)对它的值进行排序,
//所以只要我们添加了所有的位置,并以他的距离作为键,它们就会自动根据距离值排序了
std::map<float, glm::vec3> sorted;
for (unsigned int i = ; i < vegetation.size(); i++)
{
float distance = glm::length(camera.Position - vegetation[i]);
sorted[distance] = vegetation[i]; //一个距离对应一个位置
}
//结果就是一个排序后的容器对象,它根据distance健值从低到高存储了每个窗户的位置 //之后,这次在渲染的时候,我们将以逆序(从远到近)从map中获取值,之后以正确的顺序绘制对应的窗户
/*glBindVertexArray(grassVAO);
glBindTexture(GL_TEXTURE_2D, grassTexture);
for (std::map<float, glm::vec3>::reverse_iterator it = sorted.rbegin(); it != sorted.rend(); it++)
{
model = glm::mat4();
model = glm::translate(model, it->second);
shader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 6);
}*/ glBindVertexArray(grassVAO);
glBindTexture(GL_TEXTURE_2D, grassTexture);
for (unsigned int i = ; i < vegetation.size(); i++)
{
model = glm::mat4();
model = glm::translate(model, vegetation[i]);
shader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, , );
} //glfw: swap buffers and poll IO events (keys pressed / released, mouse moved etc.)
glfwSwapBuffers(window);
glfwPollEvents();
} //optional: de - allocate all resources once they've outlived their purpose;
glDeleteVertexArrays(, &cubeVAO);
glDeleteVertexArrays(, &floorVAO);
glDeleteBuffers(, &cubeVBO);
glDeleteBuffers(, &floorVBO); glfwTerminate();
return ;
} void processInput(GLFWwindow *window)
{
if (glfwGetKey(window, GLFW_KEY_ENTER) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
camera.ProcessKeyboard(FORWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
camera.ProcessKeyboard(BACKWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
camera.ProcessKeyboard(LEFT, deltaTime);
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
camera.ProcessKeyboard(RIGHT, deltaTime);
} void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(, , width, height);
} void mouse_callback(GLFWwindow *window, double xpos, double ypos)
{
if (firstMouse)
{
lastX = xpos;
lastY = ypos;
firstMouse = false;
} float xoffset = xpos - lastX;
float yoffset = lastY - ypos; lastX = xpos;
lastY = ypos; camera.ProcessMouseMovement(xoffset, yoffset);
} void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
camera.ProcessMouseScroll(yoffset);
} unsigned int loadTexture(char const *path)
{
unsigned int textureID;
glGenTextures(, &textureID); int width, height, nrChannels;
unsigned char *data = stbi_load(path, &width, &height, &nrChannels, );
if (data)
{
GLenum format;
if (nrChannels == )
format = GL_RED;
else if (nrChannels == )
format = GL_RGB;
else if (nrChannels == )
format = GL_RGBA; glBindTexture(GL_TEXTURE_2D, textureID);
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glTexImage2D(GL_TEXTURE_2D, , format, width, height, , format, GL_UNSIGNED_BYTE, data); //create a texture
glGenerateMipmap(GL_TEXTURE_2D); /*glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);*/
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); stbi_image_free(data);
}
else
{
std::cout << "Texture failed to load at path: " << path << std::endl;
stbi_image_free(data);
}
return textureID; }

Shader.h

 #ifndef SHADER_H_INCLUDE
#define SHADER_H_INCLUDE #include <iostream>
#include <string>
#include <sstream>
#include <fstream> #include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp> class Shader {
public:
unsigned int ID; Shader(const GLchar* vertexPath, const GLchar* fragmentPath)
{
std::string vertexCode;
std::string fragmentCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile; vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); try {
//open files
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath); std::stringstream vShaderStream, fShaderStream; //read file's buffer contents into streams
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf(); //close file handlers
vShaderFile.close();
fShaderFile.close(); //convert stream into string
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
}
catch (std::ifstream::failure e)
{
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ" << std::endl;
}
const char* vShaderCode = vertexCode.c_str();
const char* fShaderCode = fragmentCode.c_str(); //2.compile shaders
unsigned int vertex, fragment;
int success;
char infoLog[]; //vertex shader
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, , &vShaderCode, NULL);
glCompileShader(vertex);
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertex, , NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED!" << std::endl;
} fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, , &fShaderCode, NULL);
glCompileShader(fragment);
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragment, , NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED!" << std::endl;
} ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
glLinkProgram(ID);
glGetProgramiv(ID, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(ID, , NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKTING_FAILED!" << std::endl;
} //delete the shaders sa they are linked into our program now and no long necessary
glDeleteShader(vertex);
glDeleteShader(fragment);
} //activate the shader
void use()
{
glUseProgram(ID);
} //utility uniform functions
void setBool(const std::string &name, bool value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
} void setInt(const std::string &name, int value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
} void setFloat(const std::string &name, float value) const
{
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
} void setVec3(const std::string &name, const glm::vec3 &value) const
{
glUniform3fv(glGetUniformLocation(ID, name.c_str()), , &value[]);
} void setVec3(const std::string &name, float x, float y, float z) const
{
glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z);
} void setMat4(const std::string &name, glm::mat4 &trans) const
{ glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), , GL_FALSE, &trans[][]);
} /*void setMat4(const std::string &name, glm::mat4 trans) const
{ //'trans': formal parameter with requested alignment of 16 won't be aligned,请求对齐的16的形式参数不会对齐
glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, glm::value_ptr(trans));
}*/ }; #endif

camera.h

 #ifndef CAMERA_H
#define CAMERA_H #include <GL/glew.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <vector> // Defines several possible options for camera movement. Used as abstraction to stay away from window-system specific input methods
enum Camera_Movement {
FORWARD,
BACKWARD,
LEFT,
RIGHT
}; // Default camera values
const float YAW = -90.0f;
const float PITCH = 0.0f;
const float SPEED = 2.5f;
const float SENSITIVITY = 0.1f;
const float ZOOM = 45.0f; // An abstract camera class that processes input and calculates the corresponding Euler Angles, Vectors and Matrices for use in OpenGL
class Camera
{
public:
// Camera Attributes
glm::vec3 Position;
glm::vec3 Front;
glm::vec3 Up;
glm::vec3 Right;
glm::vec3 WorldUp;
// Euler Angles
float Yaw;
float Pitch;
// Camera options
float MovementSpeed;
float MouseSensitivity;
float Zoom; // Constructor with vectors
Camera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), float yaw = YAW, float pitch = PITCH) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVITY), Zoom(ZOOM)
{
Position = position;
WorldUp = up;
Yaw = yaw;
Pitch = pitch;
updateCameraVectors();
}
// Constructor with scalar values
Camera(float posX, float posY, float posZ, float upX, float upY, float upZ, float yaw, float pitch) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVITY), Zoom(ZOOM)
{
Position = glm::vec3(posX, posY, posZ);
WorldUp = glm::vec3(upX, upY, upZ);
Yaw = yaw;
Pitch = pitch;
updateCameraVectors();
} // Returns the view matrix calculated using Euler Angles and the LookAt Matrix
glm::mat4 GetViewMatrix()
{
return glm::lookAt(Position, Position + Front, Up);
} // Processes input received from any keyboard-like input system. Accepts input parameter in the form of camera defined ENUM (to abstract it from windowing systems)
void ProcessKeyboard(Camera_Movement direction, float deltaTime)
{
float velocity = MovementSpeed * deltaTime;
if (direction == FORWARD)
Position += Front * velocity;
if (direction == BACKWARD)
Position -= Front * velocity;
if (direction == LEFT)
Position -= Right * velocity;
if (direction == RIGHT)
Position += Right * velocity;
} // Processes input received from a mouse input system. Expects the offset value in both the x and y direction.
void ProcessMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch = true)
{
xoffset *= MouseSensitivity;
yoffset *= MouseSensitivity; Yaw += xoffset;
Pitch += yoffset; // Make sure that when pitch is out of bounds, screen doesn't get flipped
if (constrainPitch)
{
if (Pitch > 89.0f)
Pitch = 89.0f;
if (Pitch < -89.0f)
Pitch = -89.0f;
} // Update Front, Right and Up Vectors using the updated Euler angles
updateCameraVectors();
} // Processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis
void ProcessMouseScroll(float yoffset)
{
if (Zoom >= 1.0f && Zoom <= 45.0f) //zoom缩放,就是视野
Zoom -= yoffset;
if (Zoom <= 1.0f)
Zoom = 1.0f;
if (Zoom >= 45.0f)
Zoom = 45.0f;
} private:
// Calculates the front vector from the Camera's (updated) Euler Angles
void updateCameraVectors()
{
// Calculate the new Front vector
glm::vec3 front;
front.x = cos(glm::radians(Yaw)) * cos(glm::radians(Pitch));
front.y = sin(glm::radians(Pitch));
front.z = sin(glm::radians(Yaw)) * cos(glm::radians(Pitch));
Front = glm::normalize(front);
// Also re-calculate the Right and Up vector
Right = glm::normalize(glm::cross(Front, WorldUp)); // Normalize the vectors, because their length gets closer to 0 the more you look up or down which results in slower movement.
Up = glm::normalize(glm::cross(Right, Front));
}
};
#endif

stb_image.h下载

图片:

高级openg 混合,一个完整程序的更多相关文章

  1. yii2高级模板使用一个域名管理前后台

    yii2的高级模板分为backend和frontend,最开始用yii的时候并没怎么在意,就使用了两个域名分别解析前后台.今天无意间看见 可以使用一个域名指向前后台. 1.修改 advanced/ba ...

  2. python高级编程 编写一个包1

    #目的是:编写,发行python包可重复过程"""1:是缩短开始真正工作之前所需要的设置时间,也就是提供模板2:提供编写包的标准化方法3:简化测试驱动开发方法的使用4:为 ...

  3. Java高级特性--自定义一个StringBuilder的类

    案例讲解--自定义一个StringBuilder的类 一:案例设计介绍 自义一个M定yStringBuilder来实现StringBuilder的功能 二:案例设计 实现append()方法追加字符串 ...

  4. constraintLayout的一些高级用法 布局一个16:9的图片 以及GuideLine的使用

    <!-- "W,9:16" 同样的效果 --> <ImageView android:layout_width="0dp" android:l ...

  5. Java高级应用(一个)-文件夹监控服务

    最近.在研究一些比较成熟的框架.他们还发现,他们中的一些相当不错的文章.现在,对于一些在你们中间一个简单的翻译(版的英文文章,非常有帮助). 译:原文链接 你有没有发现,当你编辑一个文件.同一时候使用 ...

  6. Yii2 高级版新建一个 Api 应用

    原文地址:http://www.getyii.com/topic/28 先在项目的根目录下复制一份 backend 为 api: cp backend/ api -r 拷贝 api 环境 cp -a ...

  7. UNIX环境高级编程——初始化一个守护进程

    #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h&g ...

  8. yii2 高级版新建一个应用(api应用为例子)

    先在项目的根目录下复制一份 backend 为 api: cp backend/ api -r 拷贝 api 环境 cp -a environments/dev/frontend environmen ...

  9. webdriver高级应用- 改变一个页面对象的属性值

    适用于一些无法操作的元素,可以直接改他的属性从而操作,代码如下: #encoding=utf-8 from selenium import webdriver import unittest impo ...

随机推荐

  1. <HBase><读写><LSM>

    Overview HBase中的一个big table,首先会按行划分成一些region(这些region之间是有序的,由startkey保证),每个region分配到不同的节点进行存储.因此,reg ...

  2. 20165326 java实验一

    <Java程序设计>Java开发环境的熟悉 实验报告 课程:Java程序设计 班级:1653班 姓名:陈卓 学号:20165326 指导教师:娄嘉鹏 实验日期:2018年4月2日 实验时间 ...

  3. python Django rest-framework 序列化步骤

    django-rest-framework,是一套基于Django 的 REST 框架,是一个强大灵活的构建 Web API 的工具包.本文介绍一下 django-rest-framework 的简单 ...

  4. mysql 数据库复制方法

    同一台MySQL服务器上复制数据库的方法 CREATE DATABASE `新库` DEFAULT CHARACTER SET UTF8 COLLATE UTF8_GENERAL_CI; mysqld ...

  5. Python 类的约束

    # 项目经理 class Base: # 对子类进行了约束. 必须重写该方法 # 以后上班了. 拿到公司代码之后. 发现了notImplementedError 继承他 直接重写他 def login ...

  6. jenkins + nodejs + git 自动化部署前端

    1.  创建自定义风格任务 2.填写项目描述 3.配置源码管理 4. 系统管理->插件管理 ->安装插件 5.配置系统管理->全局工具配置-> 6.配置全局 ssh 7. 继续 ...

  7. HDU 6077 17多校4 Time To Get Up 水题

    Problem Description Little Q's clock is alarming! It's time to get up now! However, after reading th ...

  8. HDU 5776 sum(抽屉原理)

    题目传送:http://acm.hdu.edu.cn/showproblem.php?pid=5776 Problem Description Given a sequence, you're ask ...

  9. vue 之 key

    key 的特殊属性主要用在 Vue的虚拟DOM算法,在新旧nodes对比时辨识VNodes.如果不使用key,Vue会使用一种最大限度减少动态元素并且尽可能的尝试修复/再利用相同类型元素的算法.使用k ...

  10. Spring Boot 揭秘与实战(四) 配置文件篇 - 有哪些很棒的特性

    文章目录 1. 使用属性文件2. YAML文件 1.1. 自定义属性 1.2. 参数引用 1.3. 随机数属性 1.4. application-{profile}.properties参数加载 3. ...