OpenGL:光照模型视图投影变换
Posted unclerunning
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenGL:光照模型视图投影变换相关的知识,希望对你有一定的参考价值。
OpenGL:光照、模型视图投影变换
数学基础
OpenGL Normal Vector Transformation
程序
太阳系,为简化内容,所以使用正方体代替球体,模拟太阳系中的太阳,地球和月亮。主要目的是展示OpenGL中用到的几个坐标系变换以及光照处理。
库配置
程序图示
代码
#include <iostream>
#include <cmath>
// GLEW
#define GLEW_STATIC
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h>
// GLM Mathematics
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
// Other includes
#include "shaderwrapper.h"
// Function prototypes
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
static void init();
static void initBuffer();
// Window dimensions
static const GLuint WIDTH = 800, HEIGHT = 600;
static GLFWwindow* window;
static GLuint VBO, VAO;
// The MAIN function, from here we start the application and run the game loop
int main()
init();
initBuffer();
//light position in world space
glm::vec3 lightPos(8.0f,8.0f,8.0f);
//eye position in world space
glm::vec3 eyePos(-12.0f, 12.0f, 12.0f);
//local positions
glm::vec3 cubePositions[] =
glm::vec3(8.0f,0.0f,0.0f),
glm::vec3(3.0f,0.0f,0.0f)
;
//sun
GLfloat Sun_angle = 0.0f;
GLfloat Sun_angle_step = 1.0f;
glm::vec3 Sun_color(1.0f,0.0f,0.0f);
//earth
GLfloat Earth_self_angle = 0.0f;
GLfloat Earth_angle_step = 1.0f;
GLfloat Earth_sun_angle = 0.0f;
GLfloat Earth_sun_step = 2.0f;
glm::vec3 Earth_color(0.0f, 1.0f, 0.0f);
//moon
GLfloat Moon_self_angle = 0.0f;
GLfloat Moon_angle_step = 2.0f;
GLfloat Moon_earth_angle = 0.0f;
GLfloat Moon_earth_step = 3.0f;
glm::vec3 Moon_color(1.0f, 1.0f, 1.0f);
// Build and compile our shader program
Shader ourShader("shaders/mvp_test.vs", "shaders/mvp_test.frag");
//get locations of uniform variables
GLint viewLoc = glGetUniformLocation(ourShader.Program, "view");
GLint projLoc = glGetUniformLocation(ourShader.Program, "projection");
GLint lightPosLoc = glGetUniformLocation(ourShader.Program, "lightPos");
GLint colorLoc = glGetUniformLocation(ourShader.Program, "objectColor");
GLint viewPosLoc = glGetUniformLocation(ourShader.Program, "viewPos");
// Camera/View transformation
glm::mat4 view;
view = glm::lookAt(eyePos, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
// Projection
glm::mat4 projection;
projection = glm::perspective(45.0f, (GLfloat)WIDTH / (GLfloat)HEIGHT, 0.1f, 100.0f);
// Activate shader
ourShader.Use();
// Pass the matrices to the shader
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
glUniform3f(lightPosLoc, lightPos.x, lightPos.y, lightPos.z);
glUniform3fv(viewPosLoc, 1, glm::value_ptr(eyePos));
// loop
GLfloat startTime = glfwGetTime();
while (!glfwWindowShouldClose(window))
glfwPollEvents();
// Render
// Clear the color buffer and depth buffer
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Calculate delta time of current frame
GLfloat deltaTime = glfwGetTime() - startTime;
//sun
Sun_angle = Sun_angle_step * deltaTime;
//earth
Earth_self_angle = Earth_angle_step * deltaTime;
Earth_sun_angle = Earth_sun_step*deltaTime;
//moon
Moon_self_angle = Moon_angle_step * deltaTime;
Moon_earth_angle = Moon_earth_step * deltaTime;
// Get the uniform locations
GLint modelLoc = glGetUniformLocation(ourShader.Program, "model");
GLint normalTransformLoc = glGetUniformLocation(ourShader.Program, "normalTransform");
glBindVertexArray(VAO);
//### sun ###
glm::mat4 sun_model;
sun_model = glm::scale(sun_model,glm::vec3(1.6f,1.6f,1.6f)); //放大坐标系
sun_model = glm::rotate(sun_model, Sun_angle, glm::vec3(0.0f, 1.0f, 0.0f)); //绕坐标系y轴旋转
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(sun_model));
//normal transform
glm::mat4 sun_normalTransform;
sun_normalTransform = glm::inverse(sun_model);
sun_normalTransform = glm::transpose(sun_normalTransform);
glUniformMatrix4fv(normalTransformLoc, 1, GL_FALSE, glm::value_ptr(sun_normalTransform));
glUniform3fv(colorLoc, 1, glm::value_ptr(Sun_color));
glDrawArrays(GL_TRIANGLES, 0, 36);
//### earth ###
glm::mat4 earth_model;
//绕y轴旋转坐标系W得到新坐标系W1
earth_model = glm::rotate(earth_model, Earth_sun_angle, glm::vec3(0.0f, 1.0f, 0.0f));
//平移坐标系W1得到新坐标系W2
earth_model = glm::translate(earth_model, cubePositions[0]);
//绕y轴旋转坐标系W2得到新坐标系W3
earth_model = glm::rotate(earth_model, Earth_self_angle, glm::vec3(0.0f, 1.0f, 0.0f));
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(earth_model));
//normal transform
glm::mat4 earth_normalTransform;
earth_normalTransform = glm::inverse(earth_model);
earth_normalTransform = glm::transpose(earth_normalTransform);
glUniformMatrix4fv(normalTransformLoc, 1, GL_FALSE, glm::value_ptr(earth_normalTransform));
glUniform3fv(colorLoc, 1, glm::value_ptr(Earth_color));
glDrawArrays(GL_TRIANGLES, 0, 36);
//### moon ###
glm::mat4 moon_model;
//start from earth's coordinate
moon_model = earth_model;
moon_model = glm::scale(moon_model, glm::vec3(0.5f, 0.5f, 0.5f));
moon_model = glm::rotate(moon_model, Moon_earth_angle, glm::vec3(0.0f, 1.0f, 0.0f));
moon_model = glm::translate(moon_model, cubePositions[1]);
moon_model = glm::rotate(moon_model, Moon_self_angle, glm::vec3(0.0f, 1.0f, 0.0f));
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(moon_model));
//normal transform
glm::mat4 moon_normalTransform;
moon_normalTransform = glm::inverse(moon_model);
moon_normalTransform = glm::transpose(moon_normalTransform);
glUniformMatrix4fv(normalTransformLoc, 1, GL_FALSE, glm::value_ptr(moon_normalTransform));
glUniform3fv(colorLoc, 1, glm::value_ptr(Moon_color));
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
// Swap the screen buffers
glfwSwapBuffers(window);
// Properly de-allocate all resources once they've outlived their purpose
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
// Terminate GLFW, clearing any resources allocated by GLFW.
glfwTerminate();
return 0;
// Is called whenever a key is pressed/released via GLFW
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
static void init()
// Init GLFW
glfwInit();
// Set all the required options for GLFW
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
// Create a GLFWwindow object that we can use for GLFW's functions
window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);
glfwMakeContextCurrent(window);
// Set the required callback functions
glfwSetKeyCallback(window, key_callback);
// Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions
glewExperimental = GL_TRUE;
// Initialize GLEW to setup the OpenGL Function pointers
glewInit();
// Define the viewport dimensions
glViewport(0, 0, WIDTH, HEIGHT);
glEnable(GL_DEPTH_TEST);
static void initBuffer()
// Set up vertex data (and buffer(s)) and attribute pointers
GLfloat vertices[] =
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f
;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// Normal attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glBindVertexArray(0); // Unbind VAO
shaderwrapper.h:
#ifndef SHADER_H
#define SHADER_H
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <GL/glew.h>
class Shader
public:
GLuint Program;
// Constructor generates the shader on the fly
Shader(const GLchar* vertexPath, const GLchar* fragmentPath)
// 1. Retrieve the vertex/fragment source code from filePath
std::string vertexCode;
std::string fragmentCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile;
// ensures ifstream objects can throw exceptions:
vShaderFile.exceptions(std::ifstream::badbit);
fShaderFile.exceptions(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_SUCCESFULLY_READ" << std::endl;
const GLchar* vShaderCode = vertexCode.c_str();
const GLchar * fShaderCode = fragmentCode.c_str();
// 2. Compile shaders
GLuint vertex, fragment;
GLint success;
GLchar infoLog[512];
// Vertex Shader
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
// Print compile errors if any
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success)
glGetShaderInfoLog(vertex, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\\n" << infoLog << std::endl;
// Fragment Shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
// Print compile errors if any
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success)
glGetShaderInfoLog(fragment, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\\n" << infoLog << std::endl;
// Shader Program
this->Program = glCreateProgram();
glAttachShader(this->Program, vertex);
glAttachShader(this->Program, fragment);
glLinkProgram(this->Program);
// Print linking errors if any
glGetProgramiv(this->Program, GL_LINK_STATUS, &success);
if (!success)
glGetProgramInfoLog(this->Program, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\\n" << infoLog << std::endl;
// Delete the shaders as they're linked into our program now and no longer necessery
glDeleteShader(vertex);
glDeleteShader(fragment);
// Uses the current shader
void Use()
glUseProgram(this->Program);
;
#endif
vertex shader(mvp_test.vs):
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
out vec3 Normal;
out vec3 FragPos;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform mat4 normalTransform;
void main()
gl_Position = projection * view * model * vec4(position, 1.0f);
Normal = vec3(normalTransform*vec4(normal,1.0f));
FragPos = vec3(model * vec4(position, 1.0f));
fragment shader(mvp_test.frag):
#version 330 core
in vec3 Normal;
in vec3 FragPos;
out vec4 color;
uniform vec3 lightPos;
uniform vec3 viewPos;
uniform vec3 objectColor;
void main()
vec3 lightColor = vec3(1.0f,1.0f,1.0f);
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(lightPos - FragPos);
// ambient component
float ambientStrength = 0.28f;
vec3 ambient = ambientStrength * lightColor;
// diffuse component
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * lightColor;
// specular component
float specularStrength = 0.5f;
int shininess = 256;
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), shininess);
vec3 specular = specularStrength * spec * lightColor;
// together
vec3 result = (ambient + diffuse + specular) * objectColor;
color = vec4(result, 1.0f);
references:
Basic Lighting
深入探索透视投影变换
OpenGL Projection Matrix
OpenGL Normal Vector Transformation
以上是关于OpenGL:光照模型视图投影变换的主要内容,如果未能解决你的问题,请参考以下文章