在金属iOS中使用不同颜色的灯罩的单个3d模型上的多个灯点

时间:2017-03-17 05:17:01

标签: 3d swift3 sprite-kit scenekit metal

我想在金属IOS中使用不同颜色的灯光阴影在单个3D模型上放置多个灯光点。

我已完成此作业IOS - Metal

现在,我想在一个3d模型中应用不同颜色的多个灯光点。

enter image description here 查看附图(在SceneKit和SpriteKit -SKLightNode中开发),在3D模型上需要类似的灯光反射效果。

1 个答案:

答案 0 :(得分:3)

要实现的基本要素是从表面反射的光是添加剂:每种光都会产生一定量的辐照度,表面的辐射出射率是表面的总和&# 39;对这种能量的反应。我们将使用的数量仍然不是完全基于物理的,但这种洞察力将帮助我们选择不会过度破坏最终颜色的值。

为简单起见,我们会坚持定向灯。您可以轻松地将其概括为指向或点亮灯;它只是传递你需要的属性并计算每个光的贡献。

首先,删除struct Light的定义和全局light值。我们将这些内容提升到统一结构中,以便我们可以从应用程序代码中设置它们。

重新定义" Shared.h"中的Light结构。标题,因此可以从Objective-C和Metal代码中看到:

#define kMaxLights 4

typedef struct
{
    vector_float3 direction;
    vector_float3 ambientColor;
    vector_float3 diffuseColor;
    vector_float3 specularColor;
} Light;

在我们处理它的同时,让我们从使用simd命名空间切换到使用vector_matrix_前缀,只是为了减少对Objective的依赖-C ++:

typedef struct
{
    matrix_float4x4 modelViewProjectionMatrix;
    matrix_float4x4 modelViewMatrix;
    matrix_float3x3 normalMatrix;
    Light lights [kMaxLights];
} Uniforms;

在这里,我们在制服结构中包含一个固定大小的灯光阵列,这样我们就可以在我们的着色器中指定最多四个没有分支的灯光。您可以根据需要减少或增加此数字。

在应用程序代码(特别是updateUniforms方法)中,我们可以重新定义第一个灯光以匹配先前的值:

Uniforms uniforms = { 0 };

(将制服结构清零,然后)

uniforms.lights[0].direction = (vector_float3){ 0.13, 0.72, 0.68 };
uniforms.lights[0].ambientColor = (vector_float3){ 0.05, 0.05, 0.05 };
uniforms.lights[0].diffuseColor = (vector_float3){ 0.9, 0.9, 0.9 };
uniforms.lights[0].specularColor = (vector_float3){ 1, 1, 1 };

您现在可以运行应用程序以查看与之前相同的结果,其优点是光属性现在可编程而不是硬编码。

此时,我将通过在着色器代码中将环境响应和漫反应响应设置为白色来切换到白色,有光泽的表面材质:

constant Material material = {
    .ambientColor = { 1, 1, 1 },
    .diffuseColor = { 1, 1, 1 },
    .specularColor = { 1, 1, 1 },
    .specularPower = 100
};

让我们修改我们的着色器以循环各种灯光,记住在我们遇到它的任何地方将光线方向标准化,这样我们就不会得到过多的贡献:

fragment float4 fragment_main(ProjectedVertex vert [[stage_in]],
                              constant Uniforms &uniforms [[buffer(0)]])
{
    float3 color(0);

    for (int i = 0; i < kMaxLights; ++i) {
        constant Light *light = &uniforms.lights[i];
        float3 ambientTerm = light->ambientColor * material.ambientColor;

        float3 normal = normalize(vert.normal);
        float diffuseIntensity = saturate(dot(normal, normalize(light->direction)));
        float3 diffuseTerm = light->diffuseColor * material.diffuseColor * diffuseIntensity;

        float3 specularTerm(0);
        if (diffuseIntensity > 0)
        {
            float3 eyeDirection = normalize(vert.eye);
            float3 halfway = normalize(normalize(light->direction) + eyeDirection);
            float specularFactor = pow(saturate(dot(normal, halfway)), material.specularPower);
            specularTerm = light->specularColor * material.specularColor * specularFactor;
        }

        color += ambientTerm + diffuseTerm + specularTerm;
    }

    return float4(color, 1);
}

现在我们可以在updateUniforms方法中定义所有四个灯光的属性:

uniforms.lights[0].direction = (vector_float3){ -1, 1, 1 };
uniforms.lights[0].ambientColor = (vector_float3){ 0.1, 0.1, 0.1 };
uniforms.lights[0].diffuseColor = (vector_float3){ 0.7, 0, 0 };
uniforms.lights[0].specularColor = (vector_float3){ 0.15, 0.15, 0.15 };

uniforms.lights[1].direction = (vector_float3){ 1, 1, 1 };
uniforms.lights[1].ambientColor = (vector_float3){ 0 };
uniforms.lights[1].diffuseColor = (vector_float3){ 0, 0.4, 0 };
uniforms.lights[1].specularColor = (vector_float3){ 0.15, 0.15, 0.15 };

uniforms.lights[2].direction = (vector_float3){ -1, -1, 1 };
uniforms.lights[2].ambientColor = (vector_float3){ 0 };
uniforms.lights[2].diffuseColor = (vector_float3){ 0, 0, 0.7 };
uniforms.lights[2].specularColor = (vector_float3){ 0.15, 0.15, 0.15 };

uniforms.lights[3].direction = (vector_float3){ 1, 1, 1 };
uniforms.lights[3].ambientColor = (vector_float3){ 0 };
uniforms.lights[3].diffuseColor = (vector_float3){ 0.1, 0.1, 0.1 };
uniforms.lights[3].specularColor = (vector_float3){ 0.15, 0.15, 0.15 };

结果是,一个白色的茶壶从几个不同的方向被不同属性的灯点亮:

Multicolored teapot