Jak napisać modyfikator sceneKit shader dla efektu

Chciałbym zbudować grę Scenekit. Przyglądałem się modyfikatorom shader, ponieważ wydają się być najlżejsze i nie miałem szczęścia w replikowaniu tego efektu: {]}

Efekt Dissolve shader

Czy można użyć modyfikatorów shader do stworzenia tego efektu? Jak byś to zrobił?

Author: warrenm, 2019-02-06

1 answers

Możesz zbliżyć się do zamierzonego efektu za pomocą modyfikatora shadera fragmentów. Podstawowe podejście jest następujące:

  • próbka z tekstury szumu
  • jeśli próbka szumu jest poniżej pewnego progu (który nazywam "ujawnieniem"), odrzuć ją, czyniąc ją całkowicie przezroczystą
  • W przeciwnym razie, jeśli fragment znajduje się blisko krawędzi, zastąp jego kolor preferowanym kolorem krawędzi (lub gradientem)
  • Zastosuj bloom, aby krawędzie świeciły

Oto kod modyfikatora shadera do tego celu:

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

Zwróć uwagę, że parametr revealage jest wyświetlany jako parametr materialny, ponieważ możesz chcieć go animować. Istnieją inne stałe wewnętrzne, takie jak szerokość krawędzi i skala szumów, które można dopracować, aby uzyskać pożądany efekt z zawartością.

Różne tekstury szumów dają różne efekty rozpuszczania, więc możesz z tym eksperymentować. Właśnie użyłem tego szumu wartości multioktave image:

Wartość obrazu szumu używana jako Tekstura rozpuszczania

Załaduj obraz jako UIImage lub NSImage i ustaw go na właściwości materiału, który zostanie odsłonięty jako noiseTexture:

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

Musisz dodać bloom jako post-proces, aby uzyskać ten błyszczący, e-wire efekt. W SceneKit jest to tak proste, jak włączenie potoku HDR i ustawienie niektórych parametrów:

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

Wszystkie parametry numeryczne będą musiały być dopasowane do Twojej zawartości.

Aby wszystko było uporządkowane, wolę zachować shader modyfikatory w ich własnych plikach tekstowych (ja nazwałem swój " dissolve.fragment.txt"). Oto jak załadować kod modyfikujący i dołączyć go do materiału.

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

I na koniec, aby ożywić efekt, możesz użyć CABasicAnimation owiniętego 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!

 33
Author: warrenm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-02-07 09:32:03