OpenGL 学习笔记--冯氏光照模型(09)

冯氏光照模型

Notes

  • 冯氏光照模型
    在这里插入图片描述
    主要由三部分构成:
    环境光照:世界上通常有的一些光亮
    漫反射光照:模拟光源对物体的方向性影响
    镜面光照:模拟有光泽物体上面的亮点

人眼看到物体的颜色为:光颜色*物体颜色

  • 冯氏光照模型表达式
    在这里插入图片描述

I p = k a i a + ∑ m ∈ l i g h t s ( k d ( L m → ⋅ N → ) i m , d + k s ( R m → ⋅ V → ) α i m , s ) {{I}_{p}}={{k}_{a}}{{i}_{a}}+\sum\limits_{m\in lights}{({{k}_{d}}(\overrightarrow{{{L}_{m}}}\centerdot \overrightarrow{N}){{i}_{m,d}}+{{k}_{s}}{{(\overrightarrow{{{R}_{m}}}\centerdot \overrightarrow{V})}^{\alpha }}{{i}_{m,s}})} Ip=kaia+mlights(kd(Lm N )im,d+ks(Rm V )αim,s)
环境光:
k a {{k}_{a}} ka: 环境光常数
i a {{i}_{a}} ia:环境光强度
漫反射光:
k d {{k}_{d}} kd:漫反射光常数
L m → \overrightarrow{{{L}_{m}}} Lm : 光源-物体方向
N → \overrightarrow{N} N : 物体法线方向
i m , d {{i}_{m,d}} im,d: 漫反射光强度
镜面光:
k s {{k}_{s}} ks:镜面光常数
R m → \overrightarrow{{{R}_{m}}} Rm : 物体-光源反射方向
V → \overrightarrow{V} V : 视角-物体视野方向
α ^{\alpha } α: 高光反光度
i m , s {{i}_{m,s}} im,s: 镜面光强度

  • 法线矩阵
    在这里插入图片描述
    在片段着色器中世界坐标系下计算冯氏光照模型,而法线方向在顶点着色器中在物体坐标下,因此需要转换到世界坐标下即用Model矩阵作用后。而非等比缩放就会发生法线不垂直于物体,因此为法线再作用一个矩阵,使其能够垂直于物体,该矩阵即为法线矩阵。
    N   ˋ → ⋅ T   ˋ → = ( G ⋅ N ) ⋅ ( M T ) = 0 \overrightarrow{{{N}^{\grave{\ }}}}\centerdot \overrightarrow{{{T}^{\grave{\ }}}}=(G\centerdot N)\centerdot (MT)=0 N ˋ T ˋ =(GN)(MT)=0
    G = ( M − 1 ) T G={{({{M}^{-1}})}^{T}} G=(M1)T
  • 顶点着色器
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;

out vec3 FragPos;
out vec3 Normal;
out vec2 TexCoords;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    FragPos = vec3(model * vec4(aPos, 1.0));
    Normal = mat3(transpose(inverse(model))) * aNormal;  
    TexCoords = aTexCoords;
    
    gl_Position = projection * view * vec4(FragPos, 1.0);
}
  • 片段着色器
#version 330 core
out vec4 FragColor;

struct Material {
    sampler2D diffuse;
    sampler2D specular;    
    float shininess;
}; 

struct Light {
    vec3 position;

    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
};

in vec3 FragPos;  
in vec3 Normal;  
in vec2 TexCoords;
  
uniform vec3 viewPos;
uniform Material material;
uniform Light light;

void main()
{
    // ambient
    float ambientStrength = 0.2;
    vec3 ambient = ambientStrength * light.ambient * vec3(texture(material.diffuse, TexCoords));
  	
    // diffuse 
    float diffuseStrength = 1.0;
    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(light.position - FragPos);
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diffuseStrength * diff * light.diffuse * vec3(texture(material.diffuse, TexCoords));  
    
    // specular
    float specularStrength = 0.5;
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, norm);  
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
    vec3 specular = specularStrength * spec * light.specular * vec3(texture(material.specular, TexCoords));  
        
    vec3 result = ambient + diffuse + specular;
    FragColor = vec4(result, 1.0);
} 
  • 平行光
    在这里插入图片描述
    平行光在漫反射光和镜面反射光中不需要计算光源-物体的方向
  • 点光源
    在这里插入图片描述
    点光源在漫反射光和镜面反射光中需要计算光源-物体的方向
  • 聚光源
    在这里插入图片描述
    聚光源光照强度,外光切->内光切之间逐渐增强,内光切之内完全增强
    ϕ {\phi} ϕ: 内光切
    γ {\gamma} γ: 外光切
    θ {\theta } θ: 角度
    i n t e n s i t y = cos ⁡ θ − cos ⁡ γ cos ⁡ ϕ − cos ⁡ γ intensity=\frac{\cos \theta -\cos \gamma }{\cos \phi -\cos \gamma } intensity=cosϕcosγcosθcosγ
intensity=clamp(intensity,0,1);
  • 光线衰减
    随着光线传播距离原来越远,光的强度逐渐减小
    在这里插入图片描述

代码示例

https://gitee.com/NiMiKiss/opengl-notes.git
cubetexture.fs

#version 400 core
out vec4 FragColor;

uniform sampler2D ourTexture1;
uniform sampler2D ourTexture2;

uniform vec3 lightColor;
uniform vec3 objectColor;

uniform vec4 lightPos;
uniform vec3 cameraPos;
uniform vec3 cameraFront;

in vec3 Normal;
in vec3 FragPos;
in vec2 TexCoords;

struct Material {
	vec3 ambient;
	vec3 diffuse;
	vec3 specular;
	float shininess;
};

struct PointLight {
	vec4 lightDir;

	vec3 ambient;
	vec3 diffuse;
	vec3 specular;

	float constant;
	float linear;
	float quadratic;
};

struct SportLight {
	vec3 position;
	vec3 direction;
	float cutOff;
	float outerCutOff;

	vec3 ambient;
	vec3 diffuse;
	vec3 specular;

	float constant;
	float linear;
	float quadratic;
};

Material material;

vec3 CalcPointLight(PointLight pointLight)
{
	// ambient
	float ambientStrength = 1.0;
	vec3 ambient = ambientStrength * pointLight.ambient * material.ambient;

	// diffuse 
	vec3 norm = normalize(Normal), lightDir;
	float distance = 0.0f;
	if (0 == pointLight.lightDir.w)
		lightDir = normalize(vec3(pointLight.lightDir));
	if (1 == pointLight.lightDir.w)
	{
		lightDir = vec3(pointLight.lightDir) - FragPos;
		distance = length(lightDir);
		lightDir = normalize(lightDir);
	}
	float diff = max(dot(norm, lightDir), 0.0);
	vec3 diffuse = diff * pointLight.diffuse * material.diffuse;

	// specular
	float specularStrength = 1.0;
	vec3 cameraDir = normalize(cameraPos - FragPos);
	vec3 reflectLightDir = reflect(-lightDir, norm);
	float spec = pow(max(dot(cameraDir, reflectLightDir), 0.0), material.shininess);
	vec3 specular = specularStrength * spec * pointLight.specular * material.specular;

	float attenuation = 1.0 / (pointLight.constant + pointLight.linear * distance + pointLight.quadratic * distance * distance);
	return vec3(ambient + diffuse + specular) * attenuation;
}

vec3 CalSpotLight(SportLight sportLight)
{
	float theta = dot(normalize(sportLight.position - FragPos), normalize(-sportLight.direction));
	float epsilon = cos(radians(sportLight.cutOff))-cos(radians(sportLight.outerCutOff));
	float spotI = clamp((theta-cos(radians(sportLight.outerCutOff)))/epsilon,0.0,1.0);
	
	// diffuse 
	vec3 norm = normalize(Normal);
	vec3 lightDir = normalize(-sportLight.direction);
	float diff = max(dot(norm, lightDir), 0.0);
	vec3 diffuse = diff * sportLight.diffuse * material.diffuse;

	// specular
	float specularStrength = 1.0;
	vec3 cameraDir = normalize(sportLight.position - FragPos);
	vec3 reflectLightDir = reflect(-lightDir, norm);
	float spec = pow(max(dot(cameraDir, reflectLightDir), 0.0), material.shininess);
	vec3 specular = specularStrength * spec * sportLight.specular * material.specular;

	float distance = length(sportLight.position - FragPos);
	float attenuation = 1.0 / (sportLight.constant + sportLight.linear * distance + sportLight.quadratic * distance * distance);

	return vec3(diffuse + specular) * attenuation * spotI;
}

void main()
{
	material.ambient = vec3(texture(ourTexture1, TexCoords));
	material.diffuse = vec3(texture(ourTexture1, TexCoords));
	material.specular = vec3(texture(ourTexture2, TexCoords));
	material.shininess = 32;

	PointLight pointLight;
	pointLight.lightDir = lightPos;
	pointLight.ambient = vec3(0.2f, 0.2f, 0.2f);
	pointLight.diffuse = vec3(0.6f, 0.6f, 0.6f);
	pointLight.specular = vec3(1.0f, 1.0f, 1.0f);
	pointLight.constant = 1.0;
	pointLight.linear = 0.09;
	pointLight.quadratic = 0.032;

	SportLight sportLight;
	sportLight.position = cameraPos;
	sportLight.direction = cameraFront;
	sportLight.cutOff = 5.5;
	sportLight.outerCutOff = 12.5;
	sportLight.ambient = vec3(0.0f, 0.0f, 0.0f);
	sportLight.diffuse = vec3(1.0f, 1.0f, 1.0f);
	sportLight.specular = vec3(1.0f, 1.0f, 1.0f);
	sportLight.constant = 1.0;
	sportLight.linear = 0.09;
	sportLight.quadratic = 0.032;

	vec3 light = CalcPointLight(pointLight) + CalSpotLight(sportLight) ;
	FragColor=vec4(light,1.0f);
}

cubetexture.vs

#version 400 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

out vec3 Normal;
out vec3 FragPos;
out vec2 TexCoords;

void main()
{
	Normal = mat3(transpose(inverse(model))) * aNormal;  
	TexCoords = aTexCoords;
	FragPos = vec3(model * vec4(aPos,1.0f));

	gl_Position = projection * view * vec4(FragPos,1.0f);
}

light.fs

#version 400 core
out vec4 FragColor;
uniform vec3 lightColor;
void main()
{
   FragColor = vec4(lightColor,1.0f);
}

light.vs

#version 400 core
layout (location = 0) in vec3 aPos;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

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

OpenGL.cpp

#include <stb_image.h>
#include <camera.h>
#include <shader.h>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>

#pragma region 顶点数据
float vertices[] = {
	// positions          // normals           // texture coords
	-0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f,  0.0f,
	 0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f,  0.0f,
	 0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f,  1.0f,
	 0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f,  1.0f,
	-0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f,  1.0f,
	-0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f,  0.0f,

	-0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  0.0f,  0.0f,
	 0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  1.0f,  0.0f,
	 0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  1.0f,  1.0f,
	 0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  1.0f,  1.0f,
	-0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  0.0f,  1.0f,
	-0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  0.0f,  0.0f,

	-0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  1.0f,  0.0f,
	-0.5f,  0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  1.0f,  1.0f,
	-0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  0.0f,  1.0f,
	-0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  0.0f,  1.0f,
	-0.5f, -0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  0.0f,  0.0f,
	-0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  1.0f,  0.0f,

	 0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  1.0f,  0.0f,
	 0.5f,  0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  1.0f,  1.0f,
	 0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  0.0f,  1.0f,
	 0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  0.0f,  1.0f,
	 0.5f, -0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  0.0f,  0.0f,
	 0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  1.0f,  0.0f,

	-0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  0.0f,  1.0f,
	 0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  1.0f,  1.0f,
	 0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  1.0f,  0.0f,
	 0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  1.0f,  0.0f,
	-0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  0.0f,  0.0f,
	-0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  0.0f,  1.0f,

	-0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  0.0f,  1.0f,
	 0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  1.0f,  1.0f,
	 0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  1.0f,  0.0f,
	 0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  1.0f,  0.0f,
	-0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  0.0f,  0.0f,
	-0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  0.0f,  1.0f
};

glm::vec3 lightPos[] = {
	glm::vec3(1.2f, 1.0f, 2.0f)
};

glm::vec3 cubePos[] = {
	glm::vec3(0.0f, 0.0f, 0.0f),
	glm::vec3(-3.0f, 1.0f, -2.0f),
};
#pragma endregion

GLFWwindow* Init();
void SetVAO();
void SetTexture(Shader& shader);
void LoadTexture(char const* path);
void processinput_callback(GLFWwindow* window);
void mouse_callback(GLFWwindow* window, double xpose, double ypose);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);

Camera camera(glm::vec3(0.0f, 0.0f, 5.0f));
unsigned int cubeVAO, lightVAO;
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

bool firstMouse = true;
static float lastX = 0.0f, lastY = 0.0f;
float deltaTime = 0.0f;
float lastFrame = 0.0f;

void SetVAO()
{
	unsigned int VBO;
	glGenVertexArrays(1, &cubeVAO);
	glGenVertexArrays(1, &lightVAO);
	glGenBuffers(1, &VBO);

	glBindVertexArray(cubeVAO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
	glEnableVertexAttribArray(0);
	glEnableVertexAttribArray(1);
	glEnableVertexAttribArray(2);

	glBindVertexArray(lightVAO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
	glEnableVertexAttribArray(0);
	glEnableVertexAttribArray(1);
}

void SetTexture(Shader& shader)
{
	stbi_set_flip_vertically_on_load(true);
	unsigned int texture[2];
	glGenTextures(2, texture);

	glBindTexture(GL_TEXTURE_2D, texture[0]);
	LoadTexture("../OpenGL/resources/textures/container2.png");

	glBindTexture(GL_TEXTURE_2D, texture[1]);
	LoadTexture("../OpenGL/resources/textures/container2_specular.png");

	glActiveTexture(GL_TEXTURE0); //先激活再绑定
	glBindTexture(GL_TEXTURE_2D, texture[0]);

	glActiveTexture(GL_TEXTURE1); //先激活再绑定
	glBindTexture(GL_TEXTURE_2D, texture[1]);

	shader.use();
	shader.setInt("ourTexture1", 0);
	shader.setInt("ourTexture2", 1);
}

void LoadTexture(char const* path)
{
	int width(0), height(0), nrChannels(0);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	unsigned char* data = stbi_load(path, &width, &height, &nrChannels, 0);
	GLenum format;
	if (1 == nrChannels)
	{
		format = GL_RED;
	}
	else if (3 == nrChannels)
	{
		format = GL_RGB;
	}
	else if (4 == nrChannels)
	{
		format = GL_RGBA;
	}

	glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
	glGenerateMipmap(GL_TEXTURE_2D);
	stbi_image_free(data);
}

int main()
{
	auto window = Init();

	Shader lightShader("../OpenGL/shaders/light.vs", "../OpenGL/shaders/light.fs");
	Shader cubeShader("../OpenGL/shaders/cubetexture.vs", "../OpenGL/shaders/cubetexture.fs");
	SetVAO();
	SetTexture(cubeShader);
	glEnable(GL_DEPTH_TEST);
	while (!glfwWindowShouldClose(window))
	{
		float currentFrame = glfwGetTime();
		deltaTime = currentFrame - lastFrame;
		lastFrame = currentFrame;
		processinput_callback(window);

		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		glm::mat4 trans(glm::mat4(1.0f)), view(glm::mat4(1.0f)), projection(glm::mat4(1.0f)), model(glm::mat4(1.0f));;
		view = camera.GetViewMatrix();
		projection = glm::perspective(glm::radians(camera.Zoom), 800.0f / 600.0f, 0.1f, 100.0f);

		//Draw Cube
		for (size_t i = 0; i < 2; ++i)
		{
			model = glm::mat4(1.0f);
			model = glm::translate(model, cubePos[i]);
			model = glm::rotate(model, currentFrame, glm::vec3(1.5f, 3.0f, 0.0f));
			
			cubeShader.use();
			cubeShader.setMat4("model", model);
			cubeShader.setMat4("view", view);
			cubeShader.setMat4("projection", projection);

			cubeShader.setVec3("lightColor", glm::vec3(1.0f, 1.0f, 1.0f));
			cubeShader.setVec3("objectColor", glm::vec3(1.0f, 0.5f, 0.31f));

			cubeShader.setVec4("lightPos", glm::vec4(lightPos[0], 1.0f));
			cubeShader.setVec3("cameraPos", camera.Position);
			cubeShader.setVec3("cameraFront", camera.Front);
			glBindVertexArray(cubeVAO);
			glDrawArrays(GL_TRIANGLES, 0, 36);
		}


		//Draw light1
		for (size_t i = 0; i < 1; ++i)
		{
			model = glm::mat4(1.0f);
			model = glm::translate(model, lightPos[i]);
			model = glm::scale(model, glm::vec3(0.2f, 0.2f, 0.2f));

			lightShader.use();
			lightShader.setMat4("model", model);
			lightShader.setMat4("view", view);
			lightShader.setMat4("projection", projection);

			lightShader.setVec3("lightColor", glm::vec3(1.0f, 1.0f, 1.0f));
			glBindVertexArray(lightVAO);
			glDrawArrays(GL_TRIANGLES, 0, 36);
		}

		glfwSwapBuffers(window);
		glfwPollEvents();
	}
}

GLFWwindow* Init()
{
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	auto window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
	if (window == NULL)
	{
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
	}
	glfwMakeContextCurrent(window);

	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
		std::cout << "Failed to initialize GLAD" << std::endl;
	}

	glfwSetCursorPosCallback(window, mouse_callback);
	glfwSetScrollCallback(window, scroll_callback);
	glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
	return window;
}

void processinput_callback(GLFWwindow* window)
{
	if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
	{
		camera.ProcessKeyboard(FORWARD, deltaTime);
	}
	if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
	{
		camera.ProcessKeyboard(LEFT, deltaTime);
	}
	if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
	{
		camera.ProcessKeyboard(BACKWARD, deltaTime);
	}
	if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
	{
		camera.ProcessKeyboard(RIGHT, deltaTime);
	}
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
	{
		glfwSetWindowShouldClose(window, true);
	}
}

void mouse_callback(GLFWwindow* window, double xpose, double ypose)
{
	if (firstMouse)
	{
		lastX = xpose;
		lastY = ypose;
		firstMouse = false;
	}
	auto xoffset = xpose - lastX;
	lastX = xpose;

	auto yoffset = lastY - ypose;
	lastY = ypose;

	camera.ProcessMouseMovement(xoffset, yoffset);
}

void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
	camera.ProcessMouseScroll(yoffset);
}

输出结果,两个不同位置的木箱,两个光源(一个太阳光,一个手电筒)
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值