计算机图形学期末大作业:实现 Skybox 天空盒,以及 Shadow volume 阴影体。

写在前面

本人才疏学浅,水平有限,只实现了 SkyboxShadow volume 没有完全实现(我真的太菜了)。前期跟着老师课堂教学,感觉都能跟上。后期直接跳到引入 模型 ,发现自己真的跟不上了。大作业做得我心态爆炸,网上教程看一下午,就是看不进去,怎么也做不出来。

加上隔得时间有点长,所以本篇博客可能写得会非常水。见谅~

一、思路

参照网上教程,完成 Skybox 天空盒部分。再实现 Shadow volume 阴影体。

二、代码

  • main.cpp
//
// main.cpp
// Course 4
//
// Created by rui huang on 10/27/17.
// Copyright © 2017 rui huang. All rights reserved.
//


#include <iostream>

#define GLM_ENABLE_EXPERIMENTAL
#define GLEW_STATIC
#include <GL/glew.h>

#include <GLFW/glfw3.h>

#include "Shader.h"

#include "SOIL2/SOIL2.h"
#include "SOIL2/stb_image.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/rotate_vector.hpp>

#include <glm/gtc/type_ptr.hpp>

#include "Camera.h"
#include "Model.h"
#include "Mesh.h"
#include "Light.h"
const GLint WIDTH = 800, HEIGHT = 800;
void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mode);
void ScrollCallback(GLFWwindow *window, double xOffset, double yOffset);
void MouseCallback(GLFWwindow *window, double xPos, double yPos);
//
GLuint loadCubemap(vector<const GLchar*> faces);
void DoMovement();

Camera camera(glm::vec3(0.0f, 0.0f, 2.0f));
GLfloat lastX = WIDTH / 2.0;
GLfloat lastY = HEIGHT / 2.0;
bool keys[1024];

GLfloat deltaTime = 0.0f;
GLfloat lastTime = 0.0f;
bool firstMouse = true;


int main()
{
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
	glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

	GLFWwindow *window = glfwCreateWindow(WIDTH, HEIGHT, "OpenGL B16xxxxxx", nullptr, nullptr);

	int screenWidth, screenHeight;
	glfwGetFramebufferSize(window, &screenWidth, &screenHeight);

	if (nullptr == window) {
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);

	// Set the required callback function
	glfwSetKeyCallback(window, KeyCallback);
	glfwSetCursorPosCallback(window, MouseCallback);
	glfwSetScrollCallback(window, ScrollCallback);
	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);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);
	//glDepthFunc(GL_LESS);
	Shader shader("shaders/modelLoad.vs", "shaders/modelLoad.frag");
	Shader lightShader("shaders/core.vs", "shaders/core.frag");
	Shader skyboxShader("shaders/skybox.vs", "shaders/skybox.frag");
	Shader volumeShader("shaders/shadow_volume.vs", "shaders/shadow_volume.frag", "shaders/shadow_volume.geom");
	Shader floor("shaders/plane.vs", "shaders/plane.frag");
	//Shader floor("shaders/silhouette.vs", "shaders/silhouette.gs");
	// Load models
	Model ourModel((GLchar *)"models/nanosuit.obj");
	Light lightModel = Light();

	glm::vec3 LightPos1 = glm::vec3(1.0f, 1.5f, 0.0f);
	//glm::vec3 LightPos1 = glm::vec3(15.0f, 1.5f, 2.5f); //横向光源
	//glm::vec3 LightPos2 = glm::vec3(0.0f, 5.0f, 0.0f); //第一个:左右 第二个:上下 第三个:前后
	//glm::vec3 LightPos3 = glm::vec3(1.3f, 0.0f, 0.0f);

	float skyboxVertices[] = {
		// positions 
		-1.0f,  1.0f, -1.0f,
		-1.0f, -1.0f, -1.0f,
		 1.0f, -1.0f, -1.0f,
		 1.0f, -1.0f, -1.0f,
		 1.0f,  1.0f, -1.0f,
		-1.0f,  1.0f, -1.0f,

		-1.0f, -1.0f,  1.0f,
		-1.0f, -1.0f, -1.0f,
		-1.0f,  1.0f, -1.0f,
		-1.0f,  1.0f, -1.0f,
		-1.0f,  1.0f,  1.0f,
		-1.0f, -1.0f,  1.0f,

		 1.0f, -1.0f, -1.0f,
		 1.0f, -1.0f,  1.0f,
		 1.0f,  1.0f,  1.0f,
		 1.0f,  1.0f,  1.0f,
		 1.0f,  1.0f, -1.0f,
		 1.0f, -1.0f, -1.0f,

		-1.0f, -1.0f,  1.0f,
		-1.0f,  1.0f,  1.0f,
		 1.0f,  1.0f,  1.0f,
		 1.0f,  1.0f,  1.0f,
		 1.0f, -1.0f,  1.0f,
		-1.0f, -1.0f,  1.0f,

		-1.0f,  1.0f, -1.0f,
		 1.0f,  1.0f, -1.0f,
		 1.0f,  1.0f,  1.0f,
		 1.0f,  1.0f,  1.0f,
		-1.0f,  1.0f,  1.0f,
		-1.0f,  1.0f, -1.0f,

		-1.0f, -1.0f, -1.0f,
		-1.0f, -1.0f,  1.0f,
		 1.0f, -1.0f, -1.0f,
		 1.0f, -1.0f, -1.0f,
		-1.0f, -1.0f,  1.0f,
		 1.0f, -1.0f,  1.0f
	};
	GLfloat plainVertices[] = {
		15.0f, 0.0f, 15.0f,     //1.0f, 0.0f, 0.0f,
		-15.0f, 0.0f, 15.0f,    //1.0f, 0.0f, 0.0f,
		15.0f, 0.0f, -15.0f,    //1.0f, 0.0f, 0.0f,
		-15.0f, 0.0f, -15.0f,   //1.0f, 0.0f, 0.0f

	};

	unsigned int indices[] = {
	0,1,3,
	1,2,3
	};

	GLuint VBO[1], VAO[1];
	glGenVertexArrays(1, VAO);
	glGenBuffers(1, VBO);

	glBindVertexArray(VAO[0]);
	glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
	glBufferData(GL_ARRAY_BUFFER, sizeof(plainVertices), plainVertices, GL_STATIC_DRAW);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GL_FLOAT), (GLvoid*)0);
	glEnableVertexAttribArray(0);
	//glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GL_FLOAT), (GLvoid*)(3 * sizeof(GLfloat)));
	//glEnableVertexAttribArray(1);
	glBindVertexArray(0);

	GLuint EBO;
	glGenBuffers(1, &EBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
	glBindVertexArray(0);


	// Setup skybox VAO
	GLuint skyboxVAO, skyboxVBO;
	glGenVertexArrays(1, &skyboxVAO);
	glGenBuffers(1, &skyboxVBO);
	glBindVertexArray(skyboxVAO);
	glBindBuffer(GL_ARRAY_BUFFER, skyboxVBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices, GL_STATIC_DRAW);
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
	glBindVertexArray(0);

	// Cubemap (Skybox)
	vector<const GLchar*> faces;
	faces.push_back("skybox/right.jpg");
	faces.push_back("skybox/left.jpg");
	faces.push_back("skybox/top.jpg");
	faces.push_back("skybox/bottom.jpg");
	faces.push_back("skybox/back.jpg");
	faces.push_back("skybox/front.jpg");
	GLuint cubemapTexture = loadCubemap(faces);


	while (!glfwWindowShouldClose(window)) {

		// Get the delta time between frames
		GLfloat currentFrame = glfwGetTime();
		deltaTime = currentFrame - lastTime;
		lastTime = currentFrame;
		//LightPos1 = glm::rotate(LightPos1, 0.01f, glm::vec3(0.0f, 1.0f, 0.0f));
		//LightPos2 = glm::rotate(LightPos2, 0.01f, glm::vec3(1.0f, 0.0f, 0.0f));

		// Check and call events
		glfwPollEvents();
		DoMovement();

		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		//glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
		glm::mat4 view = camera.GetViewMatrix();
		glm::mat4 projection = glm::perspective(glm::radians(camera.GetZoom()), (float)screenWidth / (float)screenHeight, 0.1f, 100.0f);
		glm::mat4 model = glm::mat4(1.0f);

		// Draw skybox first
		glDepthMask(GL_FALSE);// 关掉深度
		skyboxShader.Use();
		view = glm::mat4(glm::mat3(camera.GetViewMatrix()));	// Remove any translation component of the view matrix
		//view = camera.GetViewMatrix();
		//glm::mat4(glm::mat3(camera.GetViewMatrix()));
		//glm::mat4 projection = glm::perspective(glm::radians(camera.GetZoom()), (float)screenWidth / (float)screenHeight, 0.1f, 100.0f);
		//projection = glm::perspective(glm::radians(camera.GetZoom()), (float)screenWidth / (float)screenHeight, 0.1f, 100.0f);
		glUniformMatrix4fv(glGetUniformLocation(skyboxShader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view));
		glUniformMatrix4fv(glGetUniformLocation(skyboxShader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));

		// skybox cube
		glBindVertexArray(skyboxVAO);
		glActiveTexture(GL_TEXTURE0);
		glUniform1i(glGetUniformLocation(shader.Program, "skybox"), 0);
		glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);
		glDrawArrays(GL_TRIANGLES, 0, 36);
		glBindVertexArray(0);

		// depth
		//view = camera.GetViewMatrix();
		glDepthMask(GL_TRUE);
		lightShader.Use();
		view = camera.GetViewMatrix();
		//projection = glm::perspective(glm::radians(camera.GetZoom()), (float)screenWidth / (float)screenHeight, 0.1f, 100.0f);

		model = glm::mat4(1.0f);
		model = glm::translate(model, LightPos1);
		//model = glm::translate(model, LightPos1 + glm::vec3(0.0f, 2.0f, 0.0f));
		model = glm::scale(model, glm::vec3(0.1f, 0.1f, 0.1f));
		//glUniformMatrix4fv(glGetUniformLocation(lightShader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
		//lightModel.Draw(lightShader);
		glUniformMatrix4fv(glGetUniformLocation(lightShader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view));
		glUniformMatrix4fv(glGetUniformLocation(lightShader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
		glUniformMatrix4fv(glGetUniformLocation(lightShader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
		lightModel.Draw(lightShader);

		/* // 第二个光源 model = glm::mat4(1.0f); model = glm::translate(model, LightPos2); //model = glm::translate(model, LightPos2 + glm::vec3(0.0f, 2.0f, 0.0f)); model = glm::scale(model, glm::vec3(0.1f, 0.1f, 0.1f)); glUniformMatrix4fv(glGetUniformLocation(lightShader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); lightModel.Draw(lightShader); */

		/* // 第三个光源 model = glm::mat4(1.0f); //model = glm::translate(model, LightPos3); model = glm::scale(model, glm::vec3(0.1f, 0.1f, 0.1f)); glUniformMatrix4fv(glGetUniformLocation(lightShader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); lightModel.Draw(lightShader); */


		// model
		view = camera.GetViewMatrix();
		glDepthMask(GL_TRUE);
		// 关闭颜色缓存写入
		glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
		shader.Use();
		model = glm::mat4(1.0f);
		model = glm::scale(model, glm::vec3(0.0f, -10.0f, -20.0f));
		model = glm::scale(model, glm::vec3(0.2f, 0.2f, 0.2f));
		glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view));
		glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
		glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
		glUniform3f(glGetUniformLocation(shader.Program, "ViewPos"), camera.GetPosition().x, camera.GetPosition().y, camera.GetPosition().z);
		glUniform3f(glGetUniformLocation(shader.Program, "LightPos1"), LightPos1.x, LightPos1.y, LightPos1.z);
		//glUniform3f(glGetUniformLocation(shader.Program, "LightPos2"), LightPos2.x, LightPos2.y, LightPos2.z);
		//glUniform3f(glGetUniformLocation(shader.Program, "LightPos"), LightPos3.x, LightPos3.y, LightPos3.z);
		glUniform1f(glGetUniformLocation(shader.Program, "material.shininess"), 64.0f);
		ourModel.Draw(shader);
		glDepthMask(GL_TRUE);
		glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

		// floor
		floor.Use();
		model = glm::mat4(1.0f);
		model = glm::translate(model, glm::vec3(0.0f, -10.0f, -20.0f));
		glUniformMatrix4fv(glGetUniformLocation(floor.Program, "view"), 1, GL_FALSE, glm::value_ptr(view));
		glUniformMatrix4fv(glGetUniformLocation(floor.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
		glUniformMatrix4fv(glGetUniformLocation(floor.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
		glBindVertexArray(VAO[0]);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

		// shadow volume
		glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
		glDepthMask(GL_FALSE);
		glEnable(GL_DEPTH_CLAMP);
		glClear(GL_STENCIL_BUFFER_BIT);
		glEnable(GL_STENCIL_TEST);
		glClearStencil(1);
		glStencilFunc(GL_ALWAYS, 1, 0xff);
		// zfail
		glStencilOpSeparate(GL_BACK, GL_KEEP, GL_INCR_WRAP, GL_KEEP);
		glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR_WRAP, GL_KEEP);
		volumeShader.Use();
		model = glm::mat4(1.0f);
		model = glm::translate(model, glm::vec3(0.0f, -10.0f, -20.0f));
		model = glm::scale(model, glm::vec3(0.2f, 0.2f, 0.2f));
		glUniformMatrix4fv(glGetUniformLocation(volumeShader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
		glUniformMatrix4fv(glGetUniformLocation(volumeShader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view));
		glUniformMatrix4fv(glGetUniformLocation(volumeShader.Program, "ProjMatrix"), 1, GL_FALSE, glm::value_ptr(projection));
		glUniform3f(glGetUniformLocation(volumeShader.Program, "LightPosition"), (LightPos1).x, (LightPos1).y, (LightPos1).z);
		ourModel.Draw(volumeShader);
		glDisable(GL_DEPTH_CLAMP);
		glDisable(GL_STENCIL_TEST);

		// ambient light
		glStencilFunc(GL_ALWAYS, 1, 0xff);
		glDepthMask(GL_TRUE);
		glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
		floor.Use();
		model = glm::mat4(1.0f);
		model = glm::translate(model, glm::vec3(0.0f, -10.0f, -20.0f));
		glUniform1f(glGetUniformLocation(floor.Program, "ambientStrength"), 0.1f);
		glUniform1f(glGetUniformLocation(floor.Program, "diffuseStrength"), 0.0f);
		glUniform1f(glGetUniformLocation(floor.Program, "specularStrength"), 0.0f);
		glUniformMatrix4fv(glGetUniformLocation(floor.Program, "view"), 1, GL_FALSE, glm::value_ptr(view));
		glUniformMatrix4fv(glGetUniformLocation(floor.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
		glUniformMatrix4fv(glGetUniformLocation(floor.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
		glUniform3f(glGetUniformLocation(floor.Program, "objectColor"), 1.0f, 0.5f, 0.3f);
		glUniform3f(glGetUniformLocation(floor.Program, "lightColor"), 1.0f, 1.0f, 1.0f);
		glUniform3f(glGetUniformLocation(floor.Program, "lightPos"), LightPos1.x, LightPos1.y, LightPos1.z);
		glUniform3f(glGetUniformLocation(floor.Program, "viewPos"), camera.GetPosition().x, camera.GetPosition().y, camera.GetPosition().z);
		glBindVertexArray(VAO[0]);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

		glStencilFunc(GL_ALWAYS, 1, 0xff);
		shader.Use();
		model = glm::mat4(1.0f);
		model = glm::translate(model, glm::vec3(0.0f, -10.0f, -20.0f));
		model = glm::scale(model, glm::vec3(0.2f, 0.2f, 0.2f));
		glUniform1f(glGetUniformLocation(shader.Program, "ambientStrength"), 0.4f);
		glUniform1f(glGetUniformLocation(shader.Program, "diffuseStrength"), 0.0f);
		glUniform1f(glGetUniformLocation(shader.Program, "specularStrength"), 0.0f);
		glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view));
		glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
		glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
		glUniform3f(glGetUniformLocation(shader.Program, "ViewPos"), camera.GetPosition().x, camera.GetPosition().y, camera.GetPosition().z);
		glUniform3f(glGetUniformLocation(shader.Program, "LightPos1"), LightPos1.x, LightPos1.y, LightPos1.z);
		glUniform1f(glGetUniformLocation(shader.Program, "material.shininess"), 64.0f);
		ourModel.Draw(shader);

		// diffuse light
		glEnable(GL_BLEND);
		glBlendEquation(GL_FUNC_ADD);
		glBlendFunc(GL_ONE, GL_ONE);
		glDepthFunc(GL_LEQUAL);
		glDepthMask(GL_TRUE);
		glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
		glEnable(GL_STENCIL_TEST);
		glEnable(GL_STENCIL);
		glStencilFunc(GL_EQUAL, 1, 0xff);
		glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_KEEP);
		shader.Use();
		model = glm::mat4(1.0f);
		model = glm::translate(model, glm::vec3(0.0f, -10.0f, -20.0f));
		model = glm::scale(model, glm::vec3(0.2f, 0.2f, 0.2f));
		glUniform1f(glGetUniformLocation(shader.Program, "ambientStrength"), 0.0f);
		glUniform1f(glGetUniformLocation(shader.Program, "diffuseStrength"), 0.6f);
		glUniform1f(glGetUniformLocation(shader.Program, "specularStrength"), 0.9f);
		glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view));
		glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
		glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
		glUniform3f(glGetUniformLocation(shader.Program, "ViewPos"), camera.GetPosition().x, camera.GetPosition().y, camera.GetPosition().z);
		glUniform3f(glGetUniformLocation(shader.Program, "LightPos"), LightPos1.x, LightPos1.y, LightPos1.z);
		glUniform1f(glGetUniformLocation(shader.Program, "material.shininess"), 64.0f);
		ourModel.Draw(shader);

		glStencilFunc(GL_EQUAL, 1, 0xff);
		glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_KEEP);
		floor.Use();
		model = glm::mat4(1.0f);
		model = glm::translate(model, glm::vec3(0.0f, -10.0f, -20.0f));
		glUniform1f(glGetUniformLocation(floor.Program, "ambientStrength"), 0.0f);
		glUniform1f(glGetUniformLocation(floor.Program, "diffuseStrength"), 0.6f);
		glUniform1f(glGetUniformLocation(floor.Program, "specularStrength"), 0.9f);
		glUniformMatrix4fv(glGetUniformLocation(floor.Program, "view"), 1, GL_FALSE, glm::value_ptr(view));
		glUniformMatrix4fv(glGetUniformLocation(floor.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
		glUniformMatrix4fv(glGetUniformLocation(floor.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
		glUniform3f(glGetUniformLocation(floor.Program, "objectColor"), 1.0f, 0.5f, 0.3f);
		glUniform3f(glGetUniformLocation(floor.Program, "lightColor"), 1.0f, 1.0f, 1.0f);
		glUniform3f(glGetUniformLocation(floor.Program, "lightPos"), LightPos1.x, LightPos1.y, LightPos1.z);
		glUniform3f(glGetUniformLocation(floor.Program, "viewPos"), camera.GetPosition().x, camera.GetPosition().y, camera.GetPosition().z);
		glBindVertexArray(VAO[0]);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
		glDisable(GL_STENCIL_TEST);
		glDisable(GL_BLEND);

		glEnable(GL_CULL_FACE);
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
		glDisable(GL_CULL_FACE);


		glDisable(GL_STENCIL_TEST);

		glfwSwapBuffers(window);
	}

	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;

		}
		else if (action == GLFW_RELEASE)
		{
			keys[key] = false;
		}
	}
}
void ScrollCallback(GLFWwindow *window, double xOffset, double yOffset)
{
	camera.ProcessMouseScroll(yOffset);
}
void MouseCallback(GLFWwindow *window, double xPos, double yPos)
{
	if (firstMouse) {
		lastX = xPos;
		lastY = yPos;
		firstMouse = false;
	}
	GLfloat xOffset = xPos - lastX;
	GLfloat yOffset = lastY - yPos;

	lastX = xPos;
	lastY = yPos;

	// Process the camera direction
	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);
	}

}

//Skybox
GLuint loadCubemap(vector<const GLchar*> faces)
{
	GLuint textureID;
	glGenTextures(1, &textureID);
	glActiveTexture(GL_TEXTURE0);

	int width, height;
	unsigned char* image;

	glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
	for (GLuint i = 0; i < faces.size(); i++)
	{
		image = SOIL_load_image(faces[i], &width, &height, 0, SOIL_LOAD_RGB);
		glTexImage2D(
			GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0,
			GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image
		);
	}
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//GL_LINEAR整体看效果稍微模糊
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);//边界处采用纹理边缘自己的的颜色,和边框无关
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
	glBindTexture(GL_TEXTURE_CUBE_MAP, 0);

	return textureID;
}
  • shadow_volume.geom
/* #version 330 layout (triangles_adjacency) in; layout (triangle_strip, max_vertices = 18) out; in vec3 WorldPos[]; uniform vec3 gLightPos; uniform mat4 gVP; float EPSILON = 0.01; void EmitQuad(int StartIndex, vec3 StartVertex, int EndIndex, vec3 EndVertex) { vec3 LightDir = normalize(StartVertex - gLightPos); vec3 l = LightDir * EPSILON; gl_Position = gVP * vec4((StartVertex + l), 1.0); EmitVertex(); gl_Position = gVP * vec4(LightDir, 0.0); EmitVertex(); LightDir = normalize(EndVertex - gLightPos); l = LightDir * EPSILON; gl_Position = gVP * vec4((EndVertex + l), 1.0); EmitVertex(); gl_Position = gVP * vec4(LightDir, 0.0); EmitVertex(); EndPrimitive(); } void main() { vec3 e1 = WorldPos[2] - WorldPos[0]; vec3 e2 = WorldPos[4] - WorldPos[0]; vec3 e3 = WorldPos[1] - WorldPos[0]; vec3 e4 = WorldPos[3] - WorldPos[2]; vec3 e5 = WorldPos[4] - WorldPos[2]; vec3 e6 = WorldPos[5] - WorldPos[0]; vec3 Normal = cross(e1,e2); vec3 LightDir = gLightPos - WorldPos[0]; if (dot(Normal, LightDir) > 0.000001) { Normal = cross(e3,e1); if (dot(Normal, LightDir) <= 0) { vec3 StartVertex = WorldPos[0]; vec3 EndVertex = WorldPos[2]; EmitQuad(0, StartVertex, 2, EndVertex); } Normal = cross(e4,e5); LightDir = gLightPos - WorldPos[2]; if (dot(Normal, LightDir) <= 0) { vec3 StartVertex = WorldPos[2]; vec3 EndVertex = WorldPos[4]; EmitQuad(2, StartVertex, 4, EndVertex); } Normal = cross(e2,e6); LightDir = gLightPos - WorldPos[4]; if (dot(Normal, LightDir) <= 0) { vec3 StartVertex = WorldPos[4]; vec3 EndVertex = WorldPos[0]; EmitQuad(4, StartVertex, 0, EndVertex); } vec3 LightDir = (normalize(WorldPos[0] - gLightPos)) * EPSILON; gl_Position = gVP * vec4((WorldPos[0] + LightDir), 1.0); EmitVertex(); LightDir = (normalize(WorldPos[2] - gLightPos)) * EPSILON; gl_Position = gVP * vec4((WorldPos[2] + LightDir), 1.0); EmitVertex(); LightDir = (normalize(WorldPos[4] - gLightPos)) * EPSILON; gl_Position = gVP * vec4((WorldPos[4] + LightDir), 1.0); EmitVertex(); EndPrimitive(); } } */


#version 430

layout(triangles_adjacency) in;
layout( triangle_strip, max_vertices = 18 ) out;

in vec3 VPosition[];

uniform vec3 LightPosition;
uniform mat4 ProjMatrix;

float EPSILON = 0.01;

bool facesLight( vec3 a, vec3 b, vec3 c )
{
  vec3 n = cross( b - a, c - a );
  vec3 da = LightPosition.xyz - a;
  vec3 db = LightPosition.xyz - b;
  vec3 dc = LightPosition.xyz - c;

  return dot(n, da) > 0 || dot(n, db) > 0 || dot(n, dc) > 0; 
}

void emitEdgeQuad( vec3 a, vec3 b ) {
  vec3 LightDir = normalize(a - LightPosition.xyz); 
  vec3 deviation = LightDir * EPSILON;
  gl_Position = ProjMatrix * vec4(a + deviation, 1);
  EmitVertex();
  
  gl_Position = ProjMatrix * vec4(LightDir, 0);
  EmitVertex();

  LightDir = normalize(b - LightPosition.xyz); 
  deviation = LightDir * EPSILON;
  gl_Position = ProjMatrix * vec4(b + deviation, 1);
  EmitVertex();

  gl_Position = ProjMatrix * vec4(LightDir, 0);
  EmitVertex();
  EndPrimitive();
}

void main()
{
    if( facesLight(VPosition[0], VPosition[2], VPosition[4]) ) {
        if( ! facesLight(VPosition[0],VPosition[1],VPosition[2]) ) 
          emitEdgeQuad(VPosition[0],VPosition[2]);
        if( ! facesLight(VPosition[2],VPosition[3],VPosition[4]) ) 
          emitEdgeQuad(VPosition[2],VPosition[4]);
        if( ! facesLight(VPosition[4],VPosition[5],VPosition[0]) ) 
          emitEdgeQuad(VPosition[4],VPosition[0]);

		//FRONT CAP
		vec3 LightDir = normalize(VPosition[0] - LightPosition.xyz); 
		vec3 deviation = LightDir * EPSILON;
		gl_Position = ProjMatrix * vec4(VPosition[0] + deviation, 1);
		EmitVertex();

		LightDir = normalize(VPosition[2] - LightPosition.xyz); 
		deviation = LightDir * EPSILON;
		gl_Position =  ProjMatrix * vec4(VPosition[2] + deviation, 1);
		EmitVertex();

		LightDir = normalize(VPosition[4] - LightPosition.xyz); 
		deviation = LightDir * EPSILON;
		gl_Position =  ProjMatrix * vec4(VPosition[4] + deviation, 1);
		EmitVertex();
	    EndPrimitive();
		
		//BACK CAP
		LightDir = normalize(VPosition[0] - LightPosition.xyz); 
		gl_Position = ProjMatrix * vec4(LightDir, 0);
		EmitVertex();

		LightDir = normalize(VPosition[4] - LightPosition.xyz); 
		gl_Position =  ProjMatrix * vec4(LightDir, 0);
		EmitVertex();

		LightDir = normalize(VPosition[2] - LightPosition.xyz); 
		gl_Position =  ProjMatrix * vec4(LightDir, 0);
		EmitVertex();
	    EndPrimitive();
    }

}
  • shadow_volume.frag
#version 430
out vec4 color;

void main() {
    color = vec4(1.0f, 0.0f, 0.0f, 1.0f);
}
  • shadow_volume.vs
/* #version 330 layout (location = 0) in vec3 Position; layout (location = 1) in vec2 TexCoord; layout (location = 2) in vec3 Normal; out vec3 WorldPos; uniform mat4 gWVP; uniform mat4 gWorld; void main() { vec4 PosL = vec4(Position, 1.0); gl_Position = gWVP * PosL; WorldPos = (gWorld * PosL).xyz; } */


#version 430
layout (location = 0) in vec3 VertexPosition;
layout (location = 1) in vec3 VertexNormal;

out vec3 VPosition;

uniform mat4 ModelViewMatrix;

void main()
{ 
	VPosition = (ModelViewMatrix * vec4(VertexPosition,1.0)).xyz;
}
  • plane.vs
/* #version 330 layout (location = 0) in vec3 Position; layout (location = 1) in vec2 TexCoord; layout (location = 2) in vec3 Normal; out vec3 WorldPos; uniform mat4 gWVP; uniform mat4 gWorld; void main() { vec4 PosL = vec4(Position, 1.0); gl_Position = gWVP * PosL; WorldPos = (gWorld * PosL).xyz; } */


#version 430
layout (location = 0) in vec3 VertexPosition;
layout (location = 1) in vec3 VertexNormal;

out vec3 VPosition;

uniform mat4 ModelViewMatrix;

void main()
{ 
	VPosition = (ModelViewMatrix * vec4(VertexPosition,1.0)).xyz;
}
  • 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 values
    Camera(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)
    {
        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) {
            if (this->pitch >89.0f) {
                this->pitch = 89.0f;
            }
            if (this->pitch < -89.0f) {
                this->pitch = -89.0f;
            }
            
        }
        this->updateCameraVectors();
    }
    
    void ProcessMouseScroll( GLfloat yOffset)
    {
        if ( this->zoom >= 1.0f && this->zoom <= 60.0f )
        {
            this->zoom += yOffset;
        }
        if ( this->zoom <= 1.0f )
        {
            this->zoom = 1.0f;
        }
        
        if ( this->zoom >= 60.0f )
        {
            this->zoom = 60.0f;
        }

    }
    
    glm::mat4 GetViewMatrix()
    {
        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;
        front.x = cos( glm::radians(this->pitch)) * cos( glm::radians(this->yaw));
        front.y = sin( glm::radians(this->pitch));
        front.z = cos( glm::radians(this->pitch)) * sin( glm::radians(this->yaw));
        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.h
//
// Light.h
// Course 4
//
// Created by rui huang on 11/15/17.
// Copyright © 2017 rui huang. All rights reserved.
//

#pragma once

#include <GL/glew.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>


GLfloat vertices[] =
{
    -0.5f, -0.5f, -0.5f, 
    0.5f, -0.5f, -0.5f,  
    0.5f,  0.5f, -0.5f,  
    0.5f,  0.5f, -0.5f,  
    -0.5f,  0.5f, -0.5f, 
    -0.5f, -0.5f, -0.5f, 
    
    -0.5f, -0.5f,  0.5f, 
    0.5f, -0.5f,  0.5f,  
    0.5f,  0.5f,  0.5f,  
    0.5f,  0.5f,  0.5f,  
    -0.5f,  0.5f,  0.5f, 
    -0.5f, -0.5f,  0.5f, 
    
    -0.5f,  0.5f,  0.5f, 
    -0.5f,  0.5f, -0.5f, 
    -0.5f, -0.5f, -0.5f, 
    -0.5f, -0.5f, -0.5f, 
    -0.5f, -0.5f,  0.5f, 
    -0.5f,  0.5f,  0.5f, 
    
    0.5f,  0.5f,  0.5f,  
    0.5f,  0.5f, -0.5f,  
    0.5f, -0.5f, -0.5f,  
    0.5f, -0.5f, -0.5f,  
    0.5f, -0.5f,  0.5f,  
    0.5f,  0.5f,  0.5f,  
    
    -0.5f, -0.5f, -0.5f, 
    0.5f, -0.5f, -0.5f,  
    0.5f, -0.5f,  0.5f,  
    0.5f, -0.5f,  0.5f,  
    -0.5f, -0.5f,  0.5f, 
    -0.5f, -0.5f, -0.5f, 
    
    -0.5f,  0.5f, -0.5f, 
    0.5f,  0.5f, -0.5f,  
    0.5f,  0.5f,  0.5f,  
    0.5f,  0.5f,  0.5f,  
    -0.5f,  0.5f,  0.5f, 
    -0.5f,  0.5f, -0.5f
};


class Light{
public:
    Light()
    {
        this->update();
    }
    void Draw(Shader &shader)
    {
        glBindVertexArray(this->VAO);
        glDrawArrays(GL_TRIANGLES, 0, 36);
        glBindVertexArray(0);
    }
private:
    GLuint VAO, VBO;
    void update()
    {
        glGenVertexArrays(1, &this->VAO);
        glGenBuffers(1, &this->VBO);
        
        glBindVertexArray(this->VAO);
        
        glBindBuffer(GL_ARRAY_BUFFER, this->VBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
        
        // position attribute
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
        glEnableVertexAttribArray(0);
        glBindVertexArray(0);

    }
};
  • Model.h
//
// Model.h
// Course 4
//
// Created by rui huang on 11/1/17.
// Copyright © 2017 rui huang. All rights reserved.
//

#pragma once

#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <map>
#include <vector>

#include <GL/glew.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "SOIL2/SOIL2.h"
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>

#include "Mesh.h"

using namespace std;

GLint TextureFromFile( const char *path, string directory);

class Model
{
public:
    Model( GLchar *path)
    {
        this->loadModel(path);
    }
    
    void Draw( Shader &shader)
    {
        for ( GLuint i = 0; i < this->meshes.size( ); i++ )
        {
            this->meshes[i].Draw( shader );
        }
        
    }
private:
    // Model Data
    vector<Mesh> meshes;
    string directory;
    vector<Texture> textures_loaded;
    
    // Functions
    void loadModel( string path)
    {
        // Read file via ASSIMP
        Assimp::Importer importer;
        const aiScene *scene = importer.ReadFile(path,
                                                 aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_GenNormals);
        // Check for errors
        if (!scene || scene->mFlags == AI_SCENE_FLAGS_INCOMPLETE|| !scene->mRootNode) {
            cout << "ERROR::ASSIMP:: " << importer.GetErrorString() << endl;
            return;
        }
        
        this->directory = path.substr(0, path.find_last_of( '/'));
        
        this->processNode( scene->mRootNode, scene);
    }
    
    void processNode(aiNode *node, const aiScene *scene)
    {
        // Process each mesh located at the current node
        for ( GLuint i = 0; i < node->mNumMeshes; i++)
        {
            
            aiMesh *mesh = scene->mMeshes[node->mMeshes[i]];
            this->meshes.push_back( this->processMesh( mesh, scene));
            
        }
        
        for (GLuint i = 0; i<node->mNumChildren; i++)
        {
            this->processNode(node->mChildren[i], scene);
        }
    }
    Mesh processMesh( aiMesh *mesh, const aiScene *scene )
    {
        // Data to fill
        vector<Vertex> vertices;
        vector<GLuint> indices;
        vector<Texture> textures;
        
        // each of the mesh's vertices
        for (GLuint i = 0; i< mesh->mNumVertices; i++) {
            Vertex vertex;
            glm::vec3 vector;
            // Positions
            vector.x = mesh->mVertices[i].x;
            vector.y = mesh->mVertices[i].y;
            vector.z = mesh->mVertices[i].z;
            vertex.Position = vector;
            
            // Normals
            vector.x = mesh->mNormals[i].x;
            vector.y = mesh->mNormals[i].y;
            vector.z = mesh->mNormals[i].z;
            vertex.Normal = vector;
            
            // UV coords
            if (mesh->mTextureCoords[0]) {
                glm::vec2 vec;
                
                vec.x = mesh->mTextureCoords[0][i].x;
                vec.y = mesh->mTextureCoords[0][i].y;
                vertex.TexCoords = vec;
            } else{
                vertex.TexCoords = glm::vec2( 0.0f, 0.0f);
            }
            vertices.push_back( vertex);
        }
        // Indices
        for ( GLuint i = 0; i<mesh->mNumFaces; i++)
        {
            aiFace face = mesh->mFaces[i];
            
            for (GLuint j = 0; j < face.mNumIndices; j++)
            {
                indices.push_back(face.mIndices[j]);
            }
        }
        
        // Process materials
        if (mesh->mMaterialIndex >= 0) {
            aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
            // 1. Diffuse maps
            vector<Texture> diffuseMaps = this->loadMaterialTextures( material, aiTextureType_DIFFUSE, "texture_diffuse");
            textures.insert( textures.end(), diffuseMaps.begin(), diffuseMaps.end());
            // 2. Specular maps
            vector<Texture> specularMaps = this->loadMaterialTextures( material, aiTextureType_SPECULAR, "texture_specular");
            textures.insert( textures.end(), specularMaps.begin(), specularMaps.end());
        }
        return Mesh( vertices, indices, textures);
    }
    
    vector<Texture> loadMaterialTextures( aiMaterial * mat, aiTextureType type, string typeName)
    {
        vector<Texture> textures;
        for ( GLuint i = 0; i < mat->GetTextureCount(type); i++)
        {
            aiString str;
            mat->GetTexture(type, i, &str);
            
            // Check if texture was loaded before
            GLboolean skip = false;
            
            for ( GLuint j = 0; j < this->textures_loaded.size(); j++)
            {
                if (this->textures_loaded[j].path == str) {
                    textures.push_back(this->textures_loaded[j]);
                    skip = true;
                    break;
                }
            }
            if (!skip)
            {
                Texture texture;
                texture.id = TextureFromFile( str.C_Str(), this->directory);
                texture.type = typeName;
                texture.path   = str;
                textures.push_back(texture);
                
                this->textures_loaded.push_back( texture);
            }
        }
        return textures;
        
    }
};

GLint TextureFromFile( const char *path, string directory)
{
    string filename = string(path);
    filename = directory + '/' + filename;
    GLuint textureID;
    glGenTextures(1, &textureID);
    
    int width, height;
    unsigned char *image = SOIL_load_image(filename.c_str(), &width, &height, 0, SOIL_LOAD_RGBA);
    // Assign texture to ID
    glBindTexture( GL_TEXTURE_2D, textureID );
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image );
    
    glGenerateMipmap(GL_TEXTURE_2D);
    
    // Parameters
    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_MIPMAP_LINEAR );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glBindTexture( GL_TEXTURE_2D, 0 );
    SOIL_free_image_data( image );
    
    return textureID;
    
}
  • plane.frag
#version 430
in vec3 Position;
in vec3 Normal;
//in vec3 ourColor;

//out vec4 color;

uniform vec4 LightPosition;
uniform float LightIntensity;
uniform vec3 u_color;

layout( location = 0 ) out vec4 Ambient;
layout( location = 1 ) out vec4 DiffSpec;

void main() {
    vec3 toLight = normalize(vec3(LightPosition) - Position);
	vec3 toV = normalize(vec3(-Position));
	vec3 r = reflect( -toLight, Normal );
	//color = vec4(ourColor, 0.7f);
	//color = vec4(1.0f, 0.0f, 0.0f, 0.1f);

	float diffuse = max(0.0f, dot(Normal, toLight));
	float specular = pow(max(0.0, dot(r, Normal)), 640.0);

	Ambient = vec4(u_color, 1.0f) * 0.2f *LightIntensity;
    DiffSpec =vec4(u_color, 1.0f)*(diffuse+specular)*LightIntensity+Ambient;
}
  • Shader.h
#pragma once
//#ifndef shader_h
//#define shader_h
//#endif // !shader.hpp
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <GL/glew.h>


class Shader {
	GLuint vertex, fragment, geometry;
	bool flag = false;
public:
	GLuint Program;
	Shader(const GLchar *vertexPath, const GLchar *fragmentPath, const GLchar* geometryPath = nullptr) {
		std::string vertexCode;
		std::string fragmentCode;
		std::string geometryCode;
		std::ifstream vShaderFile;
		std::ifstream fShaderFile;
		std::ifstream gShaderFile;
		vShaderFile.exceptions(std::ifstream::badbit  | std::ifstream::badbit);
		fShaderFile.exceptions(std::ifstream::badbit  | std::ifstream::badbit);
		gShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
		try {
			// 打开文件
			vShaderFile.open(vertexPath);
			fShaderFile.open(fragmentPath);
			//gShaderFile.open(geometryPath);
			std::stringstream vShaderStream, fShaderStream;
			// 读取文件
			vShaderStream << vShaderFile.rdbuf();
			fShaderStream << fShaderFile.rdbuf();
			//gShaderStream << gShaderFile.rdbuf();
			// 关闭文件
			vShaderFile.close();
			fShaderFile.close();
			//gShaderFile.close();
			//将流转换为字符串
			vertexCode = vShaderStream.str();
			fragmentCode = fShaderStream.str();
			//geometryCode = gShaderStream.str();

		}
		catch (std::ifstream::failure e) {
			std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ" << std::endl;
		}

		// 编译着色器
		const GLchar *vShaderCode = vertexCode.c_str();
		const GLchar *fShaderCode = fragmentCode.c_str();
		//const GLchar *gShaderCode = geometryCode.c_str();

		vertex = 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;
		}

		if (geometryPath != nullptr) {
			flag = true;
			const char * gShaderCode = geometryCode.c_str();
			geometry = glCreateShader(GL_GEOMETRY_SHADER);//几何着色器
			glShaderSource(geometry, 1, &gShaderCode, NULL);
			glCompileShader(geometry);

			glGetShaderiv(geometry, GL_COMPILE_STATUS, &success);
			if (!success) {
				glGetShaderInfoLog(geometry, 512, NULL, infoLog);
				std::cout << "ERROR::SHADER:geometry::COMPILATION_FAILED\n" << infoLog << std::endl;
			}
		}
			

		//链接
		this->Program = glCreateProgram();//创建着色器程序
		glAttachShader(this->Program, vertex);
		glAttachShader(this->Program, fragment);
		if (geometryPath != nullptr)
			glAttachShader(this->Program, geometry);
		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);
		if (flag == true)
			glDeleteShader(geometry);
		glDeleteProgram(this->Program);

	}
	void Use() {
		glUseProgram(this->Program);
	}
};
  • skybox.frag
#version 330 core
in vec3 TexCoords;
out vec4 color;

uniform samplerCube skybox;  // 立方体贴图纹理采样器

void main()
{
	color = texture(skybox, TexCoords);
}
  • skybox.vs
#version 330 core
layout (location = 0) in vec3 position;
out vec3 TexCoords;

uniform mat4 view;
uniform mat4 projection;


void main()
{
	gl_Position = projection * view * vec4(position, 1.0f);
	TexCoords = position;
}

程序正常运行,能得到以下结果。(GIF文件太大,传个截图随便看看吧:)

三、讲解

1. Skybox

天空盒部分网上官方教程写得还是很详细的。

2. Shadow volume

注意,要用到 Stencil Buffer

显示阴影有两种方法:Z-pass 算法Z-fail 算法

四、致谢

立方体贴图与 Skybox

第四十课 模板阴影体

OpenGL 阴影,Shadow Volumes(附源程序,使用 VCGlib )

Tutorial 40: Stencil Shadow Volume