Love2d GLSL 着色器脚本无法检索 texture_coords 变量

Love2d GLSL shader script fails to retrieve texture_coords variable

大家好! 我一直在尝试编写一个使用 GLSL 渲染 Mandelbrot 集的脚本,但发生了一些奇怪的事情。

我这样调用效果函数:

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

但是,当我尝试使用 texture_coords 值时,可以这样说:

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

它returns每个像素的值相同;另一方面,如果我改用 screen_coords,它会起作用,但我担心如果我将 window 拖到它周围可能会使结果变得模糊。

为什么我无法检索 texture_coords?

对程序和问题的更多见解


更新

我修改了代码,现在看起来像这样:

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++;
}

效果很好。但是当我使用 texture_coords 而不是 window_coords 时,代码 returns 每个像素的值都相同,尽管我使用的纹理与 [=41] 的大小相同=].

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

好吧,让我们调查一下。您提供的信息不多,不过我们还是看看吧。

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

那是什么?好吧,我们知道 texture_coords 是什么。来自 Love2D 维基:

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).

所以你从这个纹理坐标中减去WD/2。您没有提到 WD 值是什么。但无论如何,你将结果除以 100。

那么,WD到底是什么?让我们看看代数是否可以提供帮助:

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

那么,什么是WD?好吧,从这个方程式,我可以确定……什么都没有。这个等式似乎是乱码。

我猜您打算让 WD 表示 "width"(说真的,它是 另外三个字符 ;您不能输入吗? ).据推测,纹理的宽度。如果是这样......等式仍然是胡言乱语.

您正在取 [0, 1] 范围内的值,然后从中减去纹理宽度的一半。那是什么意思?为什么要除以 100?由于纹理宽度可能比 texture_coords(又名:1)中的最大值大得多,因此结果基本上是 -WD/200.

除非您渲染到 floating-point 图像,否则它将被限制在有效的颜色范围内:[0, 1]。所以你所有的值都是相同的颜色:黑色。

既然你在谈论 Mandelbrot 等等,我 怀疑 你试图生成范围 [-1, 1] 或其他范围内的值。你的等式可能会这样做......如果 texture_coords 不是 标准化纹理坐标 在 [0, 1] 范围内。你知道,就像 Wiki 所说的那样。

如果想把贴图坐标变成[-1, 1]范围内,就真的简单多了。这就是为什么我们使用 normalized 纹理坐标:

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

如果您希望它在 [-100, 100] 范围内,只需将结果乘以 100。

问题是 love.graphics 的某些可绘制对象如果不加载图像则不会设置任何纹理坐标。所以,而不是使用 draw.rectangle,你应该使用 Mesh:

A 2D polygon mesh used for drawing arbitrary textured shapes

为了添加网格对象,您可以将其添加到加载函数中:

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

在绘制函数中:

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

完整的代码,考虑到你之前的问题和我的回答,添加一些行来管理坐标转换变成:

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