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

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

目录

光照贴图

光源分类

平行光

点光源

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输出。

渲染结果

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
课程解决的问题: 作为游戏行业或者图形学从业者,你是否面临以下问题: 到底openGL底层如何实现的? 到底矩阵操作变换是怎么做到的? 到底光栅化的算法以及原理是什么? 到底如何才能从3D世界投射到2D屏幕呢? 图形学有这么多的矩阵操作,到底如何推导如何应用呢? 学完这门课程,你应该就可以从底层了解一个初级的openGL图形接口如何实现,图形学最底层的封装到底面临哪些挑战;跟随我们一行一行写完代码,你就会得到一个迷你版本的openGL图形库,你可以深度体会图形从模型变换,观察矩阵变换,投影矩阵变换一直到光栅化纹理操作的全套模拟流程。 课程介绍: 本课程将带领学员不使用任何图形库,实现从0到1的图形学接口封装以及算法讲解,并且带领大家手敲代码,一行一行进行实现。 涵盖了(环境搭建,绘制点,Bresenham算法绘制完美直线,三角形拆分绘制算法,颜色插值算法,图片操作,图片二次插值放缩算法,纹理系统接口搭建及封装,矩阵操作理论以及实践openGL类似接口封装,3D世界的图形学理论及接口封装等) 最终将带领大家通过C++实现一个3D世界的图形接口,方便所有人入门图形学,进行接下来的openGL接口以及GPU编程的学习   本课程为系列课程的第一步入门,且带领所有人进行实现,更加实用,可以让大家打牢图形学的基础知识及编程技能

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值