opengl渲染器入门02光源模型

76 阅读3分钟

引言

在前面给出了一些纹理,渲染管线和坐标变换等,这里开始实现一些简单的渲染和光照的效果,还没有进行核对只是负责自己使用。

Lambert模型

在图形学中,已经给出了其BRDF函数,和光照方程:

图片11.png

图片18.png

在这里,我们需要法线N,着色点的坐标,入射光线I(指向光源),在opengl传入光源的信息和相机的位置:
while (!glfwWindowShouldClose(window))
{
    processInput(window);                            //按键控制
    glClearColor(0.1f, 0.1f, 0.1f, 1.0f);            //清空区域的颜色
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);       //清空颜色缓冲和深度缓冲
    lightingShader.use();
    lightingShader.setVec3("lightcolor", glm::vec3(1,1,1));     //光的强度
    lightingShader.setVec3("lightposition", glm::vec3(1,10,1));  //光的位置
}

这里顶点着色器和片元着色器的代码实现:

//顶点着色器
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aUV;
layout (location = 2) in vec3 aNormal;
out vec3 normal;
out vec2 texcoord;
out vec3 FragPos;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0);
FragPos = vec3(model * vec4(aPos, 1.0));
normal = mat3(transpose(inverse(model))) * aNormal;
texcoord = aUV;
}
//片元着色器
#version 330 core
in vec3 normal;
in vec2 texcoord;
in vec3 FragPos;
out vec4 FragColor;
uniform sampler2D ourTexture;
uniform vec3 lightPos;
uniform vec3 lightColor;
void main()
{
vec3 ambient = lightColor * 0.15;    //环境光
vec3 norm = normalize(normal);        //法线单位化
vec3 lightDir = normalize(lightPos - FragPos);     //I指向光源
vec3 diffuse = vec3(texture(ourTexture, texcoord));   //纹理采样,teture之后是四维的,需要变成三维
float cosine = max(dot(norm, lightDir), 0.0);    //计算cos
FragColor = vec4(ambient + lightColor * diffuse * cosine, 1.0);  
}

需要特别注意的是,在渲染的时候可能对于顶点也进行一定的变化,所以在处理法线的时候也需要对于法线做变化,这里直接给出了变化,不做推导: normal = mat3(transpose(inverse(model))) * aNormal;

Phong模型

还是先给出其BRDF函数,如下:

图片14.png

相比于lanbert模型,需要多一个相机的位置参数
shader.setVec3("lightPos", glm::vec3(0, 3, 2));
shader.setVec3("lightColor", glm::vec3(1, 1, 1));
shader.setVec3("cameraPos", camera->cameraPos);

只需要加入高光的反射的量,只给出片元着色器:

//片元着色器
#version 330 core
in vec3 normal;
in vec2 texcoord;
in vec3 FragPos;
out vec4 FragColor;
uniform sampler2D ourTexture;
uniform vec3 lightPos;
uniform vec3 lightColor;
uniform vec3 cameraPos;
void main()
{
vec3 ambient = lightColor * 0.15;
vec3 norm = normalize(normal);
vec3 lightDir = normalize(lightPos - FragPos);   //像素指向光源
vec3 rho_d = vec3(texture(ourTexture, texcoord));
float cosine = max(dot(norm, lightDir), 0.0);
float rho_s = 0.5;
vec3 viewDir = normalize(cameraPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);   //relect的传入是指向着色点
float cosine2 = pow(max(dot(viewDir, reflectDir), 0.0), 16);  //高光反射项
FragColor = vec4(ambient + lightColor * (rho_d * cosine + rho_s * cosine2), 1.0);
}

Blin-Phong模型

图片15.png

只需要把Phong其中的换成dot(N,H)就可以了。

H=normalize(I+V)

光源的衰减

一般的有,对于光源都有一定程度的衰减,距离光源的越远的物体,接受到光强越微弱,保留一下通常用如下的公式进行计算:

图片25.png

通常下面由一个分母表示,一般记为基础衰减,一次下降的,二次下降的速度,一般由constant,linear,quadratic组成:

float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));

模型的导入

一般采用assimp库进行导入,或者和tiny_loader都可以进行数据的导入,网上有很多的教程和使用,不做多余的解释。