[Solved] How to apply shader?

I want to create just simple rectangular grid with shaders. I tried to search but haven’t found how to’s or examples, not for shader’s code itself (internet is full of such examples), but how to apply that shader in defold.

Am I understand it right. That instead of adding a sprite and material to it, I just should create texture in code with resourse.create_texture() and then somehow apply material to this texture (haven’t found how). Or I’m heading in the wrong direction?
Any example?

Can you describe a bit more in detail what you want to achieve?

Just a frame grid with transparent squares and only visible grid

Maybe it is simpler to just create it with a factory and a sprite of 1 square frame? But then I’m thinking of changing the transparency of it on runtime, so double frames would be half as transparent right?
So this approach would require more memory, but faster at runtime?

I have something similar for prototyping. I’ll share the shader project later today

2 Likes

I obviously have read this links before. Or I’m totally missing something, or in my opinion they are not answering my question.

I have something similar for prototyping. I’ll share the shader project later today

Thanks, will wait for it for sure.

You need three things:

  1. A mesh (surface) to draw your grid on
  2. A material with a shader program that is used by the model component
  3. A shader program that draws a grid

1. Mesh to draw on
Here you can for instance add a model component to a game object and use the /builtins/assets/meshes/quad.dae which is a basic rectangle

2. A material with a shader program that is used by the model component
Copy the default model.material and model.vp and model.fp from /builtins/materials. Edit your copy of the model.material so that it uses your copied model.vp and model.fp. In the example below I decided to name my material grid.material:

3. A shader program that draws a grid
Like you said, there are many such shaders on shader toy.

https://www.google.com/search?q=shadertoy+grid+shader

One additional thing to consider is how the mesh should be rendered. You can keep the default projection in the render script and simply stretch the game object with the mesh so that it covers the entire screen. The mesh will be 1x1 pixel but if you stretch the game object to the size of the display it will obviously cover the entire screen. The other option is to add a perspective camera and position it so that your mesh is rendered properly.

Here’s me using the default projection and simply stretching the game object with the mesh:

And the result:

The gradient is done with some basic modifications of the default model.fp:

void main()
{
    // Pre-multiply alpha since all runtime textures already are
    vec4 tint_pm = vec4(tint.xyz * tint.w, tint.w);
    vec4 color = texture2D(tex0, var_texcoord0.xy) * tint_pm;
    color.x = var_texcoord0.x;
    color.y = var_texcoord0.y;

    // Diffuse light calculations
    vec3 ambient_light = vec3(1.0);
    vec3 diff_light = vec3(normalize(var_light.xyz - var_position.xyz));
    diff_light = max(dot(var_normal,diff_light), 0.0) + ambient_light;
    diff_light = clamp(diff_light, 0.0, 1.0);

    gl_FragColor = vec4(color.rgb*diff_light,1.0);
}

The ambient_light was set to 1.0 and the color takes the UV’s as input.

Now that you have this setup it should be possible for you to simply replace the fragment program to whatever shadertoy shader you find. Good luck!

3 Likes

Thank You. That’s answers my question. Going to try it right now.

So to understand it better, when you create a sprite you are under the hood creating model with quad mesh too?

1 Like

It works. Thanks again.

1 Like

Not exactly a model, but there will be an underlying set of triangles that are drawn using the sprite shader which will be sampling pixels from a texture, optionally applying a tint to the pixel color.

@britzl Could I disturb one more time?
I have a code for a grid (it’s not exactly what I want, but for now it draws some grid). But to work futher seems like I can’t make it transparent whatever I do. I have a scene with this model and some sprite with an image. And it always draws red grid, but the image isn’t visible. Here is grid.fp

#version 330

in vec4 var_position;
in vec2 var_texcoord0;

out vec4 out_color;

void main()
{
    // How often to draw lines
    float interval = .1;
    // Line thiccness
    float thicc = .003;
    vec4 color = vec4(0, 0, 0, 0);

    // Draw gridlines based on UV (float offset used to center the grid)
    float offset = (thicc / 2) - ((1 - interval) / 2);
    if(mod(var_texcoord0.x + offset, interval) < thicc || mod(var_texcoord0.y + offset, interval) < thicc) {
        color.r = 1;
        color.a = 1;
    }

    out_color = vec4(color.rgb * color.a, color.a);
}

Since you are drawing a mesh/model there’s some extra tricks to transparency. I’m honestly not sure what the “correct” approach is, but you can try discarding pixels with an alpha value below a threshold, instead of setting alpha to 0. Here’s me doing the same in a noise shader:

I’m sure @jhonny.goransson , @Dragosha, @astrochili or someone else playing with 3D stuff can tell what the correct approach is :slight_smile:

1 Like

I decided to add this as an example:

I also added a noise shader example with a time value passed to the shader to animate it:

3 Likes

Seems you are right. I have found that I can make colors transparent, they just lie on opaque mesh.

Thats what I have for now

name: "grid"
tags: "model"
vertex_program: "/materials/grid/grid.vp"
fragment_program: "/materials/grid/grid.fp"
vertex_space: VERTEX_SPACE_LOCAL
vertex_constants {
  name: "mtx_worldview"
  type: CONSTANT_TYPE_WORLDVIEW
}
vertex_constants {
  name: "mtx_proj"
  type: CONSTANT_TYPE_PROJECTION
}
fragment_constants {
  name: "grid_color"
  type: CONSTANT_TYPE_USER
  value {
  }
}
fragment_constants {
  name: "cell_size"
  type: CONSTANT_TYPE_USER
  value {
  }
}
fragment_constants {
  name: "cell_border"
  type: CONSTANT_TYPE_USER
  value {
  }
}
#version 330

in vec4 position;
in vec2 texcoord0;

uniform vertex_constants {
    mat4 mtx_worldview;
    mat4 mtx_proj;
};

out vec4 var_position;
out vec2 var_texcoord0;

void main()
{
    vec4 p = mtx_worldview * vec4(position.xyz, 1.0);
    var_position = p;
    var_texcoord0 = texcoord0;
    gl_Position = mtx_proj * p;
}
#version 330

in vec4 var_position;
in vec2 var_texcoord0;

uniform fragment_constants {
    vec4 cell_border;
    vec4 cell_size;
    vec4 grid_color;
};

out vec4 out_color;

void main()
{
    vec4 color = vec4(0, 0, 0, 0);

    if(mod(var_texcoord0.x, cell_size.x) < cell_border.x
            || mod(var_texcoord0.y, cell_size.y) < cell_border.y) {
        color = grid_color;
    }

    out_color = vec4(color.rgb * color.a, color.a);
}
function init()
    local border = 2
    local size = 100
    local scale = go.get_scale() + vmath.vector3(border, border, 0)
    local cell_border = vmath.vector4(border / scale.x, border / scale.y, 0, 0)
    local cell_size = vmath.vector4()
    cell_size.x = size / scale.x
    cell_size.y = size / scale.y

    go.set("#model", "cell_border", cell_border)
    go.set("#model", "grid_color", vmath.vector4(0, 1, 0, 0.5))
    go.set("#model", "cell_size", cell_size)
end

I ended up using sprite
cell

With repeatable shader with some clipping on he edges.
End result is like this.

This may be because the default render_script draws models before sprites.
You need to either change the order or give them the same predicate.

    -- render `model` predicate for default 3D material
    --
    render.enable_state(render.STATE_CULL_FACE)
    render.draw(predicates.model, camera_world.frustum) ---  your grid <<<<<
    render.set_depth_mask(false)
    render.disable_state(render.STATE_CULL_FACE)

    -- render the other components: sprites, tilemaps, particles etc
    --
    render.enable_state(render.STATE_BLEND)
    render.draw(predicates.tile, camera_world.frustum) ---- others <<<<<
    render.draw(predicates.particle, camera_world.frustum)
    render.disable_state(render.STATE_DEPTH_TEST)
2 Likes

Thanks, will test it tomorrow.