Last active
October 26, 2020 17:08
-
-
Save playatwork/8a16166f95f606ef56ec926f0cb939e1 to your computer and use it in GitHub Desktop.
Simplex noise custom node for Shader Graph
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Simplex noise custom node for Shader Graph | |
// | |
// Original work (webgl-noise) Copyright (C) 2011 Ashima Arts. | |
// Translation and modification was made by Keijiro Takahashi. | |
// Ported to Shader Graph by Sergio L. Valladares | |
// | |
// This shader is based on the webgl-noise GLSL shader. For further details | |
// of the original shader, please see the following description from the | |
// original source code. | |
// | |
// | |
// Description : Array and textureless GLSL 2D/3D/4D simplex | |
// noise functions. | |
// Author : Ian McEwan, Ashima Arts. | |
// Maintainer : ijm | |
// Lastmod : 20110822 (ijm) | |
// License : Copyright (C) 2011 Ashima Arts. All rights reserved. | |
// Distributed under the MIT License. See LICENSE file. | |
// https://github.com/ashima/webgl-noise | |
// | |
using UnityEngine; | |
using UnityEditor.ShaderGraph; | |
using System.Reflection; | |
[Title("Custom", "Simplex Noise 3D")] | |
public class SimplexNoise3Node : CodeFunctionNode | |
{ | |
public SimplexNoise3Node() | |
{ | |
name = "Simplex Noise 3D"; | |
} | |
public override bool hasPreview { get { return true; } } | |
protected override MethodInfo GetFunctionToConvert() | |
{ | |
return GetType().GetMethod("NoiseFunction", BindingFlags.Static | BindingFlags.NonPublic); | |
} | |
static string NoiseFunction( | |
[Slot(0, Binding.WorldSpacePosition)] Vector3 Vertex, | |
[Slot(1, Binding.None)] out Vector1 Noise, | |
[Slot(2, Binding.None)] out Vector3 Gradient) | |
{ | |
Gradient = Vector3.zero; | |
return @" | |
{ | |
float4 noise_vector = snoise_grad(Vertex); | |
Noise = noise_vector.w; | |
Gradient = noise_vector.xyz; | |
} | |
"; | |
} | |
public override void GenerateNodeFunction(FunctionRegistry registry, GraphContext graphContext, GenerationMode generationMode) | |
{ | |
registry.ProvideFunction("mod289_3", s => s.Append(@" | |
float3 mod289_3(float3 x) | |
{ | |
return x - floor(x / 289.0) * 289.0; | |
} | |
")); | |
registry.ProvideFunction("mod289_4", s => s.Append(@" | |
float4 mod289_4(float4 x) | |
{ | |
return x - floor(x / 289.0) * 289.0; | |
} | |
")); | |
registry.ProvideFunction("permute", s => s.Append(@" | |
float4 permute(float4 x) | |
{ | |
return mod289_4((x * 34.0 + 1.0) * x); | |
} | |
")); | |
registry.ProvideFunction("taylorInvSqrt", s => s.Append(@" | |
float4 taylorInvSqrt(float4 r) | |
{ | |
return 1.79284291400159 - r * 0.85373472095314; | |
} | |
")); | |
registry.ProvideFunction("snoise_grad", s => s.Append(@" | |
float4 snoise_grad(float3 v) | |
{ | |
const float2 C = float2(1.0 / 6.0, 1.0 / 3.0); | |
// First corner | |
float3 i = floor(v + dot(v, C.yyy)); | |
float3 x0 = v - i + dot(i, C.xxx); | |
// Other corners | |
float3 g = step(x0.yzx, x0.xyz); | |
float3 l = 1.0 - g; | |
float3 i1 = min(g.xyz, l.zxy); | |
float3 i2 = max(g.xyz, l.zxy); | |
// x1 = x0 - i1 + 1.0 * C.xxx; | |
// x2 = x0 - i2 + 2.0 * C.xxx; | |
// x3 = x0 - 1.0 + 3.0 * C.xxx; | |
float3 x1 = x0 - i1 + C.xxx; | |
float3 x2 = x0 - i2 + C.yyy; | |
float3 x3 = x0 - 0.5; | |
// Permutations | |
i = mod289_3(i); // Avoid truncation effects in permutation | |
float4 p = | |
permute(permute(permute(i.z + float4(0.0, i1.z, i2.z, 1.0)) | |
+ i.y + float4(0.0, i1.y, i2.y, 1.0)) | |
+ i.x + float4(0.0, i1.x, i2.x, 1.0)); | |
// Gradients: 7x7 points over a square, mapped onto an octahedron. | |
// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) | |
float4 j = p - 49.0 * floor(p / 49.0); // mod(p,7*7) | |
float4 x_ = floor(j / 7.0); | |
float4 y_ = floor(j - 7.0 * x_); // mod(j,N) | |
float4 x = (x_ * 2.0 + 0.5) / 7.0 - 1.0; | |
float4 y = (y_ * 2.0 + 0.5) / 7.0 - 1.0; | |
float4 h = 1.0 - abs(x) - abs(y); | |
float4 b0 = float4(x.xy, y.xy); | |
float4 b1 = float4(x.zw, y.zw); | |
//float4 s0 = float4(lessThan(b0, 0.0)) * 2.0 - 1.0; | |
//float4 s1 = float4(lessThan(b1, 0.0)) * 2.0 - 1.0; | |
float4 s0 = floor(b0) * 2.0 + 1.0; | |
float4 s1 = floor(b1) * 2.0 + 1.0; | |
float4 sh = -step(h, 0.0); | |
float4 a0 = b0.xzyw + s0.xzyw * sh.xxyy; | |
float4 a1 = b1.xzyw + s1.xzyw * sh.zzww; | |
float3 g0 = float3(a0.xy, h.x); | |
float3 g1 = float3(a0.zw, h.y); | |
float3 g2 = float3(a1.xy, h.z); | |
float3 g3 = float3(a1.zw, h.w); | |
// Normalise gradients | |
float4 norm = taylorInvSqrt(float4(dot(g0, g0), dot(g1, g1), dot(g2, g2), dot(g3, g3))); | |
g0 *= norm.x; | |
g1 *= norm.y; | |
g2 *= norm.z; | |
g3 *= norm.w; | |
// Compute noise and gradient at P | |
float4 m = max(0.6 - float4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0); | |
float4 m2 = m * m; | |
float4 m3 = m2 * m; | |
float4 m4 = m2 * m2; | |
float3 grad = | |
-6.0 * m3.x * x0 * dot(x0, g0) + m4.x * g0 + | |
-6.0 * m3.y * x1 * dot(x1, g1) + m4.y * g1 + | |
-6.0 * m3.z * x2 * dot(x2, g2) + m4.z * g2 + | |
-6.0 * m3.w * x3 * dot(x3, g3) + m4.w * g3; | |
float4 px = float4(dot(x0, g0), dot(x1, g1), dot(x2, g2), dot(x3, g3)); | |
return 42.0 * float4(grad, dot(m4, px)); | |
} | |
")); | |
base.GenerateNodeFunction(registry, graphContext, generationMode); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi! Thanks for this, it was helpful.
As Unity changed the API for the CodeFunctionNode in 2019.1 - https://forum.unity.com/threads/unable-to-create-custom-shader-graph-node-due-to-inaccessibility-of-customfunctionnode-class.586876/?_ga=2.254749640.1300780445.1603731888-1478299893.1603731888
So, I made an updated HLSL version of your gist:
https://gist.github.com/ma77os/de66fd807cbd77eac4d3a9023b590c7a
Best