【Metal API 教程:第二讲】编写Metal Shader并渲染3D模型(上)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tomicyo/article/details/42360257

前言


本文不讲述图形变换的理论(可参考计算机图形学和线性代数),图形编程(场景物体剔除、光照等)涉及到很多的数学基础,本文直接从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);
}

看见Shader里的数学函数,相信很多用过HLSL的同学一定都很熟悉吧,Metal要使用这些数学函数要包含simd库的头文件,不像GLSL和HLSL那样是内置的函数和类型(其实Metal也是内置的)。留意红色字体部分,Shader中的变量传递也是通过变量属性来声明的。

纹理和采样声明

texture2d<half> tex [[ texture(QUAD_IMAGE_TEXTURE) ]];
constexpr sampler s_quad(filter::linear);
half4 image_color = tex.sample(s_quad, in.uv);

完全就是 HLSL的翻版有木有啊!!

渲染结果





本文版权DsoTsin所有,转载文章请注明出处!


猜你喜欢

转载自blog.csdn.net/tomicyo/article/details/42360257