Как написать модификатор шейдера sceneKit для эффекта растворения - PullRequest
0 голосов
/ 06 февраля 2019

Я хотел бы создать эффект растворения для игры Scenekit.Я изучал модификаторы шейдеров, так как они кажутся наиболее легкими и не удавалось воспроизвести этот эффект:

Dissolve shader effect

Можно ли использовать модификаторы шейдеров для создания этого эффекта?Как бы вы пошли о реализации одного?

1 Ответ

0 голосов
/ 07 февраля 2019

С модификатором шейдера фрагмента вы можете приблизиться к ожидаемому эффекту.Основной подход заключается в следующем:

  • Образец из текстуры шума
  • Если образец шума ниже определенного порога (который я называю «раскрытием»), откажитесь от него, сделав егополностью прозрачный
  • В противном случае, если фрагмент находится близко к краю, замените его цвет на предпочитаемый цвет края (или градиент)
  • Примените цветение, чтобы края светились

Вот код модификатора шейдера для этого:

#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;
}

Обратите внимание, что параметр раскрытия представлен как параметр материала, так как вы можете захотеть его анимировать.Существуют и другие внутренние константы, такие как ширина края и шкала шума, которые можно точно настроить для получения желаемого эффекта с вашим контентом.

Различные текстуры шума производят разные эффекты растворения, так что вы также можете поэкспериментировать с этим,Я просто использовал это многооктавное шумовое изображение:

Value noise image used as dissolve texture

Загрузите изображение как UIImage или NSImage и установите его для свойства материала, котороевыставляется как noiseTexture:

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

Вам нужно будет добавить цветение в качестве пост-процесса, чтобы получить эффект светящегося электронного провода.В SceneKit это так же просто, как включить конвейер HDR и установить некоторые параметры:

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

Все числовые параметры потенциально должны быть настроены на ваш контент.

Чтобы сохранить вещиЯ предпочитаю хранить модификаторы шейдеров в своих собственных текстовых файлах (я назвал мой "discolve.fragment.txt").Вот как загрузить некоторый код модификатора и прикрепить его к материалу.

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

И, наконец, для анимации эффекта вы можете использовать CABasicAnimation, заключенный в 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")

Et voila!

...