如何解决从片段着色器恢复像素数据会导致意外行为
我目前正在尝试使用片段着色器来传输一些粒子位置数据(并在将来修改它)。我使用 sampler2D 纹理将数据发送到着色器没有问题,但是当我尝试恢复数据时,我的 20 个粒子突然出现了错误的位置。我已经打印了尽可能多的输出,并尽可能减少了代码,但仍然无法理解我错在哪里。
在 p5js 网站 here
上提供了可重现的最小化版本这是我的 Sketch.js :
let theShader;
let shaderTexture;
let NUM_PARTICLES = 20;
let particleTexture;
let particles = [];
function preload(){
theShader = loadShader('basic.vert','basic.frag');
}
function setup() {
createCanvas(400,400,WEBGL);
// Initiate Particles
for(let i = 0; i < NUM_PARTICLES;i++){
particles.push(createVector(i*20,i*20,0));
}
// Initialize Shader
shaderTexture = createGraphics(NUM_PARTICLES,1,WEBGL);
shaderTexture.nostroke();
// Create Particle Texture
particleTexture = createImage(NUM_PARTICLES,1);
// Fill Particle Texture
particleTexture.loadPixels();
for (let i = 0; i < NUM_PARTICLES; i++) {
particleTexture.pixels[i*4+0] = map(particles[i].x,width,255); // R
particleTexture.pixels[i*4+1] = map(particles[i].y,height,255); // G
particleTexture.pixels[i*4+2] = 0; // B
particleTexture.pixels[i*4+3] = 255; // A
}
particleTexture.updatePixels();
}
function draw() {
translate(-width/2,-height/2);
background(255);
// display Particles Before Modification
for(let i = 0; i < NUM_PARTICLES;i++){
circle(particles[i].x,particles[i].y,10); // draw circle at particle location
}
// Apply Texture
shaderTexture.shader(theShader); // set shader
theShader.setUniform('text',particleTexture); // send particleTexture to shader
shaderTexture.rect(0,NUM_PARTICLES,1); // set rect to recieve shader out
// Print Shader Output
for(let i = 0; i < NUM_PARTICLES;i++){
let newPos = shaderTexture.get(i,0);
print(newPos);
}
// Update and display Particles
for(let i = 0; i < NUM_PARTICLES;i++){
let newPos = shaderTexture.get(i,0);
particles[i].x = map(newPos[0],255,width);
particles[i].y = map(newPos[1],height);
fill(255,0);
circle(particles[i].x,10);
}
noLoop();
}
#ifdef GL_ES
precision highp float;
#endif
uniform sampler2D text;
void main() {
vec2 particle = texture2D(text,vec2(gl_FragCoord.x,gl_FragCoord.y)).xy;
gl_FragColor = vec4(particle.x,particle.y,0.0,1.0); // R,G,B,A
}
也是我的默认顶点着色器:
#ifdef GL_ES
precision highp float;
#endif
attribute vec3 aPosition;
void main() {
vec4 positionVec4 = vec4(aPosition,1.0);
positionVec4.xy = positionVec4.xy * 2.0 - 1.0;
gl_Position = positionVec4;
}
解决方法
使用 texture2D
查找纹理时,纹理坐标必须在 [0.0,1.0] 范围内指定。 (0,0) 是左下角, (1,1) 是右上角。但是 gl_FragCoord.xy
包含窗口坐标,左上角 (0.5,0.5) 和右上角 (width-0.5,height-0.5)。
因此,您需要将 gl_FragCoord
除以视口的大小。由于您在大小为 NUM_PARTICLESx1(宽度 == NUM_PARTICLES,高度 = 1)的矩形上绘制,您必须将 gl_FragCoord.x
除以 NUM_PARTICLES:
vec2 particle = texture2D(text,vec2(gl_FragCoord.x,gl_FragCoord.y)).xy;
vec2 particle = texture2D(text,vec2(gl_FragCoord.x/20.0,0.0)).xy;
或者,您可以向片段着色器添加 size
统一并将 gl_FragCoord.xy
除以 size
:
#ifdef GL_ES
precision highp float;
#endif
uniform sampler2D text;
uniform vec2 size;
void main() {
vec2 particle = texture2D(text,gl_FragCoord.xy / size).xy;
gl_FragColor = vec4(particle.x,particle.y,0.0,1.0); // R,G,B,A
}
通过size
设置[NUM_PARTICLES,1]
统一的值:
// Apply Texture
shaderTexture.shader(theShader); // set shader
theShader.setUniform('text',particleTexture); // send particleTexture to shader
theShader.setUniform('size',[NUM_PARTICLES,1]);
shaderTexture.rect(0,NUM_PARTICLES,1); // set rect to recieve shader out
如果您使用 OpenGL ES Shading Language 3.00,您可以选择使用 texelFetch
查找具有整数像素坐标的纹理或使用 textureSize
获取纹理的大小。
不幸的是,p5.js (createCanvas()
) 似乎没有提供 WebGL 2.0 上下文,所以这不是一个选项。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。