一步步学Metal图形引擎6-《漫反射》
Posted Mr_厚厚
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一步步学Metal图形引擎6-《漫反射》相关的知识,希望对你有一定的参考价值。
教程 6
漫反射
教程源码下载地址: https://github.com/jiangxh1992/MetalTutorialDemos
CSDN完整版专栏: https://blog.csdn.net/cordova/category_9734156.html
一、原理
1.1 基础光照
之前的教程我们实现了将一个模型加载到场景中,并实现了模型的矩阵变换和相机的移动变换。但我们之前并没有开始真正的渲染,只是通过纹理采样将贴图上的颜色显示到了屏幕上。这篇教程开始我们将讨论场景中的一些基础光照模型的渲染,将光线的计算加入到我们的场景中。
基础的光照计算主要包括漫反射、镜面反射和环境光,这些光照模型属于本地照明模型,是在模型表面上对光照建模计算光照后的颜色。
模型表面建模的几个关键变量有:法线n,入射光L和观察者视线v。计算过程中只关心进入眼睛的光线。
1.2 平行光
平行光是一种只有固定方向,没有光源的光线,实际上指的就是太阳光。由于太阳离地球太远,可以认为太阳光线是平行光,光线全都平行,以一个固定方向射到物体表面。定义一个平行光只需要一个表示方向的向量,另外可以定义光源的颜色。太阳光的颜色为白光。
1.3 漫反射模型
漫反射是一种理想光照模型,指的是物体表面等同的向各个方向散射的现象。漫反射可以通过兰伯特定律(Lambert’s Law)来描述,计算公式为:
I是我们计算的漫反射光强结果,IL是光源的强度,kd(0~1)是物体表面的反射系数,theta是光线方向和法线的夹角。
Lambert漫反射描述的实际上是光源以一定角度入射到物体表面,在法线方向上的投影光强度。可见直射到表面时漫反射最强,随着夹角增大漫反射的强度逐渐衰弱。漫反射的光强和入射光的方向与表面法线夹角的余弦成正比即为Lambert定律。
二、源码分析
2.1 Render.m
- (void)updateGameState
Uniforms * uniforms = (Uniforms*)_uniformBuffer.contents;
// P
uniforms->projectionMatrix = _projectionMatrix;
// V
uniforms->viewMatrix = matrix_multiply(matrix4x4_translation(0, -100, 1100),
matrix4x4_rotation(-0.5, (vector_float3)1,0,0));
// M
uniforms->modelMatrix = matrix_multiply(matrix4x4_rotation(_rotation, (vector_float3)0,1,0),
matrix4x4_translation(0, 0, 0));
// MV
uniforms->modelViewMatrix = matrix_multiply(uniforms->viewMatrix, uniforms->modelMatrix);
// 平行光
uniforms->directionalLightDirection = (vector_float3)-1.0,-1.0,-1.0;
uniforms->directionalLightColor = (vector_float3)0.8,0.8,0.8;
uniforms->IL = 10.0f;
uniforms->Kd = 0.1f;
_rotation += 0.002f;
上一片教程我们通过矩阵变换实现让相机围着模型旋转,这里我们为了更好的展示光照模型效果,更新Uniform Buffer中的矩阵变量,固定相机视角,调整相机距离,并让模型自转。
此外这里我们要添加第一个光源,最基础的平行光,也就是太阳光。太阳光的光源认为无穷远,是一种只有方向没有光源的光照,我们只需要在Uniform Buffer中定义一个方向和光源颜色来表达这个光源即可。光源的方向我们设置为从右上方2点钟方向照向左下方,光源颜色设置为一定灰度的白光。
最后我们要在Uniform Buffer中添加并设置光源强度IL,物体表面漫反射系数Kd,这个系数的取值范围为0~1之间,这里设置为0.1。
2.2 ShaderTypes.h
typedef struct
matrix_float4x4 projectionMatrix;
matrix_float4x4 modelViewMatrix;
matrix_float4x4 modelMatrix;
matrix_float4x4 viewMatrix;
float IL; // 光源强度
float Kd; // 漫反射系数
vector_float3 directionalLightDirection;
vector_float3 directionalLightColor;
Uniforms;
Uniform Buffer结构体中我们增加了平行光相关的数据,以及光源强度IL和漫反射系数Kd。
2.3 Shaders.metal
// ...
out.normal = normalize(uniforms.modelMatrix * float4((float3)in.normal,0));
// ...
我们模型顶点buffer中的坐标都是定义在模型空间坐标系的,光源是定义在世界空间,这里顶点着色器中我们需要将法线从模型空间变换到世界空间,统一在世界空间进行漫反射光照计算。
// ...
float3 N = float3(in.normal.xyz);
float3 L = normalize(-uniforms.directionalLightDirection);
// Lambert diffuse
float diffuse = uniforms.IL * uniforms.Kd * max(dot(N,L),0.0);
float3 out = float3(uniforms.directionalLightColor) * float3(color_sample.xyz) * diffuse;
// ...
光照的计算我们在片段着色器逐像素进行。参与计算的法向量为N,入射光方向取反和法线同向,向量都单位化。法线和入射光向量点积乘以反射系数Kd即为当前片段的漫反射光强度系数,乘以光强IL得到当前片段最终的漫反射光强度。
最后片段纹理颜色乘以光源颜色进行颜色叠加,然后乘以漫反射强度得到片段最终的漫反射颜色值,直接返回。
三、运行效果
根据漫反射的明暗层次可以看出光源在右上方,模型背向光源的会是漆黑一片,面向光源的则比较明亮。
以上是关于一步步学Metal图形引擎6-《漫反射》的主要内容,如果未能解决你的问题,请参考以下文章