0

Heello, everyone! I've been trying to write a script that uses GLSL to render a Mandelbrot set, but something weird is happening.

I call the effect functio like this:

vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords){

But, when I try to use the texture_coords values, say, like this:

vec2 c = vec2((texture_coords[0]-WD/2)/100, (texture_coords[1]-HT/2)/100);

It returns the same value for every pixel; if, on the other hand, I use screen_coords instead, it works, but I'm affraid that if I drag the window around it might fuzz with the results.

Why am I unable to retrieve texture_coords?

More insight on the program and the problems here


UPDATE

I have reworked the code, now it looks like this:

vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 window_coords)
{

    vec2 c = vec2( ( MinRe + window_coords[0] * ( MaxRe - MinRe ) / ( width + 1 ) ),
                   ( MaxIm - window_coords[1] * ( MaxIm - MinIm ) / ( height + 1 ) )
    );

    vec2 z = c;
    vec2 zn = vec2(0.0, 0.0);

    int n_iter = 0;

    while( (z[0]*z[0] + z[1]*z[1] < 4) && (n_iter < max_iter)) {
      zn[0] = z[0]*z[0] - z[1]*z[1] + c[0];
      zn[1] = 2* z[0]*z[1] + c[1];

      z[0] = zn[0];
      z[1] = zn[1];
      n_iter++;
}

Which works beautifully. But when I use texture_coords instead of window_coords, the code returns the same value to every pixel, despite the fact that the texture I'm using is the same size of the window.

Community
  • 1
  • 1
Vitu Tomaz
  • 61
  • 1
  • 8

2 Answers2

1

The problem is that some drawable objects of love.graphics don't set any texture coordinate if you don't load an image. So, instead of using draw.rectangle, you should use a Mesh:

A 2D polygon mesh used for drawing arbitrary textured shapes

In order to add a mesh object you can add to the load function:

function love.load()
    width, height = love.graphics.getDimensions( )
    local vertices = {
        {
            -- top-left corner 
            0, 0, -- position of the vertex
            0, 0, -- texture coordinate at the vertex position
            255, 0, 0, -- color of the vertex
        },
        {
            -- top-right corner 
            width, 0,
            1, 0, -- texture coordinates are in the range of [0, 1]
            0, 255, 0
        },
        {
            -- bottom-right corner 
            width, height,
            1, 1,
            0, 0, 255
        },
        {
            -- bottom-left corner 
            0, height,
            0, 1,
            255, 255, 0
        },
    }

    -- the Mesh DrawMode "fan" works well for 4-vertex Meshes.
    mesh = love.graphics.newMesh(vertices, "fan")

    -- ... other stuff here ...

end

and in the draw function:

function love.draw()
    -- ...
    love.graphics.draw(mesh,0,0)
    -- ...
end

The complete code, considering your previous question and my answer to that, adding some lines to manage the coordinate tranformations become:

function love.load()
    width, height = love.graphics.getDimensions( )
    local vertices = {
        {
            -- top-left corner 
            0, 0, -- position of the vertex
            0, 0, -- texture coordinate at the vertex position
            255, 0, 0, -- color of the vertex
        },
        {
            -- top-right corner 
            width, 0,
            1, 0, -- texture coordinates are in the range of [0, 1]
            0, 255, 0
        },
        {
            -- bottom-right corner 
            width, height,
            1, 1,
            0, 0, 255
        },
        {
            -- bottom-left corner 
            0, height,
            0, 1,
            255, 255, 0
        },
    }

    mesh = love.graphics.newMesh(vertices, "fan")

    GLSLShader = love.graphics.newShader[[
        vec4 black = vec4(0.0, 0.0, 0.0, 1.0);
        vec4 white = vec4(1.0, 1.0, 1.0, 1.0);
        extern int max_iter;
        extern vec2 size;
        extern vec2 left_top;

        vec4 clr(int n){
            if(n == max_iter){return black;}

            float m = float(n)/float(max_iter);
            float r = float(mod(n,256))/32;
            float g = float(128 - mod(n+64,127))/255;
            float b = float(127 + mod(n,64))/255;

            if (r > 1.0) {r = 1.0;}
            else{ 
                if(r<0){r = 0;}
            }

            if (g > 1.0) {g = 1.0;}
            else{
                if(g<0){g = 0;}
            }

            if (b > 1.0) {b = 1.0;}
            else{
                if(b<0){b = 0;}
            }
            return vec4(r, g, b, 1.0);
        }

        vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 window_coords){  

            vec2 c = vec2(texture_coords[0]*size[0] + left_top[0],texture_coords[1]*size[1] - left_top[1]);
            vec2 z = vec2(0.0,0.0);
            vec2 zn = vec2(0.0,0.0);
            int n_iter = 0;
            while ( (z[0]*z[0] + z[1]*z[1] < 4) &&  (n_iter < max_iter) ) {
                zn[0] = z[0]*z[0] - z[1]*z[1] + c[0];
                zn[1] = 2*z[0]*z[1] + c[1];
                z[0] = zn[0];
                z[1] = zn[1];
                n_iter++;
            }
            return clr(n_iter);
        }
    ]]

end

function love.draw()

    center_x = -0.5
    center_y = 0.0
    size_x = 3
    size_y = size_x*height/width
    GLSLShader:send("left_top",{center_x-size_x*0.5,center_y+size_y*0.5})
    GLSLShader:send("size",{size_x,size_y})
    GLSLShader:sendInt("max_iter",1024)

    love.graphics.setShader(GLSLShader)
    love.graphics.draw(mesh,0,0)
    love.graphics.setShader()
end
Bob__
  • 12,361
  • 3
  • 28
  • 42
0

But it's somewhat misguiding, because my texture was the size of the window, and it didn't work

Well, let's investigate that. You didn't exactly provide a lot of information, but let's look anyway.

(texture_coords[0]-WD/2)/100

What is that? Well, we know what texture_coords is. From the Love2D wiki:

The location inside the texture to get pixel data from. Texture coordinates are usually normalized to the range of (0, 0) to (1, 1), with the top-left corner being (0, 0).

So you subtract from this texture coordinate WD/2. You didn't bother mentioning what that WD value was. But regardless, you divide the result by 100.

So, what exactly is WD? Let's see if algebra can help:

val = (texture_coords[0]-WD/2)/100
val * 100 = texture_coords[0] - WD / 2
(val * 100) - texture_coords[0] = -WD / 2
-2 * ((val * 100) - texture_coords[0]) = WD

So, what is WD? Well, from this equation, I can determine... nothing. This equation seems to be gibberish.

I'm guessing you intend for WD to mean "width" (seriously, it's three more characters; you couldn't type that out?). Presumably, the texture's width. If so... the equation remains gibberish.

You're taking a value that ranges from [0, 1], then subtracting half of the texture width from it. What does that mean? Why divide by 100? Since the texture width is probably much larger than the largest value from texture_coords (aka: 1), the result of this is going to be basically -WD/200.

And unless you're rendering to a floating-point image, that's going to get clamped to the valid color range: [0, 1]. So all your values come out to be the same color: black.

Since you're talking about Mandelbrot and so forth, I suspect you're trying to generate values on the range [-1, 1] or whatever. And your equation might do that... if texture_coords weren't normalized texture coordinates on the range [0, 1]. You know, exactly like the Wiki says they are.

If you want to turn texture coordinates into the [-1, 1] range, it's really much simpler. This is why we use normalized texture coordinates:

vec2 c = (2 * texture_coord) - 1; //Vector math is good.

If you want that to be the [-100, 100] range, just multiply the result by 100.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • I'm sorry I didn't provide enough information... I'm new to the forum and I'm trying to figure out how to properly write a post. In my last one I was told to provide less code, I can see this time I not only provided little code, but not nearly enough information. The code I provided was a later trial, but I have previously tried it like this `(texture_coords[0]-WD/2/100)`, but it didn't help... I am also new to programming, and I have very little knowledge on proper coding practices... Anyway, thanks for the help, I'll try to be more explicit with my future coding :) – Vitu Tomaz Jan 08 '16 at 18:26
  • My overall point was that the width doesn't matter. The width has already been factored out. It doesn't matter how big or how small you draw the quad; the texture coordinate will still go from 0 at the top/left to 1 at the bottom/right. – Nicol Bolas Jan 08 '16 at 18:28
  • I made an update to the post. I've completely reworked the code, but it's still acting weird with texture_coords... – Vitu Tomaz Jan 08 '16 at 18:35
  • Man, I really do appreciate the help, but you really didn't need to be this rude... I understand perfectly these concepts, and if you check the update, I made it work with screen_coords, which is, theoretically, the same. And if you check Bob__'s answer, the problem is with how the drawables work, not my logic – Vitu Tomaz Jan 10 '16 at 00:44
  • "I made it work with screen_coords, which is, theoretically, the same." It's not the same. That's the point I'm trying to get across to you. The top-right part of your quad will have a window coordinate of (width, 0). But the ***texture coordinate*** will be (1, 0). That's what "normalized" means. – Nicol Bolas Jan 10 '16 at 00:56
  • OK, I double checked the wiki and now I see what you meant. Sorry about the misunderstanding, but I really think you could have been a bit more polite. Thank you for the help – Vitu Tomaz Jan 10 '16 at 02:29