如何编写SceneKit着色器修改器以使效果溶解 [英] How to write a sceneKit shader modifier for a dissolve in effect

查看:76
本文介绍了如何编写SceneKit着色器修改器以使效果溶解的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想为Scenekit游戏创建一个效果器.我一直在研究着色器修改器,因为它们似乎是最轻的,并且在复制此效果方面没有任何运气:

I'd like to build a dissolve in effect for a Scenekit game. I've been looking into shader modifiers since they seem to be the most light weight and haven't had any luck in replicating this effect:

是否可以使用着色器修改器来创建此效果? 您将如何实施?

Is it possible to use shader modifiers to create this effect? How would you go about implementing one?

推荐答案

使用片段着色器修改器可以非常接近预期的效果.基本方法如下:

You can get pretty close to the intended effect with a fragment shader modifier. The basic approach is as follows:

  • 噪声纹理中的样本
  • 如果噪声样本低于某个阈值(我称之为泄露"),则将其丢弃,使其完全透明
  • 否则,如果片段靠近边缘,则用您喜欢的边缘颜色(或渐变)替换其颜色
  • 应用绽放使边缘发光

这是执行此操作的着色器修改器代码:

Here's the shader modifier code for doing this:

#pragma arguments

float revealage;
texture2d<float, access::sample> noiseTexture;

#pragma transparent
#pragma body

const float edgeWidth = 0.02;
const float edgeBrightness = 2;
const float3 innerColor = float3(0.4, 0.8, 1);
const float3 outerColor = float3(0, 0.5, 1);
const float noiseScale = 3;

constexpr sampler noiseSampler(filter::linear, address::repeat);
float2 noiseCoords = noiseScale * _surface.ambientTexcoord;
float noiseValue = noiseTexture.sample(noiseSampler, noiseCoords).r;

if (noiseValue > revealage) {
    discard_fragment();
}

float edgeDist = revealage - noiseValue;
if (edgeDist < edgeWidth) {
    float t = edgeDist / edgeWidth;
    float3 edgeColor = edgeBrightness * mix(outerColor, innerColor, t);
    _output.color.rgb = edgeColor;
}

请注意,由于您可能希望为其设置动画,因此显示参数作为材料参数公开.还可以对其他内部常量(例如边缘宽度和噪点比例)进行微调,以使您的内容获得所需的效果.

Notice that the revealage parameter is exposed as a material parameter, since you might want to animate it. There are other internal constants, such as edge width and noise scale that can be fine-tuned to get the desired effect with your content.

不同的噪波纹理会产生不同的溶解效果,因此您也可以尝试一下.我只是使用了这个倍频程值噪声图像:

Different noise textures produce different dissolve effects, so you can experiment with that as well. I just used this multioctave value noise image:

将图像加载为UIImageNSImage并将其设置在显示为noiseTexture的材质属性上:

Load the image as a UIImage or NSImage and set it on the material property that gets exposed as noiseTexture:

material.setValue(SCNMaterialProperty(contents: noiseImage), forKey: "noiseTexture")

您需要添加绽放作为后期处理,以获得发光的电子线效果.在SceneKit中,这就像启用HDR管道并设置一些参数一样简单:

You'll need to add bloom as a post-process to get that glowy, e-wire effect. In SceneKit, this is as simple as enabling the HDR pipeline and setting some parameters:

let camera = SCNCamera()
camera.wantsHDR = true
camera.bloomThreshold = 0.8
camera.bloomIntensity = 2
camera.bloomBlurRadius = 16.0
camera.wantsExposureAdaptation = false

所有数字参数可能都需要根据您的内容进行调整.

All of the numeric parameters will potentially need to be tuned to your content.

为了使内容整洁,我更喜欢将着色器修改器保留在自己的文本文件中(我将其命名为"dissolve.fragment.txt").这是加载一些修改器代码并将其附加到材料的方法.

To keep things tidy, I prefer to keep shader modifiers in their own text files (I named mine "dissolve.fragment.txt"). Here's how to load some modifier code and attach it to a material.

let modifierURL = Bundle.main.url(forResource: "dissolve.fragment", withExtension: "txt")!
let modifierString = try! String(contentsOf: modifierURL)
material.shaderModifiers = [
    SCNShaderModifierEntryPoint.fragment : modifierString
]

最后,要设置效果动画,可以使用CABasicAnimation并用SCNAnimation包装:

And finally, to animate the effect, you can use a CABasicAnimation wrapped with a SCNAnimation:

let revealAnimation = CABasicAnimation(keyPath: "revealage")
revealAnimation.timingFunction = CAMediaTimingFunction(name: .linear)
revealAnimation.duration = 2.5
revealAnimation.fromValue = 0.0
revealAnimation.toValue = 1.0
let scnRevealAnimation = SCNAnimation(caAnimation: revealAnimation)
material.addAnimation(scnRevealAnimation, forKey: "Reveal")

这篇关于如何编写SceneKit着色器修改器以使效果溶解的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆