Set same source texture for n shapes.

edited July 2016 in GLSL / Shaders

Hi all. Very new to shaders, but I've done a fair bit of research.

My sketch is trying to emulate an image "shatter" - a bunch of different PShapes fly around, all with static UV coordinates referencing the same image. Imagine a stained glass window smashing - little bits of image everywhere.

I have things working, albeit slowly, and have been told I can improve my performance with shaders.

I've tried to create a simple working version before implementing into the full sketch. Just trying to draw one PShape with a texture.

Sketch

PShader myShader;
PShape myShape;
PImage myImage;

void setup(){
    size(200, 200, P3D);

    myImage = loadImage("Grug.jpg");
    myShader = loadShader("frag.glsl", "vert.glsl");
    myShape = createShape();

    myShape.beginShape();
    myShape.noFill();
    myShape.noStroke();
    myShape.vertex(20, 20, 20, 20);
    myShape.vertex(80, 20, 80, 20);
    myShape.vertex(80, 80, 80, 80);
    myShape.vertex(20, 80, 20, 80);
    myShape.endShape();
}

void draw(){
    background(150);
    myShader.set("myImage", myImage);
    shader(myShader);
    shape(myShape);
}

Vert shader

#define PROCESSING_TEXTURE_SHADER

uniform mat4 transform;
uniform mat4 texMatrix;

attribute vec4 vertex;
attribute vec4 color;
attribute vec2 texCoord;

varying vec4 vertColor;
varying vec4 vertTexCoord;

void main() {
  gl_Position = transform * vertex;

  vertColor = color;
  vertTexCoord = texMatrix * vec4(texCoord, 1.0, 1.0);
}

Frag shader

#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif

uniform sampler2D texture;
uniform sampler2D myImage;

varying vec4 vertColor;
varying vec4 vertTexCoord;

void main() {
    gl_FragColor = texture2D(myImage, vertTexCoord.st);
}

However, nothing displays. Note that I want to avoid calling myShape.texture(myImage) when defining the shape. This call does make things work, but on a large scale the framerate dives.

I'm pretty sure it's possible to have a few thousand verts flying about referencing the same texture - please correct me if I'm mistaken. What am I missing? Or is my approach a bit wonky?! Shaders have been a bit to wrap my head around.

Thanks in advance! (Mac OSX 10.11.5, Processing 3.1.1.)

Answers

  • that looks a lot like the example here: https://processing.org/tutorials/pshader/ (code listing 5.1)

    except you are missing a multiplication at the end of fragColor call.

    also, your vertexes are only 2d.

    and calling noStroke() and noFill(), would that mean you aren't drawing anything to the screen? and if you aren't drawing anything then the shader won't be called. try fill(255);

  • Aha, I removed the last fragColor multiplication while trying something. Have put it back in.

    If I set a fill() for the shape, I get this message when I run the skecth: Your shader needs to be of COLOR type to render this geometry properly, using default shader instead. Which goes away when I call noFill() - I thought this might be the way to push vertices to the shader and assign the fill information there.

    Is there another way to make a shape without a .texture() call work with a PROCESSING_TEXTURE_SHADER?

    Thanks!

  • Have you had a look at this tutorial? https://processing.org/tutorials/pshader/

  • Yep, read that a couple of times. I've done a fair bit of digging on this, and it feels like I've got something fundamental a bit twisted. I'll elaborate on my confusion:

    From my understanding of shaders, they get passed a bunch of vertices (in Processing's case, using shader() and vertex() calls), and the shader will run over those vertices and the fragments they construct.

    From the fragment shader I have above, I don't see why this line:

    gl_FragColor = texture2D(myImage, vertTexCoord.st);

    isn't creating a visible outcome.

    Either A) the shader is not being applied to the vertices, B) the shader is missing something that would make it produce a visible outcome, or C) the texture isn't coming into the shader properly.

    Hope that clears things up a little - any light? Thanks again.

  • edited July 2016

    How about:

    gl_FragColor = vec4(texture2D(myImage,vertTexCoord.st).rgb,1.0);

    texture2D returns a vec4, so I don't really see why what you have isn't working, but making sure the alpha channel is set to 1.0 won't hurt. A lot of problems I have in glsl seem to be related its strict handling of types.

  • Still no cigar, thanks though.

    I've done a bit more experimenting though, with the following tweak:

    Sketch:

    PShader myShader;
    
    PShape myShape;
    
    PImage imageOne;
    PImage imageTwo;
    
    float[] uvs;
    
    void setup(){
        size(200, 200, P3D);
    
        myShader = loadShader("frag.glsl", "vert.glsl");
        imageOne = loadImage("Grug.jpg");
        imageTwo = loadImage("Grug_Cover_Field.jpg");
    
        myShape = createShape();
    
        myShape.beginShape();
        myShape.noFill();
        myShape.noStroke();
        myShape.texture(imageOne);
        myShape.vertex(20, 20, 20, 20);
        myShape.vertex(80, 20, 80, 20);
        myShape.vertex(80, 80, 80, 80);
        myShape.vertex(20, 80, 20, 80);
        myShape.endShape();
    
    }
    
    void draw(){
        background(150);
        myShader.set("myImage", imageTwo);
        shader(myShader);
        shape(myShape);
    }
    

    Frag:

    #ifdef GL_ES
    precision mediump float;
    precision mediump int;
    #endif
    
    uniform sampler2D texture;
    uniform sampler2D myImage;
    
    varying vec4 vertColor;
    varying vec4 vertTexCoord;
    
    void main() {
        gl_FragColor = texture2D(myImage, vertTexCoord.xy) * vertColor;
    }
    

    I set myShape.texture(imageOne), but imageTwo is being displayed. This makes sense - the shader only uses the "myImage" sampler2d, it doesn't touch the default "texture" sampler2D.

    However, without a call to myShape.texture(), nothing displays. The same is true when calling myShape.texture(null).

    So, I believe, this means that using the .texture() call is the only way for Processing to allow vertices to use a PROCESSING_TEXTURE_SHADER.

    Is there another way to allow a set of vertices to use a texture shader?

    Would it be possible to "fake" a TEXTURE shader by using a COLOR shader, and manually passing through UV and texture matrix information via custom attributes and uniforms?

    Thanks team.

Sign In or Register to comment.