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