Skip to content

Commit 22addb5

Browse files
committed
Add more examples, document shader version
1 parent 4744428 commit 22addb5

File tree

2 files changed

+145
-2
lines changed

2 files changed

+145
-2
lines changed

src/webgl/material.js

Lines changed: 127 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,12 +211,21 @@ p5.prototype.loadShader = function (
211211
* ```
212212
*
213213
* Then, in your vertex shader source, you can run a hook by calling a function
214-
* with the same name prefixed by `HOOK_`:
214+
* with the same name prefixed by `HOOK_`. If you want to check if the default
215+
* hook has been replaced, maybe to avoid extra overhead, you can check if the
216+
* same name prefixed by `AUGMENTED_HOOK_` has been defined:
215217
*
216218
* ```glsl
217219
* void main() {
220+
* // In most cases, just calling the hook is fine:
218221
* HOOK_beforeVertex();
219-
* // Add the rest ofy our shader code here!
222+
*
223+
* // Alternatively, for more efficiency:
224+
* #ifdef AUGMENTED_HOOK_beforeVertex
225+
* HOOK_beforeVertex();
226+
* #endif
227+
*
228+
* // Add the rest of your shader code here!
220229
* }
221230
* ```
222231
*
@@ -453,6 +462,75 @@ p5.prototype.loadShader = function (
453462
* }
454463
* </code>
455464
* </div>
465+
*
466+
* <div>
467+
* <code>
468+
* // A shader with hooks.
469+
* let myShader;
470+
*
471+
* // A shader with modified hooks.
472+
* let modifiedShader;
473+
*
474+
* // Create a string with the vertex shader program.
475+
* // The vertex shader is called for each vertex.
476+
* let vertSrc = `
477+
* precision highp float;
478+
* uniform mat4 uModelViewMatrix;
479+
* uniform mat4 uProjectionMatrix;
480+
*
481+
* attribute vec3 aPosition;
482+
* attribute vec2 aTexCoord;
483+
*
484+
* void main() {
485+
* vec4 positionVec4 = vec4(aPosition, 1.0);
486+
* gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;
487+
* }
488+
* `;
489+
*
490+
* // Create a fragment shader that uses a hook.
491+
* let fragSrc = `
492+
* precision highp float;
493+
* void main() {
494+
* // Let users override the color
495+
* gl_FragColor = HOOK_getColor(vec4(1., 0., 0., 1.));
496+
* }
497+
* `;
498+
*
499+
* function setup() {
500+
* createCanvas(50, 50, WEBGL);
501+
*
502+
* // Create a shader with hooks
503+
* myShader = createShader(vertSrc, fragSrc, {
504+
* fragment: {
505+
* 'vec4 getColor': '(vec4 color) { return color; }'
506+
* }
507+
* });
508+
*
509+
* // Make a version of the shader with a hook overridden
510+
* modifiedShader = myShader.modify({
511+
* 'vec4 getColor': `(vec4 color) {
512+
* return vec4(0., 0., 1., 1.);
513+
* }`
514+
* });
515+
* }
516+
*
517+
* function draw() {
518+
* noStroke();
519+
*
520+
* push();
521+
* shader(myShader);
522+
* translate(-width/3, 0);
523+
* sphere(10);
524+
* pop();
525+
*
526+
* push();
527+
* shader(modifiedShader);
528+
* translate(width/3, 0);
529+
* sphere(10);
530+
* pop();
531+
* }
532+
* </code>
533+
* </div>
456534
*/
457535
p5.prototype.createShader = function (vertSrc, fragSrc, options) {
458536
p5._validateParameters('createShader', arguments);
@@ -841,6 +919,9 @@ p5.prototype.shader = function (s) {
841919
* - `vec4 getFinalColor`: Update the final color after mixing. It takes in a `vec4 color` and must return a modified version.
842920
* - `void afterFragment`: Called at the end of the fragment shader.
843921
*
922+
* Most of the time, you will need to write your hooks in GLSL ES version 300. If you
923+
* are using WebGL 1 instead of 2, write your hooks in GLSL ES 100 instead.
924+
*
844925
* Call `materialShader().inspectHooks()` to see all the possible hooks and
845926
* their default implementations.
846927
*
@@ -883,6 +964,41 @@ p5.prototype.shader = function (s) {
883964
* function setup() {
884965
* createCanvas(200, 200, WEBGL);
885966
* myShader = materialShader().modify({
967+
* declarations: 'vec3 myNormal;',
968+
* 'Inputs getPixelInputs': `(Inputs inputs) {
969+
* myNormal = inputs.normal;
970+
* return inputs;
971+
* }`,
972+
* 'vec4 getFinalColor': `(vec4 color) {
973+
* return mix(
974+
* vec4(1.0, 1.0, 1.0, 1.0),
975+
* color,
976+
* abs(dot(myNormal, vec3(0.0, 0.0, 1.0)))
977+
* );
978+
* }`
979+
* });
980+
* }
981+
*
982+
* function draw() {
983+
* background(255);
984+
* rotateY(millis() * 0.001);
985+
* shader(myShader);
986+
* lights();
987+
* noStroke();
988+
* fill('red');
989+
* torus(30);
990+
* }
991+
* </code>
992+
* </div>
993+
*
994+
* @example
995+
* <div modernizr='webgl'>
996+
* <code>
997+
* let myShader;
998+
*
999+
* function setup() {
1000+
* createCanvas(200, 200, WEBGL);
1001+
* myShader = materialShader().modify({
8861002
* 'Inputs getPixelInputs': `(Inputs inputs) {
8871003
* vec3 newNormal = inputs.normal;
8881004
* // Simple bump mapping: adjust the normal based on position
@@ -943,6 +1059,9 @@ p5.prototype.materialShader = function() {
9431059
* - `vec4 getFinalColor`: Update the final color after mixing. It takes in a `vec4 color` and must return a modified version.
9441060
* - `void afterFragment`: Called at the end of the fragment shader.
9451061
*
1062+
* Most of the time, you will need to write your hooks in GLSL ES version 300. If you
1063+
* are using WebGL 1 instead of 2, write your hooks in GLSL ES 100 instead.
1064+
*
9461065
* Call `normalShader().inspectHooks()` to see all the possible hooks and
9471066
* their default implementations.
9481067
*
@@ -1030,6 +1149,9 @@ p5.prototype.normalShader = function() {
10301149
* - `vec4 getFinalColor`: Update the final color after mixing. It takes in a `vec4 color` and must return a modified version.
10311150
* - `void afterFragment`: Called at the end of the fragment shader.
10321151
*
1152+
* Most of the time, you will need to write your hooks in GLSL ES version 300. If you
1153+
* are using WebGL 1 instead of 2, write your hooks in GLSL ES 100 instead.
1154+
*
10331155
* Call `colorShader().inspectHooks()` to see all the possible hooks and
10341156
* their default implementations.
10351157
*
@@ -1092,6 +1214,9 @@ p5.prototype.colorShader = function() {
10921214
* - `vec4 getFinalColor`: Update the final color after mixing. It takes in a `vec4 color` and must return a modified version.
10931215
* - `void afterFragment`: Called at the end of the fragment shader.
10941216
*
1217+
* Most of the time, you will need to write your hooks in GLSL ES version 300. If you
1218+
* are using WebGL 1 instead of 2, write your hooks in GLSL ES 100 instead.
1219+
*
10951220
* Call `strokeShader().inspectHooks()` to see all the possible hooks and
10961221
* their default implementations.
10971222
*

src/webgl/p5.Shader.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,24 @@ p5.Shader = class {
216216
return preMain + hooks + main + postMain;
217217
}
218218

219+
/**
220+
* Shaders are written in <a href="https://developer.mozilla.org/en-US/docs/Games/Techniques/3D_on_the_web/GLSL_Shaders">GLSL</a>, but
221+
* there are different versions of GLSL that it might be written in.
222+
*
223+
* Calling this method on a `p5.Shader` will return the GLSL version it uses, either `100 es` or `300 es`.
224+
* WebGL 1 shaders will only use `100 es`, and WebGL 2 shaders may use either.
225+
*
226+
* @returns {String} The GLSL version used by the shader.
227+
*/
228+
version() {
229+
const match = /#version (.+)$/.exec(this.vertSrc());
230+
if (match) {
231+
return match[1];
232+
} else {
233+
return '100 es';
234+
}
235+
}
236+
219237
vertSrc() {
220238
return this.shaderSrc(this._vertSrc, 'vertex');
221239
}

0 commit comments

Comments
 (0)