您的位置:首页 > 运维架构

OpenGL:光照、模型视图投影变换

2017-05-02 18:18 253 查看

OpenGL:光照、模型视图投影变换

OpenGL光照模型视图投影变换
数学基础

程序
库配置

程序图示

代码
shaderwrapperh

vertex shadermvp_testvs

fragment shadermvp_testfrag

references

数学基础

矩阵与线性变换

坐标系变换

深入探索透视投影变换

OpenGL Normal Vector Transformation

程序

太阳系,为简化内容,所以使用正方体代替球体,模拟太阳系中的太阳,地球和月亮。主要目的是展示OpenGL中用到的几个坐标系变换以及光照处理。

库配置

Creating a window

GLM

程序图示





代码

#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
相关文章推荐