给之前画出来的立方体加一个围绕它转的光源。

一、代码

  • 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 学习(十一)- 基本光照模拟

图形学笔记(九)增加一个光源相关推荐

  1. 图形学笔记(十九)动画 —— 动画的历史、关键帧插值、物理仿真、质点弹簧系统、粒子系统、(反向IK)动力学、Rigging 绑定、Blend Shapes、动作捕捉

    图形学笔记(十八)光场.颜色和感知-- 光场相机(全光函数.光线和光场的定义).可见光谱.谱功率密度.颜色的生物学基础.Tristimulus Theory.同色异谱.加色与减色系统.颜色空间SPD ...

  2. 图形学笔记(九)几何 ——几何表示方法(CSG、距离函数、水平集 、点云、网格(obj格式))、贝塞尔曲线(面)

    图形学笔记(八)着色2 -- 纹理映射.重心坐标.双线性插值.Mipmap.三线性插值.各向异性过滤.纹理的应用(环境贴图.法线贴图等) 图形学笔记(十)几何2 -- 曲面细分(Loop细分.Catm ...

  3. 图形学笔记(二十)粒子、刚体、流体的模拟—— 欧拉方法、Errors 和 Instability、中点法、自适应步长、隐式欧拉方法、Runge-Kutta方法、刚体与流体模拟(质点法、网格法、MPM)

    图形学笔记(十九)粒子.刚体.流体的模拟-- 欧拉方法.Errors 和 Instability.中点法.自适应步长.隐式欧拉方法.Runge-Kutta方法.刚体与流体模拟(质点法.网格法.MPM) ...

  4. 图形学笔记(八)着色2 —— 纹理映射、重心坐标、双线性插值、Mipmap、三线性插值、各向异性过滤、纹理的应用(环境贴图、法线贴图等)

    图形学笔记(七)着色 -- Blinn-Phone 反射模型.着色频率.渲染管线.GPU 图形学笔记(九)几何 --几何表示方法(CSG.距离函数.水平集 .点云.网格(obj格式)).贝塞尔曲线(面 ...

  5. 图形学笔记(十)几何2 —— 曲面细分(Loop细分、Catmull-Clark细分)、曲面简化(边坍缩、二次度量误差)、曲面正则化

    图形学笔记(九)几何 --几何表示方法(CSG.距离函数.水平集 .点云.网格(obj格式)).贝塞尔曲线(面) 图形学笔记(十一)光线追踪--Shadow Mapping.光线追踪.光线投射.软硬阴 ...

  6. 吴恩达《机器学习》学习笔记九——神经网络相关(1)

    吴恩达<机器学习>学习笔记九--神经网络相关(1) 一. 非线性假设的问题 二. 神经网络相关知识 1.神经网络的大致历史 2.神经网络的表示 3.前向传播:向量化表示 三. 例子与直觉理 ...

  7. 《MFC游戏开发》笔记九 游戏中的碰撞判定初步怪物运动简单AI

    本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/9374935 作者:七十一雾央 新浪微博:http:// ...

  8. at24c16如何划分出多个读写区_AVR学习笔记九、基于AT24C16的数据存储实验

    Ema{@AVR 学习笔记九.基于 AT24C16 的数据存储实验 ------- 基于 LT_Mini_M16 9.1 用 I/O 口模拟 I2C 总线实现 AT24C16 的读写 9.1.1 .实 ...

  9. [统计学笔记九] 方差分析(ANOVA)

    [统计学笔记九] 方差分析(ANOVA) 方差分析(Analysis of Variance,简称ANOVA) 方差分析(ANOVA)又称"变异数分析"或"F检验&quo ...

最新文章

  1. [网络流24题] 最长k可重区间集
  2. 通过sql语句对MySql数据库的基本操作
  3. mysql中创建用户并授权_MySQL中创建用户及授权[转]
  4. SolrJ查询索引库
  5. 丑憨批的html笔记
  6. python如何安装scrapy_Python爬虫之Scrapy的安装
  7. Augury翻译---io-demo
  8. 谷歌这波操作,预警了什么信号??
  9. Storm0.9.4安装 - OPEN 开发经验库
  10. 利用Python来玩扫雷,极致的思维体验
  11. POS tagging中英文对应
  12. 如何卸载Edge/如何降Edge版本
  13. sklearn中的make_blobs
  14. 中山大学羽毛球场馆自动订场(Python+selenium+百度aip)
  15. 面向对象软件设计原则【JAVA】(开闭原则、里氏代换、依赖倒转、接口隔离、迪米特法则、合成复用原则)
  16. uC/OS-III系统移植STM32F103C8
  17. [Vue]github案例
  18. 牛客网 KY6 手机键盘
  19. 服务器之间文件同步 go,基于golang文件实时监控并同步远端服务器工具
  20. 携程CPS分佣怎么推广?

热门文章

  1. 小米开机显示android很慢,安卓手机久了越来越慢卡顿怎么办?小米手机正确技巧优化提升网速...
  2. lwip网络接口netif
  3. 爬取可搜索百度图片并下载到本地——以远洋椿萱茂词条为例
  4. SSIS Execute SQL Task 用法
  5. linux安装 openbabel pybel
  6. 眉山市职称计算机成绩,眉山市2014年第1次(2月份)全国职称计算机考试成绩.doc
  7. python迷宫小游戏代码_pygame简易迷宫游戏_mask应用示例程序
  8. 关于我国计算机事业发展的描述,[说明]冯康的计算数学人生.doc
  9. 飞凡汽车,你拿什么和人斗?
  10. 华硕也开始做开源硬件了---tinkerboard卡片电脑主板