【问题标题】:Love2d GLSL shader script fails to retrieve texture_coords variableLove2d GLSL 着色器脚本无法检索 texture_coords 变量
【发布时间】:2016-01-09 06:36:26
【问题描述】:

大家好! 我一直在尝试编写一个使用 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 代替,它可以工作,但我担心如果我在它周围拖动窗口可能会导致结果模糊。

为什么我无法检索纹理坐标?

对程序和问题的更多见解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 时,代码会为每个像素返回相同的值,尽管我使用的纹理与窗口的大小相同。

【问题讨论】:

  • screen_coords 名称不正确;实际名称是window_coords
  • 所以它检索相对于窗口的坐标,对吧?什么是 texture_coords?
  • 你知道的,Love2D has a wiki.
  • 维基说它实际上是相对于屏幕的坐标....
  • 是的。这些人将他们命名为“screen_coords”。当然,他们认为这与屏幕有关。我的观点是,它为您提供了texture_coords 含义的定义。

标签: lua glsl love2d mandelbrot


【解决方案1】:

问题是love.graphics 的一些可绘制对象在不加载图像的情况下不会设置任何纹理坐标。因此,您应该使用Mesh,而不是使用draw.rectangle

用于绘制任意纹理形状的二维多边形网格

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

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

在draw函数中:

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

【讨论】:

    【解决方案2】:

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

    好吧,让我们调查一下。你没有提供很多信息,但还是让我们看看吧。

    (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(又名: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。

    【讨论】:

    • 很抱歉我没有提供足够的信息...我是论坛的新手,我正在尝试弄清楚如何正确地写一篇文章。在上一次我被告知要提供更少的代码时,我可以看到这次我不仅提供了很少的代码,而且还没有提供足够的信息。我提供的代码是后来的试用版,但我之前也尝试过这样(texture_coords[0]-WD/2/100),但没有帮助...我也是编程新手,对正确的编码实践知之甚少...无论如何,感谢您的帮助,我会尝试在未来的编码中更加明确:)
    • 我的总体观点是宽度并不重要。宽度已经计算出来了。绘制四边形的大小无关紧要。纹理坐标仍会从顶部/左侧的 0 变为底部/右侧的 1。
    • 我更新了帖子。我已经完全重新编写了代码,但它仍然在使用 texture_coords 时表现得很奇怪......
    • 伙计,我真的很感谢你的帮助,但你真的不需要这么粗鲁......我完全理解这些概念,如果你检查更新,我让它与 screen_coords 一起工作,理论上是一样的。如果您检查 Bob__ 的答案,问题在于可绘制对象的工作方式,而不是我的逻辑
    • “我让它与 screen_coords 一起工作,理论上是一样的。”这是不一样的。这就是我试图传达给你的观点。四边形的右上角的窗口坐标为(宽度,0)。但是 纹理坐标 将是 (1, 0)。这就是“标准化”的意思。
    猜你喜欢
    • 1970-01-01
    • 2011-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多