单个3d模型上的多个灯光点,在金属iOS中具有不同颜色的灯光阴影

单个3d模型上的多个灯光点,在金属iOS中具有不同颜色的灯光阴影,3d,swift3,sprite-kit,scenekit,metal,3d,Swift3,Sprite Kit,Scenekit,Metal,我想在单个3d模型上放置多个灯光点,并在金属IOS中使用不同颜色的灯光阴影 我已经完成了这个任务 现在,我想在一个3d模型中应用具有不同颜色的多个灯光点 查看附加图像(在SceneKit和SpriteKit-SKLightNode中开发),3D模型上需要类似的灯光反射效果。需要了解的基本情况是,从表面反射的灯光是相加的:每个灯光都会产生一定的辐照度,表面的辐射出射度是表面对这种能量的反应的总和。我们将使用的数量仍然不是完全基于物理的,但这一洞察将帮助我们选择不会严重破坏最终颜色的值 为了简单起

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

我已经完成了这个任务

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


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

需要了解的基本情况是,从表面反射的灯光是相加的:每个灯光都会产生一定的辐照度,表面的辐射出射度是表面对这种能量的反应的总和。我们将使用的数量仍然不是完全基于物理的,但这一洞察将帮助我们选择不会严重破坏最终颜色的值

为了简单起见,我们将坚持使用平行光。您可以很容易地将其推广到点光源或聚光灯;这只是一个传递所需属性并计算每光贡献的问题

首先,删除
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;
在这里,我们在制服结构中包含了一个固定大小的灯光数组,因此我们可以在着色器中指定最多四个灯光,而无需分支。您可以根据需要减少或增加此数字

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

Uniforms uniforms = { 0 };
(将制服结构归零,然后)

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

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

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);
}
结果是,一个白色的茶壶被不同属性的灯光从几个不同的方向照亮:


要认识到的基本点是,从表面反射的光是相加的:每一束光都会产生一定量的辐照度,而表面的辐射出射度是表面对该能量响应的总和。我们将使用的数量仍然不是完全基于物理的,但这一洞察将帮助我们选择不会严重破坏最终颜色的值

为了简单起见,我们将坚持使用平行光。您可以很容易地将其推广到点光源或聚光灯;这只是一个传递所需属性并计算每光贡献的问题

首先,删除
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;
在这里,我们在制服结构中包含了一个固定大小的灯光数组,因此我们可以在着色器中指定最多四个灯光,而无需分支。您可以根据需要减少或增加此数字

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

Uniforms uniforms = { 0 };
(将制服结构归零,然后)

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

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

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);
}
结果是,一个白色的茶壶被不同属性的灯光从几个不同的方向照亮:


我认为可以使用iOS的SceneKit而不是Metal来完成。Metal提供了对GPU的最低开销访问。这是苹果公司的一项全新技术。我认为可以用iOS的SceneKit而不是Metal来实现。Metal提供了对GPU的最低开销访问。这是苹果公司的一项全新技术。很好!,谢谢你的解释。事实上,给出的解决方案很好。但它改变了模型的纹理特性。我需要的是,我想在不改变实际属性的情况下在3d模型上添加灯光效果,我已经使用scenekit和SpriteKit(SKLightNode)在2d图形中完成了-请查看附加图像。scenekit-我们可以在单个模型上使用多个灯光吗?每个灯光阴影都需要不同的颜色,它应该看起来像上面讨论的图像。我相信每个
SCNNode
只能有一个
SCNLight
,但是您可以向场景添加任意数量的节点。是的,我正在为不同类型的灯光颜色(方向灯)添加多个节点,但问题是我无法改变它在现场的位置。我试过两种姿势&physicsBody。很好!,感谢