p5 2.0.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{src → dist}/accessibility/color_namer.js +48 -3
- package/{src → dist}/accessibility/describe.js +2 -2
- package/{src → dist}/accessibility/gridOutput.js +2 -2
- package/dist/accessibility/index.js +60 -0
- package/{src → dist}/accessibility/outputs.js +2 -2
- package/{src → dist}/accessibility/textOutput.js +2 -2
- package/dist/app.js +120 -0
- package/{src → dist}/color/color_conversion.js +48 -10
- package/{src → dist}/color/color_spaces/hsb.js +3 -1
- package/dist/color/creating_reading.js +3 -0
- package/dist/color/index.js +13 -0
- package/dist/color/p5.Color.culori.js +1 -0
- package/dist/color/p5.Color.js +3 -0
- package/{src → dist}/color/setting.js +9 -6
- package/{src/core/constants.js → dist/constants-C-g_eAdC.js} +266 -130
- package/{src → dist}/core/States.js +3 -1
- package/dist/core/constants.js +1 -0
- package/{src → dist}/core/environment.js +7 -6
- package/{src → dist}/core/friendly_errors/browser_errors.js +1 -1
- package/{src → dist}/core/friendly_errors/fes_core.js +14 -44
- package/{src → dist}/core/friendly_errors/file_errors.js +6 -3
- package/dist/core/friendly_errors/index.js +23 -0
- package/dist/core/friendly_errors/param_validator.js +5455 -0
- package/{src → dist}/core/friendly_errors/sketch_reader.js +50 -4
- package/{src → dist}/core/friendly_errors/sketch_verifier.js +6 -6
- package/{src → dist}/core/friendly_errors/stacktrace.js +3 -5
- package/{src → dist}/core/friendly_errors/validate_params.js +50 -41
- package/{src → dist}/core/helpers.js +9 -6
- package/dist/core/init.js +105 -0
- package/dist/core/internationalization.js +302 -0
- package/dist/core/legacy.js +73 -0
- package/dist/core/main.js +44 -0
- package/dist/core/noop.js +3 -0
- package/dist/core/p5.Graphics.js +40 -0
- package/dist/core/p5.Renderer.js +11 -0
- package/dist/core/p5.Renderer2D.js +44 -0
- package/dist/core/reference.js +1 -0
- package/dist/core/rendering.js +40 -0
- package/{src → dist}/core/structure.js +3 -3
- package/{src → dist}/core/transform.js +2 -2
- package/{src/color/creating_reading.js → dist/creating_reading-D4AAKRbx.js} +841 -13
- package/{src → dist}/data/index.js +3 -1
- package/{src → dist}/data/local_storage.js +2 -8
- package/{src → dist}/dom/dom.js +11 -5
- package/dist/dom/index.js +18 -0
- package/{src → dist}/dom/p5.Element.js +14 -12
- package/{src → dist}/dom/p5.File.js +4 -4
- package/{src → dist}/dom/p5.MediaElement.js +10 -4
- package/{src → dist}/events/acceleration.js +2 -2
- package/{src → dist}/events/index.js +3 -1
- package/{src → dist}/events/keyboard.js +14 -11
- package/{src → dist}/events/pointer.js +16 -17
- package/dist/image/const.js +9 -0
- package/{src → dist}/image/filterRenderer2D.js +57 -37
- package/{src → dist}/image/filters.js +1 -3
- package/dist/image/image.js +40 -0
- package/dist/image/index.js +51 -0
- package/dist/image/loading_displaying.js +40 -0
- package/dist/image/p5.Image.js +11 -0
- package/{src → dist}/image/pixels.js +4 -3
- package/{src → dist}/io/csv.js +72 -70
- package/dist/io/files.js +40 -0
- package/dist/io/index.js +51 -0
- package/{src → dist}/io/p5.Table.js +6 -6
- package/{src → dist}/io/p5.TableRow.js +3 -4
- package/{src → dist}/io/p5.XML.js +2 -5
- package/{src → dist}/io/utilities.js +1 -1
- package/{src/core/p5.Renderer2D.js → dist/main-s72KWcUy.js} +735 -57
- package/{src → dist}/math/Matrices/Matrix.js +10 -8
- package/{src → dist}/math/Matrices/MatrixInterface.js +5 -3
- package/{src → dist}/math/Matrices/MatrixNumjs.js +12 -26
- package/{src → dist}/math/calculation.js +2 -2
- package/{src → dist}/math/index.js +6 -3
- package/{src → dist}/math/math.js +2 -2
- package/{src → dist}/math/noise.js +2 -2
- package/{src → dist}/math/p5.Matrix.js +7 -4
- package/{src → dist}/math/p5.Vector.js +6 -6
- package/{src → dist}/math/random.js +2 -2
- package/{src → dist}/math/trigonometry.js +16 -15
- package/{src/image/p5.Image.js → dist/p5.Renderer-CwAYZOC2.js} +390 -19
- package/dist/rendering--aAe5aq3.js +24925 -0
- package/{src → dist}/shape/2d_primitives.js +18 -17
- package/{src → dist}/shape/attributes.js +18 -17
- package/{src → dist}/shape/curves.js +2 -2
- package/{src → dist}/shape/custom_shapes.js +44 -64
- package/{src → dist}/shape/index.js +10 -2
- package/{src → dist}/shape/vertex.js +2 -3
- package/dist/type/index.js +25 -0
- package/{src → dist}/type/lib/Typr.js +76 -94
- package/{src → dist}/type/p5.Font.js +37 -61
- package/{src → dist}/type/textCore.js +34 -57
- package/{src → dist}/type/unicodeRanges.js +3 -1
- package/{src → dist}/utilities/conversion.js +2 -2
- package/{src → dist}/utilities/index.js +3 -1
- package/{src → dist}/utilities/time_date.js +6 -7
- package/{src → dist}/utilities/utility_functions.js +2 -2
- package/dist/webgl/3d_primitives.js +40 -0
- package/{src → dist}/webgl/GeometryBufferCache.js +3 -1
- package/{src → dist}/webgl/GeometryBuilder.js +12 -8
- package/{src → dist}/webgl/ShaderGenerator.js +79 -82
- package/{src → dist}/webgl/ShapeBuilder.js +26 -23
- package/dist/webgl/index.js +76 -0
- package/{src → dist}/webgl/interaction.js +7 -6
- package/dist/webgl/light.js +40 -0
- package/{src → dist}/webgl/loading.js +45 -12
- package/dist/webgl/material.js +40 -0
- package/dist/webgl/p5.Camera.js +40 -0
- package/{src → dist}/webgl/p5.DataArray.js +3 -5
- package/dist/webgl/p5.Framebuffer.js +40 -0
- package/{src → dist}/webgl/p5.Geometry.js +12 -15
- package/{src → dist}/webgl/p5.Quat.js +5 -4
- package/{src → dist}/webgl/p5.RenderBuffer.js +2 -3
- package/dist/webgl/p5.RendererGL.js +40 -0
- package/dist/webgl/p5.Shader.js +40 -0
- package/dist/webgl/p5.Texture.js +40 -0
- package/{src → dist}/webgl/text.js +51 -9
- package/lib/p5.esm.js +102 -48
- package/lib/p5.js +102 -48
- package/lib/p5.min.js +1 -1
- package/package.json +17 -16
- package/translations/dev.js +6 -6
- package/translations/index.js +1 -1
- package/src/README.md +0 -27
- package/src/accessibility/index.js +0 -13
- package/src/app.js +0 -61
- package/src/color/index.js +0 -9
- package/src/color/p5.Color.culori.js +0 -66
- package/src/color/p5.Color.js +0 -851
- package/src/core/README.md +0 -91
- package/src/core/friendly_errors/index.js +0 -13
- package/src/core/friendly_errors/param_validator.js +0 -561
- package/src/core/init.js +0 -58
- package/src/core/internationalization.js +0 -195
- package/src/core/legacy.js +0 -29
- package/src/core/main.js +0 -689
- package/src/core/noop.js +0 -1
- package/src/core/p5.Graphics.js +0 -696
- package/src/core/p5.Renderer.js +0 -408
- package/src/core/reference.js +0 -2060
- package/src/core/rendering.js +0 -697
- package/src/dom/index.js +0 -11
- package/src/image/const.js +0 -6
- package/src/image/image.js +0 -731
- package/src/image/index.js +0 -15
- package/src/image/loading_displaying.js +0 -1431
- package/src/io/files.js +0 -2210
- package/src/io/index.js +0 -11
- package/src/math/README.md +0 -40
- package/src/type/index.js +0 -9
- package/src/webgl/3d_primitives.js +0 -2741
- package/src/webgl/index.js +0 -37
- package/src/webgl/light.js +0 -1851
- package/src/webgl/material.js +0 -3854
- package/src/webgl/p5.Camera.js +0 -4010
- package/src/webgl/p5.Framebuffer.js +0 -1865
- package/src/webgl/p5.RendererGL.js +0 -2867
- package/src/webgl/p5.Shader.js +0 -1505
- package/src/webgl/p5.Texture.js +0 -541
- package/src/webgl/shaders/basic.frag +0 -6
- package/src/webgl/shaders/filters/base.frag +0 -22
- package/src/webgl/shaders/filters/base.vert +0 -19
- package/src/webgl/shaders/filters/blur.frag +0 -60
- package/src/webgl/shaders/filters/default.vert +0 -18
- package/src/webgl/shaders/filters/dilate.frag +0 -39
- package/src/webgl/shaders/filters/erode.frag +0 -39
- package/src/webgl/shaders/filters/gray.frag +0 -16
- package/src/webgl/shaders/filters/invert.frag +0 -15
- package/src/webgl/shaders/filters/opaque.frag +0 -12
- package/src/webgl/shaders/filters/posterize.frag +0 -29
- package/src/webgl/shaders/filters/threshold.frag +0 -23
- package/src/webgl/shaders/font.frag +0 -216
- package/src/webgl/shaders/font.vert +0 -44
- package/src/webgl/shaders/imageLight.vert +0 -33
- package/src/webgl/shaders/imageLightDiffused.frag +0 -82
- package/src/webgl/shaders/imageLightSpecular.frag +0 -134
- package/src/webgl/shaders/light.vert +0 -37
- package/src/webgl/shaders/light_texture.frag +0 -26
- package/src/webgl/shaders/lighting.glsl +0 -227
- package/src/webgl/shaders/line.frag +0 -74
- package/src/webgl/shaders/line.vert +0 -294
- package/src/webgl/shaders/normal.frag +0 -6
- package/src/webgl/shaders/normal.vert +0 -72
- package/src/webgl/shaders/phong.frag +0 -84
- package/src/webgl/shaders/phong.vert +0 -87
- package/src/webgl/shaders/point.frag +0 -29
- package/src/webgl/shaders/point.vert +0 -19
- package/src/webgl/shaders/sphereMapping.frag +0 -26
- package/src/webgl/shaders/webgl2Compatibility.glsl +0 -34
package/src/webgl/p5.Shader.js
DELETED
|
@@ -1,1505 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This module defines the p5.Shader class
|
|
3
|
-
* @module 3D
|
|
4
|
-
* @submodule Material
|
|
5
|
-
* @for p5
|
|
6
|
-
* @requires core
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { Texture } from './p5.Texture';
|
|
10
|
-
|
|
11
|
-
class Shader {
|
|
12
|
-
constructor(renderer, vertSrc, fragSrc, options = {}) {
|
|
13
|
-
// TODO: adapt this to not take ids, but rather,
|
|
14
|
-
// to take the source for a vertex and fragment shader
|
|
15
|
-
// to enable custom shaders at some later date
|
|
16
|
-
this._renderer = renderer;
|
|
17
|
-
this._vertSrc = vertSrc;
|
|
18
|
-
this._fragSrc = fragSrc;
|
|
19
|
-
this._vertShader = -1;
|
|
20
|
-
this._fragShader = -1;
|
|
21
|
-
this._glProgram = 0;
|
|
22
|
-
this._loadedAttributes = false;
|
|
23
|
-
this.attributes = {};
|
|
24
|
-
this._loadedUniforms = false;
|
|
25
|
-
this.uniforms = {};
|
|
26
|
-
this._bound = false;
|
|
27
|
-
this.samplers = [];
|
|
28
|
-
this.hooks = {
|
|
29
|
-
// These should be passed in by `.modify()` instead of being manually
|
|
30
|
-
// passed in.
|
|
31
|
-
|
|
32
|
-
// Stores uniforms + default values.
|
|
33
|
-
uniforms: options.uniforms || {},
|
|
34
|
-
|
|
35
|
-
// Stores custom uniform + helper declarations as a string.
|
|
36
|
-
declarations: options.declarations,
|
|
37
|
-
|
|
38
|
-
// Stores helper functions to prepend to shaders.
|
|
39
|
-
helpers: options.helpers || {},
|
|
40
|
-
|
|
41
|
-
// Stores the hook implementations
|
|
42
|
-
vertex: options.vertex || {},
|
|
43
|
-
fragment: options.fragment || {},
|
|
44
|
-
|
|
45
|
-
// Stores whether or not the hook implementation has been modified
|
|
46
|
-
// from the default. This is supplied automatically by calling
|
|
47
|
-
// yourShader.modify(...).
|
|
48
|
-
modified: {
|
|
49
|
-
vertex: (options.modified && options.modified.vertex) || {},
|
|
50
|
-
fragment: (options.modified && options.modified.fragment) || {}
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
hookTypes(hookName) {
|
|
56
|
-
let fullSrc = this._vertSrc;
|
|
57
|
-
let body = this.hooks.vertex[hookName];
|
|
58
|
-
if (!body) {
|
|
59
|
-
body = this.hooks.fragment[hookName];
|
|
60
|
-
fullSrc = this._fragSrc;
|
|
61
|
-
}
|
|
62
|
-
if (!body) {
|
|
63
|
-
throw new Error(`Can't find hook ${hookName}!`);
|
|
64
|
-
}
|
|
65
|
-
const nameParts = hookName.split(/\s+/g);
|
|
66
|
-
const functionName = nameParts.pop();
|
|
67
|
-
const returnType = nameParts.pop();
|
|
68
|
-
const returnQualifiers = [...nameParts];
|
|
69
|
-
|
|
70
|
-
const parameterMatch = /\(([^\)]*)\)/.exec(body);
|
|
71
|
-
if (!parameterMatch) {
|
|
72
|
-
throw new Error(`Couldn't find function parameters in hook body:\n${body}`);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const structProperties = structName => {
|
|
76
|
-
const structDefMatch = new RegExp(`struct\\s+${structName}\\s*\{([^\}]*)\}`).exec(fullSrc);
|
|
77
|
-
if (!structDefMatch) return undefined;
|
|
78
|
-
|
|
79
|
-
const properties = [];
|
|
80
|
-
for (const defSrc of structDefMatch[1].split(';')) {
|
|
81
|
-
// E.g. `int var1, var2;` or `MyStruct prop;`
|
|
82
|
-
const parts = defSrc.trim().split(/\s+|,/g);
|
|
83
|
-
const typeName = parts.shift();
|
|
84
|
-
const names = [...parts];
|
|
85
|
-
const typeProperties = structProperties(typeName);
|
|
86
|
-
for (const name of names) {
|
|
87
|
-
properties.push({
|
|
88
|
-
name,
|
|
89
|
-
type: {
|
|
90
|
-
typeName,
|
|
91
|
-
qualifiers: [],
|
|
92
|
-
properties: typeProperties,
|
|
93
|
-
},
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return properties;
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const parameters = parameterMatch[1].split(',').map(paramString => {
|
|
101
|
-
// e.g. `int prop` or `in sampler2D prop` or `const float prop`
|
|
102
|
-
const parts = paramString.trim().split(/\s+/g);
|
|
103
|
-
const name = parts.pop();
|
|
104
|
-
const typeName = parts.pop();
|
|
105
|
-
const qualifiers = [...parts];
|
|
106
|
-
const properties = structProperties(typeName);
|
|
107
|
-
return {
|
|
108
|
-
name,
|
|
109
|
-
type: {
|
|
110
|
-
typeName,
|
|
111
|
-
qualifiers,
|
|
112
|
-
properties,
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
return {
|
|
118
|
-
name: functionName,
|
|
119
|
-
returnType: {
|
|
120
|
-
typeName: returnType,
|
|
121
|
-
qualifiers: returnQualifiers,
|
|
122
|
-
properties: structProperties(returnType)
|
|
123
|
-
},
|
|
124
|
-
parameters
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
shaderSrc(src, shaderType) {
|
|
129
|
-
const main = 'void main';
|
|
130
|
-
let [preMain, postMain] = src.split(main);
|
|
131
|
-
|
|
132
|
-
let hooks = '';
|
|
133
|
-
let defines = '';
|
|
134
|
-
for (const key in this.hooks.uniforms) {
|
|
135
|
-
hooks += `uniform ${key};\n`;
|
|
136
|
-
}
|
|
137
|
-
if (this.hooks.declarations) {
|
|
138
|
-
hooks += this.hooks.declarations + '\n';
|
|
139
|
-
}
|
|
140
|
-
if (this.hooks[shaderType].declarations) {
|
|
141
|
-
hooks += this.hooks[shaderType].declarations + '\n';
|
|
142
|
-
}
|
|
143
|
-
for (const hookDef in this.hooks.helpers) {
|
|
144
|
-
hooks += `${hookDef}${this.hooks.helpers[hookDef]}\n`;
|
|
145
|
-
}
|
|
146
|
-
for (const hookDef in this.hooks[shaderType]) {
|
|
147
|
-
if (hookDef === 'declarations') continue;
|
|
148
|
-
const [hookType, hookName] = hookDef.split(' ');
|
|
149
|
-
|
|
150
|
-
// Add a #define so that if the shader wants to use preprocessor directives to
|
|
151
|
-
// optimize away the extra function calls in main, it can do so
|
|
152
|
-
if (this.hooks.modified[shaderType][hookDef]) {
|
|
153
|
-
defines += '#define AUGMENTED_HOOK_' + hookName + '\n';
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
hooks +=
|
|
157
|
-
hookType + ' HOOK_' + hookName + this.hooks[shaderType][hookDef] + '\n';
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Allow shaders to specify the location of hook #define statements. Normally these
|
|
161
|
-
// go after function definitions, but one might want to have them defined earlier
|
|
162
|
-
// in order to only conditionally make uniforms.
|
|
163
|
-
if (preMain.indexOf('#define HOOK_DEFINES') !== -1) {
|
|
164
|
-
preMain = preMain.replace('#define HOOK_DEFINES', '\n' + defines + '\n');
|
|
165
|
-
defines = '';
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return preMain + '\n' + defines + hooks + main + postMain;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Shaders are written in <a href="https://developer.mozilla.org/en-US/docs/Games/Techniques/3D_on_the_web/GLSL_Shaders">GLSL</a>, but
|
|
173
|
-
* there are different versions of GLSL that it might be written in.
|
|
174
|
-
*
|
|
175
|
-
* Calling this method on a `p5.Shader` will return the GLSL version it uses, either `100 es` or `300 es`.
|
|
176
|
-
* WebGL 1 shaders will only use `100 es`, and WebGL 2 shaders may use either.
|
|
177
|
-
*
|
|
178
|
-
* @returns {String} The GLSL version used by the shader.
|
|
179
|
-
*/
|
|
180
|
-
version() {
|
|
181
|
-
const match = /#version (.+)$/.exec(this.vertSrc());
|
|
182
|
-
if (match) {
|
|
183
|
-
return match[1];
|
|
184
|
-
} else {
|
|
185
|
-
return '100 es';
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
vertSrc() {
|
|
190
|
-
return this.shaderSrc(this._vertSrc, 'vertex');
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
fragSrc() {
|
|
194
|
-
return this.shaderSrc(this._fragSrc, 'fragment');
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Logs the hooks available in this shader, and their current implementation.
|
|
199
|
-
*
|
|
200
|
-
* Each shader may let you override bits of its behavior. Each bit is called
|
|
201
|
-
* a *hook.* A hook is either for the *vertex* shader, if it affects the
|
|
202
|
-
* position of vertices, or in the *fragment* shader, if it affects the pixel
|
|
203
|
-
* color. This method logs those values to the console, letting you know what
|
|
204
|
-
* you are able to use in a call to
|
|
205
|
-
* <a href="#/p5.Shader/modify">`modify()`</a>.
|
|
206
|
-
*
|
|
207
|
-
* For example, this shader will produce the following output:
|
|
208
|
-
*
|
|
209
|
-
* ```js
|
|
210
|
-
* myShader = baseMaterialShader().modify({
|
|
211
|
-
* declarations: 'uniform float time;',
|
|
212
|
-
* 'vec3 getWorldPosition': `(vec3 pos) {
|
|
213
|
-
* pos.y += 20. * sin(time * 0.001 + pos.x * 0.05);
|
|
214
|
-
* return pos;
|
|
215
|
-
* }`
|
|
216
|
-
* });
|
|
217
|
-
* myShader.inspectHooks();
|
|
218
|
-
* ```
|
|
219
|
-
*
|
|
220
|
-
* ```
|
|
221
|
-
* ==== Vertex shader hooks: ====
|
|
222
|
-
* void beforeVertex() {}
|
|
223
|
-
* vec3 getLocalPosition(vec3 position) { return position; }
|
|
224
|
-
* [MODIFIED] vec3 getWorldPosition(vec3 pos) {
|
|
225
|
-
* pos.y += 20. * sin(time * 0.001 + pos.x * 0.05);
|
|
226
|
-
* return pos;
|
|
227
|
-
* }
|
|
228
|
-
* vec3 getLocalNormal(vec3 normal) { return normal; }
|
|
229
|
-
* vec3 getWorldNormal(vec3 normal) { return normal; }
|
|
230
|
-
* vec2 getUV(vec2 uv) { return uv; }
|
|
231
|
-
* vec4 getVertexColor(vec4 color) { return color; }
|
|
232
|
-
* void afterVertex() {}
|
|
233
|
-
*
|
|
234
|
-
* ==== Fragment shader hooks: ====
|
|
235
|
-
* void beforeFragment() {}
|
|
236
|
-
* Inputs getPixelInputs(Inputs inputs) { return inputs; }
|
|
237
|
-
* vec4 combineColors(ColorComponents components) {
|
|
238
|
-
* vec4 color = vec4(0.);
|
|
239
|
-
* color.rgb += components.diffuse * components.baseColor;
|
|
240
|
-
* color.rgb += components.ambient * components.ambientColor;
|
|
241
|
-
* color.rgb += components.specular * components.specularColor;
|
|
242
|
-
* color.rgb += components.emissive;
|
|
243
|
-
* color.a = components.opacity;
|
|
244
|
-
* return color;
|
|
245
|
-
* }
|
|
246
|
-
* vec4 getFinalColor(vec4 color) { return color; }
|
|
247
|
-
* void afterFragment() {}
|
|
248
|
-
* ```
|
|
249
|
-
*
|
|
250
|
-
* @beta
|
|
251
|
-
*/
|
|
252
|
-
inspectHooks() {
|
|
253
|
-
console.log('==== Vertex shader hooks: ====');
|
|
254
|
-
for (const key in this.hooks.vertex) {
|
|
255
|
-
console.log(
|
|
256
|
-
(this.hooks.modified.vertex[key] ? '[MODIFIED] ' : '') +
|
|
257
|
-
key +
|
|
258
|
-
this.hooks.vertex[key]
|
|
259
|
-
);
|
|
260
|
-
}
|
|
261
|
-
console.log('');
|
|
262
|
-
console.log('==== Fragment shader hooks: ====');
|
|
263
|
-
for (const key in this.hooks.fragment) {
|
|
264
|
-
console.log(
|
|
265
|
-
(this.hooks.modified.fragment[key] ? '[MODIFIED] ' : '') +
|
|
266
|
-
key +
|
|
267
|
-
this.hooks.fragment[key]
|
|
268
|
-
);
|
|
269
|
-
}
|
|
270
|
-
console.log('');
|
|
271
|
-
console.log('==== Helper functions: ====');
|
|
272
|
-
for (const key in this.hooks.helpers) {
|
|
273
|
-
console.log(key + this.hooks.helpers[key]);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Returns a new shader, based on the original, but with custom snippets
|
|
279
|
-
* of shader code replacing default behaviour.
|
|
280
|
-
*
|
|
281
|
-
* Each shader may let you override bits of its behavior. Each bit is called
|
|
282
|
-
* a *hook.* A hook is either for the *vertex* shader, if it affects the
|
|
283
|
-
* position of vertices, or in the *fragment* shader, if it affects the pixel
|
|
284
|
-
* color. You can inspect the different hooks available by calling
|
|
285
|
-
* <a href="#/p5.Shader/inspectHooks">`yourShader.inspectHooks()`</a>. You can
|
|
286
|
-
* also read the reference for the default material, normal material, color, line, and point shaders to
|
|
287
|
-
* see what hooks they have available.
|
|
288
|
-
*
|
|
289
|
-
* `modify()` takes one parameter, `hooks`, an object with the hooks you want
|
|
290
|
-
* to override. Each key of the `hooks` object is the name
|
|
291
|
-
* of a hook, and the value is a string with the GLSL code for your hook.
|
|
292
|
-
*
|
|
293
|
-
* If you supply functions that aren't existing hooks, they will get added at the start of
|
|
294
|
-
* the shader as helper functions so that you can use them in your hooks.
|
|
295
|
-
*
|
|
296
|
-
* To add new <a href="#/p5.Shader/setUniform">uniforms</a> to your shader, you can pass in a `uniforms` object containing
|
|
297
|
-
* the type and name of the uniform as the key, and a default value or function returning
|
|
298
|
-
* a default value as its value. These will be automatically set when the shader is set
|
|
299
|
-
* with `shader(yourShader)`.
|
|
300
|
-
*
|
|
301
|
-
* You can also add a `declarations` key, where the value is a GLSL string declaring
|
|
302
|
-
* custom uniform variables, globals, and functions shared
|
|
303
|
-
* between hooks. To add declarations just in a vertex or fragment shader, add
|
|
304
|
-
* `vertexDeclarations` and `fragmentDeclarations` keys.
|
|
305
|
-
*
|
|
306
|
-
* @beta
|
|
307
|
-
* @param {Object} [hooks] The hooks in the shader to replace.
|
|
308
|
-
* @returns {p5.Shader}
|
|
309
|
-
*
|
|
310
|
-
* @example
|
|
311
|
-
* <div modernizr='webgl'>
|
|
312
|
-
* <code>
|
|
313
|
-
* let myShader;
|
|
314
|
-
*
|
|
315
|
-
* function setup() {
|
|
316
|
-
* createCanvas(200, 200, WEBGL);
|
|
317
|
-
* myShader = baseMaterialShader().modify({
|
|
318
|
-
* uniforms: {
|
|
319
|
-
* 'float time': () => millis() // Uniform for time
|
|
320
|
-
* },
|
|
321
|
-
* 'Vertex getWorldInputs': `(Vertex inputs) {
|
|
322
|
-
* inputs.position.y +=
|
|
323
|
-
* 20. * sin(time * 0.001 + inputs.position.x * 0.05);
|
|
324
|
-
* return inputs;
|
|
325
|
-
* }`
|
|
326
|
-
* });
|
|
327
|
-
* }
|
|
328
|
-
*
|
|
329
|
-
* function draw() {
|
|
330
|
-
* background(255);
|
|
331
|
-
* shader(myShader); // Apply the custom shader
|
|
332
|
-
* lights(); // Enable lighting
|
|
333
|
-
* noStroke(); // Disable stroke
|
|
334
|
-
* fill('red'); // Set fill color to red
|
|
335
|
-
* sphere(50); // Draw a sphere with the shader applied
|
|
336
|
-
* }
|
|
337
|
-
* </code>
|
|
338
|
-
* </div>
|
|
339
|
-
*
|
|
340
|
-
* @example
|
|
341
|
-
* <div modernizr='webgl'>
|
|
342
|
-
* <code>
|
|
343
|
-
* let myShader;
|
|
344
|
-
*
|
|
345
|
-
* function setup() {
|
|
346
|
-
* createCanvas(200, 200, WEBGL);
|
|
347
|
-
* myShader = baseMaterialShader().modify({
|
|
348
|
-
* // Manually specifying a uniform
|
|
349
|
-
* declarations: 'uniform float time;',
|
|
350
|
-
* 'Vertex getWorldInputs': `(Vertex inputs) {
|
|
351
|
-
* inputs.position.y +=
|
|
352
|
-
* 20. * sin(time * 0.001 + inputs.position.x * 0.05);
|
|
353
|
-
* return inputs;
|
|
354
|
-
* }`
|
|
355
|
-
* });
|
|
356
|
-
* }
|
|
357
|
-
*
|
|
358
|
-
* function draw() {
|
|
359
|
-
* background(255);
|
|
360
|
-
* shader(myShader);
|
|
361
|
-
* myShader.setUniform('time', millis());
|
|
362
|
-
* lights();
|
|
363
|
-
* noStroke();
|
|
364
|
-
* fill('red');
|
|
365
|
-
* sphere(50);
|
|
366
|
-
* }
|
|
367
|
-
* </code>
|
|
368
|
-
* </div>
|
|
369
|
-
*/
|
|
370
|
-
modify(hooks) {
|
|
371
|
-
// p5._validateParameters('p5.Shader.modify', arguments);
|
|
372
|
-
const newHooks = {
|
|
373
|
-
vertex: {},
|
|
374
|
-
fragment: {},
|
|
375
|
-
helpers: {}
|
|
376
|
-
};
|
|
377
|
-
for (const key in hooks) {
|
|
378
|
-
if (key === 'declarations') continue;
|
|
379
|
-
if (key === 'uniforms') continue;
|
|
380
|
-
if (key === 'vertexDeclarations') {
|
|
381
|
-
newHooks.vertex.declarations =
|
|
382
|
-
(newHooks.vertex.declarations || '') + '\n' + hooks[key];
|
|
383
|
-
} else if (key === 'fragmentDeclarations') {
|
|
384
|
-
newHooks.fragment.declarations =
|
|
385
|
-
(newHooks.fragment.declarations || '') + '\n' + hooks[key];
|
|
386
|
-
} else if (this.hooks.vertex[key]) {
|
|
387
|
-
newHooks.vertex[key] = hooks[key];
|
|
388
|
-
} else if (this.hooks.fragment[key]) {
|
|
389
|
-
newHooks.fragment[key] = hooks[key];
|
|
390
|
-
} else {
|
|
391
|
-
newHooks.helpers[key] = hooks[key];
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
const modifiedVertex = Object.assign({}, this.hooks.modified.vertex);
|
|
395
|
-
const modifiedFragment = Object.assign({}, this.hooks.modified.fragment);
|
|
396
|
-
for (const key in newHooks.vertex || {}) {
|
|
397
|
-
if (key === 'declarations') continue;
|
|
398
|
-
modifiedVertex[key] = true;
|
|
399
|
-
}
|
|
400
|
-
for (const key in newHooks.fragment || {}) {
|
|
401
|
-
if (key === 'declarations') continue;
|
|
402
|
-
modifiedFragment[key] = true;
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
return new Shader(this._renderer, this._vertSrc, this._fragSrc, {
|
|
406
|
-
declarations:
|
|
407
|
-
(this.hooks.declarations || '') + '\n' + (hooks.declarations || ''),
|
|
408
|
-
uniforms: Object.assign({}, this.hooks.uniforms, hooks.uniforms || {}),
|
|
409
|
-
fragment: Object.assign({}, this.hooks.fragment, newHooks.fragment || {}),
|
|
410
|
-
vertex: Object.assign({}, this.hooks.vertex, newHooks.vertex || {}),
|
|
411
|
-
helpers: Object.assign({}, this.hooks.helpers, newHooks.helpers || {}),
|
|
412
|
-
modified: {
|
|
413
|
-
vertex: modifiedVertex,
|
|
414
|
-
fragment: modifiedFragment
|
|
415
|
-
}
|
|
416
|
-
});
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
/**
|
|
420
|
-
* Creates, compiles, and links the shader based on its
|
|
421
|
-
* sources for the vertex and fragment shaders (provided
|
|
422
|
-
* to the constructor). Populates known attributes and
|
|
423
|
-
* uniforms from the shader.
|
|
424
|
-
* @chainable
|
|
425
|
-
* @private
|
|
426
|
-
*/
|
|
427
|
-
init() {
|
|
428
|
-
if (this._glProgram === 0 /* or context is stale? */) {
|
|
429
|
-
const gl = this._renderer.GL;
|
|
430
|
-
|
|
431
|
-
// @todo: once custom shading is allowed,
|
|
432
|
-
// friendly error messages should be used here to share
|
|
433
|
-
// compiler and linker errors.
|
|
434
|
-
|
|
435
|
-
//set up the shader by
|
|
436
|
-
// 1. creating and getting a gl id for the shader program,
|
|
437
|
-
// 2. compliling its vertex & fragment sources,
|
|
438
|
-
// 3. linking the vertex and fragment shaders
|
|
439
|
-
this._vertShader = gl.createShader(gl.VERTEX_SHADER);
|
|
440
|
-
//load in our default vertex shader
|
|
441
|
-
gl.shaderSource(this._vertShader, this.vertSrc());
|
|
442
|
-
gl.compileShader(this._vertShader);
|
|
443
|
-
// if our vertex shader failed compilation?
|
|
444
|
-
if (!gl.getShaderParameter(this._vertShader, gl.COMPILE_STATUS)) {
|
|
445
|
-
const glError = gl.getShaderInfoLog(this._vertShader);
|
|
446
|
-
if (typeof IS_MINIFIED !== 'undefined') {
|
|
447
|
-
console.error(glError);
|
|
448
|
-
} else {
|
|
449
|
-
throw glError;
|
|
450
|
-
p5._friendlyError(
|
|
451
|
-
`Yikes! An error occurred compiling the vertex shader:${glError}`
|
|
452
|
-
);
|
|
453
|
-
}
|
|
454
|
-
return null;
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
this._fragShader = gl.createShader(gl.FRAGMENT_SHADER);
|
|
458
|
-
//load in our material frag shader
|
|
459
|
-
gl.shaderSource(this._fragShader, this.fragSrc());
|
|
460
|
-
gl.compileShader(this._fragShader);
|
|
461
|
-
// if our frag shader failed compilation?
|
|
462
|
-
if (!gl.getShaderParameter(this._fragShader, gl.COMPILE_STATUS)) {
|
|
463
|
-
const glError = gl.getShaderInfoLog(this._fragShader);
|
|
464
|
-
if (typeof IS_MINIFIED !== 'undefined') {
|
|
465
|
-
console.error(glError);
|
|
466
|
-
} else {
|
|
467
|
-
throw glError;
|
|
468
|
-
p5._friendlyError(
|
|
469
|
-
`Darn! An error occurred compiling the fragment shader:${glError}`
|
|
470
|
-
);
|
|
471
|
-
}
|
|
472
|
-
return null;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
this._glProgram = gl.createProgram();
|
|
476
|
-
gl.attachShader(this._glProgram, this._vertShader);
|
|
477
|
-
gl.attachShader(this._glProgram, this._fragShader);
|
|
478
|
-
gl.linkProgram(this._glProgram);
|
|
479
|
-
if (!gl.getProgramParameter(this._glProgram, gl.LINK_STATUS)) {
|
|
480
|
-
p5._friendlyError(
|
|
481
|
-
`Snap! Error linking shader program: ${gl.getProgramInfoLog(
|
|
482
|
-
this._glProgram
|
|
483
|
-
)}`
|
|
484
|
-
);
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
this._loadAttributes();
|
|
488
|
-
this._loadUniforms();
|
|
489
|
-
}
|
|
490
|
-
return this;
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
/**
|
|
494
|
-
* @private
|
|
495
|
-
*/
|
|
496
|
-
setDefaultUniforms() {
|
|
497
|
-
for (const key in this.hooks.uniforms) {
|
|
498
|
-
const [, name] = key.split(' ');
|
|
499
|
-
const initializer = this.hooks.uniforms[key];
|
|
500
|
-
let value;
|
|
501
|
-
if (initializer instanceof Function) {
|
|
502
|
-
value = initializer();
|
|
503
|
-
} else {
|
|
504
|
-
value = initializer;
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
if (value !== undefined && value !== null) {
|
|
508
|
-
this.setUniform(name, value);
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
/**
|
|
514
|
-
* Copies the shader from one drawing context to another.
|
|
515
|
-
*
|
|
516
|
-
* Each `p5.Shader` object must be compiled by calling
|
|
517
|
-
* <a href="#/p5/shader">shader()</a> before it can run. Compilation happens
|
|
518
|
-
* in a drawing context which is usually the main canvas or an instance of
|
|
519
|
-
* <a href="#/p5.Graphics">p5.Graphics</a>. A shader can only be used in the
|
|
520
|
-
* context where it was compiled. The `copyToContext()` method compiles the
|
|
521
|
-
* shader again and copies it to another drawing context where it can be
|
|
522
|
-
* reused.
|
|
523
|
-
*
|
|
524
|
-
* The parameter, `context`, is the drawing context where the shader will be
|
|
525
|
-
* used. The shader can be copied to an instance of
|
|
526
|
-
* <a href="#/p5.Graphics">p5.Graphics</a>, as in
|
|
527
|
-
* `myShader.copyToContext(pg)`. The shader can also be copied from a
|
|
528
|
-
* <a href="#/p5.Graphics">p5.Graphics</a> object to the main canvas using
|
|
529
|
-
* the `p5.instance` variable, as in `myShader.copyToContext(p5.instance)`.
|
|
530
|
-
*
|
|
531
|
-
* Note: A <a href="#/p5.Shader">p5.Shader</a> object created with
|
|
532
|
-
* <a href="#/p5/createShader">createShader()</a>,
|
|
533
|
-
* <a href="#/p5/createFilterShader">createFilterShader()</a>, or
|
|
534
|
-
* <a href="#/p5/loadShader">loadShader()</a>
|
|
535
|
-
* can be used directly with a <a href="#/p5.Framebuffer">p5.Framebuffer</a>
|
|
536
|
-
* object created with
|
|
537
|
-
* <a href="#/p5/createFramebuffer">createFramebuffer()</a>. Both objects
|
|
538
|
-
* have the same context as the main canvas.
|
|
539
|
-
*
|
|
540
|
-
* @param {p5|p5.Graphics} context WebGL context for the copied shader.
|
|
541
|
-
* @returns {p5.Shader} new shader compiled for the target context.
|
|
542
|
-
*
|
|
543
|
-
* @example
|
|
544
|
-
* <div>
|
|
545
|
-
* <code>
|
|
546
|
-
* // Note: A "uniform" is a global variable within a shader program.
|
|
547
|
-
*
|
|
548
|
-
* // Create a string with the vertex shader program.
|
|
549
|
-
* // The vertex shader is called for each vertex.
|
|
550
|
-
* let vertSrc = `
|
|
551
|
-
* precision highp float;
|
|
552
|
-
* uniform mat4 uModelViewMatrix;
|
|
553
|
-
* uniform mat4 uProjectionMatrix;
|
|
554
|
-
*
|
|
555
|
-
* attribute vec3 aPosition;
|
|
556
|
-
* attribute vec2 aTexCoord;
|
|
557
|
-
* varying vec2 vTexCoord;
|
|
558
|
-
*
|
|
559
|
-
* void main() {
|
|
560
|
-
* vTexCoord = aTexCoord;
|
|
561
|
-
* vec4 positionVec4 = vec4(aPosition, 1.0);
|
|
562
|
-
* gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;
|
|
563
|
-
* }
|
|
564
|
-
* `;
|
|
565
|
-
*
|
|
566
|
-
* // Create a string with the fragment shader program.
|
|
567
|
-
* // The fragment shader is called for each pixel.
|
|
568
|
-
* let fragSrc = `
|
|
569
|
-
* precision mediump float;
|
|
570
|
-
* varying vec2 vTexCoord;
|
|
571
|
-
*
|
|
572
|
-
* void main() {
|
|
573
|
-
* vec2 uv = vTexCoord;
|
|
574
|
-
* vec3 color = vec3(uv.x, uv.y, min(uv.x + uv.y, 1.0));
|
|
575
|
-
* gl_FragColor = vec4(color, 1.0);\
|
|
576
|
-
* }
|
|
577
|
-
* `;
|
|
578
|
-
*
|
|
579
|
-
* let pg;
|
|
580
|
-
*
|
|
581
|
-
* function setup() {
|
|
582
|
-
* createCanvas(100, 100, WEBGL);
|
|
583
|
-
*
|
|
584
|
-
* background(200);
|
|
585
|
-
*
|
|
586
|
-
* // Create a p5.Shader object.
|
|
587
|
-
* let original = createShader(vertSrc, fragSrc);
|
|
588
|
-
*
|
|
589
|
-
* // Compile the p5.Shader object.
|
|
590
|
-
* shader(original);
|
|
591
|
-
*
|
|
592
|
-
* // Create a p5.Graphics object.
|
|
593
|
-
* pg = createGraphics(50, 50, WEBGL);
|
|
594
|
-
*
|
|
595
|
-
* // Copy the original shader to the p5.Graphics object.
|
|
596
|
-
* let copied = original.copyToContext(pg);
|
|
597
|
-
*
|
|
598
|
-
* // Apply the copied shader to the p5.Graphics object.
|
|
599
|
-
* pg.shader(copied);
|
|
600
|
-
*
|
|
601
|
-
* // Style the display surface.
|
|
602
|
-
* pg.noStroke();
|
|
603
|
-
*
|
|
604
|
-
* // Add a display surface for the shader.
|
|
605
|
-
* pg.plane(50, 50);
|
|
606
|
-
*
|
|
607
|
-
* describe('A square with purple-blue gradient on its surface drawn against a gray background.');
|
|
608
|
-
* }
|
|
609
|
-
*
|
|
610
|
-
* function draw() {
|
|
611
|
-
* background(200);
|
|
612
|
-
*
|
|
613
|
-
* // Draw the p5.Graphics object to the main canvas.
|
|
614
|
-
* image(pg, -25, -25);
|
|
615
|
-
* }
|
|
616
|
-
* </code>
|
|
617
|
-
* </div>
|
|
618
|
-
*
|
|
619
|
-
* <div class='notest'>
|
|
620
|
-
* <code>
|
|
621
|
-
* // Note: A "uniform" is a global variable within a shader program.
|
|
622
|
-
*
|
|
623
|
-
* // Create a string with the vertex shader program.
|
|
624
|
-
* // The vertex shader is called for each vertex.
|
|
625
|
-
* let vertSrc = `
|
|
626
|
-
* precision highp float;
|
|
627
|
-
* uniform mat4 uModelViewMatrix;
|
|
628
|
-
* uniform mat4 uProjectionMatrix;
|
|
629
|
-
*
|
|
630
|
-
* attribute vec3 aPosition;
|
|
631
|
-
* attribute vec2 aTexCoord;
|
|
632
|
-
* varying vec2 vTexCoord;
|
|
633
|
-
*
|
|
634
|
-
* void main() {
|
|
635
|
-
* vTexCoord = aTexCoord;
|
|
636
|
-
* vec4 positionVec4 = vec4(aPosition, 1.0);
|
|
637
|
-
* gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;
|
|
638
|
-
* }
|
|
639
|
-
* `;
|
|
640
|
-
*
|
|
641
|
-
* // Create a string with the fragment shader program.
|
|
642
|
-
* // The fragment shader is called for each pixel.
|
|
643
|
-
* let fragSrc = `
|
|
644
|
-
* precision mediump float;
|
|
645
|
-
*
|
|
646
|
-
* varying vec2 vTexCoord;
|
|
647
|
-
*
|
|
648
|
-
* void main() {
|
|
649
|
-
* vec2 uv = vTexCoord;
|
|
650
|
-
* vec3 color = vec3(uv.x, uv.y, min(uv.x + uv.y, 1.0));
|
|
651
|
-
* gl_FragColor = vec4(color, 1.0);
|
|
652
|
-
* }
|
|
653
|
-
* `;
|
|
654
|
-
*
|
|
655
|
-
* let copied;
|
|
656
|
-
*
|
|
657
|
-
* function setup() {
|
|
658
|
-
* createCanvas(100, 100, WEBGL);
|
|
659
|
-
*
|
|
660
|
-
* // Create a p5.Graphics object.
|
|
661
|
-
* let pg = createGraphics(25, 25, WEBGL);
|
|
662
|
-
*
|
|
663
|
-
* // Create a p5.Shader object.
|
|
664
|
-
* let original = pg.createShader(vertSrc, fragSrc);
|
|
665
|
-
*
|
|
666
|
-
* // Compile the p5.Shader object.
|
|
667
|
-
* pg.shader(original);
|
|
668
|
-
*
|
|
669
|
-
* // Copy the original shader to the main canvas.
|
|
670
|
-
* copied = original.copyToContext(p5.instance);
|
|
671
|
-
*
|
|
672
|
-
* // Apply the copied shader to the main canvas.
|
|
673
|
-
* shader(copied);
|
|
674
|
-
*
|
|
675
|
-
* describe('A rotating cube with a purple-blue gradient on its surface drawn against a gray background.');
|
|
676
|
-
* }
|
|
677
|
-
*
|
|
678
|
-
* function draw() {
|
|
679
|
-
* background(200);
|
|
680
|
-
*
|
|
681
|
-
* // Rotate around the x-, y-, and z-axes.
|
|
682
|
-
* rotateX(frameCount * 0.01);
|
|
683
|
-
* rotateY(frameCount * 0.01);
|
|
684
|
-
* rotateZ(frameCount * 0.01);
|
|
685
|
-
*
|
|
686
|
-
* // Draw the box.
|
|
687
|
-
* box(50);
|
|
688
|
-
* }
|
|
689
|
-
* </code>
|
|
690
|
-
* </div>
|
|
691
|
-
*/
|
|
692
|
-
copyToContext(context) {
|
|
693
|
-
const shader = new Shader(
|
|
694
|
-
context._renderer,
|
|
695
|
-
this._vertSrc,
|
|
696
|
-
this._fragSrc
|
|
697
|
-
);
|
|
698
|
-
shader.ensureCompiledOnContext(context._renderer);
|
|
699
|
-
return shader;
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
/**
|
|
703
|
-
* @private
|
|
704
|
-
*/
|
|
705
|
-
ensureCompiledOnContext(context) {
|
|
706
|
-
if (this._glProgram !== 0 && this._renderer !== context) {
|
|
707
|
-
throw new Error(
|
|
708
|
-
'The shader being run is attached to a different context. Do you need to copy it to this context first with .copyToContext()?'
|
|
709
|
-
);
|
|
710
|
-
} else if (this._glProgram === 0) {
|
|
711
|
-
this._renderer = context?._renderer?.filterRenderer?._renderer || context;
|
|
712
|
-
this.init();
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
/**
|
|
718
|
-
* Queries the active attributes for this shader and loads
|
|
719
|
-
* their names and locations into the attributes array.
|
|
720
|
-
* @private
|
|
721
|
-
*/
|
|
722
|
-
_loadAttributes() {
|
|
723
|
-
if (this._loadedAttributes) {
|
|
724
|
-
return;
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
this.attributes = {};
|
|
728
|
-
|
|
729
|
-
const gl = this._renderer.GL;
|
|
730
|
-
|
|
731
|
-
const numAttributes = gl.getProgramParameter(
|
|
732
|
-
this._glProgram,
|
|
733
|
-
gl.ACTIVE_ATTRIBUTES
|
|
734
|
-
);
|
|
735
|
-
for (let i = 0; i < numAttributes; ++i) {
|
|
736
|
-
const attributeInfo = gl.getActiveAttrib(this._glProgram, i);
|
|
737
|
-
const name = attributeInfo.name;
|
|
738
|
-
const location = gl.getAttribLocation(this._glProgram, name);
|
|
739
|
-
const attribute = {};
|
|
740
|
-
attribute.name = name;
|
|
741
|
-
attribute.location = location;
|
|
742
|
-
attribute.index = i;
|
|
743
|
-
attribute.type = attributeInfo.type;
|
|
744
|
-
attribute.size = attributeInfo.size;
|
|
745
|
-
this.attributes[name] = attribute;
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
this._loadedAttributes = true;
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
/**
|
|
752
|
-
* Queries the active uniforms for this shader and loads
|
|
753
|
-
* their names and locations into the uniforms array.
|
|
754
|
-
* @private
|
|
755
|
-
*/
|
|
756
|
-
_loadUniforms() {
|
|
757
|
-
if (this._loadedUniforms) {
|
|
758
|
-
return;
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
const gl = this._renderer.GL;
|
|
762
|
-
|
|
763
|
-
// Inspect shader and cache uniform info
|
|
764
|
-
const numUniforms = gl.getProgramParameter(
|
|
765
|
-
this._glProgram,
|
|
766
|
-
gl.ACTIVE_UNIFORMS
|
|
767
|
-
);
|
|
768
|
-
|
|
769
|
-
let samplerIndex = 0;
|
|
770
|
-
for (let i = 0; i < numUniforms; ++i) {
|
|
771
|
-
const uniformInfo = gl.getActiveUniform(this._glProgram, i);
|
|
772
|
-
const uniform = {};
|
|
773
|
-
uniform.location = gl.getUniformLocation(
|
|
774
|
-
this._glProgram,
|
|
775
|
-
uniformInfo.name
|
|
776
|
-
);
|
|
777
|
-
uniform.size = uniformInfo.size;
|
|
778
|
-
let uniformName = uniformInfo.name;
|
|
779
|
-
//uniforms that are arrays have their name returned as
|
|
780
|
-
//someUniform[0] which is a bit silly so we trim it
|
|
781
|
-
//off here. The size property tells us that its an array
|
|
782
|
-
//so we dont lose any information by doing this
|
|
783
|
-
if (uniformInfo.size > 1) {
|
|
784
|
-
uniformName = uniformName.substring(0, uniformName.indexOf('[0]'));
|
|
785
|
-
}
|
|
786
|
-
uniform.name = uniformName;
|
|
787
|
-
uniform.type = uniformInfo.type;
|
|
788
|
-
uniform._cachedData = undefined;
|
|
789
|
-
if (uniform.type === gl.SAMPLER_2D) {
|
|
790
|
-
uniform.samplerIndex = samplerIndex;
|
|
791
|
-
samplerIndex++;
|
|
792
|
-
this.samplers.push(uniform);
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
uniform.isArray =
|
|
796
|
-
uniformInfo.size > 1 ||
|
|
797
|
-
uniform.type === gl.FLOAT_MAT3 ||
|
|
798
|
-
uniform.type === gl.FLOAT_MAT4 ||
|
|
799
|
-
uniform.type === gl.FLOAT_VEC2 ||
|
|
800
|
-
uniform.type === gl.FLOAT_VEC3 ||
|
|
801
|
-
uniform.type === gl.FLOAT_VEC4 ||
|
|
802
|
-
uniform.type === gl.INT_VEC2 ||
|
|
803
|
-
uniform.type === gl.INT_VEC4 ||
|
|
804
|
-
uniform.type === gl.INT_VEC3;
|
|
805
|
-
|
|
806
|
-
this.uniforms[uniformName] = uniform;
|
|
807
|
-
}
|
|
808
|
-
this._loadedUniforms = true;
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
compile() {
|
|
812
|
-
// TODO
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
/**
|
|
816
|
-
* initializes (if needed) and binds the shader program.
|
|
817
|
-
* @private
|
|
818
|
-
*/
|
|
819
|
-
bindShader() {
|
|
820
|
-
this.init();
|
|
821
|
-
if (!this._bound) {
|
|
822
|
-
this.useProgram();
|
|
823
|
-
this._bound = true;
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
/**
|
|
828
|
-
* @chainable
|
|
829
|
-
* @private
|
|
830
|
-
*/
|
|
831
|
-
unbindShader() {
|
|
832
|
-
if (this._bound) {
|
|
833
|
-
this.unbindTextures();
|
|
834
|
-
this._bound = false;
|
|
835
|
-
}
|
|
836
|
-
return this;
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
bindTextures() {
|
|
840
|
-
const gl = this._renderer.GL;
|
|
841
|
-
|
|
842
|
-
const empty = this._renderer._getEmptyTexture();
|
|
843
|
-
|
|
844
|
-
for (const uniform of this.samplers) {
|
|
845
|
-
let tex = uniform.texture;
|
|
846
|
-
if (
|
|
847
|
-
tex === undefined ||
|
|
848
|
-
(
|
|
849
|
-
false &&
|
|
850
|
-
tex.isFramebufferTexture &&
|
|
851
|
-
!tex.src.framebuffer.antialias &&
|
|
852
|
-
tex.src.framebuffer === this._renderer.activeFramebuffer()
|
|
853
|
-
)
|
|
854
|
-
) {
|
|
855
|
-
// user hasn't yet supplied a texture for this slot.
|
|
856
|
-
// (or there may not be one--maybe just lighting),
|
|
857
|
-
// so we supply a default texture instead.
|
|
858
|
-
uniform.texture = tex = empty;
|
|
859
|
-
}
|
|
860
|
-
gl.activeTexture(gl.TEXTURE0 + uniform.samplerIndex);
|
|
861
|
-
tex.bindTexture();
|
|
862
|
-
tex.update();
|
|
863
|
-
gl.uniform1i(uniform.location, uniform.samplerIndex);
|
|
864
|
-
}
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
updateTextures() {
|
|
868
|
-
for (const uniform of this.samplers) {
|
|
869
|
-
const tex = uniform.texture;
|
|
870
|
-
if (tex) {
|
|
871
|
-
tex.update();
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
unbindTextures() {
|
|
877
|
-
const gl = this._renderer.GL;
|
|
878
|
-
const empty = this._renderer._getEmptyTexture();
|
|
879
|
-
for (const uniform of this.samplers) {
|
|
880
|
-
if (uniform.texture?.isFramebufferTexture) {
|
|
881
|
-
gl.activeTexture(gl.TEXTURE0 + uniform.samplerIndex);
|
|
882
|
-
empty.bindTexture();
|
|
883
|
-
gl.uniform1i(uniform.location, uniform.samplerIndex);
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
|
|
888
|
-
/**
|
|
889
|
-
* @chainable
|
|
890
|
-
* @private
|
|
891
|
-
*/
|
|
892
|
-
useProgram() {
|
|
893
|
-
const gl = this._renderer.GL;
|
|
894
|
-
if (this._renderer._curShader !== this) {
|
|
895
|
-
gl.useProgram(this._glProgram);
|
|
896
|
-
this._renderer._curShader = this;
|
|
897
|
-
}
|
|
898
|
-
return this;
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
/**
|
|
902
|
-
* Sets the shader’s uniform (global) variables.
|
|
903
|
-
*
|
|
904
|
-
* Shader programs run on the computer’s graphics processing unit (GPU).
|
|
905
|
-
* They live in part of the computer’s memory that’s completely separate
|
|
906
|
-
* from the sketch that runs them. Uniforms are global variables within a
|
|
907
|
-
* shader program. They provide a way to pass values from a sketch running
|
|
908
|
-
* on the CPU to a shader program running on the GPU.
|
|
909
|
-
*
|
|
910
|
-
* The first parameter, `uniformName`, is a string with the uniform’s name.
|
|
911
|
-
* For the shader above, `uniformName` would be `'r'`.
|
|
912
|
-
*
|
|
913
|
-
* The second parameter, `data`, is the value that should be used to set the
|
|
914
|
-
* uniform. For example, calling `myShader.setUniform('r', 0.5)` would set
|
|
915
|
-
* the `r` uniform in the shader above to `0.5`. data should match the
|
|
916
|
-
* uniform’s type. Numbers, strings, booleans, arrays, and many types of
|
|
917
|
-
* images can all be passed to a shader with `setUniform()`.
|
|
918
|
-
*
|
|
919
|
-
* @chainable
|
|
920
|
-
* @param {String} uniformName name of the uniform. Must match the name
|
|
921
|
-
* used in the vertex and fragment shaders.
|
|
922
|
-
* @param {Boolean|Number|Number[]|p5.Image|p5.Graphics|p5.MediaElement|p5.Texture}
|
|
923
|
-
* data value to assign to the uniform. Must match the uniform’s data type.
|
|
924
|
-
*
|
|
925
|
-
* @example
|
|
926
|
-
* <div>
|
|
927
|
-
* <code>
|
|
928
|
-
* // Note: A "uniform" is a global variable within a shader program.
|
|
929
|
-
*
|
|
930
|
-
* // Create a string with the vertex shader program.
|
|
931
|
-
* // The vertex shader is called for each vertex.
|
|
932
|
-
* let vertSrc = `
|
|
933
|
-
* precision highp float;
|
|
934
|
-
* uniform mat4 uModelViewMatrix;
|
|
935
|
-
* uniform mat4 uProjectionMatrix;
|
|
936
|
-
*
|
|
937
|
-
* attribute vec3 aPosition;
|
|
938
|
-
* attribute vec2 aTexCoord;
|
|
939
|
-
* varying vec2 vTexCoord;
|
|
940
|
-
*
|
|
941
|
-
* void main() {
|
|
942
|
-
* vTexCoord = aTexCoord;
|
|
943
|
-
* vec4 positionVec4 = vec4(aPosition, 1.0);
|
|
944
|
-
* gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;
|
|
945
|
-
* }
|
|
946
|
-
* `;
|
|
947
|
-
*
|
|
948
|
-
* // Create a string with the fragment shader program.
|
|
949
|
-
* // The fragment shader is called for each pixel.
|
|
950
|
-
* let fragSrc = `
|
|
951
|
-
* precision mediump float;
|
|
952
|
-
*
|
|
953
|
-
* uniform float r;
|
|
954
|
-
*
|
|
955
|
-
* void main() {
|
|
956
|
-
* gl_FragColor = vec4(r, 1.0, 1.0, 1.0);
|
|
957
|
-
* }
|
|
958
|
-
* `;
|
|
959
|
-
*
|
|
960
|
-
* function setup() {
|
|
961
|
-
* createCanvas(100, 100, WEBGL);
|
|
962
|
-
*
|
|
963
|
-
* // Create a p5.Shader object.
|
|
964
|
-
* let myShader = createShader(vertSrc, fragSrc);
|
|
965
|
-
*
|
|
966
|
-
* // Apply the p5.Shader object.
|
|
967
|
-
* shader(myShader);
|
|
968
|
-
*
|
|
969
|
-
* // Set the r uniform to 0.5.
|
|
970
|
-
* myShader.setUniform('r', 0.5);
|
|
971
|
-
*
|
|
972
|
-
* // Style the drawing surface.
|
|
973
|
-
* noStroke();
|
|
974
|
-
*
|
|
975
|
-
* // Add a plane as a drawing surface for the shader.
|
|
976
|
-
* plane(100, 100);
|
|
977
|
-
*
|
|
978
|
-
* describe('A cyan square.');
|
|
979
|
-
* }
|
|
980
|
-
* </code>
|
|
981
|
-
* </div>
|
|
982
|
-
*
|
|
983
|
-
* <div>
|
|
984
|
-
* <code>
|
|
985
|
-
* // Note: A "uniform" is a global variable within a shader program.
|
|
986
|
-
*
|
|
987
|
-
* // Create a string with the vertex shader program.
|
|
988
|
-
* // The vertex shader is called for each vertex.
|
|
989
|
-
* let vertSrc = `
|
|
990
|
-
* precision highp float;
|
|
991
|
-
* uniform mat4 uModelViewMatrix;
|
|
992
|
-
* uniform mat4 uProjectionMatrix;
|
|
993
|
-
*
|
|
994
|
-
* attribute vec3 aPosition;
|
|
995
|
-
* attribute vec2 aTexCoord;
|
|
996
|
-
* varying vec2 vTexCoord;
|
|
997
|
-
*
|
|
998
|
-
* void main() {
|
|
999
|
-
* vTexCoord = aTexCoord;
|
|
1000
|
-
* vec4 positionVec4 = vec4(aPosition, 1.0);
|
|
1001
|
-
* gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;
|
|
1002
|
-
* }
|
|
1003
|
-
* `;
|
|
1004
|
-
*
|
|
1005
|
-
* // Create a string with the fragment shader program.
|
|
1006
|
-
* // The fragment shader is called for each pixel.
|
|
1007
|
-
* let fragSrc = `
|
|
1008
|
-
* precision mediump float;
|
|
1009
|
-
*
|
|
1010
|
-
* uniform float r;
|
|
1011
|
-
*
|
|
1012
|
-
* void main() {
|
|
1013
|
-
* gl_FragColor = vec4(r, 1.0, 1.0, 1.0);
|
|
1014
|
-
* }
|
|
1015
|
-
* `;
|
|
1016
|
-
*
|
|
1017
|
-
* let myShader;
|
|
1018
|
-
*
|
|
1019
|
-
* function setup() {
|
|
1020
|
-
* createCanvas(100, 100, WEBGL);
|
|
1021
|
-
*
|
|
1022
|
-
* // Create a p5.Shader object.
|
|
1023
|
-
* myShader = createShader(vertSrc, fragSrc);
|
|
1024
|
-
*
|
|
1025
|
-
* // Compile and apply the p5.Shader object.
|
|
1026
|
-
* shader(myShader);
|
|
1027
|
-
*
|
|
1028
|
-
* describe('A square oscillates color between cyan and white.');
|
|
1029
|
-
* }
|
|
1030
|
-
*
|
|
1031
|
-
* function draw() {
|
|
1032
|
-
* background(200);
|
|
1033
|
-
*
|
|
1034
|
-
* // Style the drawing surface.
|
|
1035
|
-
* noStroke();
|
|
1036
|
-
*
|
|
1037
|
-
* // Update the r uniform.
|
|
1038
|
-
* let nextR = 0.5 * (sin(frameCount * 0.01) + 1);
|
|
1039
|
-
* myShader.setUniform('r', nextR);
|
|
1040
|
-
*
|
|
1041
|
-
* // Add a plane as a drawing surface.
|
|
1042
|
-
* plane(100, 100);
|
|
1043
|
-
* }
|
|
1044
|
-
* </code>
|
|
1045
|
-
* </div>
|
|
1046
|
-
*
|
|
1047
|
-
* <div>
|
|
1048
|
-
* <code>
|
|
1049
|
-
* // Note: A "uniform" is a global variable within a shader program.
|
|
1050
|
-
*
|
|
1051
|
-
* // Create a string with the vertex shader program.
|
|
1052
|
-
* // The vertex shader is called for each vertex.
|
|
1053
|
-
* let vertSrc = `
|
|
1054
|
-
* precision highp float;
|
|
1055
|
-
* uniform mat4 uModelViewMatrix;
|
|
1056
|
-
* uniform mat4 uProjectionMatrix;
|
|
1057
|
-
*
|
|
1058
|
-
* attribute vec3 aPosition;
|
|
1059
|
-
* attribute vec2 aTexCoord;
|
|
1060
|
-
* varying vec2 vTexCoord;
|
|
1061
|
-
*
|
|
1062
|
-
* void main() {
|
|
1063
|
-
* vTexCoord = aTexCoord;
|
|
1064
|
-
* vec4 positionVec4 = vec4(aPosition, 1.0);
|
|
1065
|
-
* gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;
|
|
1066
|
-
* }
|
|
1067
|
-
* `;
|
|
1068
|
-
*
|
|
1069
|
-
* // Create a string with the fragment shader program.
|
|
1070
|
-
* // The fragment shader is called for each pixel.
|
|
1071
|
-
* let fragSrc = `
|
|
1072
|
-
* precision highp float;
|
|
1073
|
-
* uniform vec2 p;
|
|
1074
|
-
* uniform float r;
|
|
1075
|
-
* const int numIterations = 500;
|
|
1076
|
-
* varying vec2 vTexCoord;
|
|
1077
|
-
*
|
|
1078
|
-
* void main() {
|
|
1079
|
-
* vec2 c = p + gl_FragCoord.xy * r;
|
|
1080
|
-
* vec2 z = c;
|
|
1081
|
-
* float n = 0.0;
|
|
1082
|
-
*
|
|
1083
|
-
* for (int i = numIterations; i > 0; i--) {
|
|
1084
|
-
* if (z.x * z.x + z.y * z.y > 4.0) {
|
|
1085
|
-
* n = float(i) / float(numIterations);
|
|
1086
|
-
* break;
|
|
1087
|
-
* }
|
|
1088
|
-
*
|
|
1089
|
-
* z = vec2(z.x * z.x - z.y * z.y, 2.0 * z.x * z.y) + c;
|
|
1090
|
-
* }
|
|
1091
|
-
*
|
|
1092
|
-
* gl_FragColor = vec4(
|
|
1093
|
-
* 0.5 - cos(n * 17.0) / 2.0,
|
|
1094
|
-
* 0.5 - cos(n * 13.0) / 2.0,
|
|
1095
|
-
* 0.5 - cos(n * 23.0) / 2.0,
|
|
1096
|
-
* 1.0
|
|
1097
|
-
* );
|
|
1098
|
-
* }
|
|
1099
|
-
* `;
|
|
1100
|
-
*
|
|
1101
|
-
* let mandelbrot;
|
|
1102
|
-
*
|
|
1103
|
-
* function setup() {
|
|
1104
|
-
* createCanvas(100, 100, WEBGL);
|
|
1105
|
-
*
|
|
1106
|
-
* // Create a p5.Shader object.
|
|
1107
|
-
* mandelbrot = createShader(vertSrc, fragSrc);
|
|
1108
|
-
*
|
|
1109
|
-
* // Compile and apply the p5.Shader object.
|
|
1110
|
-
* shader(mandelbrot);
|
|
1111
|
-
*
|
|
1112
|
-
* // Set the shader uniform p to an array.
|
|
1113
|
-
* // p is the center point of the Mandelbrot image.
|
|
1114
|
-
* mandelbrot.setUniform('p', [-0.74364388703, 0.13182590421]);
|
|
1115
|
-
*
|
|
1116
|
-
* describe('A fractal image zooms in and out of focus.');
|
|
1117
|
-
* }
|
|
1118
|
-
*
|
|
1119
|
-
* function draw() {
|
|
1120
|
-
* // Set the shader uniform r to a value that oscillates
|
|
1121
|
-
* // between 0 and 0.005.
|
|
1122
|
-
* // r is the size of the image in Mandelbrot-space.
|
|
1123
|
-
* let radius = 0.005 * (sin(frameCount * 0.01) + 1);
|
|
1124
|
-
* mandelbrot.setUniform('r', radius);
|
|
1125
|
-
*
|
|
1126
|
-
* // Style the drawing surface.
|
|
1127
|
-
* noStroke();
|
|
1128
|
-
*
|
|
1129
|
-
* // Add a plane as a drawing surface.
|
|
1130
|
-
* plane(100, 100);
|
|
1131
|
-
* }
|
|
1132
|
-
* </code>
|
|
1133
|
-
* </div>
|
|
1134
|
-
*/
|
|
1135
|
-
setUniform(uniformName, data) {
|
|
1136
|
-
this.init();
|
|
1137
|
-
|
|
1138
|
-
const uniform = this.uniforms[uniformName];
|
|
1139
|
-
if (!uniform) {
|
|
1140
|
-
return;
|
|
1141
|
-
}
|
|
1142
|
-
const gl = this._renderer.GL;
|
|
1143
|
-
|
|
1144
|
-
if (uniform.isArray) {
|
|
1145
|
-
if (
|
|
1146
|
-
uniform._cachedData &&
|
|
1147
|
-
this._renderer._arraysEqual(uniform._cachedData, data)
|
|
1148
|
-
) {
|
|
1149
|
-
return;
|
|
1150
|
-
} else {
|
|
1151
|
-
uniform._cachedData = data.slice(0);
|
|
1152
|
-
}
|
|
1153
|
-
} else if (uniform._cachedData && uniform._cachedData === data) {
|
|
1154
|
-
return;
|
|
1155
|
-
} else {
|
|
1156
|
-
if (Array.isArray(data)) {
|
|
1157
|
-
uniform._cachedData = data.slice(0);
|
|
1158
|
-
} else {
|
|
1159
|
-
uniform._cachedData = data;
|
|
1160
|
-
}
|
|
1161
|
-
}
|
|
1162
|
-
|
|
1163
|
-
const location = uniform.location;
|
|
1164
|
-
|
|
1165
|
-
this.useProgram();
|
|
1166
|
-
|
|
1167
|
-
switch (uniform.type) {
|
|
1168
|
-
case gl.BOOL:
|
|
1169
|
-
if (data === true) {
|
|
1170
|
-
gl.uniform1i(location, 1);
|
|
1171
|
-
} else {
|
|
1172
|
-
gl.uniform1i(location, 0);
|
|
1173
|
-
}
|
|
1174
|
-
break;
|
|
1175
|
-
case gl.INT:
|
|
1176
|
-
if (uniform.size > 1) {
|
|
1177
|
-
data.length && gl.uniform1iv(location, data);
|
|
1178
|
-
} else {
|
|
1179
|
-
gl.uniform1i(location, data);
|
|
1180
|
-
}
|
|
1181
|
-
break;
|
|
1182
|
-
case gl.FLOAT:
|
|
1183
|
-
if (uniform.size > 1) {
|
|
1184
|
-
data.length && gl.uniform1fv(location, data);
|
|
1185
|
-
} else {
|
|
1186
|
-
gl.uniform1f(location, data);
|
|
1187
|
-
}
|
|
1188
|
-
break;
|
|
1189
|
-
case gl.FLOAT_MAT3:
|
|
1190
|
-
gl.uniformMatrix3fv(location, false, data);
|
|
1191
|
-
break;
|
|
1192
|
-
case gl.FLOAT_MAT4:
|
|
1193
|
-
gl.uniformMatrix4fv(location, false, data);
|
|
1194
|
-
break;
|
|
1195
|
-
case gl.FLOAT_VEC2:
|
|
1196
|
-
if (uniform.size > 1) {
|
|
1197
|
-
data.length && gl.uniform2fv(location, data);
|
|
1198
|
-
} else {
|
|
1199
|
-
gl.uniform2f(location, data[0], data[1]);
|
|
1200
|
-
}
|
|
1201
|
-
break;
|
|
1202
|
-
case gl.FLOAT_VEC3:
|
|
1203
|
-
if (uniform.size > 1) {
|
|
1204
|
-
data.length && gl.uniform3fv(location, data);
|
|
1205
|
-
} else {
|
|
1206
|
-
gl.uniform3f(location, data[0], data[1], data[2]);
|
|
1207
|
-
}
|
|
1208
|
-
break;
|
|
1209
|
-
case gl.FLOAT_VEC4:
|
|
1210
|
-
if (uniform.size > 1) {
|
|
1211
|
-
data.length && gl.uniform4fv(location, data);
|
|
1212
|
-
} else {
|
|
1213
|
-
gl.uniform4f(location, data[0], data[1], data[2], data[3]);
|
|
1214
|
-
}
|
|
1215
|
-
break;
|
|
1216
|
-
case gl.INT_VEC2:
|
|
1217
|
-
if (uniform.size > 1) {
|
|
1218
|
-
data.length && gl.uniform2iv(location, data);
|
|
1219
|
-
} else {
|
|
1220
|
-
gl.uniform2i(location, data[0], data[1]);
|
|
1221
|
-
}
|
|
1222
|
-
break;
|
|
1223
|
-
case gl.INT_VEC3:
|
|
1224
|
-
if (uniform.size > 1) {
|
|
1225
|
-
data.length && gl.uniform3iv(location, data);
|
|
1226
|
-
} else {
|
|
1227
|
-
gl.uniform3i(location, data[0], data[1], data[2]);
|
|
1228
|
-
}
|
|
1229
|
-
break;
|
|
1230
|
-
case gl.INT_VEC4:
|
|
1231
|
-
if (uniform.size > 1) {
|
|
1232
|
-
data.length && gl.uniform4iv(location, data);
|
|
1233
|
-
} else {
|
|
1234
|
-
gl.uniform4i(location, data[0], data[1], data[2], data[3]);
|
|
1235
|
-
}
|
|
1236
|
-
break;
|
|
1237
|
-
case gl.SAMPLER_2D:
|
|
1238
|
-
if (typeof data == 'number') {
|
|
1239
|
-
if (
|
|
1240
|
-
data < gl.TEXTURE0 ||
|
|
1241
|
-
data > gl.TEXTURE31 ||
|
|
1242
|
-
data !== Math.ceil(data)
|
|
1243
|
-
) {
|
|
1244
|
-
console.log(
|
|
1245
|
-
'🌸 p5.js says: ' +
|
|
1246
|
-
"You're trying to use a number as the data for a texture." +
|
|
1247
|
-
'Please use a texture.'
|
|
1248
|
-
);
|
|
1249
|
-
return this;
|
|
1250
|
-
}
|
|
1251
|
-
gl.activeTexture(data);
|
|
1252
|
-
gl.uniform1i(location, data);
|
|
1253
|
-
} else {
|
|
1254
|
-
gl.activeTexture(gl.TEXTURE0 + uniform.samplerIndex);
|
|
1255
|
-
uniform.texture =
|
|
1256
|
-
data instanceof Texture ? data : this._renderer.getTexture(data);
|
|
1257
|
-
gl.uniform1i(location, uniform.samplerIndex);
|
|
1258
|
-
if (uniform.texture.src.gifProperties) {
|
|
1259
|
-
uniform.texture.src._animateGif(this._renderer._pInst);
|
|
1260
|
-
}
|
|
1261
|
-
}
|
|
1262
|
-
break;
|
|
1263
|
-
case gl.SAMPLER_CUBE:
|
|
1264
|
-
case gl.SAMPLER_3D:
|
|
1265
|
-
case gl.SAMPLER_2D_SHADOW:
|
|
1266
|
-
case gl.SAMPLER_2D_ARRAY:
|
|
1267
|
-
case gl.SAMPLER_2D_ARRAY_SHADOW:
|
|
1268
|
-
case gl.SAMPLER_CUBE_SHADOW:
|
|
1269
|
-
case gl.INT_SAMPLER_2D:
|
|
1270
|
-
case gl.INT_SAMPLER_3D:
|
|
1271
|
-
case gl.INT_SAMPLER_CUBE:
|
|
1272
|
-
case gl.INT_SAMPLER_2D_ARRAY:
|
|
1273
|
-
case gl.UNSIGNED_INT_SAMPLER_2D:
|
|
1274
|
-
case gl.UNSIGNED_INT_SAMPLER_3D:
|
|
1275
|
-
case gl.UNSIGNED_INT_SAMPLER_CUBE:
|
|
1276
|
-
case gl.UNSIGNED_INT_SAMPLER_2D_ARRAY:
|
|
1277
|
-
if (typeof data !== 'number') {
|
|
1278
|
-
break;
|
|
1279
|
-
}
|
|
1280
|
-
if (
|
|
1281
|
-
data < gl.TEXTURE0 ||
|
|
1282
|
-
data > gl.TEXTURE31 ||
|
|
1283
|
-
data !== Math.ceil(data)
|
|
1284
|
-
) {
|
|
1285
|
-
console.log(
|
|
1286
|
-
'🌸 p5.js says: ' +
|
|
1287
|
-
"You're trying to use a number as the data for a texture." +
|
|
1288
|
-
'Please use a texture.'
|
|
1289
|
-
);
|
|
1290
|
-
break;
|
|
1291
|
-
}
|
|
1292
|
-
gl.activeTexture(data);
|
|
1293
|
-
gl.uniform1i(location, data);
|
|
1294
|
-
break;
|
|
1295
|
-
//@todo complete all types
|
|
1296
|
-
}
|
|
1297
|
-
return this;
|
|
1298
|
-
}
|
|
1299
|
-
|
|
1300
|
-
/**
|
|
1301
|
-
* @chainable
|
|
1302
|
-
* @private
|
|
1303
|
-
*/
|
|
1304
|
-
enableAttrib(attr, size, type, normalized, stride, offset) {
|
|
1305
|
-
if (attr) {
|
|
1306
|
-
if (
|
|
1307
|
-
typeof IS_MINIFIED === 'undefined' &&
|
|
1308
|
-
this.attributes[attr.name] !== attr
|
|
1309
|
-
) {
|
|
1310
|
-
console.warn(
|
|
1311
|
-
`The attribute "${attr.name}"passed to enableAttrib does not belong to this shader.`
|
|
1312
|
-
);
|
|
1313
|
-
}
|
|
1314
|
-
const loc = attr.location;
|
|
1315
|
-
if (loc !== -1) {
|
|
1316
|
-
const gl = this._renderer.GL;
|
|
1317
|
-
// Enable register even if it is disabled
|
|
1318
|
-
if (!this._renderer.registerEnabled.has(loc)) {
|
|
1319
|
-
gl.enableVertexAttribArray(loc);
|
|
1320
|
-
// Record register availability
|
|
1321
|
-
this._renderer.registerEnabled.add(loc);
|
|
1322
|
-
}
|
|
1323
|
-
this._renderer.GL.vertexAttribPointer(
|
|
1324
|
-
loc,
|
|
1325
|
-
size,
|
|
1326
|
-
type || gl.FLOAT,
|
|
1327
|
-
normalized || false,
|
|
1328
|
-
stride || 0,
|
|
1329
|
-
offset || 0
|
|
1330
|
-
);
|
|
1331
|
-
}
|
|
1332
|
-
}
|
|
1333
|
-
return this;
|
|
1334
|
-
}
|
|
1335
|
-
|
|
1336
|
-
/**
|
|
1337
|
-
* Once all buffers have been bound, this checks to see if there are any
|
|
1338
|
-
* remaining active attributes, likely left over from previous renders,
|
|
1339
|
-
* and disables them so that they don't affect rendering.
|
|
1340
|
-
* @private
|
|
1341
|
-
*/
|
|
1342
|
-
disableRemainingAttributes() {
|
|
1343
|
-
for (const location of this._renderer.registerEnabled.values()) {
|
|
1344
|
-
if (
|
|
1345
|
-
!Object.keys(this.attributes).some(
|
|
1346
|
-
key => this.attributes[key].location === location
|
|
1347
|
-
)
|
|
1348
|
-
) {
|
|
1349
|
-
this._renderer.GL.disableVertexAttribArray(location);
|
|
1350
|
-
this._renderer.registerEnabled.delete(location);
|
|
1351
|
-
}
|
|
1352
|
-
}
|
|
1353
|
-
}
|
|
1354
|
-
};
|
|
1355
|
-
|
|
1356
|
-
function shader(p5, fn){
|
|
1357
|
-
/**
|
|
1358
|
-
* A class to describe a shader program.
|
|
1359
|
-
*
|
|
1360
|
-
* Each `p5.Shader` object contains a shader program that runs on the graphics
|
|
1361
|
-
* processing unit (GPU). Shaders can process many pixels or vertices at the
|
|
1362
|
-
* same time, making them fast for many graphics tasks. They’re written in a
|
|
1363
|
-
* language called
|
|
1364
|
-
* <a href="https://developer.mozilla.org/en-US/docs/Games/Techniques/3D_on_the_web/GLSL_Shaders" target="_blank">GLSL</a>
|
|
1365
|
-
* and run along with the rest of the code in a sketch.
|
|
1366
|
-
*
|
|
1367
|
-
* A shader program consists of two files, a vertex shader and a fragment
|
|
1368
|
-
* shader. The vertex shader affects where 3D geometry is drawn on the screen
|
|
1369
|
-
* and the fragment shader affects color. Once the `p5.Shader` object is
|
|
1370
|
-
* created, it can be used with the <a href="#/p5/shader">shader()</a>
|
|
1371
|
-
* function, as in `shader(myShader)`.
|
|
1372
|
-
*
|
|
1373
|
-
* A shader can optionally describe *hooks,* which are functions in GLSL that
|
|
1374
|
-
* users may choose to provide to customize the behavior of the shader. For the
|
|
1375
|
-
* vertex or the fragment shader, users can pass in an object where each key is
|
|
1376
|
-
* the type and name of a hook function, and each value is a string with the
|
|
1377
|
-
* parameter list and default implementation of the hook. For example, to let users
|
|
1378
|
-
* optionally run code at the start of the vertex shader, the options object could
|
|
1379
|
-
* include:
|
|
1380
|
-
*
|
|
1381
|
-
* ```js
|
|
1382
|
-
* {
|
|
1383
|
-
* vertex: {
|
|
1384
|
-
* 'void beforeVertex': '() {}'
|
|
1385
|
-
* }
|
|
1386
|
-
* }
|
|
1387
|
-
* ```
|
|
1388
|
-
*
|
|
1389
|
-
* Then, in your vertex shader source, you can run a hook by calling a function
|
|
1390
|
-
* with the same name prefixed by `HOOK_`:
|
|
1391
|
-
*
|
|
1392
|
-
* ```glsl
|
|
1393
|
-
* void main() {
|
|
1394
|
-
* HOOK_beforeVertex();
|
|
1395
|
-
* // Add the rest ofy our shader code here!
|
|
1396
|
-
* }
|
|
1397
|
-
* ```
|
|
1398
|
-
*
|
|
1399
|
-
* Note: <a href="#/p5/createShader">createShader()</a>,
|
|
1400
|
-
* <a href="#/p5/createFilterShader">createFilterShader()</a>, and
|
|
1401
|
-
* <a href="#/p5/loadShader">loadShader()</a> are the recommended ways to
|
|
1402
|
-
* create an instance of this class.
|
|
1403
|
-
*
|
|
1404
|
-
* @class p5.Shader
|
|
1405
|
-
* @constructor
|
|
1406
|
-
* @param {p5.RendererGL} renderer WebGL context for this shader.
|
|
1407
|
-
* @param {String} vertSrc source code for the vertex shader program.
|
|
1408
|
-
* @param {String} fragSrc source code for the fragment shader program.
|
|
1409
|
-
* @param {Object} [options] An optional object describing how this shader can
|
|
1410
|
-
* be augmented with hooks. It can include:
|
|
1411
|
-
* - `vertex`: An object describing the available vertex shader hooks.
|
|
1412
|
-
* - `fragment`: An object describing the available frament shader hooks.
|
|
1413
|
-
*
|
|
1414
|
-
* @example
|
|
1415
|
-
* <div>
|
|
1416
|
-
* <code>
|
|
1417
|
-
* // Note: A "uniform" is a global variable within a shader program.
|
|
1418
|
-
*
|
|
1419
|
-
* // Create a string with the vertex shader program.
|
|
1420
|
-
* // The vertex shader is called for each vertex.
|
|
1421
|
-
* let vertSrc = `
|
|
1422
|
-
* precision highp float;
|
|
1423
|
-
* uniform mat4 uModelViewMatrix;
|
|
1424
|
-
* uniform mat4 uProjectionMatrix;
|
|
1425
|
-
*
|
|
1426
|
-
* attribute vec3 aPosition;
|
|
1427
|
-
* attribute vec2 aTexCoord;
|
|
1428
|
-
* varying vec2 vTexCoord;
|
|
1429
|
-
*
|
|
1430
|
-
* void main() {
|
|
1431
|
-
* vTexCoord = aTexCoord;
|
|
1432
|
-
* vec4 positionVec4 = vec4(aPosition, 1.0);
|
|
1433
|
-
* gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;
|
|
1434
|
-
* }
|
|
1435
|
-
* `;
|
|
1436
|
-
*
|
|
1437
|
-
* // Create a string with the fragment shader program.
|
|
1438
|
-
* // The fragment shader is called for each pixel.
|
|
1439
|
-
* let fragSrc = `
|
|
1440
|
-
* precision highp float;
|
|
1441
|
-
*
|
|
1442
|
-
* void main() {
|
|
1443
|
-
* // Set each pixel's RGBA value to yellow.
|
|
1444
|
-
* gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
|
|
1445
|
-
* }
|
|
1446
|
-
* `;
|
|
1447
|
-
*
|
|
1448
|
-
* function setup() {
|
|
1449
|
-
* createCanvas(100, 100, WEBGL);
|
|
1450
|
-
*
|
|
1451
|
-
* // Create a p5.Shader object.
|
|
1452
|
-
* let myShader = createShader(vertSrc, fragSrc);
|
|
1453
|
-
*
|
|
1454
|
-
* // Apply the p5.Shader object.
|
|
1455
|
-
* shader(myShader);
|
|
1456
|
-
*
|
|
1457
|
-
* // Style the drawing surface.
|
|
1458
|
-
* noStroke();
|
|
1459
|
-
*
|
|
1460
|
-
* // Add a plane as a drawing surface.
|
|
1461
|
-
* plane(100, 100);
|
|
1462
|
-
*
|
|
1463
|
-
* describe('A yellow square.');
|
|
1464
|
-
* }
|
|
1465
|
-
* </code>
|
|
1466
|
-
* </div>
|
|
1467
|
-
*
|
|
1468
|
-
* <div>
|
|
1469
|
-
* <code>
|
|
1470
|
-
* // Note: A "uniform" is a global variable within a shader program.
|
|
1471
|
-
*
|
|
1472
|
-
* let mandelbrot;
|
|
1473
|
-
*
|
|
1474
|
-
* async function setup() {
|
|
1475
|
-
* mandelbrot = await loadShader('assets/shader.vert', 'assets/shader.frag');
|
|
1476
|
-
* createCanvas(100, 100, WEBGL);
|
|
1477
|
-
*
|
|
1478
|
-
* // Use the p5.Shader object.
|
|
1479
|
-
* shader(mandelbrot);
|
|
1480
|
-
*
|
|
1481
|
-
* // Set the shader uniform p to an array.
|
|
1482
|
-
* mandelbrot.setUniform('p', [-0.74364388703, 0.13182590421]);
|
|
1483
|
-
*
|
|
1484
|
-
* describe('A fractal image zooms in and out of focus.');
|
|
1485
|
-
* }
|
|
1486
|
-
*
|
|
1487
|
-
* function draw() {
|
|
1488
|
-
* // Set the shader uniform r to a value that oscillates between 0 and 2.
|
|
1489
|
-
* mandelbrot.setUniform('r', sin(frameCount * 0.01) + 1);
|
|
1490
|
-
*
|
|
1491
|
-
* // Add a quad as a display surface for the shader.
|
|
1492
|
-
* quad(-1, -1, 1, -1, 1, 1, -1, 1);
|
|
1493
|
-
* }
|
|
1494
|
-
* </code>
|
|
1495
|
-
* </div>
|
|
1496
|
-
*/
|
|
1497
|
-
p5.Shader = Shader;
|
|
1498
|
-
}
|
|
1499
|
-
|
|
1500
|
-
export default shader;
|
|
1501
|
-
export { Shader };
|
|
1502
|
-
|
|
1503
|
-
if(typeof p5 !== 'undefined'){
|
|
1504
|
-
shader(p5, p5.prototype);
|
|
1505
|
-
}
|