[Solved] How to make an interpolated Triangle w/ vertex & pixel shaders?

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
AllanAxolotls
Prole
Posts: 7
Joined: Sun Jan 22, 2023 3:42 pm

[Solved] How to make an interpolated Triangle w/ vertex & pixel shaders?

Post by AllanAxolotls »

I've been trying to make one of those interpolated triangles that has 3 main colors at the vertices of a triangle: Red, Green and Blue. However, I have absolutely no idea how to implement this in Love2D with GLSL. I'm trying to follow a tutorial that is focused on OpenGL and GLSL and all of those other libraries and they go from Vertex Shader to Fragment Shader and that somehow interpolates some color. However, since I can't use the "in" and "out" keywords, I really just don't know how to make this. The code also uses gl_VertexID which doesn't seem to work either. Next to that, when I try to make an int value, it asks for it to be a "flat in" if I put it under: "#ifdef PIXEL", but when I add it infront of my constructor I get "Unexpected Identifier" with "flat in int MyInteger;". Everything is just a mess and it's only getting worse! Help is very much appreciated. Since I'm new to using shaders and love2d I might have made a dumb mistake. I don't know if I'm allowed to link the tutorial so I didn't include the link. I believe there was another post with the same topic, but there was not a solution for it and maybe there is one now. I'm trying to make a 3D renderer btw. So I first transform my triangles using the vertex shader, but then I want to add those interpolated colors, just like the tutorial.
Last edited by AllanAxolotls on Sat Jan 28, 2023 8:55 am, edited 3 times in total.
User avatar
Bigfoot71
Party member
Posts: 287
Joined: Fri Mar 11, 2022 11:07 am

Re: How to make an interpolated Triangle w/ vertex & pixel shaders?

Post by Bigfoot71 »

Something that looks like this? (I slightly customized it to my taste). Say if it's good what you want to talk about when you say "interpolated triangles" and by the way why do you want to do it on Löve2d and not directly with OpenGL which seems more appropriate to me? (in the sense that you'll learn more by wanting to do it directly on OpenGL but that's just my opinion)

Code: Select all

local lg = love.graphics

-- Create the triangle vertices
local vertices = {
    {-0.5, -0.5, 1, 0, 0},
    {0.5, -0.5, 0, 1, 0},
    {0, 0.5, 0, 0, 1}
}

-- Create a new mesh to hold the triangle
local triangle = lg.newMesh(vertices, "triangles")

-- Create the color interpolation shader
local shader = lg.newShader[[
    extern number time;
    vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) {
        return vec4(texture_coords, sin(time), 1.0);
    }
]]

function love.draw()
    shader:send("time", love.timer.getTime())
    lg.setShader(shader)
    lg.draw(triangle,lg.getWidth()/2,lg.getHeight()/2,0,100,100)
    lg.setShader()
end
In any case this page could help you: https://love2d.org/wiki/Shader_Variables
And to pass values ​​from a vertex shader to the fragment shader you can use `varying`.

Edit:

By reading your post a bit and doing some research I think I understood what you want, here is what I did, from what I understood from your post you must have the basics to understand how the code works but if you have any doubts do not hesitate to ask me:

Code: Select all

local lg = love.graphics

-- Create attributes of the triangle

local attributes = {
    {"VertexPosition", "float", 2},
    {"VertexColor", "byte", 4},
}

-- Create the triangle vertices

local vertices = {
    {-0.5, -0.5, 1, 0, 0},
    {0.5, -0.5, 0, 1, 0},
    {0, 0.5, 0, 0, 1}
}

-- Create a new mesh to hold the triangle

local triangle = lg.newMesh(attributes, vertices, "triangles", "static")

-- Set up the color interpolation shader
local shader = lg.newShader([[

    varying vec4 vColor;

    vec4 position( mat4 transform_projection, vec4 vertex_position ) {
        vColor = VertexColor;
        return transform_projection * vertex_position;
    }

]], [[

    varying vec4 vColor;

    vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) {
        return vColor;
    }

]])

function love.draw()

    lg.setShader(shader)
    lg.draw(triangle,lg.getWidth()/2,lg.getHeight()/2,0,200,200)
    lg.setShader()

end
I had never done it before but with these pages from the Löve2D documentation: love.graphics.newMesh and Shader Variables.

And also this page which made me understand what you wanted I managed to realize it, so I hope that with all this you will also understand and that you can redo it to your sauce ^^
Attachments
Triangle-interpolation.love
(578 Bytes) Downloaded 89 times
Last edited by Bigfoot71 on Sun Jan 22, 2023 11:07 pm, edited 2 times in total.
My avatar code for the curious :D V1, V2, V3.
RNavega
Party member
Posts: 355
Joined: Sun Aug 16, 2020 1:28 pm

Re: How to make an interpolated Triangle w/ vertex & pixel shaders?

Post by RNavega »

I think you can just use the "varying" qualifier to describe an interpolated out in the vertex shader, as seen in this macro here in the Löve source:
https://github.com/love2d/love/blob/mai ... r.lua#L202

Edit: hm, and using "varying" again for the in attribute in the fragment shader, as seen a few lines below with another macro:
https://github.com/love2d/love/blob/mai ... r.lua#L248
User avatar
Bigfoot71
Party member
Posts: 287
Joined: Fri Mar 11, 2022 11:07 am

Re: How to make an interpolated Triangle w/ vertex & pixel shaders?

Post by Bigfoot71 »

RNavega wrote: Sun Jan 22, 2023 10:35 pm I think you can just use the "varying" qualifier to describe an interpolated out in the vertex shader, as seen in this macro here in the Löve source:
https://github.com/love2d/love/blob/mai ... r.lua#L202

Edit: hm, and using "varying" again for the in attribute in the fragment shader, as seen a few lines below with another macro:
https://github.com/love2d/love/blob/mai ... r.lua#L248
Exactly, after I must admit that launching nothing with only OpenGL tutorials and this information on "varying" and no other basis, I'm not sure that we can achieve it. Personally I think I could have given up if I put myself in his place. Quite special anyway what you have set yourself as a goal with Löve2D I think, but the biggest ones start like this ^^

(then maybe there is a simpler method than mine and that I am getting the wrong ideas?)
My avatar code for the curious :D V1, V2, V3.
RNavega
Party member
Posts: 355
Joined: Sun Aug 16, 2020 1:28 pm

Re: How to make an interpolated Triangle w/ vertex & pixel shaders?

Post by RNavega »

@Bigfoot71 hi. I'm not sure if I understand what you mean, but your added code at the end, with "varying vec4 vColor", looks exactly what needs to be done: a value calculated in the vertex shader stage passed around to the fragment stage using "varying", which is a legacy keyword that when used in shader code with Löve will be shadowed by Löve's #DEFINE macros.

Using that, if the GLSL version in the device running Löve is below 1.30, it'll stay as the legacy "varying" qualifier, and if it's above, it'll be overriden to be "out" in the vertex shader and "in" in the pixel shader, with no interpolation qualifiers at all, defaulting to "smooth" interpolation, as per the OpenGL wiki.

Cheers
User avatar
Bigfoot71
Party member
Posts: 287
Joined: Fri Mar 11, 2022 11:07 am

Re: How to make an interpolated Triangle w/ vertex & pixel shaders?

Post by Bigfoot71 »

Note that I added the vertex shader as an example to show how to pass a variable from the vertex to the fragment, but the variable `VertexColor` to a correspondence directly offered by Löve accessible in the fragment shader which is `VaryingColor` so the last shader that I proposed can be simplified like this:

Code: Select all

local shader = lg.newShader([[
    vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) {
        return VaryingColor;
    }
]])
Hence the fact that I say that doing it directly in OpenGL allows you to learn more because Löve does a lot of work for us at this level. After once this kind of basic acquired Löve still allows you to progress faster on learning because this kind of tests are faster to perform in Lua but you must already have these basics. Hence once again the fact that I wonder about the usefulness of following an OpenGL tutorial with Löve2d, after again it's only my opinion, I may be wrong.

Edit: I'm thinking about it but if you really want to do all that in Löve2d I can only recommend this blog post on shaders in Löve2d which is very useful! ^^ https://blogs.love2d.org/content/beginn ... de-shaders
My avatar code for the curious :D V1, V2, V3.
AllanAxolotls
Prole
Posts: 7
Joined: Sun Jan 22, 2023 3:42 pm

Re: How to make an interpolated Triangle w/ vertex & pixel shaders?

Post by AllanAxolotls »

Bigfoot71 wrote: Sun Jan 22, 2023 10:11 pm Something that looks like this? (I slightly customized it to my taste). Say if it's good what you want to talk about when you say "interpolated triangles" and by the way why do you want to do it on Löve2d and not directly with OpenGL which seems more appropriate to me? (in the sense that you'll learn more by wanting to do it directly on OpenGL but that's just my opinion)

Code: Select all

local lg = love.graphics

-- Create the triangle vertices
local vertices = {
    {-0.5, -0.5, 1, 0, 0},
    {0.5, -0.5, 0, 1, 0},
    {0, 0.5, 0, 0, 1}
}

-- Create a new mesh to hold the triangle
local triangle = lg.newMesh(vertices, "triangles")

-- Create the color interpolation shader
local shader = lg.newShader[[
    extern number time;
    vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) {
        return vec4(texture_coords, sin(time), 1.0);
    }
]]

function love.draw()
    shader:send("time", love.timer.getTime())
    lg.setShader(shader)
    lg.draw(triangle,lg.getWidth()/2,lg.getHeight()/2,0,100,100)
    lg.setShader()
end
In any case this page could help you: https://love2d.org/wiki/Shader_Variables
And to pass values ​​from a vertex shader to the fragment shader you can use `varying`.

Edit:

By reading your post a bit and doing some research I think I understood what you want, here is what I did, from what I understood from your post you must have the basics to understand how the code works but if you have any doubts do not hesitate to ask me:

Code: Select all

local lg = love.graphics

-- Create attributes of the triangle

local attributes = {
    {"VertexPosition", "float", 2},
    {"VertexColor", "byte", 4},
}

-- Create the triangle vertices

local vertices = {
    {-0.5, -0.5, 1, 0, 0},
    {0.5, -0.5, 0, 1, 0},
    {0, 0.5, 0, 0, 1}
}

-- Create a new mesh to hold the triangle

local triangle = lg.newMesh(attributes, vertices, "triangles", "static")

-- Set up the color interpolation shader
local shader = lg.newShader([[

    varying vec4 vColor;

    vec4 position( mat4 transform_projection, vec4 vertex_position ) {
        vColor = VertexColor;
        return transform_projection * vertex_position;
    }

]], [[

    varying vec4 vColor;

    vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) {
        return vColor;
    }

]])

function love.draw()

    lg.setShader(shader)
    lg.draw(triangle,lg.getWidth()/2,lg.getHeight()/2,0,200,200)
    lg.setShader()

end
I had never done it before but with these pages from the Löve2D documentation: love.graphics.newMesh and Shader Variables.

And also this page which made me understand what you wanted I managed to realize it, so I hope that with all this you will also understand and that you can redo it to your sauce ^^
It works! When I used love.graphics.newShader, the first argument I used was the fragment shader instead of the vertex shader, could that have caused issues? It looked like this:

Code: Select all

shader = love.graphics.newShader(FragmentCode, VertexCode)
So from what I can understand, varying vColor will be shared across the fragment shader and the vertex shader, but somewhere in between that process it gets interpolated by the rasterizer. Is that correct? Thank you so much! Also, how do I mark a solution on this site? :rofl:
User avatar
Bigfoot71
Party member
Posts: 287
Joined: Fri Mar 11, 2022 11:07 am

Re: How to make an interpolated Triangle w/ vertex & pixel shaders?

Post by Bigfoot71 »

The order for arguments between vertex and fragment shader doesn't matter, love2d detects the `effect` and `position` functions itself, you can even combine them into one in the `newShader` parameter like this (as it says in the doc for love.graphics.newShader):

Code: Select all

lg.newShader[[

    varying vec4 vpos;

    #ifdef VERTEX
    vec4 position( mat4 transform_projection, vec4 vertex_position )
    {
        vpos = vertex_position;
        return transform_projection * vertex_position;
    }
    #endif

    #ifdef PIXEL
    vec4 effect( vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords )
    {
        texture_coords += vec2(cos(vpos.x), sin(vpos.y));
        vec4 texcolor = Texel(tex, texture_coords);
        return texcolor * color;
    }
    #endif

]]
Finally `VertexColor` precisely represents the color of a vertex in shaders, it is generally used to give a specific color to each vertex of a polygon, rather than using a single color for the whole polygon, in "real" use this can help create color transition effects on the edges of polygons, among other things. Or rather as it is written in the page Shader variables of the doc: "The color of the vertex, sprite, or text character if a Mesh, SpriteBatch, or Text object with per-vertex colors is drawn"

For more details and to answer your question, YES, from what I know the VertexColor variable, which is defined in the vertex shader, is assigned a value for each vertex in the geometry, then when those vertices are connected to form triangles, the rasterizer uses a barycentric interpolation algorithm to interpolate the VertexColor values ​​between the vertices. This means that for each pixel in a triangle, the rasterizer determines an interpolated value of vColor based on the position of the pixel relative to the vertices of the triangle. These interpolated values ​​are then used by the fragment shader to determine the final color of the pixel.

In summary the barycentric interpolation algorithm is used to interpolate the values ​​of the triangle according to their position relative to the vertices of the triangle but it is also used to calculate the values ​​of variables such as normals, texture coordinates, etc for each pixel in the triangle. If you're interested in math, there's this Wikipedia article that looks pretty good: https://en.wikipedia.org/wiki/Interpolation

If you want to say that the problem is solved you can edit the title of your question and add a small [Solved] for example ^^

(If I ever made any inaccuracies or errors please correct me, I also encourage you to do your own research ^^)
My avatar code for the curious :D V1, V2, V3.
AllanAxolotls
Prole
Posts: 7
Joined: Sun Jan 22, 2023 3:42 pm

Re: How to make an interpolated Triangle w/ vertex & pixel shaders?

Post by AllanAxolotls »

That's nice! Now I just need to find a way to also include the Z-axis in the vertices when I create the new triangle mesh. Somewhere on the docs of love2d it was stated that using .newMesh a lot per frame can cause performance issues. So I want to just make a main array that holds every triangle mesh in the "World". However, when using .newMesh, doesn't the z data of all the vertices get lost? When I scrolled through the docs of love.graphics.newMesh I couldn't find any argument for a z-axis. This way the data wouldn't transfer to the VertexShader. Is there any solution for this?
User avatar
Bigfoot71
Party member
Posts: 287
Joined: Fri Mar 11, 2022 11:07 am

Re: [Solved] How to make an interpolated Triangle w/ vertex & pixel shaders?

Post by Bigfoot71 »

Well here you are getting into something big with Löve2D but to add the Z axis in the meshes it seems to me that you only have to modify the `VertexPosition` value in the attributes like this:

Code: Select all

local attributes = {
    {"VertexPosition", "float", 3},
    {"VertexColor", "byte", 4},
}
I changed `{"VertexPosition", "float", 2}` to ` {"VertexPosition", "float", 3}`. Otherwise yes the use of a lot of meshes has an impact on performance but like everything I want to say, it's just a warning to say "use only what is necessary", if I understand correctly your question.

Otherwise, unless you want to completely recreate a 3D engine with Löve2D (I don't really understand what you want to do) you can use the g3d library which is just awesome and very easy to use ^^
Last edited by Bigfoot71 on Mon Jan 23, 2023 4:02 pm, edited 1 time in total.
My avatar code for the curious :D V1, V2, V3.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Google [Bot] and 4 guests