Ios Swift SceneKit照明和影响发射纹理
我正在开发一个关于太阳系的应用程序。 我正试图关闭发射纹理,即光线照射到行星表面的纹理。但问题是,默认情况下,发射纹理始终显示发射点,而不管是否存在灯光 简而言之,我的要求是:(我想隐藏发射点,在光线照射到表面的地方) SceneKit非常适合这种任务 你可以看到最终结果的镜头 片段着色器修改器 我们可以使用Ios Swift SceneKit照明和影响发射纹理,ios,swift,scenekit,Ios,Swift,Scenekit,我正在开发一个关于太阳系的应用程序。 我正试图关闭发射纹理,即光线照射到行星表面的纹理。但问题是,默认情况下,发射纹理始终显示发射点,而不管是否存在灯光 简而言之,我的要求是:(我想隐藏发射点,在光线照射到表面的地方) SceneKit非常适合这种任务 你可以看到最终结果的镜头 片段着色器修改器 我们可以使用\u lightingContribution.diffuse(RGB(vec3)颜色表示应用于漫反射的灯光)来确定对象(在本例中为地球)被照亮的区域,然后使用它来遮罩场景中的发射纹理 你
\u lightingContribution.diffuse
(RGB(vec3
)颜色表示应用于漫反射的灯光)来确定对象(在本例中为地球)被照亮的区域,然后使用它来遮罩场景中的发射纹理
你使用它的方式真的取决于你。下面是我提出的最简单的解决方案(使用GLSL
语法,但如果您使用它,它将在运行时自动转换为Metal
)
\u lightingContribution.diffuse
颜色的亮度(使用公式)(如果照明不是纯白色)快速设置 首先,我们不打算使用材料的
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);
"""