目录
颜色相关理论
什么是颜色
如何计算颜色?
简单实现
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光照模型是环境光、漫反射和镜面反射的结合。
一般是一个常数,物体一直显示的颜色。来代表周围环境的光照。
在shader中的实现为:
可以看到这里直接设置为了一个常数系数,然后直接乘以光源光、乘以物体颜色即可完成运算。
入射的光线可以分为两个向量,只有垂直于平面的分量对光照亮度有贡献。说白了就是物体实际反射出来的光。
shader:
也就是说,我们只需要计算法向量与光线向量的cos夹角(单位向量即点乘),并将这个cos赋为系数,乘以光源的颜色,即可得出漫反射的光照。
值得注意的是,Normal 向量的计算是一个齐次坐标阵,并且最后一个元素为0,代表是向量。此外,对于缩放变换,有可能导致法向量Normal进行错误的变换,这里需要做特殊的处理:
shader中的具体计算方式:
光线方向需要取反,因为实际入射光是从光源射到某个点上的。之前我们定义的是从某点射到光源上的。
材质:物体对于某一种光的反射强度,在Phong模型下,就是不同物体对环境光、漫反射、镜面反射等不同光的反射强度定义。
比如:粘土罐子对于镜面反射几乎没有反应,但是对于漫反射会有很强的反应。
从RGB的角度来讲,可以理解为对RGB的做进一步的“百分比”。
上面说了这么多,需要落实到代码中去
//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;
};
//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;
};
#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);
};
#version 330 core
out vec4 FragColor;
in vec2 outUV;
uniform sampler2D ourTexture;
void main()
{
FragColor = vec4(1.0f , 1.0f ,1.0f ,1.0f );
};
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();
}