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. Effective Java Methods Common to All Objects

    Obey the general contract when overriding equals 先了解equals 和 == 的区别,如果不重写equals, equals比较的仅仅只是是否引用同一 ...

  2. zabbix 监控java通用

    监控工具 jstat jstack http://www.blogjava.net/jjshcc/archive/2014/03/05/410655.html https://www.cnblogs. ...

  3. LeetCode--219、268、283、414、448 Array(Easy)

    219. Contains Duplicate II Given an array of integers and an integer k, find out whether there are t ...

  4. 校验总结:校验是否是中英文等等(1.正则校验 2.hibernate volidator)

    1.正则校验 import java.util.regex.Matcher;import java.util.regex.Pattern; public class Validation { //-- ...

  5. MySQL常见建表选项及约束

    阅读目录---MySQL常见的建表选项及约束: 1.create table选项 1.指定列选项:default.comment 2.指定表选项:engine.auto_increment.comme ...

  6. 【转载】 看996ICU

    原文地址: https://www.jianshu.com/p/15d8726fa8a8 作者:Demisstif 来源:简书 ------------------------------------ ...

  7. Linux矫正时间

    ntpdate -u ntp.api.bz 可以写到定时任务里,每天矫正一次

  8. personal的制作

    <style>  .personal{   float: right;   height: 40px;   line-height: 40px;   width: 200px;  }  . ...

  9. Spring mvc:配置不拦截指定的路径

    <!-- 访问拦截 --> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**/ ...

  10. centos 7 防火墙的使用 firewalld

    开启端口命令 输入firewall-cmd --query-port=6379/tcp,如果返回结果为no,那么证明6379端口确实没有开启. 输入firewall-cmd --add-port=63 ...