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

时间:2016-01-08 16:19:46

标签: lua glsl love2d mandelbrot

Heello,大家好! 我一直在尝试编写一个使用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);

它为每个像素返回相同的值;另一方面,如果我使用screen_coords,它可以工作,但是我很担心如果我拖动窗口可能会对结果产生影响。

为什么我无法检索texture_coords?

更深入了解该计划和问题here

更新

我已经重做了代码,现在它看起来像这样:

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时,代码会向每个像素返回相同的值,尽管我使用的纹理与窗口的大小相同。

2 个答案:

答案 0 :(得分:1)

问题是如果不加载图像,love.graphics的某些可绘制对象不会设置任何纹理坐标。因此,您应该使用draw.rectangle

,而不是使用Mesh
  

用于绘制任意纹理形状的2D多边形网格

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

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

答案 1 :(得分:0)

  

但它有点误导,因为我的纹理是窗口的大小,而且它不起作用

好吧,让我们调查一下。你并没有完全提供很多信息,但无论如何我们都要看。

(texture_coords[0]-WD/2)/100
那是什么?好吧,我们知道texture_coords是什么。来自Love2D维基:

  

纹理内部的位置以获取像素数据。纹理坐标通常标准化为(0,0)到(1,1)的范围,左上角为(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表示“宽度”(严重的是,它是三个以上的字符;你不能输出那个?)。据推测,纹理的宽度。如果是这样......等式仍然是乱码

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

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

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

如果你想将纹理坐标转换为[-1,1]范围,它实际上要简单得多。这就是我们使用规范化纹理坐标的原因:

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

如果你希望它是[-100,100]范围,只需将结果乘以100.