OpenGL原理与实践——核心模式(六):光照贴图、光源分类以及多光源场景主要源码实现

news2025/7/6 20:39:55

本章主要以代码为主,理论理解即可。详细分析代码

目录

光照贴图

光源分类

平行光

点光源

shader——点光源

聚光灯

聚光灯边缘优化——光强递减

源码解析

main

全局变量、句柄

main函数主体逻辑

createModel()

createTexture(const char* _filename)

ininShader (const char* _vertexPath, const char* _fragPath)

render()

shader

vsunShader.glsl

fsunShader.glsl

sceneShaderv.glsl

sceneShaderf.glsl

渲染结果


光照贴图

光源分类

我们之前讨论的都是简单的点光源,并且没有考虑光源随距离的衰减。

为此,将其光源分为三类

平行光

如何区分简单点光源和平行光?

可以利用齐次向量的最后一个参数,即w。

  • 如果w为1,则标明是一个向量,是平行光;
  • 如果w为0,则标明是一个点,即点光源

点光源

 

考虑了光随距离衰减,提出了一种非线性的公式,其中d代表光源与像素点的距离。

对于公式中三个k系数,有一些经验值:

shader——点光源

聚光灯

聚光灯边缘优化——光强递减

源码解析

main

以往的不变的函数

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);

全局变量、句柄

//场景中有两种东西:物体和光源
uint VAO_cube = 0;
uint VAO_sun = 0;
//设置光源位置
glm::vec3 light_pos(1.0f);
glm::vec3 light_color(1.0f);

//光照贴图
uint _textureBox = 0;
uint _textureSpec = 0;

//类声明
Shader _shader_scene;
Shader _shader_sun;
ffImage* _pImage = nullptr;
Camera	_camera;

//初始化投影矩阵、设置宽高
glm::mat4 _projMatrix(1.0f);
int _width = 800;
int _height = 600;

main函数主体逻辑

int main() {
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);

	GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Core", NULL, NULL);
	if (window == NULL)
	{
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);

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

	glViewport(0, 0, _width, _height);
	glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

	glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
	glfwSetCursorPosCallback(window, mouse_callback);

	_camera.lookAt(glm::vec3(0.0f, 0.0f, 3.0f), glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, 1.0f, 0.0f));
	_camera.setSpeed(0.001f);

	VAO_cube = createModel();
	VAO_sun = createModel();
	light_pos = glm::vec3(2.0f, 0.0f, 0.0f);
	light_color = glm::vec3(1.0f, 1.0f, 1.0f);

	_textureBox = createTexture("res/box.png");
	_textureSpec = createTexture("res/specular.png");
	initShader("","");

	while (!glfwWindowShouldClose(window))
	{
		processInput(window);

		render();

		glfwSwapBuffers(window);
		glfwPollEvents();
	}
	glfwTerminate();
	return 0;
}

值得注意的只有

	VAO_cube = createModel();
	VAO_sun = createModel();
	light_pos = glm::vec3(2.0f, 0.0f, 0.0f);
	light_color = glm::vec3(1.0f, 1.0f, 1.0f);

	_textureBox = createTexture("res/box.png");
	_textureSpec = createTexture("res/specular.png");
	initShader("","");

这些初始化的操作。其中涉及了:

  • 初始化了:刚才提到的全局变量句柄,也就是需要渲染的两种事物cube(物体)和sun(光源),利用了createModel()
  • 初始化了:全局变量light_pos和light_color
  • 初始化了:_textureBos 和 _textureSpec,利用了createTexture
  • 初始化了:InitShader
  • 核心逻辑:render(),完成渲染

上述四个函数,接下来解析

createModel()

uint createModel()
{
	uint _VAO = 0;
	uint _VBO = 0;

	float vertices[] = {
		//位置						UV					  法线
		-0.5f, -0.5f, -0.5f,		0.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, 1.0f,           0.0f,  0.0f, -1.0f,
		 0.5f,  0.5f, -0.5f,		1.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, 0.0f,           0.0f,  0.0f, -1.0f,

		-0.5f, -0.5f,  0.5f,		0.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, 1.0f,           0.0f,  0.0f,  1.0f,
		 0.5f,  0.5f,  0.5f,		1.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, 0.0f,           0.0f,  0.0f,  1.0f,

		-0.5f,  0.5f,  0.5f,		1.0f, 0.0f,           -1.0f,  0.0f,  0.0f,
		-0.5f,  0.5f, -0.5f,		1.0f, 1.0f,           -1.0f,  0.0f,  0.0f,
		-0.5f, -0.5f, -0.5f,		0.0f, 1.0f,           -1.0f,  0.0f,  0.0f,
		-0.5f, -0.5f, -0.5f,		0.0f, 1.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,		1.0f, 0.0f,           -1.0f,  0.0f,  0.0f,

		 0.5f,  0.5f,  0.5f,		1.0f, 0.0f,           1.0f,  0.0f,  0.0f,
		 0.5f,  0.5f, -0.5f,		1.0f, 1.0f,           1.0f,  0.0f,  0.0f,
		 0.5f, -0.5f, -0.5f,		0.0f, 1.0f,           1.0f,  0.0f,  0.0f,
		 0.5f, -0.5f, -0.5f,		0.0f, 1.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,		1.0f, 0.0f,           1.0f,  0.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,		1.0f, 1.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,  0.0f,
		-0.5f, -0.5f,  0.5f,		0.0f, 0.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,  1.0f,  0.0f,
		 0.5f,  0.5f, -0.5f,		1.0f, 1.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,  0.0f,
		-0.5f,  0.5f,  0.5f,		0.0f, 0.0f,           0.0f,  1.0f,  0.0f,
		-0.5f,  0.5f, -0.5f,		0.0f, 1.0f,           0.0f,  1.0f,  0.0f,
	};


	glGenVertexArrays(1, &_VAO);
	glBindVertexArray(_VAO);

	glGenBuffers(1, &_VBO);
	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, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(sizeof(float) * 3));
	glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(sizeof(float) * 5));

	glEnableVertexAttribArray(0);
	glEnableVertexAttribArray(1);
	glEnableVertexAttribArray(2);

	glBindVertexArray(0);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	return _VAO;
}

是对顶点数据的初始化的VBO绑定操作。

createTexture(const char* _filename)

uint createTexture(const char* _filename) {
	_pImage = ffImage::readFromFile(_filename);
	uint _texture = 0;
	glGenTextures(1, &_texture);
	glBindTexture(GL_TEXTURE_2D, _texture);

	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_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _pImage->getWidth(), _pImage->getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, _pImage->getData());

	return _texture;
}

读取纹理贴图的操作

ininShader (const char* _vertexPath, const char* _fragPath)

void initShader(const char* _vertexPath, const char* _fragPath)
{
	_shader_sun.initShader("shader/vsunShader.glsl", "shader/fsunShader.glsl");
	_shader_scene.initShader("shader/sceneShaderv.glsl", "shader/sceneShaderf.glsl");
}

其实这里并不需要参数,只是一种修改之前代码的写法。用硬编码的方式。

根据代码得知:我们只需要4个shader:

  • fsunShader:光源的fragmentShader
  • vsunShader:光源的vertexShader
  • sceneShaderf:场景的fragmentShader
  • sceneShaderv:场景的vertexShader

这里多提一嘴,fragmentShader中的fragment并不是像素,而是插值而来的图元,这两个概念并不相等。

render()

在渲染中需要做:

  • 初始化:背景颜色
  • 初始化:需渲染个10个物体的位置
  • 初始化:4个点光源的位置
  • 初始化:相机朝向,以及模型投影矩阵
  • 初始化:激活纹理,已在createTexture中初始化
  • 渲染前:
    • 设置:开始相机位置
    • 设置:物体材质参数,物体的diffuse和specular已通过光照贴图设置完毕
    • 设置:平行光参数×1
    • 设置:点光源参数×4
    • 设置:聚光灯参数×1
  • 渲染:10个物体+4个点光源
void render()
{
	//设置视口背景颜色,
	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glEnable(GL_DEPTH_TEST);

	//10个物体的位置
	glm::vec3 cubePositions[] = {
		glm::vec3(0.0f,  0.0f,  0.0f),
		glm::vec3(2.0f,  5.0f, -15.0f),
		glm::vec3(-1.5f, -2.2f, -2.5f),
		glm::vec3(-3.8f, -2.0f, -12.3f),
		glm::vec3(2.4f, -0.4f, -3.5f),
		glm::vec3(-1.7f,  3.0f, -7.5f),
		glm::vec3(1.3f, -2.0f, -2.5f),
		glm::vec3(1.5f,  2.0f, -2.5f),
		glm::vec3(1.5f,  0.2f, -1.5f),
		glm::vec3(-1.3f,  1.0f, -1.5f)
	};

	//4个光源的位置
	glm::vec3 pointLightPositions[] = {
		glm::vec3(0.7f,  0.2f,  2.0f),
		glm::vec3(2.3f, -3.3f, -4.0f),
		glm::vec3(-4.0f,  2.0f, -12.0f),
		glm::vec3(0.0f,  0.0f, -3.0f)
	};

	//调整摄像机朝向位置,调用glm::lootAt
	_camera.update();
	//初始化投影矩阵
	_projMatrix = glm::perspective(glm::radians(45.0f), (float)_width / (float)_height, 0.1f, 100.0f);
	//初始化模型矩阵,为单位阵
	glm::mat4 _modelMatrix(1.0f);
	//对模型进行平移变换
	_modelMatrix = glm::translate(_modelMatrix, glm::vec3(0.0f, 0.0f, -3.0f));


	//激活纹理,并绑定相应纹理
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, _textureBox);
	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D, _textureSpec);


	//渲染
	_shader_scene.start();

		_shader_scene.setVec3("view_pos", _camera.getPosition());
		//传入物体材质属性
		_shader_scene.setInt("myMaterial.m_specular", 1);
		_shader_scene.setFloat("myMaterial.m_shiness", 32);

		_shader_scene.setMatrix("_viewMatrix", _camera.getMatrix());
		_shader_scene.setMatrix("_projMatrix", _projMatrix);

		// directional light 平行光
		_shader_scene.setVec3("_dirLight.m_direction", glm::vec3(-0.2f, -1.0f, -0.3f));
		_shader_scene.setVec3("_dirLight.m_ambient", glm::vec3(0.05f, 0.05f, 0.05f));
		_shader_scene.setVec3("_dirLight.m_diffuse", glm::vec3(0.4f, 0.4f, 0.4f));
		_shader_scene.setVec3("_dirLight.m_specular", glm::vec3(0.5f, 0.5f, 0.5f));

		// point light 点光源
		// point light 1
		_shader_scene.setVec3("_pointLight[0].m_pos", pointLightPositions[0]);
		_shader_scene.setVec3("_pointLight[0].m_ambient", glm::vec3(0.05f, 0.05f, 0.05f));
		_shader_scene.setVec3("_pointLight[0].m_diffuse", glm::vec3(0.8f, 0.8f, 0.8f));
		_shader_scene.setVec3("_pointLight[0].m_specular", glm::vec3(1.0f, 1.0f, 1.0f));
		_shader_scene.setFloat("_pointLight[0].m_c", 1.0f);
		_shader_scene.setFloat("_pointLight[0].m_l", 0.09);
		_shader_scene.setFloat("_pointLight[0].m_q", 0.032);
		// point light 2
		_shader_scene.setVec3("_pointLight[1].m_pos", pointLightPositions[1]);
		_shader_scene.setVec3("_pointLight[1].m_ambient", glm::vec3(0.05f, 0.05f, 0.05f));
		_shader_scene.setVec3("_pointLight[1].m_diffuse", glm::vec3(0.8f, 0.8f, 0.8f));
		_shader_scene.setVec3("_pointLight[1].m_specular", glm::vec3(1.0f, 1.0f, 1.0f));
		_shader_scene.setFloat("_pointLight[1].m_c", 1.0f);
		_shader_scene.setFloat("_pointLight[1].m_l", 0.09);
		_shader_scene.setFloat("_pointLight[1].m_q", 0.032);
		// point light 3
		_shader_scene.setVec3("_pointLight[2].m_pos", pointLightPositions[2]);
		_shader_scene.setVec3("_pointLight[2].m_ambient", glm::vec3(0.05f, 0.05f, 0.05f));
		_shader_scene.setVec3("_pointLight[2].m_diffuse", glm::vec3(0.8f, 0.8f, 0.8f));
		_shader_scene.setVec3("_pointLight[2].m_specular", glm::vec3(1.0f, 1.0f, 1.0f));
		_shader_scene.setFloat("_pointLight[2].m_c", 1.0f);
		_shader_scene.setFloat("_pointLight[2].m_l", 0.09);
		_shader_scene.setFloat("_pointLight[2].m_q", 0.032);
		// point light 4
		_shader_scene.setVec3("_pointLight[3].m_pos", pointLightPositions[3]);
		_shader_scene.setVec3("_pointLight[3].m_ambient", glm::vec3(0.05f, 0.05f, 0.05f));
		_shader_scene.setVec3("_pointLight[3].m_diffuse", glm::vec3(0.8f, 0.8f, 0.8f));
		_shader_scene.setVec3("_pointLight[3].m_specular", glm::vec3(1.0f, 1.0f, 1.0f));
		_shader_scene.setFloat("_pointLight[3].m_c", 1.0f);
		_shader_scene.setFloat("_pointLight[3].m_l", 0.09);
		_shader_scene.setFloat("_pointLight[3].m_q", 0.032);

		// spotLight
		_shader_scene.setVec3("_spotLight.m_pos", _camera.getPosition());//跟随相机
		_shader_scene.setVec3("_spotLight.m_direction", _camera.getDirection());//跟随相机
		_shader_scene.setVec3("_spotLight.m_ambient", glm::vec3(0.0f, 0.0f, 0.0f));
		_shader_scene.setVec3("_spotLight.m_diffuse", glm::vec3(1.0f, 1.0f, 1.0f));
		_shader_scene.setVec3("_spotLight.m_specular", glm::vec3(1.0f, 1.0f, 1.0f));
		_shader_scene.setFloat("_spotLight.m_c", 1.0f);
		_shader_scene.setFloat("_spotLight.m_l", 0.09);
		_shader_scene.setFloat("_spotLight.m_q", 0.032);
		_shader_scene.setFloat("_spotLight.m_cutOff", glm::cos(glm::radians(12.5f)));
		_shader_scene.setFloat("_spotLight.m_outCutOff", glm::cos(glm::radians(15.0f)));

		//渲染10个物体
		for (int i = 0; i < 10; i++)
		{
			//初始化单位矩阵(模型),对10个物体求各自的平移旋转变换
			_modelMatrix = glm::mat4(1.0f);
			_modelMatrix = glm::translate(_modelMatrix, cubePositions[i]);
			_modelMatrix = glm::rotate(_modelMatrix, glm::radians(i * 20.0f), glm::vec3(0.0f, 1.0f, 0.0f));

			_shader_scene.setMatrix("_modelMatrix", _modelMatrix);
			glBindVertexArray(VAO_cube);
			glDrawArrays(GL_TRIANGLES, 0, 36);
		}

	_shader_scene.end();


	_shader_sun.start();
		_shader_sun.setMatrix("_modelMatrix", _modelMatrix);
		_shader_sun.setMatrix("_viewMatrix", _camera.getMatrix());
		_shader_sun.setMatrix("_projMatrix", _projMatrix);

		//渲染4个点光源
		for (int i = 0; i < 4; i++)
		{
			_modelMatrix = glm::mat4(1.0f);
			_modelMatrix = glm::translate(_modelMatrix, pointLightPositions[i]);
			_modelMatrix = glm::scale(_modelMatrix, glm::vec3(0.2f, 0.2f, 0.2f));
			_shader_sun.setMatrix("_modelMatrix", _modelMatrix);
			glBindVertexArray(VAO_sun);
			glDrawArrays(GL_TRIANGLES, 0, 36);
		}
	_shader_sun.end();

}

shader

vsunShader.glsl

//vsunShader.glsl
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aUV;

out vec2 outUV;

uniform mat4 _modelMatrix;
uniform mat4 _viewMatrix;
uniform mat4 _projMatrix;

void main()
{
   gl_Position = _projMatrix * _viewMatrix * _modelMatrix * vec4(aPos.x, aPos.y, aPos.z, 1.0);
   outUV = aUV;
};

从C++代码中设传入数据设置MVP矩阵,

fsunShader.glsl

#version 330 core
out vec4 FragColor;

in vec2 outUV;

uniform sampler2D  ourTexture;

void main()
{
    FragColor = vec4(1.0f , 1.0f ,1.0f ,1.0f );
};

光源的颜色直接设置为白色(1,1,1,1)

sceneShaderv.glsl

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

out vec2 outUV;
out vec3 outFragPos;
out vec3 outNormal;


uniform mat4 _modelMatrix;
uniform mat4 _viewMatrix;
uniform mat4 _projMatrix;

void main()
{
   gl_Position = _projMatrix * _viewMatrix * _modelMatrix * vec4(aPos.x, aPos.y, aPos.z, 1.0);
   outUV = aUV;
   outFragPos = vec3( _modelMatrix * vec4(aPos.x, aPos.y, aPos.z, 1.0));
   outNormal = mat3(transpose(inverse(_modelMatrix))) * aNormal;
};

从C++代码中设传入数据设置MVP矩阵,设置法向量。

sceneShaderf.glsl

#version 330 core
out vec4 FragColor;

in vec2 outUV;
in vec3 outFragPos;
in vec3 outNormal;
//物体材质
struct Material
{
    sampler2D   m_diffuse;//0
    sampler2D   m_specular;//1

    float       m_shiness;
};
//平行光
struct DirLight
{
    vec3 m_direction;
    vec3 m_ambient;
    vec3 m_diffuse;
    vec3 m_specular;
};
//点光源
struct PointLight
{
    vec3 m_pos;

    vec3 m_ambient;
    vec3 m_diffuse;
    vec3 m_specular;

    float m_c;
    float m_l;
    float m_q;
};
//聚光灯
struct SpotLight
{
    vec3 m_pos;
    vec3 m_direction;
    float m_cutOff;
    float m_outCutOff;

    vec3 m_ambient;
    vec3 m_diffuse;
    vec3 m_specular;

    float m_c;
    float m_l;
    float m_q;
};

#define MAX_POINT_NUMBER 4
uniform DirLight         _dirLight;
uniform PointLight       _pointLight[MAX_POINT_NUMBER];
uniform SpotLight        _spotLight;

uniform Material myMaterial;
uniform vec3 view_pos;

vec3 calculateDir(DirLight _light, vec3 _normal, vec3 _viewDir){
    vec3 _lightDir = normalize(_light.m_direction);

    //环境光
    vec3 _ambient = _light.m_ambient * vec3(texture(myMaterial.m_diffuse, outUV));

    //漫反射
    float _diff = max(dot(_normal,-_lightDir),0.0f);
    vec3 _diffuse = _light.m_diffuse * _diff * vec3(texture(myMaterial.m_diffuse, outUV));

    //镜面反射
    vec3 _reflectDir = reflect(_lightDir, _normal);
    float _spec = pow(max(dot(_reflectDir, _viewDir),0.0f),myMaterial.m_shiness);
    vec3 _specular = _light.m_specular * _spec * vec3(texture(myMaterial.m_specular, outUV));

    return (_ambient + _diffuse + _specular);
}


vec3 calculatePoint(PointLight _light , vec3 _normal , vec3 _viewDir , vec3 _fragPos)
{
    vec3 _lightDir =  normalize( _fragPos - _light.m_pos);
//环境光
    vec3 _ambient = _light.m_ambient * vec3(texture(myMaterial.m_diffuse , outUV));
//漫反射
    float _diff = max(dot(_normal , -_lightDir) , 0.0f);
    vec3  _diffuse = _light.m_diffuse * _diff *  vec3(texture(myMaterial.m_diffuse , outUV));
//镜面反射
    vec3 _reflectDir = reflect(_lightDir , _normal);
    float _spec = pow(max(dot(_reflectDir , _viewDir) , 0.0f) , myMaterial.m_shiness);
    vec3  _specular = _light.m_specular * _spec * vec3(texture(myMaterial.m_specular , outUV));

//衰减系数计算
    float _dist = length(_light.m_pos - _fragPos);
    float _attenuation = 1.0f / (_light.m_c + _light.m_l * _dist + _light.m_q * _dist * _dist);


    return (_ambient + _diffuse + _specular) * _attenuation;
}


vec3 calculateSpot(SpotLight _light , vec3 _normal , vec3 _viewDir , vec3 _fragPos)
{
    vec3 _lightDir =  normalize( _fragPos - _light.m_pos);
    vec3 _spotDir= normalize(_light.m_direction);
    float _cosTheta = dot(-_lightDir , -_spotDir);
    float _epsilon = _light.m_cutOff - _light.m_outCutOff;
    float _intensity = clamp((_cosTheta - _light.m_outCutOff) / _epsilon , 0.0f , 1.0f);

//环境光
    vec3 _ambient = _light.m_ambient * vec3(texture(myMaterial.m_diffuse , outUV));
//漫反射
    float _diff = max(dot(_normal , -_lightDir) , 0.0f);
    vec3  _diffuse = _light.m_diffuse * _diff *  vec3(texture(myMaterial.m_diffuse , outUV));
//镜面反射
    vec3 _reflectDir = reflect(_lightDir , _normal);
    float _spec = pow(max(dot(_reflectDir , _viewDir) , 0.0f) , myMaterial.m_shiness);
    vec3  _specular = _light.m_specular * _spec * vec3(texture(myMaterial.m_specular , outUV));

//衰减系数计算
    float _dist = length(_light.m_pos - _fragPos);
    float _attenuation = 1.0f / (_light.m_c + _light.m_l * _dist + _light.m_q * _dist * _dist);

    return (_ambient + _diffuse + _specular) * _attenuation * _intensity;
}


void main()
{
    vec3 _normal = normalize(outNormal);
    vec3 _viewDir = normalize(view_pos - outFragPos);

    vec3 _result = calculateDir(_dirLight ,_normal , _viewDir);
    
    for(int i = 0;i < MAX_POINT_NUMBER;i++)
    {
        _result += calculatePoint(_pointLight[i] , _normal , _viewDir , outFragPos);
    }

    _result += calculateSpot(_spotLight ,  _normal , _viewDir , outFragPos); 

    FragColor = vec4(_result ,1.0f);
    //FragColor = vec4(vec3(gl_FragCoord.y / 600.0f) ,1.0f);
};

总体就是对之前理论的shader代码复现,最后将各个光源的贡献加在一起,作为FragColor输出。

渲染结果

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/37351.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

骨感传导蓝牙耳机怎么样,骨感传导耳机对于我们耳道是否有保护

在现在数码产品普及生活的时代&#xff0c;耳机也成为了我们每天的标准&#xff0c;以往佩戴的都是入耳式的耳机&#xff0c;但长时间佩戴下会出现耳朵疼痛&#xff0c;严重的更会导致听力障碍的问题发生&#xff0c;针对这一现象&#xff0c;一种新型的骨感传导耳机来到了我们…

后台默默付出的劳动者,四大组件之服务(Service)

后台默默付出的劳动者&#xff0c;四大组件之服务Service前言十、后台默默付出的劳动者&#xff0c;四大组件之服务&#xff08;Service&#xff09;10.1 服务是啥&#xff1f;10.2 Android异步消息处理机制10.2.1 Android异步消息处理机制介绍10.2.2 基于Android异步消息处理机…

Packet Tracer - 排除多区域 OSPFv2 故障

地址分配表 设备 接口 IP 地址 子网掩码 默认网关 ISP GigabitEthernet0/0 209.165.200.17 255.255.255.240 不适用 ASBR GigabitEthernet0/0 209.165.200.18 255.255.255.240 不适用 Serial0/0/0 10.1.1.2 255.255.255.252 不适用 Serial0/0/1 10.2.2…

制作一个企业网站——html华为官网购物商城项目的设计与实现

常见网页设计作业题材有 个人、 美食、 公司、 学校、 旅游、 电商、 宠物、 电器、 茶叶、 家居、 酒店、 舞蹈、 动漫、 服装、 体育、 化妆品、 物流、 环保、 书籍、 婚纱、 游戏、 节日、 戒烟、 电影、 摄影、 文化、 家乡、 鲜花、 礼品、 汽车、 其他等网页设计题目, A…

【Redis】使用 Java 客户端连接 Redis

一、三种客户端比较 Jedis : 学习成本低&#xff0c;以 Redis 命令作为方法名称&#xff0c;但是其线程不安全 lettuce&#xff1a;基于 Netty 实现&#xff0c;支持同步、异步、响应式编程&#xff08;SpringBoot&#xff09;&#xff0c;并且线程安全。支持 Redis 的哨兵模…

【附源码】计算机毕业设计JAVA幼儿健康管理系统

【附源码】计算机毕业设计JAVA幼儿健康管理系统 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; JAVA my…

Nacos入门

文章目录一、安装nacos二、nacos项目环境配置一、安装nacos 压缩包下载地址&#xff1a; https://github.com/alibaba/nacos/releases 压缩包解压&#xff1a; nacos 中修改端口(8848 端口被占用需要修改)&#xff1a; 进入 conf 进入 application.properties 端口位置 启…

【springboot进阶】摆脱 if/else 的高级应用 - 策略模式

目录 一、策略模式的介绍 二、策略模式的使用场景 三、策略模式的应用 1、入参和出参类 2、策略接口 3、策略具体实现 4、策略测试 三、一些使用技巧 四、总结 对于一个逻辑相对复杂的功能应用中&#xff0c;难免需要做很多的逻辑判断&#xff0c;需要写一堆的 if/els…

Flink常用Sink(elasticsearch(es)Sink、RedisSink、KafkaSink、MysqlSink、FileSink)

flink输出到es、redis、mysql、kafka、file 文章目录配置pom文件公共实体类KafkaSInkElasticsearchSink(EsSink)RedisSinkMysqlSink(JdbcSink)FileSink自己先准备一下相关环境 配置pom文件 <properties><maven.compiler.source>8</maven.compiler.source>&l…

【概率论与数理统计】第四章知识点复习与习题

思维导图 基础知识 数学期望 定义 数学期望其实很好理解&#xff0c;就是均值&#xff0c;当然这里并不是直接计算样本的均值&#xff0c;而是考虑到样本对应的概率。我们分离散和连续两类来讨论数学期望。 离散型 对随机变量X的分布律为 若级数 绝对收敛&#xff0c;则称该…

BaGet搭建Nuget私仓(window10docker)

文章目录一、搭建背景二、框架简介三、私仓搭建1、环境2、win10上部署2.1安装SDK2.2下载和解压BaGet包2.3运行项目2.4类库项目2.5将包发布到私有Nuget中2.6使用BaGetFirstLib2.7使用密码增加安全性3、Docker上部署3.1创建相关文件3.2拉取镜像3.3运行3.4访问四、结束一、搭建背景…

微服务入门

文章目录一、微服务大概认识二、单体架构架构和分布式架构三、微服务架构特征四、微服务技术对比五、SpringCloud 与 SpringBoot版本兼容关系如下&#xff1a;一、微服务大概认识 二、单体架构架构和分布式架构 单体架构&#xff1a;将业务的所有功能集中在一个项目中开发&…

“加密上海·喜玛拉雅Web3.0数字艺术大展”落幕,AIGC和数字艺术衍生品是最大赢家?...

图片来源&#xff1a;由无界版图 AI 绘画工具生成11月11日&#xff0c;为期一个月的第一届“加密上海喜玛拉雅3eb3.0数字艺术大展”在喜玛拉雅美术馆拉开帷幕。这无疑是当下中国最盛大、最集中的一次数字艺术展览。艺术展吸引了像Soul 、小红书、网易星球、bilibili、酷天下、无…

mysql实战操作总结

1、问题描述 关于mysql操作&#xff0c;记录下&#xff1b; 2、问题说明 1.停止正在执行的sql 数据量太大&#xff0c;数据库没反应&#xff0c;用的navicat&#xff0c;就在查询页面&#xff0c;执行&#xff1a; show processlist;---会显示对应的查询sql找到最前面是id…

vue js实现文件上传压缩优化处理

vue js实现文件上传压缩优化处理 两种方法 &#xff1a; 第1种是借助canvas的封装的文件压缩上传第2种&#xff08;扩展方法&#xff09;使用compressorjs第三方插件实现 目录 vue js实现文件上传压缩优化处理 借助canvas的封装的文件压缩上传 1.新建imgUpload.js 2.全局引…

高清免费壁纸网站推荐

本期内容&#xff0c;为大家整理了6个相当不错的免费壁纸网站&#xff0c;访问量极大、活跃度极高。 无需登录、注册&#xff0c;打开右键就可以下载&#xff0c;而且壁纸图片的尺寸大小&#xff0c;可以选择&#xff0c;从手机、平板、再到电脑壁纸&#xff0c;全部都是高清。…

Windows/Ubuntu安装frida和objection

​Windows/Ubuntu安装frida和objection 1.Windows环境使用管理员权限安装frida,Ubuntu使用普通或Root权限安装均可 https://github.com/frida/frida (1).安装frida(Python2.7.8及以上版本) pip install numpy matplotlib -i https://mirrors.aliyun.com/pypi/simplepip insta…

imx6ull pro BSP 工具链

BSP&#xff0c;Board Support Package&#xff0c;指板级支持包&#xff0c;是构建嵌入式操作系统所 需的引导程序(Bootload)、内核(Kernel)、根文件系统(Rootfs)和工具链 (Toolchain)。 每种开发板的 BSP 都不一样&#xff0c;并且这些源码都非常庞大。我们把这些源码都 放在…

BI-SQL丨JOB

JOB 在SQL Server中&#xff0c;JOB属于常用功能&#xff0c;我们经常需要通过JOB来执行一些定时的作业任务&#xff0c;例如数据备份、存储过程、SSIS任务、SSAS刷新等等。 通常情况下&#xff0c;我们都是在SSMS中对JOB进行创建、删除、维护等任务的。 前置条件 使用JOB功…

基于Mxnet实现实例分割-MaskRCNN【附部分源码】

文章目录前言一、什么是实例分割二、数据集的准备1.数据集标注2.VOC数据集转COCO数据集三、基于Mxnet搭建MaskRCNN1.引入库2.CPU/GPU配置3.获取训练的dataset1.coco数据集2.自定义数据集4.获取类别标签5.模型构建6.数据迭代器7.模型训练1.优化器设置2.loss计算3.acc计算4.循环训…