前言
本文不讲述图形变换的理论(可参考计算机图形学和线性代数),图形编程(场景物体剔除、光照等)涉及到很多的数学基础,本文直接从Shader语法阐述如何用Metal API渲染3D物体。
关于Shader
Shader是运行在GPU(显卡)上的程序,用于图元的着色和变换使用。Metal Shader的语法大量地参考了C++,比如
C++ 1x的变量属性[[attribute(x)]],在Metal里面用于声明变量绑定的资源索引,类似于
GLSL的layout(location=x/binding=x)式(HLSL类似)的声明,但是支持还是很有限,代码风格更类似C,仅仅提供简单的泛型、命名空间和SIMD数学库。详细的语法可以参考
Metal Shading Language Guide,有过GLSL/HLSL编程经验能很快上手,由于移动GPU的性能还很有限,Metal Shader目前还不支持曲面细分、几何着色器。
代码示例
struct Material
{
float3 ambientColor;
float3 diffuseColor;
float3 specularColor;
float specularPower;
};
//结构体的声明和初始化(常量)
constant Material material = {
.ambientColor = { 0.9, 0.1, 0 },
.diffuseColor = { 0.9, 0.1, 0 },
.specularColor = { 1, 1, 1 },
.specularPower = 100
};
//变量属性
struct Vertex
{
float4 position [[attribute(0)]];
float3 normal [[attribute(1)]];
};
#include <simd/simd.h>
typedef struct
{
simd::float4x4 modelViewProjectionMatrix;
simd::float4x4 modelViewMatrix;
simd::float3x3 normalMatrix;
} Uniforms;
使用SIMD库
声明Shader
vertex VS(Vertex vert [[stage_in]],
constant Uniforms &uniforms [[buffer(1)]])
{
ProjectedVertex outVert;
outVert.position = uniforms.modelViewProjectionMatrix * vert.position;
outVert.eye = -(uniforms.modelViewMatrix * vert.position).xyz;
outVert.normal = uniforms.normalMatrix * vert.normal;
return outVert;
}
fragment float4 PS(ProjectedVertex vert [[stage_in]], constant Uniforms &uniforms [[buffer(0)]])
{
float3 ambientTerm = light.ambientColor * material.ambientColor;
float3 normal = normalize(vert.normal);
float diffuseIntensity = saturate(dot(normal, light.direction));
float3 diffuseTerm = light.diffuseColor * material.diffuseColor * diffuseIntensity;
//Blin-Phong Shading
float3 specularTerm(0);
if (diffuseIntensity > 0)
{
float3 eyeDirection = normalize(vert.eye);
float3 halfway = normalize(light.direction + eyeDirection);
float specular = pow(saturate(dot(normal, halfway)), material.specularPower);
specularTerm = light.specularColor * material.specularColor * specular;
}
return float4(ambientTerm + diffuseTerm + specularTerm, 1);
}
纹理和采样声明
texture2d<half> tex [[ texture(QUAD_IMAGE_TEXTURE) ]];
constexpr sampler s_quad(filter::linear);
half4 image_color = tex.sample(s_quad, in.uv);
完全就是 HLSL的翻版有木有啊!!
渲染结果
本文版权DsoTsin所有,转载文章请注明出处!