Skip to content

Commit 27dea69

Browse files
Merge pull request #526 from gpujs/498-uniformly-distributed
498 uniformly distributed
2 parents 0841724 + 65de20b commit 27dea69

File tree

9 files changed

+79
-88
lines changed

9 files changed

+79
-88
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -895,13 +895,14 @@ This is a list of the supported ones:
895895
* `Math.min()`
896896
* `Math.pow()`
897897
* `Math.random()`
898-
* A note on random. We use [a plugin](src/plugins/triangle-noise.js) to generate random.
898+
* A note on random. We use [a plugin](src/plugins/math-random-uniformly-distributed.js) to generate random.
899899
Random seeded _and_ generated, _both from the GPU_, is not as good as random from the CPU as there are more things that the CPU can seed random from.
900900
However, we seed random on the GPU, _from a random value in the CPU_.
901901
We then seed the subsequent randoms from the previous random value.
902902
So we seed from CPU, and generate from GPU.
903903
Which is still not as good as CPU, but closer.
904904
While this isn't perfect, it should suffice in most scenarios.
905+
In any case, we must give thanks to [RandomPower](https://www.randompower.eu/), and this [issue](https://github.com/gpujs/gpu.js/issues/498), for assisting in improving our implementation of random.
905906
* `Math.round()`
906907
* `Math.sign()`
907908
* `Math.sin()`

dist/gpu-browser-core.js

Lines changed: 15 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* GPU Accelerated JavaScript
66
*
77
* @version 2.1.0
8-
* @date Sun Oct 13 2019 15:49:17 GMT-0400 (Eastern Daylight Time)
8+
* @date Fri Oct 18 2019 07:18:16 GMT-0400 (Eastern Daylight Time)
99
*
1010
* @license MIT
1111
* The MIT License
@@ -1842,7 +1842,6 @@ class CPUKernel extends Kernel {
18421842
module.exports = {
18431843
CPUKernel
18441844
};
1845-
18461845
},{"../../utils":111,"../function-builder":8,"../kernel":34,"./function-node":5,"./kernel-string":6}],8:[function(require,module,exports){
18471846
class FunctionBuilder {
18481847
static fromKernel(kernel, FunctionNode, extraNodeOptions) {
@@ -5087,7 +5086,6 @@ module.exports = {
50875086
GLKernel,
50885087
renderStrategy
50895088
};
5090-
50915089
},{"../../utils":111,"../kernel":34,"./texture/array-2-float":15,"./texture/array-2-float-2d":13,"./texture/array-2-float-3d":14,"./texture/array-3-float":18,"./texture/array-3-float-2d":16,"./texture/array-3-float-3d":17,"./texture/array-4-float":21,"./texture/array-4-float-2d":19,"./texture/array-4-float-3d":20,"./texture/float":24,"./texture/float-2d":22,"./texture/float-3d":23,"./texture/graphical":25,"./texture/memory-optimized":28,"./texture/memory-optimized-2d":26,"./texture/memory-optimized-3d":27,"./texture/unsigned":31,"./texture/unsigned-2d":29,"./texture/unsigned-3d":30}],13:[function(require,module,exports){
50925090
const { utils } = require('../../../utils');
50935091
const { GLTextureFloat } = require('./float');
@@ -5601,7 +5599,6 @@ class HeadlessGLKernel extends WebGLKernel {
56015599
module.exports = {
56025600
HeadlessGLKernel
56035601
};
5604-
56055602
},{"../gl/kernel-string":11,"../web-gl/kernel":67,"gl":1}],33:[function(require,module,exports){
56065603
class KernelValue {
56075604
constructor(value, settings) {
@@ -6128,7 +6125,6 @@ class Kernel {
61286125
module.exports = {
61296126
Kernel
61306127
};
6131-
61326128
},{"../input":107,"../utils":111}],35:[function(require,module,exports){
61336129
const fragmentShader = `__HEADER__;
61346130
__FLOAT_TACTIC_DECLARATION__;
@@ -7906,7 +7902,6 @@ const operatorMap = {
79067902
module.exports = {
79077903
WebGLFunctionNode
79087904
};
7909-
79107905
},{"../function-node":9}],37:[function(require,module,exports){
79117906
const { WebGLKernelValueBoolean } = require('./kernel-value/boolean');
79127907
const { WebGLKernelValueFloat } = require('./kernel-value/float');
@@ -9223,7 +9218,7 @@ const { GLKernel } = require('../gl/kernel');
92239218
const { FunctionBuilder } = require('../function-builder');
92249219
const { WebGLFunctionNode } = require('./function-node');
92259220
const { utils } = require('../../utils');
9226-
const triangleNoise = require('../../plugins/triangle-noise');
9221+
const mrud = require('../../plugins/math-random-uniformly-distributed');
92279222
const { fragmentShader } = require('./fragment-shader');
92289223
const { vertexShader } = require('./vertex-shader');
92299224
const { glKernelString } = require('../gl/kernel-string');
@@ -9235,7 +9230,7 @@ let testContext = null;
92359230
let testExtensions = null;
92369231
let features = null;
92379232

9238-
const plugins = [triangleNoise];
9233+
const plugins = [mrud];
92399234
const canvases = [];
92409235
const maxTexSizes = {};
92419236

@@ -10607,8 +10602,7 @@ class WebGLKernel extends GLKernel {
1060710602
module.exports = {
1060810603
WebGLKernel
1060910604
};
10610-
10611-
},{"../../plugins/triangle-noise":109,"../../utils":111,"../function-builder":8,"../gl/kernel":12,"../gl/kernel-string":11,"./fragment-shader":35,"./function-node":36,"./kernel-value-maps":37,"./vertex-shader":68}],68:[function(require,module,exports){
10605+
},{"../../plugins/math-random-uniformly-distributed":109,"../../utils":111,"../function-builder":8,"../gl/kernel":12,"../gl/kernel-string":11,"./fragment-shader":35,"./function-node":36,"./kernel-value-maps":37,"./vertex-shader":68}],68:[function(require,module,exports){
1061210606
const vertexShader = `__FLOAT_TACTIC_DECLARATION__;
1061310607
__INT_TACTIC_DECLARATION__;
1061410608
__SAMPLER_2D_TACTIC_DECLARATION__;
@@ -12862,7 +12856,6 @@ module.exports = {
1286212856
kernelOrder,
1286312857
kernelTypes
1286412858
};
12865-
1286612859
},{"./backend/cpu/kernel":7,"./backend/headless-gl/kernel":32,"./backend/web-gl/kernel":67,"./backend/web-gl2/kernel":102,"./kernel-run-shortcut":108,"./utils":111,"gpu-mock.js":3}],106:[function(require,module,exports){
1286712860
const { GPU } = require('./gpu');
1286812861
const { alias } = require('./alias');
@@ -13059,44 +13052,28 @@ module.exports = {
1305913052
};
1306013053
},{"./utils":111}],109:[function(require,module,exports){
1306113054
const source = `
13062-
13063-
uniform highp float triangle_noise_seed;
13064-
highp float triangle_noise_shift = 0.000001;
13065-
13066-
//https://www.shadertoy.com/view/4t2SDh
13055+
// https://www.shadertoy.com/view/4t2SDh
1306713056
//note: uniformly distributed, normalized rand, [0;1[
13068-
float nrand( vec2 n )
13069-
{
13070-
return fract(sin(dot(n.xy, vec2(12.9898, 78.233)))* 43758.5453);
13071-
}
13072-
//note: remaps v to [0;1] in interval [a;b]
13073-
float remap( float a, float b, float v )
13074-
{
13075-
return clamp( (v-a) / (b-a), 0.0, 1.0 );
13076-
}
13077-
13078-
float n4rand( vec2 n )
13079-
{
13080-
float t = fract( triangle_noise_seed + triangle_noise_shift );
13081-
float nrnd0 = nrand( n + 0.07*t );
13082-
float nrnd1 = nrand( n + 0.11*t );
13083-
float nrnd2 = nrand( n + 0.13*t );
13084-
float nrnd3 = nrand( n + 0.17*t );
13085-
float result = (nrnd0+nrnd1+nrnd2+nrnd3) / 4.0;
13086-
triangle_noise_shift = result + 0.000001;
13057+
mediump float random_seed_shift = 0.00001;
13058+
uniform mediump float random_seed1;
13059+
uniform mediump float random_seed2;
13060+
float nrand(vec2 n) {
13061+
float result = fract(sin(dot(n.xy * vec2(random_seed1, random_seed_shift * random_seed2), vec2(12.9898, 78.233)))* 43758.5453);
13062+
random_seed_shift = result;
1308713063
return result;
1308813064
}`;
1308913065

13090-
const name = 'triangle-noise-noise';
13066+
const name = 'math-random-uniformly-distributed';
1309113067

1309213068
const functionMatch = 'Math.random()';
1309313069

13094-
const functionReplace = 'n4rand(vTexCoord)';
13070+
const functionReplace = 'nrand(vTexCoord)';
1309513071

1309613072
const functionReturnType = 'Number';
1309713073

1309813074
const onBeforeRun = (kernel) => {
13099-
kernel.setUniform1f('triangle_noise_seed', Math.random());
13075+
kernel.setUniform1f('random_seed1', Math.random());
13076+
kernel.setUniform1f('random_seed2', Math.random());
1310013077
};
1310113078

1310213079
module.exports = {

dist/gpu-browser-core.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/gpu-browser.js

Lines changed: 15 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* GPU Accelerated JavaScript
66
*
77
* @version 2.1.0
8-
* @date Sun Oct 13 2019 15:49:17 GMT-0400 (Eastern Daylight Time)
8+
* @date Fri Oct 18 2019 07:18:16 GMT-0400 (Eastern Daylight Time)
99
*
1010
* @license MIT
1111
* The MIT License
@@ -6606,7 +6606,6 @@ class CPUKernel extends Kernel {
66066606
module.exports = {
66076607
CPUKernel
66086608
};
6609-
66106609
},{"../../utils":112,"../function-builder":9,"../kernel":35,"./function-node":6,"./kernel-string":7}],9:[function(require,module,exports){
66116610
class FunctionBuilder {
66126611
static fromKernel(kernel, FunctionNode, extraNodeOptions) {
@@ -9851,7 +9850,6 @@ module.exports = {
98519850
GLKernel,
98529851
renderStrategy
98539852
};
9854-
98559853
},{"../../utils":112,"../kernel":35,"./texture/array-2-float":16,"./texture/array-2-float-2d":14,"./texture/array-2-float-3d":15,"./texture/array-3-float":19,"./texture/array-3-float-2d":17,"./texture/array-3-float-3d":18,"./texture/array-4-float":22,"./texture/array-4-float-2d":20,"./texture/array-4-float-3d":21,"./texture/float":25,"./texture/float-2d":23,"./texture/float-3d":24,"./texture/graphical":26,"./texture/memory-optimized":29,"./texture/memory-optimized-2d":27,"./texture/memory-optimized-3d":28,"./texture/unsigned":32,"./texture/unsigned-2d":30,"./texture/unsigned-3d":31}],14:[function(require,module,exports){
98569854
const { utils } = require('../../../utils');
98579855
const { GLTextureFloat } = require('./float');
@@ -10365,7 +10363,6 @@ class HeadlessGLKernel extends WebGLKernel {
1036510363
module.exports = {
1036610364
HeadlessGLKernel
1036710365
};
10368-
1036910366
},{"../gl/kernel-string":12,"../web-gl/kernel":68,"gl":2}],34:[function(require,module,exports){
1037010367
class KernelValue {
1037110368
constructor(value, settings) {
@@ -10892,7 +10889,6 @@ class Kernel {
1089210889
module.exports = {
1089310890
Kernel
1089410891
};
10895-
1089610892
},{"../input":108,"../utils":112}],36:[function(require,module,exports){
1089710893
const fragmentShader = `__HEADER__;
1089810894
__FLOAT_TACTIC_DECLARATION__;
@@ -12670,7 +12666,6 @@ const operatorMap = {
1267012666
module.exports = {
1267112667
WebGLFunctionNode
1267212668
};
12673-
1267412669
},{"../function-node":10}],38:[function(require,module,exports){
1267512670
const { WebGLKernelValueBoolean } = require('./kernel-value/boolean');
1267612671
const { WebGLKernelValueFloat } = require('./kernel-value/float');
@@ -13987,7 +13982,7 @@ const { GLKernel } = require('../gl/kernel');
1398713982
const { FunctionBuilder } = require('../function-builder');
1398813983
const { WebGLFunctionNode } = require('./function-node');
1398913984
const { utils } = require('../../utils');
13990-
const triangleNoise = require('../../plugins/triangle-noise');
13985+
const mrud = require('../../plugins/math-random-uniformly-distributed');
1399113986
const { fragmentShader } = require('./fragment-shader');
1399213987
const { vertexShader } = require('./vertex-shader');
1399313988
const { glKernelString } = require('../gl/kernel-string');
@@ -13999,7 +13994,7 @@ let testContext = null;
1399913994
let testExtensions = null;
1400013995
let features = null;
1400113996

14002-
const plugins = [triangleNoise];
13997+
const plugins = [mrud];
1400313998
const canvases = [];
1400413999
const maxTexSizes = {};
1400514000

@@ -15371,8 +15366,7 @@ class WebGLKernel extends GLKernel {
1537115366
module.exports = {
1537215367
WebGLKernel
1537315368
};
15374-
15375-
},{"../../plugins/triangle-noise":110,"../../utils":112,"../function-builder":9,"../gl/kernel":13,"../gl/kernel-string":12,"./fragment-shader":36,"./function-node":37,"./kernel-value-maps":38,"./vertex-shader":69}],69:[function(require,module,exports){
15369+
},{"../../plugins/math-random-uniformly-distributed":110,"../../utils":112,"../function-builder":9,"../gl/kernel":13,"../gl/kernel-string":12,"./fragment-shader":36,"./function-node":37,"./kernel-value-maps":38,"./vertex-shader":69}],69:[function(require,module,exports){
1537615370
const vertexShader = `__FLOAT_TACTIC_DECLARATION__;
1537715371
__INT_TACTIC_DECLARATION__;
1537815372
__SAMPLER_2D_TACTIC_DECLARATION__;
@@ -17626,7 +17620,6 @@ module.exports = {
1762617620
kernelOrder,
1762717621
kernelTypes
1762817622
};
17629-
1763017623
},{"./backend/cpu/kernel":8,"./backend/headless-gl/kernel":33,"./backend/web-gl/kernel":68,"./backend/web-gl2/kernel":103,"./kernel-run-shortcut":109,"./utils":112,"gpu-mock.js":4}],107:[function(require,module,exports){
1763117624
const { GPU } = require('./gpu');
1763217625
const { alias } = require('./alias');
@@ -17823,44 +17816,28 @@ module.exports = {
1782317816
};
1782417817
},{"./utils":112}],110:[function(require,module,exports){
1782517818
const source = `
17826-
17827-
uniform highp float triangle_noise_seed;
17828-
highp float triangle_noise_shift = 0.000001;
17829-
17830-
//https://www.shadertoy.com/view/4t2SDh
17819+
// https://www.shadertoy.com/view/4t2SDh
1783117820
//note: uniformly distributed, normalized rand, [0;1[
17832-
float nrand( vec2 n )
17833-
{
17834-
return fract(sin(dot(n.xy, vec2(12.9898, 78.233)))* 43758.5453);
17835-
}
17836-
//note: remaps v to [0;1] in interval [a;b]
17837-
float remap( float a, float b, float v )
17838-
{
17839-
return clamp( (v-a) / (b-a), 0.0, 1.0 );
17840-
}
17841-
17842-
float n4rand( vec2 n )
17843-
{
17844-
float t = fract( triangle_noise_seed + triangle_noise_shift );
17845-
float nrnd0 = nrand( n + 0.07*t );
17846-
float nrnd1 = nrand( n + 0.11*t );
17847-
float nrnd2 = nrand( n + 0.13*t );
17848-
float nrnd3 = nrand( n + 0.17*t );
17849-
float result = (nrnd0+nrnd1+nrnd2+nrnd3) / 4.0;
17850-
triangle_noise_shift = result + 0.000001;
17821+
mediump float random_seed_shift = 0.00001;
17822+
uniform mediump float random_seed1;
17823+
uniform mediump float random_seed2;
17824+
float nrand(vec2 n) {
17825+
float result = fract(sin(dot(n.xy * vec2(random_seed1, random_seed_shift * random_seed2), vec2(12.9898, 78.233)))* 43758.5453);
17826+
random_seed_shift = result;
1785117827
return result;
1785217828
}`;
1785317829

17854-
const name = 'triangle-noise-noise';
17830+
const name = 'math-random-uniformly-distributed';
1785517831

1785617832
const functionMatch = 'Math.random()';
1785717833

17858-
const functionReplace = 'n4rand(vTexCoord)';
17834+
const functionReplace = 'nrand(vTexCoord)';
1785917835

1786017836
const functionReturnType = 'Number';
1786117837

1786217838
const onBeforeRun = (kernel) => {
17863-
kernel.setUniform1f('triangle_noise_seed', Math.random());
17839+
kernel.setUniform1f('random_seed1', Math.random());
17840+
kernel.setUniform1f('random_seed2', Math.random());
1786417841
};
1786517842

1786617843
module.exports = {

dist/gpu-browser.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/backend/web-gl/kernel.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const { GLKernel } = require('../gl/kernel');
22
const { FunctionBuilder } = require('../function-builder');
33
const { WebGLFunctionNode } = require('./function-node');
44
const { utils } = require('../../utils');
5-
const triangleNoise = require('../../plugins/triangle-noise');
5+
const mrud = require('../../plugins/math-random-uniformly-distributed');
66
const { fragmentShader } = require('./fragment-shader');
77
const { vertexShader } = require('./vertex-shader');
88
const { glKernelString } = require('../gl/kernel-string');
@@ -14,7 +14,7 @@ let testContext = null;
1414
let testExtensions = null;
1515
let features = null;
1616

17-
const plugins = [triangleNoise];
17+
const plugins = [mrud];
1818
const canvases = [];
1919
const maxTexSizes = {};
2020

src/plugins/triangle-noise.js renamed to src/plugins/math-random-triangle-noise.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
const source = `
2-
32
uniform highp float triangle_noise_seed;
43
highp float triangle_noise_shift = 0.000001;
54
@@ -19,19 +18,19 @@ float n4rand( vec2 n )
1918
{
2019
float t = fract( triangle_noise_seed + triangle_noise_shift );
2120
float nrnd0 = nrand( n + 0.07*t );
22-
float nrnd1 = nrand( n + 0.11*t );
21+
float nrnd1 = nrand( n + 0.11*t );
2322
float nrnd2 = nrand( n + 0.13*t );
2423
float nrnd3 = nrand( n + 0.17*t );
2524
float result = (nrnd0+nrnd1+nrnd2+nrnd3) / 4.0;
2625
triangle_noise_shift = result + 0.000001;
2726
return result;
2827
}`;
2928

30-
const name = 'triangle-noise-noise';
29+
const name = 'math-random-triangle-noise-noise';
3130

3231
const functionMatch = 'Math.random()';
3332

34-
const functionReplace = 'n4rand(vTexCoord)';
33+
const functionReplace = 'nrand(vTexCoord)';
3534

3635
const functionReturnType = 'Number';
3736

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
const source = `
2+
// https://www.shadertoy.com/view/4t2SDh
3+
//note: uniformly distributed, normalized rand, [0;1[
4+
mediump float random_seed_shift = 0.00001;
5+
uniform mediump float random_seed1;
6+
uniform mediump float random_seed2;
7+
float nrand(vec2 n) {
8+
float result = fract(sin(dot(n.xy * vec2(random_seed1, random_seed_shift * random_seed2), vec2(12.9898, 78.233)))* 43758.5453);
9+
random_seed_shift = result;
10+
return result;
11+
}`;
12+
13+
const name = 'math-random-uniformly-distributed';
14+
15+
const functionMatch = 'Math.random()';
16+
17+
const functionReplace = 'nrand(vTexCoord)';
18+
19+
const functionReturnType = 'Number';
20+
21+
const onBeforeRun = (kernel) => {
22+
kernel.setUniform1f('random_seed1', Math.random());
23+
kernel.setUniform1f('random_seed2', Math.random());
24+
};
25+
26+
/**
27+
*
28+
* @type IPlugin
29+
*/
30+
module.exports = {
31+
name,
32+
onBeforeRun,
33+
functionMatch,
34+
functionReplace,
35+
functionReturnType,
36+
source
37+
};

test/internal/math.random.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ function mathRandomUnique(mode) {
2222
const kernel = gpu.createKernel(`function() {
2323
${checkSource.join('\n')}
2424
return 0;
25-
}`, { output: [1] });
25+
}`, { output: [1], debug: true });
2626

2727
const result = kernel();
2828
assert.ok(result.every(value => value === 0));

0 commit comments

Comments
 (0)