图形学笔记(九)增加一个光源
给之前画出来的立方体加一个围绕它转的光源。
一、代码
- main.cpp
#include <iostream>// GLEW
#define GLEW_STATIC
#include <GL/glew.h>// GLFW
#include <GLFW/glfw3.h>// Shader
#include "Shader.h"// SOIL2
// Linux 用的是 \, 但是 / 都可以用
#include "SOIL2/SOIL2.h"
#include "SOIL2/stb_image.h"// 在 include 前增加这一句,才能使用 transform.hpp
#define GLM_ENABLE_EXPERIMENTAL// glm
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp> //需要什么变换,就导入什么文件,具体可以去官网看
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/rotate_vector.hpp> //旋转#include "Camera.h" //当前引用,所以用""const GLint WIDTH = 800, HEIGHT = 600; //新建窗口// 键盘操作回应
void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mode);
// 鼠标操作回应
void MouseCallback(GLFWwindow *window, double xPos, double yPos);
// 移动
void DoMovement();// 初始化一个相机
Camera camera(glm::vec3(0.0f, 0.0f, 2.0f));
// 设置初始量
GLfloat lastX = WIDTH / 2.0;
GLfloat lastY = HEIGHT / 2.0;
bool firstMouse = true;// 设置光源坐标
glm::vec3 lightPos(1.2f, 1.0f, 2.0f);bool keys[1024]; //存放获取的所有键盘操作,先存下来再进行操作GLfloat deltaTime = 0.0f; //两帧之间的间隔时间
GLfloat lastTime = 0.0f; //上一帧绘制的时间int main()
{glfwInit();// OpenGL 版本glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);// 窗口设置glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); //用的是新版的 OpenGL 3.3glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // must for MacglfwWindowHint(GLFW_RESIZABLE, GL_FALSE); //改为 GL_TRUE,改变窗口,纵横比会变GLFWwindow *window = glfwCreateWindow(WIDTH, HEIGHT, "Learn OpenGL B16112011", nullptr,nullptr); //窗口名字改成自己的学号if (nullptr == window){std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}// next two lines are for mac retina displayint screenWidth, screenHeight;glfwGetFramebufferSize(window, &screenWidth, &screenHeight); //获取窗口大小glfwMakeContextCurrent(window); //可以新建很多 window// Set the required callback function// KeyCallback 是响应键盘消息的回调函数glfwSetKeyCallback(window, KeyCallback);// MouseCallback 是响应鼠标消息的回调函数glfwSetCursorPosCallback(window, MouseCallback);glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); //不允许鼠标出现在屏幕中glewExperimental = GL_TRUE;if (GLEW_OK != glewInit()){std::cout << "Failed to initialise GLEW" << std::endl;return -1;}glViewport(0, 0, screenWidth, screenHeight); //从(0,0)开始画点,直到 WIDTH 和 HEIGHT//glEnable(GL_CULL_FACE); //只显示一半//glEnable(GL_DEPTH_TEST); //深度测试//glDepthFunc(GL_LESS); //深度信息小于当期信息,就把进行测试/*// 启动透明度混合,固定不能改,alpha 线性混合:设置当前为 α ,其他就为 1- αglEnable(GL_BLEND);// 表示把渲染的图像融合到目标区域。也就是说源的每一个像素的alpha都等于自己的alpha,// 目标的每一个像素的alpha等于1减去该位置源像素的alpha。因此不论叠加多少次,亮度是不变的。glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);*/// vs 是顶点调色器,frag 是边缘(片段)调色器Shader ourShader = Shader("core1.vs", "core1.frag"); //文件相对路径// 光源调色器Shader lightShader = Shader("light.vs", "light.frag");// now the verte information comes belowfloat 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};// the date should be transfered to the memory on the Graphics Card,传到显存GLuint VAO, VBO; //VAO:Vertex Array Object VBO:Vertex Buffer Object传数据glGenVertexArrays(1, &VAO); //创建 VAOglGenBuffers(1, &VBO);glBindVertexArray(VAO); //设当前直线glBindBuffer(GL_ARRAY_BUFFER, VBO); //VAO 和 VBO 成对出现// transfer the data:传数据glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); //静态访问,几乎不修改// set the attributeglVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,6 * sizeof(GLfloat), (GLvoid *)0); //0:对应调色器里 location 的值;3:对应 vec3 三个量;GL_FLOAT:浮点型;GL_FALSE:;6*sizeof(GLfloat):对应 Buffer 里传的数据;(GLvoid*)0:从第 0 个位置开始glEnableVertexAttribArray(0);// 法向量glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE,6 * sizeof(GLfloat), (GLvoid *)(3 * sizeof(GLfloat))); //1:对应调色器里 location 的值;3:对应 vec3 三个量;GL_FLOAT:浮点型;GL_FALSE:;6*sizeof(GLfloat):对应 Buffer 里传的数据;(GLvoid *)(3 * sizeof(GLfloat)):从第 3 个位置开始glEnableVertexAttribArray(1);glBindBuffer(GL_ARRAY_BUFFER, 0);glBindVertexArray(0);// 为光源创建一个新的 VAOGLuint lightVAO;glGenVertexArrays(1, &lightVAO);// 绑定光源 VAOglBindVertexArray(lightVAO);// 只需要绑定VBO不用再次设置VBO的数据,因为容器(物体)的VBO数据中已经包含了正确的立方体顶点数据glBindBuffer(GL_ARRAY_BUFFER, VBO);// 设置光源的顶点属性指针(仅设置灯的顶点数据)glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,6 * sizeof(GLfloat), (GLvoid *)0); //0:对应调色器里 location 的值;3:对应 vec3 三个量;GL_FLOAT:浮点型;GL_FALSE:;6*sizeof(GLfloat):对应 Buffer 里传的数据;(GLvoid*)0:从第 0 个位置开始glEnableVertexAttribArray(0);glBindBuffer(GL_ARRAY_BUFFER, 0);glBindVertexArray(0);glm::mat4 view = glm::mat4(1.0f); //初始化 4 * 4 单位矩阵// 正交投影:第一个窗口是 FoV 视域。默认焦距是 1 。// 第二个参数是长宽比。// 近:0.1f。远:1000.0f。glm::mat4 projection = glm::perspective(glm::radians(camera.GetZoom()), static_cast<GLfloat>(screenWidth) / static_cast<GLfloat>(screenHeight), 0.1f, 1000.0f);// 画图while (!glfwWindowShouldClose(window)){//旋转角度为 0.01flightPos = glm::rotate(lightPos, 0.01f, glm::vec3(1.0f, 1.0f, 0.0f));GLfloat currentFrame = glfwGetTime(); //屏幕刚画出来的时间deltaTime = currentFrame - lastTime; //更新两帧之间的间隔时间lastTime = currentFrame; //更新上一帧绘制的时间glfwPollEvents(); //把所有事件系统都取过来:键盘/鼠标等操作DoMovement(); //获取完操作之后的额外参数glClearColor(0.2f, 0.3f, 0.3f, 1.0f); //窗口背景颜色,RGB,最后一个是透明度glClear(GL_COLOR_BUFFER_BIT);//Bind the shaderourShader.Use();// 正交投影:第一个窗口是 FoV 视域。默认焦距是 1 。// 第二个参数是长宽比。// 近:0.1f。远:1000.0f。glm::mat4 model = glm::mat4(1.0f); //modelmodel = glm::rotate(model, glm::radians(20.0f) * static_cast<GLfloat>(glfwGetTime()), glm::vec3(1.0f, 1.0f, 1.0f));view = camera.GetViewMatrix();//glm 从 0.9.9 版本起,默认会将矩阵类型初始化为一个零矩阵(所有元素均为 0)//glm::mat4 transform = glm::mat4(1.0f); //初始化 4 * 4 单位矩阵//旋转//GLM 希望它的角度是弧度制,radians 将角度转化为弧度制//glfwGetTime():让图形一直变换,做一个类型转换,用 static_cast<GLfloat>,设为 GLfloat 型//glm::vec3(1.0f, 1.0f, 1.0f),分别绕 x 轴、y 轴、z 轴进行旋转,如果都为 1.0f,就是绕和向量 (1,1,1) 转//transform = glm::rotate(transform, glm::radians(20.0f) * static_cast<GLfloat>(glfwGetTime()), glm::vec3(1.0f, 1.0f, 1.0f));//缩放,x、y、z 都缩放到原来的 0.5 倍//transform = glm::scale(transform, glm::vec3(0.5f, 0.5f, 0.5f));//平移//transform = // 得到 uniform 位置GLuint modelLoc = glGetUniformLocation(ourShader.Program, "model"); //到 vs 找到那个 model 变量GLuint viewLoc = glGetUniformLocation(ourShader.Program, "view"); //到 vs 找到那个 view 变量GLuint projectionLoc = glGetUniformLocation(ourShader.Program, "projection"); //到 vs 找到那个 projection 变量//GLuint transLoc = glGetUniformLocation(ourShader.Program, "transform"); //到 vs 找到那个 transform 变量// Matrix4fv:4维矩阵,fv:浮点类型// transLoc:变量 uniform 的位置// 1:代表只传入一个矩阵// GL_FALSE:不对矩阵进行置换,即不交换矩阵的行和列。GLM 的默认布局就是列主序,所以并不需要置换矩阵// 最后:直接给出 transform 矩阵数组,这里我们要把矩阵转换成数组的格式传递。//glUniformMatrix4fv(transLoc, 1, GL_FALSE, glm::value_ptr(transform)); //glUniformMatrix4fv:四个坐标 glUniform4fv:三个坐标// Matrix4fv:4维矩阵,fv:浮点类型// modelLoc:变量 model 的位置// 1:代表只传入一个矩阵// GL_FALSE:不对矩阵进行置换,即不交换矩阵的行和列。GLM 的默认布局就是列主序,所以并不需要置换矩阵// 最后:直接给出 model 矩阵数组,这里我们要把矩阵转换成数组的格式传递。glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));// 首先使用对应的着色器程序(来设定uniform)GLint objectColorLoc = glGetUniformLocation(ourShader.Program, "objectColor");GLint lightColorLoc = glGetUniformLocation(ourShader.Program, "lightColor");GLint lightPosLoc = glGetUniformLocation(ourShader.Program, "lightPos");GLint viewPosLoc = glGetUniformLocation(ourShader.Program, "viewPos");glUniform3f(objectColorLoc, 1.0f, 0.5f, 0.3f); //珊瑚红glUniform3f(lightColorLoc, 1.0f, 1.0f, 1.0f); //把光源设置为白色glUniform3f(lightPosLoc, lightPos.x, lightPos.y, lightPos.z);glUniform3f(viewPosLoc, camera.GetPosition().x, camera.GetPosition().y, camera.GetPosition().z); //使用摄像机对象的位置坐标代替// Draw the triangleglBindVertexArray(VAO); //使用 VAO,直接绑定glDrawArrays(GL_TRIANGLES, 0, 36); //画三角形,总共有 36 个顶点//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);glBindVertexArray(0);// 画光源lightShader.Use();// 设置模型、视图和投影矩阵 uniformmodelLoc = glGetUniformLocation(lightShader.Program, "model"); //到 vs 找到那个 model 变量viewLoc = glGetUniformLocation(lightShader.Program, "view"); //到 vs 找到那个 view 变量projectionLoc = glGetUniformLocation(lightShader.Program, "projection"); //到 vs 找到那个 projection 变量// 对模型进行操作model = glm::translate(model, lightPos); //平移光源model = glm::scale(model, glm::vec3(0.2f)); //缩放光源// 传入数据glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));lightColorLoc = glGetUniformLocation(lightShader.Program, "lightColor");glUniform3f(lightColorLoc, 1.0f, 1.0f, 1.0f);// 绘制光源对象glBindVertexArray(lightVAO); //使用 VAO,直接绑定glDrawArrays(GL_TRIANGLES, 0, 36); //画三角形,总共有 36 个顶点//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);glBindVertexArray(0);glfwSwapBuffers(window); //调用双面进行画,显示一个,另一个在画,画面更流畅}glDeleteVertexArrays(1, &VAO);glDeleteVertexArrays(1, &lightVAO);glDeleteBuffers(1, &VBO);//glDeleteBuffers(1, &EBO);glfwTerminate();return 0;
}// 键盘操作回应
void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mode)
{if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {glfwSetWindowShouldClose(window, GL_TRUE); //设定关闭窗口}if (key >= 0 && key < 1024) {if (action == GLFW_PRESS){keys[key] = true; //键盘按下去了,就设置为 true,即为1}else if (action == GLFW_RELEASE){keys[key] = false; //键盘松开,设为 false}}
}// 鼠标操作回应
void MouseCallback(GLFWwindow *window, double xPos, double yPos)
{if (firstMouse) { //只有第一次才初始化lastX = xPos;lastY = yPos;firstMouse = false;}GLfloat xOffset = xPos - lastX; //当前位置 - 上一个xGLfloat yOffset = lastY - yPos;lastX = xPos;lastY = yPos;camera.ProcessMouseMovement(xOffset, yOffset);
}// 移动
void DoMovement()
{if (keys[GLFW_KEY_W] || keys[GLFW_KEY_UP]) {camera.ProcessKeyboard(FORWARD, deltaTime);}if (keys[GLFW_KEY_S] || keys[GLFW_KEY_DOWN]) {camera.ProcessKeyboard(BACKWARD, deltaTime);}if (keys[GLFW_KEY_A] || keys[GLFW_KEY_LEFT]) {camera.ProcessKeyboard(LEFT, deltaTime);}if (keys[GLFW_KEY_D] || keys[GLFW_KEY_RIGHT]) {camera.ProcessKeyboard(RIGHT, deltaTime);}
}
- Shader.h
#pragma once
//#ifndef shader_hpp
//#define shader_hpp
//#endif /* shader_hpp */
#include<string>
#include<fstream> //可以打开文件
#include<sstream>
#include<iostream>
#include<GL/glew.h>class Shader {GLuint vertex, fragment;
public:GLuint Program;Shader(const GLchar * vertexPath, const GLchar * fragmentPath){std::string vertexCode;std::string fragmentCode;std::ifstream vShaderFile;std::ifstream fShaderFile;vShaderFile.exceptions(std::ifstream::badbit);fShaderFile.exceptions(std::ifstream::badbit);try {vShaderFile.open(vertexPath);fShaderFile.open(fragmentPath);std::stringstream vShaderStream, fShaderStream;vShaderStream << vShaderFile.rdbuf();fShaderStream << fShaderFile.rdbuf();//文件关闭顺序,先 v 再 fvShaderFile.close();fShaderFile.close();vertexCode = vShaderStream.str();fragmentCode = fShaderStream.str();}catch (std::ifstream::failure a) {std::cout <<"ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ"<< std::endl;}//类型转换const GLchar *vShaderCode = vertexCode.c_str();const GLchar *fShaderCode = fragmentCode.c_str();//import and compile the shadervertex = glCreateShader(GL_VERTEX_SHADER); //不用重新定义glShaderSource(vertex, 1, &vShaderCode, NULL);glCompileShader(vertex); //编译GLint success;GLchar infoLog[512];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 = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragment, 1, &fShaderCode, NULL);glCompileShader(fragment); //编译glGetShaderiv(fragment, GL_COMPILE_STATUS, &success); //编译是否完成的位置if (!success) {glGetShaderInfoLog(fragment, 512, NULL, infoLog);std::cout <<"ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n"<< infoLog << std::endl;}//create the program and link the programthis->Program = glCreateProgram(); //创建着色器程序glAttachShader(this->Program, vertex);glAttachShader(this->Program, fragment);glLinkProgram(this->Program); //链接glValidateProgram(this->Program); //可省略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;}}~Shader() {glDetachShader(this->Program, vertex);glDetachShader(this->Program, fragment);glDeleteShader(vertex);glDeleteShader(fragment);glDeleteProgram(this->Program);}void Use() {glUseProgram(this->Program);}
};
- core1.vs
#version 330 core
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
//out vec3 Color;
out vec3 Normal; //法向量
out vec3 FragPos; //每一个点的位置
//uniform mat4 transform;
uniform mat4 model; //模型变化,传入参数
uniform mat4 view; //相机坐标系
uniform mat4 projection; //投影变换
void main() {//gl_Position = transform * vec4(position, 1.0f);gl_Position = projection * view * model * vec4(position, 1.0f); //先乘 model,最后乘 projection//Color = color;FragPos = vec3(model * vec4(position, 1.0f));Normal = mat3(transpose(inverse(model))) * normal; //平移不影响法向量,所以只要 3 * 3
}
- core1.frag
#version 330 core
//in vec3 Color;
out vec4 color;
in vec3 FragPos;
in vec3 Normal;uniform vec3 lightPos; //光源位置
uniform vec3 viewPos; //
uniform vec3 objectColor; //物体颜色
uniform vec3 lightColor; //光颜色void main() {//color = vec4(Color, 1.0f);// ambient 环境部分float ambientStrength = 0.1f;vec3 ambient = ambientStrength * lightColor;// diffuse 漫反射vec3 norm = normalize(Normal);vec3 lightDir = normalize(lightPos - FragPos); //光照方向,从光源位置到物体位置float diff = max(dot(norm, lightDir), 0.0f); //光照和法向量点乘,与 0 取较大值float diffuseStrength = 0.4f;//vec3 diffuse = diffuseStrength * diff * lightColor;vec3 diffuse = diffuseStrength * lightColor * diff;// specular 镜面反射float specularStrength = 2.5f;vec3 viewDir = normalize(viewPos - FragPos);vec3 halfAngle = normalize(viewDir + lightDir); //半角float spec = pow(max(dot(norm, halfAngle), 0.0f), 32);vec3 specular = specularStrength * spec * lightColor;// 三部分叠加vec3 result = (ambient + diffuse + specular) * objectColor; //全加一起color = vec4(result, 1.0f);
}
- Camera.h
//
// Camera.h
// Course 3
//
// Created by rui huang on 10/18/17.
// Copyright © 2017 rui huang. All rights reserved.
//#pragma once#include <vector>#define GLEW_STATIC
#include <GL/glew.h>#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>enum Camera_Movement
{FORWARD,BACKWARD,LEFT,RIGHT
};const GLfloat YAW = -90.0f;
const GLfloat PITCH = 0.0f;
const GLfloat SPEED = 6.0f;
const GLfloat SENSITIVITY = 0.25f;
const GLfloat ZOOM = 45.0f;// An abstract camera class that processes input and calculates the corresponding Eular Angles, Vectors and Matrices for OpenGL
class Camera
{public:// 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), GLfloat yaw = YAW, GLfloat pitch = PITCH) :front(glm::vec3(0.0f, 0.0f, -1.0f)), movementSpeed(SPEED), mouseSensitivity(SENSITIVITY), zoom(ZOOM){this->position = position; //相机的起点this->worldUp = up; //向前的量this->yaw = yaw; //仰角:飞机上下动this->pitch = pitch; //飞机左右动this->updateCameraVectors(); //更新:建立坐标系}// Constructor with scalar valuesCamera(GLfloat posX, GLfloat posY, GLfloat posZ, GLfloat upX, GLfloat upY, GLfloat upZ, GLfloat yaw = YAW, GLfloat pitch = PITCH) :front(glm::vec3(0.0f, 0.0f, -1.0f)), movementSpeed(SPEED), mouseSensitivity(SENSITIVITY), zoom(ZOOM){this->position = glm::vec3(posX, posY, posZ);this->worldUp = glm::vec3(upX, upY, upZ);this->yaw = yaw;this->pitch = pitch;this->updateCameraVectors();}void ProcessKeyboard(Camera_Movement direction, GLfloat deltaTime){//乘以 deltaTime:消除电脑性能,控制时间一样长GLfloat velocity = this->movementSpeed * deltaTime;//处理键盘//向前:加上向前if (direction == FORWARD) {this->position += this->front * velocity;}//向后:减去向前if (direction == BACKWARD) {this->position -= this->front * velocity;}if (direction == LEFT) {this->position -= this->right * velocity;}if (direction == RIGHT) {this->position += this->right * velocity;}}void ProcessMouseMovement(GLfloat xOffset, GLfloat yOffset, GLboolean constrainPith = true){xOffset *= this->mouseSensitivity;yOffset *= this->mouseSensitivity;this->yaw += xOffset;this->pitch += yOffset;if (constrainPith) { //保证用户只能看到天空或脚下,但是不能超越这个限制//设置界限 < 90.0f,超过 90 度就会失效,视角发生逆转,因为直角是 90 度if (this->pitch > 89.0f) {this->pitch = 89.0f;}if (this->pitch < -89.0f) {this->pitch = -89.0f;}}this->updateCameraVectors();}void ProcessMouseScroll(GLfloat yOffset){}glm::mat4 GetViewMatrix(){//lookAt:观察矩阵:摄像机位置;目标位置;上向量return glm::lookAt(this->position, this->position + this->front, this->up);}GLfloat GetZoom(){return this->zoom;}//返回相机位置glm::vec3 GetPosition(){return this->position;}
private:glm::vec3 position;glm::vec3 front;glm::vec3 up;glm::vec3 right;glm::vec3 worldUp;GLfloat yaw;GLfloat pitch;GLfloat movementSpeed;GLfloat mouseSensitivity;GLfloat zoom;void updateCameraVectors(){glm::vec3 front;//通过俯仰角和偏航角来计算以得到真正的方向向量//极坐标系下的:x、y、z轴front.x = cos(glm::radians(this->pitch)) * cos(glm::radians(this->yaw)); //x 轴向前front.y = sin(glm::radians(this->pitch)); //y 轴向上front.z = cos(glm::radians(this->pitch)) * sin(glm::radians(this->yaw)); //z 轴向右this->front = glm::normalize(front); //向前this->right = glm::normalize(glm::cross(this->front, this->worldUp)); //向右:向前 × 向上this->up = glm::normalize(glm::cross(this->right, this->front)); //向上:向右 × 向前}
};
- light.vs
#version 330 core
layout(location = 0) in vec3 position;
uniform mat4 model; //模型变化,传入参数
uniform mat4 view; //相机坐标系
uniform mat4 projection; //投影变换
void main() {gl_Position = projection * view * model * vec4(position, 1.0f); //先乘 model,最后乘 projection
}
- light.frag
#version 330 core
uniform vec3 lightColor; //光颜色
out vec4 color;void main() {color = vec4(lightColor, 1.0f);
}
程序正常运行,能得到已下图形。
二、讲解
设置光源坐标。
// 设置光源坐标
glm::vec3 lightPos(1.2f, 1.0f, 2.0f);
光源调色器。
// 光源调色器Shader lightShader = Shader("light.vs", "light.frag");
为光源创建一个新的 VAO。
// 为光源创建一个新的 VAOGLuint lightVAO;glGenVertexArrays(1, &lightVAO);// 绑定光源 VAOglBindVertexArray(lightVAO);// 只需要绑定VBO不用再次设置VBO的数据,因为容器(物体)的VBO数据中已经包含了正确的立方体顶点数据glBindBuffer(GL_ARRAY_BUFFER, VBO);// 设置光源的顶点属性指针(仅设置灯的顶点数据)glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,6 * sizeof(GLfloat), (GLvoid *)0); //0:对应调色器里 location 的值;3:对应 vec3 三个量;GL_FLOAT:浮点型;GL_FALSE:;6*sizeof(GLfloat):对应 Buffer 里传的数据;(GLvoid*)0:从第 0 个位置开始glEnableVertexAttribArray(0);glBindBuffer(GL_ARRAY_BUFFER, 0);glBindVertexArray(0);
设置 uniform。
// 首先使用对应的着色器程序(来设定uniform)GLint objectColorLoc = glGetUniformLocation(ourShader.Program, "objectColor");GLint lightColorLoc = glGetUniformLocation(ourShader.Program, "lightColor");GLint lightPosLoc = glGetUniformLocation(ourShader.Program, "lightPos");GLint viewPosLoc = glGetUniformLocation(ourShader.Program, "viewPos");
设置光源信息。
glUniform3f(objectColorLoc, 1.0f, 0.5f, 0.3f); //珊瑚红glUniform3f(lightColorLoc, 1.0f, 1.0f, 1.0f); //把光源设置为白色glUniform3f(lightPosLoc, lightPos.x, lightPos.y, lightPos.z);glUniform3f(viewPosLoc, camera.GetPosition().x, camera.GetPosition().y, camera.GetPosition().z); //使用摄像机对象的位置坐标代替
画光源。
// 画光源lightShader.Use();// 设置模型、视图和投影矩阵 uniformmodelLoc = glGetUniformLocation(lightShader.Program, "model"); //到 vs 找到那个 model 变量viewLoc = glGetUniformLocation(lightShader.Program, "view"); //到 vs 找到那个 view 变量projectionLoc = glGetUniformLocation(lightShader.Program, "projection"); //到 vs 找到那个 projection 变量// 对模型进行操作model = glm::translate(model, lightPos); //平移光源model = glm::scale(model, glm::vec3(0.2f)); //缩放光源
传入数据。
// 传入数据glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));lightColorLoc = glGetUniformLocation(lightShader.Program, "lightColor");glUniform3f(lightColorLoc, 1.0f, 1.0f, 1.0f);
绘制光源对象。
// 绘制光源对象glBindVertexArray(lightVAO); //使用 VAO,直接绑定glDrawArrays(GL_TRIANGLES, 0, 36); //画三角形,总共有 36 个顶点//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);glBindVertexArray(0);
三、致谢
光照
从 0 开始的 OpenGL 学习(十一)- 基本光照模拟
图形学笔记(九)增加一个光源相关推荐
- 图形学笔记(十九)动画 —— 动画的历史、关键帧插值、物理仿真、质点弹簧系统、粒子系统、(反向IK)动力学、Rigging 绑定、Blend Shapes、动作捕捉
图形学笔记(十八)光场.颜色和感知-- 光场相机(全光函数.光线和光场的定义).可见光谱.谱功率密度.颜色的生物学基础.Tristimulus Theory.同色异谱.加色与减色系统.颜色空间SPD ...
- 图形学笔记(九)几何 ——几何表示方法(CSG、距离函数、水平集 、点云、网格(obj格式))、贝塞尔曲线(面)
图形学笔记(八)着色2 -- 纹理映射.重心坐标.双线性插值.Mipmap.三线性插值.各向异性过滤.纹理的应用(环境贴图.法线贴图等) 图形学笔记(十)几何2 -- 曲面细分(Loop细分.Catm ...
- 图形学笔记(二十)粒子、刚体、流体的模拟—— 欧拉方法、Errors 和 Instability、中点法、自适应步长、隐式欧拉方法、Runge-Kutta方法、刚体与流体模拟(质点法、网格法、MPM)
图形学笔记(十九)粒子.刚体.流体的模拟-- 欧拉方法.Errors 和 Instability.中点法.自适应步长.隐式欧拉方法.Runge-Kutta方法.刚体与流体模拟(质点法.网格法.MPM) ...
- 图形学笔记(八)着色2 —— 纹理映射、重心坐标、双线性插值、Mipmap、三线性插值、各向异性过滤、纹理的应用(环境贴图、法线贴图等)
图形学笔记(七)着色 -- Blinn-Phone 反射模型.着色频率.渲染管线.GPU 图形学笔记(九)几何 --几何表示方法(CSG.距离函数.水平集 .点云.网格(obj格式)).贝塞尔曲线(面 ...
- 图形学笔记(十)几何2 —— 曲面细分(Loop细分、Catmull-Clark细分)、曲面简化(边坍缩、二次度量误差)、曲面正则化
图形学笔记(九)几何 --几何表示方法(CSG.距离函数.水平集 .点云.网格(obj格式)).贝塞尔曲线(面) 图形学笔记(十一)光线追踪--Shadow Mapping.光线追踪.光线投射.软硬阴 ...
- 吴恩达《机器学习》学习笔记九——神经网络相关(1)
吴恩达<机器学习>学习笔记九--神经网络相关(1) 一. 非线性假设的问题 二. 神经网络相关知识 1.神经网络的大致历史 2.神经网络的表示 3.前向传播:向量化表示 三. 例子与直觉理 ...
- 《MFC游戏开发》笔记九 游戏中的碰撞判定初步怪物运动简单AI
本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/9374935 作者:七十一雾央 新浪微博:http:// ...
- at24c16如何划分出多个读写区_AVR学习笔记九、基于AT24C16的数据存储实验
Ema{@AVR 学习笔记九.基于 AT24C16 的数据存储实验 ------- 基于 LT_Mini_M16 9.1 用 I/O 口模拟 I2C 总线实现 AT24C16 的读写 9.1.1 .实 ...
- [统计学笔记九] 方差分析(ANOVA)
[统计学笔记九] 方差分析(ANOVA) 方差分析(Analysis of Variance,简称ANOVA) 方差分析(ANOVA)又称"变异数分析"或"F检验&quo ...
最新文章
- [网络流24题] 最长k可重区间集
- 通过sql语句对MySql数据库的基本操作
- mysql中创建用户并授权_MySQL中创建用户及授权[转]
- SolrJ查询索引库
- 丑憨批的html笔记
- python如何安装scrapy_Python爬虫之Scrapy的安装
- Augury翻译---io-demo
- 谷歌这波操作,预警了什么信号??
- Storm0.9.4安装 - OPEN 开发经验库
- 利用Python来玩扫雷,极致的思维体验
- POS tagging中英文对应
- 如何卸载Edge/如何降Edge版本
- sklearn中的make_blobs
- 中山大学羽毛球场馆自动订场(Python+selenium+百度aip)
- 面向对象软件设计原则【JAVA】(开闭原则、里氏代换、依赖倒转、接口隔离、迪米特法则、合成复用原则)
- uC/OS-III系统移植STM32F103C8
- [Vue]github案例
- 牛客网 KY6 手机键盘
- 服务器之间文件同步 go,基于golang文件实时监控并同步远端服务器工具
- 携程CPS分佣怎么推广?
热门文章
- 小米开机显示android很慢,安卓手机久了越来越慢卡顿怎么办?小米手机正确技巧优化提升网速...
- lwip网络接口netif
- 爬取可搜索百度图片并下载到本地——以远洋椿萱茂词条为例
- SSIS Execute SQL Task 用法
- linux安装 openbabel pybel
- 眉山市职称计算机成绩,眉山市2014年第1次(2月份)全国职称计算机考试成绩.doc
- python迷宫小游戏代码_pygame简易迷宫游戏_mask应用示例程序
- 关于我国计算机事业发展的描述,[说明]冯康的计算数学人生.doc
- 飞凡汽车,你拿什么和人斗?
- 华硕也开始做开源硬件了---tinkerboard卡片电脑主板