【问题标题】:Multiple lights points on single 3d model with different colours of lights shades in Metal iOSMetal iOS中具有不同颜色灯罩的单个3d模型上的多个灯点
【发布时间】:2017-08-08 13:12:34
【问题描述】:

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

我已经完成了这个任务IOS - Metal

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

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

【问题讨论】:

  • 我认为可以使用 iOS 的 SceneKit 而不是 Metal。
  • Metal 提供对 GPU 的最低开销访问。它是 Apple 的一项全新技术。

标签: 3d swift3 sprite-kit scenekit metal


【解决方案1】:

需要意识到的是,从表面反射的光是加法:每个光都会贡献一定量的辐照度,而表面的辐射出射度是表面响应的总和到这个能量。我们将使用的数量仍然不是完全基于物理的,但这种洞察力将帮助我们选择不会使最终颜色过于糟糕的值。

为简单起见,我们将坚持使用定向灯。您可以轻松地将其概括为点光源或聚光灯;只需传入您需要的属性并计算每个光源的贡献即可。

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

重新定义“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;

在这里,我们在 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 };

结果如下,一个白色茶壶被不同属性的灯光从几个不同的方向照亮:

【讨论】:

  • 好!谢谢您的精彩解释。
  • 其实,给定的解决方案是好的。但它改变了模型的纹理属性。我到底需要什么,我想在不改变实际属性的情况下在 3d 模型上添加灯光效果,我已经使用 scenekit 和 SpriteKit (SKLightNode) 在 2d 图形中完成了 - 请查看附图。
  • SceneKit - 我们可以在单个模型上使用多个灯吗?每个灯罩都需要不同的颜色,它应该看起来像上面的图片。
  • 我相信每个SCNNode 只能有一个SCNLight,但您可以在场景中添加任意数量的节点。
  • 是的,我正在为不同类型的光色(方向光)添加多个节点,但我无法改变它在场景中的位置。我已经为那个位置和物理体尝试了两个属性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-29
  • 2021-07-16
  • 2011-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-01
相关资源
最近更新 更多