OpenGL原理与实践——核心模式(五):颜色、基础光照、Phong模型、材质与光

目录

颜色相关理论

什么是颜色

如何计算颜色?

简单实现

Phong光照模型——局部光照模型

环境光

​编辑

漫反射

镜面反射

材质与光

材质与纹理的关系

材质在shader的体现

材质属性与光属性

光在shader的体现

整体源码实现及渲染结果

关键代码

shader——vertexShader.glsl(读取物体数据)

shader——vsunShader.glsl(读取光源数据)

shader——fragmentShader.glsl(定义材质、光结构体数据结构,读取数据并计算像素颜色)

shader——fsunShader.glsl( 定义光源颜色)

render——传入shader数据并渲染

渲染结果


颜色相关理论

什么是颜色

说白了就是光反射进人眼的那部分。

如何计算颜色?

以这个图为例,设自然光照为RGB分量为(1,1,1),一个物体的颜色RGB为(1,0.5,0.31),由之前所说的颜色理论,物体的颜色即为反射光照所占光源RGB百分比,所以直接相乘即可得到最终颜色。

再比如,如果光源本身就没有红色(RGB中的R分量为0),那么物体自然也不会反射红光,即R值。所以最终颜色的结果的R也是0。

简单实现

我们需要一个光源和一个物体,那么自然需要构建两组VAO,并进行VBO的绑定;同时设定光源的位置和光源颜色:

//main.cpp
VAO_cube = createModel();
VAO_sun = createModel();
light_pos = glm::vec3(3.0f, 0.0f, -1.0f);
light_color = glm::vec3(1.0f, 1.0f, 1.0f);
uint createModel()
{
	uint _VAO = 0;
	uint _VBO = 0;

	float vertices[] = {
		-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;
}

Phong光照模型——局部光照模型

 

Phong光照模型是环境光、漫反射和镜面反射的结合。

环境光

一般是一个常数,物体一直显示的颜色。来代表周围环境的光照。

在shader中的实现为:

可以看到这里直接设置为了一个常数系数,然后直接乘以光源光、乘以物体颜色即可完成运算。

漫反射

入射的光线可以分为两个向量,只有垂直于平面的分量对光照亮度有贡献。说白了就是物体实际反射出来的光。

shader:

 

也就是说,我们只需要计算法向量与光线向量的cos夹角(单位向量即点乘),并将这个cos赋为系数,乘以光源的颜色,即可得出漫反射的光照。

值得注意的是,Normal 向量的计算是一个齐次坐标阵,并且最后一个元素为0,代表是向量。此外,对于缩放变换,有可能导致法向量Normal进行错误的变换,这里需要做特殊的处理:

镜面反射

  • 考虑入射光和反射光位置的反射方式
  • 光强考虑观察者位置,视线与反射光夹角决定了光强

shader中的具体计算方式:

光线方向需要取反,因为实际入射光是从光源射到某个点上的。之前我们定义的是从某点射到光源上的。

材质与光

材质:物体对于某一种光的反射强度,在Phong模型下,就是不同物体对环境光、漫反射、镜面反射等不同光的反射强度定义。

比如:粘土罐子对于镜面反射几乎没有反应,但是对于漫反射会有很强的反应。

从RGB的角度来讲,可以理解为对RGB的做进一步的“百分比”。

材质与纹理的关系

  • 纹理:可理解为普通的贴图,即物体本身最基础的颜色
  • 材质:给物体表面做的进一步的光源反射属性。比如,具有金属质感(材质)木头(纹理)、具有木头质感(材质)金属(纹理)

材质在shader的体现

材质属性与光属性

  • 材质属性:我们可以根据自己的喜好来决定如何反射光
  • 光属性:我们可以根据自己的喜好来决定如何发射光

光在shader的体现

整体源码实现及渲染结果

上面说了这么多,需要落实到代码中去

关键代码

shader——vertexShader.glsl(读取物体数据)

//vertexShader.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;
};

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

shader——fragmentShader.glsl(定义材质、光结构体数据结构,读取数据并计算像素颜色)

#version 330 core
out vec4 FragColor;

in vec2 outUV;
in vec3 outFragPos;
in vec3 outNormal;

struct Material
{
    vec3 m_ambient;
    vec3 m_diffuse;
    vec3 m_specular;

    float m_shiness;
};

uniform Material myMaterial;

struct Light
{
    vec3 m_pos;
    vec3 m_ambient;
    vec3 m_diffuse;
    vec3 m_specular;
};

uniform Light myLight;


uniform sampler2D  ourTexture;
uniform vec3 view_pos;

void main()
{
//环境光
    vec3 _ambient = myLight.m_ambient * myMaterial.m_ambient;

//漫反射
    vec3 _normal = normalize(outNormal);
    vec3 _lightDir = normalize(myLight.m_pos - outFragPos);
    float _diff = max(dot(_normal , _lightDir) , 0.0f);
    vec3 _diffuse = myLight.m_diffuse * _diff * myMaterial.m_diffuse;

//镜面反射
    float _specular_strength = 0.5;
    vec3 _viewDir = normalize(view_pos - outFragPos);
    vec3 _reflectDir = reflect(-_lightDir , outNormal);

    float _spec = pow(max(dot(_viewDir , _reflectDir) , 0.0f) , myMaterial.m_shiness);

    vec3 _sepcular = myLight.m_specular * _spec * myMaterial.m_specular;


    vec3 result = _ambient  + _diffuse + _sepcular;
    FragColor = texture(ourTexture , outUV) * vec4(result ,1.0f);
};

shader——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 );
};

 render——传入shader数据并渲染

void render()
{
	glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glEnable(GL_DEPTH_TEST);


	_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));
	glBindTexture(GL_TEXTURE_2D, _texture);

	//物体shader
	_shader_cube.start();
		_shader_cube.setVec3("view_pos", _camera.getPosition());

		//传入光照属性
		light_color = glm::vec3((float)glfwGetTime() * 0.4f, (float)glfwGetTime() * 0.5f, (float)glfwGetTime() * 0.7f);
		_shader_cube.setVec3("myLight.m_ambient", light_color * glm::vec3(0.1f));
		_shader_cube.setVec3("myLight.m_diffuse", light_color * glm::vec3(0.7f));
		_shader_cube.setVec3("myLight.m_specular", light_color * glm::vec3(0.5f));
		_shader_cube.setVec3("myLight.m_pos", light_pos);

		//传入物体材质属性
		_shader_cube.setVec3("myMaterial.m_ambient", glm::vec3(0.1f));
		_shader_cube.setVec3("myMaterial.m_diffuse", glm::vec3(0.7f));
		_shader_cube.setVec3("myMaterial.m_specular", glm::vec3(0.8f));
		_shader_cube.setFloat("myMaterial.m_shiness", 32);

		_shader_cube.setMatrix("_modelMatrix", _modelMatrix);
		_shader_cube.setMatrix("_viewMatrix", _camera.getMatrix());
		_shader_cube.setMatrix("_projMatrix", _projMatrix);
		glBindVertexArray(VAO_cube);
		glDrawArrays(GL_TRIANGLES, 0, 36);
	_shader_cube.end();

	//光源shader
	_shader_sun.start();
		_shader_sun.setMatrix("_modelMatrix", _modelMatrix);
		_shader_sun.setMatrix("_viewMatrix", _camera.getMatrix());
		_shader_sun.setMatrix("_projMatrix", _projMatrix);

		_modelMatrix = glm::mat4(1.0f);
		_modelMatrix = glm::translate(_modelMatrix, light_pos);
		_shader_sun.setMatrix("_modelMatrix", _modelMatrix);
		glBindVertexArray(VAO_sun);
		glDrawArrays(GL_TRIANGLES, 0, 36);
	_shader_cube.end();
}

渲染结果

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值