不清楚你为什么要做你想做的事。最好问一些类似“我正在尝试绘制图像/实现后处理辉光/do-ray跟踪/……为了做到这一点,我想使用非标准化的纹理坐标,因为“然后我们可以告诉你你的解决方案是否可行以及如何解决它。
无论如何,传球
int
或
unsigned int
或
ivec2/3/4
或
uvec2/3/4
因为一个变量是支持的,但是
非插值
. 你必须把它们声明为
flat
.
但是,可以将未规范化的值作为
float
或
vec2/3/4
以及转化为
int
,
IVEC2/3/4
在片段明暗器中。
另一个问题是你不能用
texelFetch
,使用texel坐标而不是标准化纹理坐标的函数。它只返回一个像素的精确值。它不支持像正常一样的过滤
texture
功能。
例子:
function main() {
const gl = document.querySelector('canvas').getContext('webgl2');
if (!gl) {
return alert("need webgl2");
}
const vs = `
#version 300 es
in vec4 position;
in ivec2 texelcoord;
out vec2 v_texcoord;
void main() {
v_texcoord = vec2(texelcoord);
gl_Position = position;
}
`;
const fs = `
#version 300 es
precision mediump float;
in vec2 v_texcoord;
out vec4 outColor;
uniform sampler2D tex;
void main() {
outColor = texelFetch(tex, ivec2(v_texcoord), 0);
}
`;
// compile shaders, link program, look up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
// create buffers via gl.createBuffer, gl.bindBuffer, gl.bufferData)
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
position: {
numComponents: 2,
data: [
-.5, -.5,
.5, -.5,
0, .5,
],
},
texelcoord: {
numComponents: 2,
data: new Int32Array([
0, 0,
15, 0,
8, 15,
]),
}
});
// make a 16x16 texture
const ctx = document.createElement('canvas').getContext('2d');
ctx.canvas.width = 16;
ctx.canvas.height = 16;
for (let i = 23; i > 0; --i) {
ctx.fillStyle = `hsl(${i / 23 * 360 | 0}, 100%, ${i % 2 ? 25 : 75}%)`;
ctx.beginPath();
ctx.arc(8, 15, i, 0, Math.PI * 2, false);
ctx.fill();
}
const tex = twgl.createTexture(gl, { src: ctx.canvas });
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
// no need to set uniforms since they default to 0
// and only one texture which is already on texture unit 0
gl.drawArrays(gl.TRIANGLES, 0, 3);
}
main();
<canvas></canvas>
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
因此,对于您更新后的问题,仍然不清楚您想要做什么。为什么要将varying传递到片段明暗器?你不能在片段着色程序中做你想要的任何数学吗?
例子:
uniform sampler2D tex;
out float result;
// some all the values in the texture
vec4 sum4 = vec4(0);
ivec2 texDim = textureSize(tex, 0);
for (int y = 0; y < texDim.y; ++y) {
for (int x = 0; x < texDim.x; ++x) {
sum4 += texelFetch(tex, ivec2(x, y), 0);
}
}
result = sum4.x + sum4.y + sum4.z + sum4.w;
例2
uniform isampler2D indices;
uniform sampler2D data;
out float result;
// some only values in data pointed to by indices
vec4 sum4 = vec4(0);
ivec2 texDim = textureSize(indices, 0);
for (int y = 0; y < texDim.y; ++y) {
for (int x = 0; x < texDim.x; ++x) {
ivec2 index = texelFetch(indices, ivec2(x, y), 0).xy;
sum4 += texelFetch(tex, index, 0);
}
}
result = sum4.x + sum4.y + sum4.z + sum4.w;
注意,我也不是GPGPU的专家,但我有一个预感,上面的代码不是最快的方法,因为我相信并行化是基于输出发生的。上面的代码只有1个输出,所以没有并行化?很容易更改,所以它将块ID、图块ID、区域ID作为输入,并只计算该区域的和。然后用每个块的和写出一个更大的纹理,最后求和块的和。
此外,依赖和不均匀的纹理读取是一个已知的性能问题。第一个示例按顺序读取纹理。缓存友好。第二个示例以随机顺序(由索引指定)读取纹理,这不利于缓存。