So I just figured out how to achieve vertex manipulation in scripted shaders (not shadergraph) and I want to get the Mathf.Perlin (and maybe Mathf.Sin) function into the shader. I’ve seen many suggestions saying that it’s easier to use a texture but from my understanding, Mathf.Perlin (and Mathf.Sin) generates the noise instead of tiling a texture.
The reason that I want to do this in a shader is that I want to manipulate many vertices in real time, which can be hard on my cpu at times.
I already have a formula for the y-axis of the vertex, but it uses Mathf.Perlin in it:
float sinWave = amplitude * Mathf.Sin(_x / length + offset);
float perlinWave = amplitude * Mathf.PerlinNoise(_x / length + offset, _y[0] / length + offset);
return sinWave * perlinWave;
Any help on this would be really appreciated, thanks
For Mathf.Sin(x), you can simply use sin(x) in a shader.
To compute the exact same function as Mathf.PerlinNoise, you would need the source code and unfortunately it doesn’t seem to be publicly available. That said, it’s some variation of perlin noise and how perlin noise works is no secret. You can implement it as a shader function but because we don’t know how Unity generates their pseudo-random directions, it will only give you very similar patterns, not the exact same individual values as Mathf.PerlinNoise. If you need to generate the exact same values in a C# script and a shader, you need to implement the same version of perlin noise in both languages.
Below is a shader implementation of perlin noise.
float PerlinNoise(float2 position) {
// Compute the positions of the four closest grid vertices
float4 grid = float4(floor(position), ceil(position));
float4 gridX = grid.xzxz;
float4 gridY = grid.yyww;
// Compute a pseudorandom number for each grid vertex
// The hash function used here is pcg_hash:
// https://www.reedbeta.com/blog/hash-functions-for-gpu-rendering/
uint4 hash = int4(gridX) ^ int4(gridY) << 16;
hash = hash * 747796405 + 2891336453;
hash = (hash >> (hash >> 28) + 4 ^ hash) * 277803737;
hash = hash >> 22 ^ hash;
// Compute a pseudorandom gradient vector for each grid vertex
// Sums of random variables approximate a normal distribution
// Normally distributed coordinates result in uniformly distributed directions
float4 gradientX = ((hash >> 0) & 1023) + ((hash >> 7) & 1023) - 1023.0;
float4 gradientY = ((hash >> 15) & 1023) + ((hash >> 22) & 1023) - 1023.0;
// Compute distance vectors from grid vertices to input point
float4 deltaX = position.x - gridX;
float4 deltaY = position.y - gridY;
// The contribution of each grid vertex is the dot product of the gradients and distance vectors
float4 contribution = deltaX * gradientX + deltaY * gradientY;
// Apply gradient normalisation
contribution *= rsqrt(gradientX * gradientX + gradientY * gradientY);
// Interpolation parameters
float2 t = position - grid.xy;
// Apply smoothstep function for smooth transitions between grid cells
t = t * t * t * (t * (t * 6 - 15) + 10);
// Interpolate between the contributions of each grid vertex
float2 temp = lerp(contribution.xz, contribution.yw, t.x);
float noise = lerp(temp.x, temp.y, t.y);
// Scale and offset values to get a result range of [0, 1]
noise = noise * rsqrt(2.0) + 0.5;
return noise;
}