我的目标是将一个点数组传递给着色器,计算它们与碎片的距离,并用一个渐变的圆圈绘制它们,这个圆形取决于该计算。
例如:
(来自working example I set up on shader toy)
不幸的是,我不清楚如何计算和转换在着色器内传递的处理坐标。
我目前正在尝试将两个浮点数 - 一个用于x位置,一个用于每个点的y位置 - 通过一个制服传递给着色器。然后在着色器中迭代遍历每个点,如下所示:
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
uniform float sourceX[100];
uniform float sourceY[100];
uniform vec2 resolution;
in vec4 gl_FragCoord;
varying vec4 vertColor;
varying vec2 center;
varying vec2 pos;
void main()
{
float intensity = 0.0;
for(int i=0; i<100; i++)
{
vec2 source = vec2(sourceX[i],sourceY[i]);
vec2 position = ( gl_FragCoord.xy / resolution.xy );
float d = distance(position, source);
intensity += exp(-0.5*d*d);
}
intensity=3.0*pow(intensity,0.02);
if (intensity<=1.0)
gl_FragColor=vec4(0.0,intensity*0.5,0.0,1.0);
else if (intensity<=2.0)
gl_FragColor=vec4(intensity-1.0, 0.5+(intensity-1.0)*0.5,0.0,1.0);
else
gl_FragColor=vec4(1.0,3.0-intensity,0.0,1.0);
}
但这不起作用 - 我相信这可能是因为我试图使用像素坐标而不正确翻译它们。谁能向我解释如何使这项工作?
更新
目前的结果是: 草图的代码是:
PShader pointShader;
float[] sourceX;
float[] sourceY;
void setup()
{
size(1024, 1024, P3D);
background(255);
sourceX = new float[100];
sourceY = new float[100];
for (int i = 0; i<100; i++)
{
sourceX[i] = random(0, 1023);
sourceY[i] = random(0, 1023);
}
pointShader = loadShader("pointfrag.glsl", "pointvert.glsl");
shader(pointShader, POINTS);
pointShader.set("sourceX", sourceX);
pointShader.set("sourceY", sourceY);
pointShader.set("resolution", float(width), float(height));
}
void draw()
{
for (int i = 0; i<100; i++) {
strokeWeight(60);
point(sourceX[i], sourceY[i]);
}
}
而顶点着色器是:
#define PROCESSING_POINT_SHADER
uniform mat4 projection;
uniform mat4 transform;
attribute vec4 vertex;
attribute vec4 color;
attribute vec2 offset;
varying vec4 vertColor;
varying vec2 center;
varying vec2 pos;
void main() {
vec4 clip = transform * vertex;
gl_Position = clip + projection * vec4(offset, 0, 0);
vertColor = color;
center = clip.xy;
pos = offset;
}
答案 0 :(得分:2)
更新
根据评论,您似乎混淆了两种不同的方法:
另一个问题是您的点数以像素为单位但代码需要0到1的范围,因此d
很大且点数为黑色。将此问题修复为@RetoKoradi describes应解决黑点问题,但我怀疑当许多问题非常接近时,您会发现斜坡剪切问题。将点传递到着色器会限制可伸缩性,并且除非点覆盖整个视口,否则效率低下。
如下所示,我认为坚持方法2更好。要重构代码,请删除循环,不要传入点数组,而是使用center
作为点坐标:
//calc center in pixel coordinates
vec2 centerPixels = (center * 0.5 + 0.5) * resolution.xy;
//find the distance in pixels (avoiding aspect ratio issues)
float dPixels = distance(gl_FragCoord.xy, centerPixels);
//scale down to the 0 to 1 range
float d = dPixels / resolution.y;
//write out the intensity
gl_FragColor = vec4(exp(-0.5*d*d));
Draw this to a texture(来自评论:opengl-tutorial.org code和this question)加上blending:
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
现在,纹理将包含原始循环之后的intensity
。在全屏传递期间的另一个片段着色器中(绘制覆盖整个视口的单个三角形),继续:
uniform sampler2D intensityTex;
...
float intensity = texture2D(intensityTex, gl_FragCoord.xy/resolution.xy).r;
intensity = 3.0*pow(intensity, 0.02);
...
您显示的代码很好,假设您正在绘制全屏多边形,因此片段着色器为每个像素运行一次。潜在的问题是:
resolution
未正确设置d
会被纵横比拉伸,因此您可能会更好地将点缩放到像素坐标和潜水距离resolution.y
。这看起来非常类似于为2D metaballs创建密度字段。对于性能而言,最好限制每个点的密度函数,以便它不会永远持续下去,然后使用添加剂混合将光盘喷射到纹理中。这样可以节省处理点不会影响的像素(就像在延迟着色中一样)。结果是密度字段,或者在您的情况下为每像素intensity
。
这些有点相关:
答案 1 :(得分:0)
当你减去它们时,看起来点中心和碎片位置在不同的坐标空间中:
vec2 source = vec2(sourceX[i],sourceY[i]);
vec2 position = ( gl_FragCoord.xy / resolution.xy );
float d = distance(position, source);
根据您的说明和代码,source
和source
位于窗口坐标中,这意味着它们以像素为单位。 gl_FragCoord
位于相同的坐标空间中。即使您没有直接显示,我也认为resolution
是窗口的大小(以像素为单位)。
这意味着:
vec2 position = ( gl_FragCoord.xy / resolution.xy );
计算窗口内片段的标准化位置,x和y的范围均为[0.0,1.0]。但接下来就行:
float d = distance(position, source);
你从标准化坐标中的这个位置继承source
,它仍然是窗口坐标。
因为看起来你想要标准化坐标中的距离,这是有意义的,你还需要标准化source
:
vec2 source = vec2(sourceX[i],sourceY[i]) / resolution.xy;