p5.js-website
p5.js-website copied to clipboard
"Shader as Texture" example
The current example "Shader as a Texture" uses createGraphics()
and texture()
to apply the output of the shader as a material for the geometry.
However, I think a better approach would be to just use the shader()
function and avoid all these extra steps. Here is a live example of said changes (and a simpler example by aferriss (live, src)). The example can then be renamed as "Shader as a Material".
function preload() {
myShader = loadShader("shader.vert", "shader.frag");
}
function draw() {
...
// shader() sets the active shader with our shader
shader(myShader);
...
// Draw some geometry to the screen
box(width / 4);
}
To demonstrate how createGraphics
can be useful with shaders, I propose adding a second example titled "Multipass Shader" that demonstrates how createGraphics
can be used to achieve multiple render passes. For this second example, I would like to add the Texture Delay example (live, src) by @aferriss. (Or maybe the Multi-Pass Blur is a better example due to simpler code (live, src). Though it is not as visually striking with regards to multiple passes).
Would you like to work on the issue?
Yes
I think the idea for the Shader as a Texture example is to show that you can use one buffer as a texture for a 3d model, so maybe there's a better way to show that. Perhaps something that is doing texture based manipulations on a texture, like a simple blur or something would better illustrate the point here.
Maybe an example that renders 2 3d scenes, and uses the first as a texture for the second could work?
Ah, I see.
I think the idea for the Shader as a Texture example is to show that you can use one buffer as a texture for a 3d model
Would it be better to move such an example from the "Shaders" section to "Textures" section? I.e. treat it as a texture example rather than a shader example. For example, currently in the reference docs for texture()
, there are a couple of examples demonstrating different ways to generate a texture (such as loadImage, loadVideo, createGraphics). What if a simple example of generating a texture from a shader is appended here? Likewise for the "Textures" example.
Perhaps something that is doing texture based manipulations on a texture, like a simple blur or something would better illustrate the point here.
For demonstrating texture based manipulation, would your "Single Pass Blur" be a good candidate for this (live, src)?
function preload(){
// load the shader
camShader = loadShader('effect.vert', 'effect.frag');
}
function setup() {
...
// initialize the webcam at the window size
cam = createCapture(VIDEO);
cam.size(windowWidth, windowHeight);
...
}
function draw() {
// shader() sets the active shader with our shader
shader(camShader);
// lets just send the cam to our shader as a uniform
camShader.setUniform('tex0', cam);
// also send the size of 1 texel on the screen
camShader.setUniform('texelSize', [1.0/width, 1.0/height]);
...
}
// lets grab texcoords just for fun
varying vec2 vTexCoord;
// our texture coming from p5
uniform sampler2D tex0;
uniform vec2 texelSize;
void main() {
vec2 uv = vTexCoord;
// the texture is loaded upside down and backwards by default so lets flip it
uv = 1.0 - uv;
...
// create our offset variable by multiplying the size of a texel with spread
vec2 offset = texelSize * spread;
// get all the neighbor pixels!
vec4 tex = texture2D(tex0, uv); // middle middle -- the actual texel / pixel
tex += texture2D(tex0, uv + vec2(-offset.x, -offset.y)); // top left
tex += texture2D(tex0, uv + vec2(0.0, -offset.y)); // top middle
tex += texture2D(tex0, uv + vec2(offset.x, -offset.y)); // top right
...
gl_FragColor = tex;
}
Maybe an example that renders 2 3d scenes, and uses the first as a texture for the second could work?
This is what I'm hoping to demonstrate by potentially adding either "Texture Delay" (live, src) or "Multi-Pass Blur" (live, src) as a multipass shader example.
function preload(){
// load the shaders, we will use the same vertex shader and frag shaders for both passes
blurH = loadShader('base.vert', 'blur.frag');
blurV = loadShader('base.vert', 'blur.frag');
}
function setup() {
...
// initialize the createGraphics layers
pass1 = createGraphics(windowWidth, windowHeight, WEBGL);
pass2 = createGraphics(windowWidth, windowHeight, WEBGL);
...
}
function draw() {
// set the shader for our first pass
pass1.shader(blurH);
// send the camera texture to the horizontal blur shader
// send the size of the texels
// send the blur direction that we want to use [1.0, 0.0] is horizontal
blurH.setUniform('tex0', cam);
blurH.setUniform('texelSize', [1.0/width, 1.0/height]);
blurH.setUniform('direction', [1.0, 0.0]);
...
// set the shader for our second pass
pass2.shader(blurV);
// instead of sending the webcam, we will send our first pass to the vertical blur shader
// texelSize remains the same as above
// direction changes to [0.0, 1.0] to do a vertical pass
blurV.setUniform('tex0', pass1);
blurV.setUniform('texelSize', [1.0/width, 1.0/height]);
blurV.setUniform('direction', [0.0, 1.0]);
// again, make sure we have some geometry to draw on in our 2nd pass
pass2.rect(0,0,width, height);
// draw the second pass to the screen
image(pass2, 0,0, width, height);
}
I've spent some time working on the shader examples as commented above.
Below is a list of current and potential examples as they would appear on the examples page.
- "Basic Shader"
// Rect gives us some geometry
rect(-width / 2, -height / 2, width, height);
/* Uncomment to try.
Use box geometry instead.
*/
// clear();
// rotateX(millis() * 0.0005);
// rotateY(millis() * 0.00025);
// box(width / 4);
-
"Shader as Texture"
- propose removing this example for the reasons above
- to demonstrate when
texture()
would be useful with shaders, I think the multipass example below is a better candidate (since the resulting code is messier without it)
-
"Passing Shader Uniforms"
- not modified
-
"Shader Using Webcam"
- not modified
-
"Texel Manipulation Shader"
- live demo with source code
- demonstrates how a texture's texels can be sampled and manipulated
- not sure what the best name for this example is
-
"Multipass Shader"
- live demo with source code
- demonstrates how "buffers" (made by
createGraphics()
) can be used to emulate "passes" - demonstrates practical use case for
texture()
with shaders - (the TODOs will be replaced with proper descriptions)
-
"Matrix-Unaware Shader" / "Shader Using Pixel Coordinates"
- live demo with source code
- demonstrates how to write shaders that do not use model/view/projection matrices and instead use absolute pixel coordinates (via
gl_FragCoord
) - the code in the demo is based on the current "shader as texture" example
- not sure what the best name for this example is
@aferriss What do you think?