Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/image/filterRenderer2D.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ import filterBaseVert from '../webgl/shaders/filters/base.vert';
import webgl2CompatibilityShader from '../webgl/shaders/webgl2Compatibility.glsl';
import { glslBackend } from '../webgl/strands_glslBackend';
import { getShaderHookTypes } from '../webgl/shaderHookUtils';
import noiseGLSL from '../webgl/shaders/functions/noise3DGLSL.glsl';
import randomGLSL from '../webgl/shaders/functions/randomGLSL.glsl';
import randomVertGLSL from '../webgl/shaders/functions/randomVertGLSL.glsl';
import { makeFilterShader } from '../core/filterShaders';

class FilterRenderer2D {
Expand Down Expand Up @@ -309,6 +312,14 @@ class FilterRenderer2D {
}


getRandomFragmentShaderSnippet() {
return randomGLSL;
}

getRandomVertexShaderSnippet() {
return randomVertGLSL;
}

/**
* Set the current filter operation and parameter. If a customShader is provided,
* that overrides the operation-based shader.
Expand Down
4 changes: 4 additions & 0 deletions src/strands/p5.strands.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ function strands(p5, fn) {
ctx.windowOverrides = {};
ctx.fnOverrides = {};
ctx.graphicsOverrides = {};
ctx._randomCallCount = 0;
ctx._randomSeed = null;
if (active) {
p5.disableFriendlyErrors = true;
}
Expand All @@ -64,6 +66,8 @@ function strands(p5, fn) {
ctx.computeDeclarations = new Set();
ctx.hooks = [];
ctx.active = false;
ctx._randomCallCount = 0;
ctx._randomSeed = null;
p5.disableFriendlyErrors = ctx.previousFES;
for (const key in ctx.windowOverrides) {
window[key] = ctx.windowOverrides[key];
Expand Down
85 changes: 85 additions & 0 deletions src/strands/strands_api.js
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,8 @@ export function initGlobalStrandsAPI(p5, fn, strandsContext) {
// Add noise function with backend-agnostic implementation
const originalNoise = fn.noise;
const originalNoiseDetail = fn.noiseDetail;
const originalRandom = fn.random;
const originalRandomSeed = fn.randomSeed;
const originalMillis = fn.millis;

strandsContext._noiseOctaves = null;
Expand Down Expand Up @@ -382,6 +384,89 @@ export function initGlobalStrandsAPI(p5, fn, strandsContext) {
return createStrandsNode(id, dimension, strandsContext);
});

strandsContext._randomSeed = null;
strandsContext._randomCallCount = 0;

augmentFn(fn, p5, 'randomSeed', function (seed) {
if (!strandsContext.active) {
return originalRandomSeed.apply(this, arguments);
}
strandsContext._randomSeed = seed;
});

augmentFn(fn, p5, 'random', function (...args) {
if (!strandsContext.active) {
return originalRandom.apply(this, args);
}

const randomVertSnippet = this._renderer.getRandomVertexShaderSnippet();
const randomFragSnippet = this._renderer.getRandomFragmentShaderSnippet();

strandsContext.vertexDeclarations.add(randomVertSnippet);
strandsContext.fragmentDeclarations.add(randomFragSnippet);

if (this._renderer.getRandomComputeShaderSnippet) {
const randomComputeSnippet = this._renderer.getRandomComputeShaderSnippet();
strandsContext.computeDeclarations.add(randomComputeSnippet);
}

let seedNode;
if (strandsContext._randomSeed !== null && strandsContext._randomSeed.isStrandsNode) {
seedNode = strandsContext._randomSeed;
} else {
const userSeed = strandsContext._randomSeed;
seedNode = getOrCreateUniformNode(
strandsContext,
'_p5_randomSeed',
DataType.float1,
userSeed !== null
? () => userSeed
: () => performance.now(),
);
}

const callIndex = strandsContext._randomCallCount++;

const nodeArgs = [seedNode, callIndex];

if (args.length === 0) {
const { id, dimension } = build.functionCallNode(strandsContext, 'random', nodeArgs, {
overloads: [{
params: [DataType.float1, DataType.float1],
returnType: DataType.float1,
}]
});
return createStrandsNode(id, dimension, strandsContext);
} else if (args.length === 1) {
// random(max) → [0, max)
const rawNode = build.functionCallNode(strandsContext, 'random', nodeArgs, {
overloads: [{
params: [DataType.float1, DataType.float1],
returnType: DataType.float1,
}]
});
const rawStrandsNode = createStrandsNode(rawNode.id, rawNode.dimension, strandsContext);
return rawStrandsNode.mult(p5.strandsNode(args[0]));
} else if (args.length === 2) {
// random(min, max) → [min, max)
const rawNode = build.functionCallNode(strandsContext, 'random', nodeArgs, {
overloads: [{
params: [DataType.float1, DataType.float1],
returnType: DataType.float1,
}]
});
const rawStrandsNode = createStrandsNode(rawNode.id, rawNode.dimension, strandsContext);
const minNode = p5.strandsNode(args[0]);
const maxNode = p5.strandsNode(args[1]);
// min + raw * (max - min)
return rawStrandsNode.mult(maxNode.sub(minNode)).add(minNode);
} else {
p5._friendlyError(
`It looks like you've called random() with ${args.length} arguments. In strands, random() supports 0, 1, or 2 numeric arguments.`
);
}
});

augmentFn(fn, p5, 'millis', function (...args) {
if (!strandsContext.active) {
return originalMillis.apply(this, args);
Expand Down
15 changes: 15 additions & 0 deletions src/webgl/p5.RendererGL.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ import { Image } from '../image/p5.Image';
import { glslBackend } from './strands_glslBackend';
import { TypeInfoFromGLSLName } from '../strands/ir_types.js';
import { getShaderHookTypes } from './shaderHookUtils';
import noiseGLSL from './shaders/functions/noise3DGLSL.glsl';
import randomGLSL from './shaders/functions/randomGLSL.glsl';
import randomVertGLSL from './shaders/functions/randomVertGLSL.glsl';

import filterBaseVert from "./shaders/filters/base.vert";
import lightingShader from "./shaders/lighting.glsl";
Expand Down Expand Up @@ -1904,6 +1907,18 @@ class RendererGL extends Renderer3D {
}
}

getNoiseShaderSnippet() {
return noiseGLSL;
}

getRandomFragmentShaderSnippet() {
return randomGLSL;
}

getRandomVertexShaderSnippet() {
return randomVertGLSL;
}

}

function rendererGL(p5, fn) {
Expand Down
23 changes: 23 additions & 0 deletions src/webgl/shaders/functions/randomGLSL.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// _p5_hash: "Hash without Sine" by Dave Hoskins (https://www.shadertoy.com/view/4djSRW)
// Mixing constants: R₂ sequence by Martin Roberts (https://extremelearning.com.au/unreasonable-effectiveness-of-quasirandom-sequences/)
// α₁ = 1/φ₂ = 0.7548776662 (plastic constant reciprocal)
// α₂ = 1/φ₂² = 0.5698402910
// 1/φ = 0.6180339887 (golden ratio conjugate)

float _p5_hash(vec3 p) {
p = fract(p * vec3(0.1031, 0.1030, 0.0973));
p += dot(p, p.yxz + 33.33);
return fract((p.x + p.y) * p.z);
}

float random(float seed, float callIndex) {
vec2 pixelCoord = gl_FragCoord.xy;
// fract(seed * α₁) normalizes large seeds (e.g. performance.now()) into [0,1)
// and spreads them optimally via the R₂ sequence's plastic constant
float s = fract(seed * 0.7548776662);
return _p5_hash(vec3(
pixelCoord.x + s,
pixelCoord.y + callIndex * 0.5698402910,
s + callIndex * 0.6180339887
));
}
21 changes: 21 additions & 0 deletions src/webgl/shaders/functions/randomVertGLSL.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// _p5_hash: "Hash without Sine" by Dave Hoskins (https://www.shadertoy.com/view/4djSRW)
// Mixing constants: R₂ sequence by Martin Roberts (https://extremelearning.com.au/unreasonable-effectiveness-of-quasirandom-sequences/)
// α₁ = 1/φ₂ = 0.7548776662 (plastic constant reciprocal)
// α₂ = 1/φ₂² = 0.5698402910
// 1/φ = 0.6180339887 (golden ratio conjugate)

float _p5_hash(vec3 p) {
p = fract(p * vec3(0.1031, 0.1030, 0.0973));
p += dot(p, p.yxz + 33.33);
return fract((p.x + p.y) * p.z);
}

float random(float seed, float callIndex) {
float vid = float(gl_VertexID);
float s = fract(seed * 0.7548776662);
return _p5_hash(vec3(
vid + s,
vid * 0.5698402910 + callIndex * 0.6180339887,
s + callIndex * 0.7548776662
));
}
Loading
Loading