Ios Swift SceneKit照明和影响发射纹理

Ios Swift SceneKit照明和影响发射纹理,ios,swift,scenekit,Ios,Swift,Scenekit,我正在开发一个关于太阳系的应用程序。 我正试图关闭发射纹理,即光线照射到行星表面的纹理。但问题是,默认情况下,发射纹理始终显示发射点,而不管是否存在灯光 简而言之,我的要求是:(我想隐藏发射点,在光线照射到表面的地方) SceneKit非常适合这种任务 你可以看到最终结果的镜头 片段着色器修改器 我们可以使用\u lightingContribution.diffuse(RGB(vec3)颜色表示应用于漫反射的灯光)来确定对象(在本例中为地球)被照亮的区域,然后使用它来遮罩场景中的发射纹理 你

我正在开发一个关于太阳系的应用程序。 我正试图关闭发射纹理,即光线照射到行星表面的纹理。但问题是,默认情况下,发射纹理始终显示发射点,而不管是否存在灯光

简而言之,我的要求是:(我想隐藏发射点,在光线照射到表面的地方)

SceneKit非常适合这种任务

你可以看到最终结果的镜头

片段着色器修改器

我们可以使用
\u lightingContribution.diffuse
(RGB(
vec3
)颜色表示应用于漫反射的灯光)来确定对象(在本例中为地球)被照亮的区域,然后使用它来遮罩场景中的发射纹理

你使用它的方式真的取决于你。下面是我提出的最简单的解决方案(使用
GLSL
语法,但如果您使用它,它将在运行时自动转换为
Metal

  • 计算
    \u lightingContribution.diffuse
    颜色的亮度(使用公式)(如果照明不是纯白色)
  • 从一中减去它得到“黑暗面”的亮度
  • 使用漫反射UV坐标(已授予发射和漫反射纹理具有相同的坐标)从自定义纹理获取发射,并通过乘法将亮度应用于该纹理
  • 将其添加到最终输出颜色(与应用常规发射的方式相同)
  • 这就是着色器部分,现在让我们来看一下事物的快速方面


    快速设置 首先,我们不打算使用材料的
    emission.contents
    属性,而是需要创建自定义
    SCNMaterialProperty

    let emissionTexture = UIImage(named: "earthEmission.jpg")!
    let emission = SCNMaterialProperty(contents: emissionTexture)
    
    并使用
    setValue(u1;:forKey:)

    请密切注意该关键点——它应该与着色器修改器中的一致性相同。另外,您不需要自己保存材质属性,
    setValue
    创建一个强引用

    剩下要做的就是将碎片着色器修改器设置为材质:

    let shaderModifier =
    """
    uniform sampler2D emissionTexture;
    
    vec3 light = _lightingContribution.diffuse;
    float lum = max(0.0, 1 - (0.2126*light.r + 0.7152*light.g + 0.0722*light.b));
    vec4 emission = texture2D(emissionTexture, _surface.diffuseTexcoord) * lum;
    _output.color += emission;
    """
    earthMaterial.shaderModifiers = [.fragment: shaderModifier]
    
    下面是此着色器修改器的运动状态

    请注意,光源必须非常明亮,否则在“地球”上会看到暗淡的灯光。我必须在您的设置中将
    lightNode.light?.intensity
    设置为至少2000,它才能按预期工作。您可能希望尝试计算光度并将其应用于发射的方法,以获得更好的结果


    如果您可能需要它,
    \u lightingContribution
    是碎片着色器修改器中可用的结构,它还具有
    环境光
    镜面反射
    成员(以下是
    金属
    语法):


    我喜欢Lësha的答案,对着色器做了一个小的修改,使其能够在较低的光照水平下工作。添加了一个阈值(t),低于该阈值时发射值将不显示,然后在阈值和零之间,它在漫反射和漫反射+发射之间插值。改变t的值会调整描绘夜间和白天过渡的频带宽度。我还在发射公式上附加了一个0.5的乘数,因为我使用的发射纹理在没有它的情况下看起来是人为地明亮的

    let shaderModifier =
    """
    uniform sampler2D emissionTexture;
    
    vec3 light = _lightingContribution.diffuse;
    float lum = max(0.0, 1 - (0.2126*light.r + 0.7152*light.g + 0.0722*light.b));
    vec4 emission = texture2D(emissionTexture, _surface.diffuseTexcoord) * lum * 0.5;
    float t = 0.11; // no emission will show above this threshold
    _output.color = vec4(
        light.r > t ? _output.color.r : light.r/t * _output.color.r + (1-light.r/t) * (_output.color.r + emission.r),
        light.g > t ? _output.color.g : light.g/t * _output.color.g + (1-light.g/t) * (_output.color.g + emission.g),
        light.b > t ? _output.color.b : light.b/t * _output.color.b + (1-light.b/t) * (_output.color.b + emission.b),1);
    """
    

    现在面对同样的问题,发射应该只显示在夜间侧,即由SCNLight照亮的侧。有什么想法吗?SceneKit有纹理的位图掩蔽吗?谢谢你,Lësha,这正是我所需要的。也很高兴我现在知道如何设置着色器修改器,以前在Unity中已经做过,只是还没有在Swift/Scenekit中!
    earthMaterial.setValue(emission, forKey: "emissionTexture")
    
    let shaderModifier =
    """
    uniform sampler2D emissionTexture;
    
    vec3 light = _lightingContribution.diffuse;
    float lum = max(0.0, 1 - (0.2126*light.r + 0.7152*light.g + 0.0722*light.b));
    vec4 emission = texture2D(emissionTexture, _surface.diffuseTexcoord) * lum;
    _output.color += emission;
    """
    earthMaterial.shaderModifiers = [.fragment: shaderModifier]
    
    struct SCNShaderLightingContribution {
        float3 ambient;
        float3 diffuse;
        float3 specular;
    } _lightingContribution;
    
    let shaderModifier =
    """
    uniform sampler2D emissionTexture;
    
    vec3 light = _lightingContribution.diffuse;
    float lum = max(0.0, 1 - (0.2126*light.r + 0.7152*light.g + 0.0722*light.b));
    vec4 emission = texture2D(emissionTexture, _surface.diffuseTexcoord) * lum * 0.5;
    float t = 0.11; // no emission will show above this threshold
    _output.color = vec4(
        light.r > t ? _output.color.r : light.r/t * _output.color.r + (1-light.r/t) * (_output.color.r + emission.r),
        light.g > t ? _output.color.g : light.g/t * _output.color.g + (1-light.g/t) * (_output.color.g + emission.g),
        light.b > t ? _output.color.b : light.b/t * _output.color.b + (1-light.b/t) * (_output.color.b + emission.b),1);
    """