我想在顶点着色器中发送大于4 * 4(mat4)的矩阵。我想将矩阵放在纹理中,然后将纹理发送到着色器。
问题在于我不知道究竟是怎么做到的。 你能帮我一个关于如何在纹理中设置矩阵以及如何从着色器中的纹理中获取元素的基本示例吗?
以下是我的代码的一些部分: 有2个矩阵:m1和m2:
r1 = m1.rows,
r2 = m2.rows,
c1 = m1.cols,
c2 = m2.cols,
d1 = m1.data,
d2 = m2.data;
要放入纹理的数据:
count = Math.max(r1, r2) * Math.max(c1, c2);
var texels = new Float32Array(3 * count); // RGB
/* same dimensions for both matrices */
if (r1 == r2 && c1 == c2) {
/* put m1 in red channel and m2 in green channel */
var i = 0, index1 = 0, index2 = 0;
do {
texels[i++] = d1[index1++];
texels[i++] = d2[index2++];
i++; // skip blue channel
} while (--count);
} else {
var index, row = 0, col = 0;
for (index = 0; index < r1 * c1; index++) {
texels[index * 3] = d1[index];
}
for (index = 0; index < r2 * c2; index++) {
texels[index * 3 + 1] = d2[index];
}
}
制作纹理:
var texture = gl.createTexture();
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, Math.max(m1.c, m2.c), Math.max(m1.r, m2.r), 0, gl.RGB, gl.FLOAT, texels);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
var sampler = gl.getUniformLocation(program, "usampler");
gl.uniform1i(sampler, 0);
顶点着色器:
#ifdef GL_ES
precision highp float;
#endif
attribute vec3 a_position;
attribute vec2 a_texcoord;
varying vec2 vTex;
void main(void)
{
gl_Position = vec4(a_position, 1.0);
vTex = a_texcoord;
}
片段着色器:
#ifdef GL_ES
precision highp float;
#endif
// passed in from the vertex shader.
varying vec2 vTex; // row, column to calculate
uniform sampler2D usampler;
uniform int uLength;
uniform float uStepS; // increment across source texture
uniform float uStepT; // increment down source texture
uniform float uOutRows;
uniform float uOutCols;
// sum row r x col c
float sumrowcol(float row, float col) {
float sum = 0.; // sum
float ss = 0.; // column on source texture
float tt = 0.; // row on source texture
float r = row*uStepT; // moving texture coordinate
float c = col*uStepS; // moving texture coordinate
for (int pos=0; pos<2048; ++pos) {
if(pos >= uLength) break; // stop when we multiple a row by a column
float m1 = texture2D(usampler,vec2(r,ss)).r;
float m2 = texture2D(usampler,vec2(tt,c)).g;
sum += (m1*m2);
ss += uStepS;
tt += uStepT;
}
return sum;
}
float shift_right (float v, float amt) {
v = floor(v) + 0.5;
return floor(v / exp2(amt));
}
float shift_left (float v, float amt) {
return floor(v * exp2(amt) + 0.5);
}
float mask_last (float v, float bits) {
return mod(v, shift_left(1.0, bits));
}
float extract_bits (float num, float from, float to) {
from = floor(from + 0.5); to = floor(to + 0.5);
return mask_last(shift_right(num, from), to - from);
}
vec4 encode_float (float val) {
if (val == 0.0) return vec4(0, 0, 0, 0);
float sign = val > 0.0 ? 0.0 : 1.0;
val = abs(val);
float exponent = floor(log2(val));
float biased_exponent = exponent + 127.0;
float fraction = ((val / exp2(exponent)) - 1.0) * 8388608.0;
float t = biased_exponent / 2.0;
float last_bit_of_biased_exponent = fract(t) * 2.0;
float remaining_bits_of_biased_exponent = floor(t);
float byte4 = extract_bits(fraction, 0.0, 8.0) / 255.0;
float byte3 = extract_bits(fraction, 8.0, 16.0) / 255.0;
float byte2 = (last_bit_of_biased_exponent * 128.0 + extract_bits(fraction, 16.0, 23.0)) / 255.0;
float byte1 = (sign * 128.0 + remaining_bits_of_biased_exponent) / 255.0;
return vec4(byte1, byte2, byte3, byte4);
}
void main(void) {
// get the implied row and column from .s and .t of passed texel
float col = floor((vTex.s*uOutRows));
float row = floor((vTex.t*uOutCols));
// sum row x col for the passed pixel
float v = sumrowcol(row,col);
gl_FragColor = encode_float(v);
}
答案 0 :(得分:0)
这是你需要做的:
GL_RED
,GL_RG
,GL_RGB
或GL_RGBA
。频道类型肯定应为GL_FLOAT
。glTexSubImage2D
。GL_NEAREST
,否则除了texelFetch
系列之外的任何纹理采样函数都会接近相邻颜色,这很可能不是您想要的。 W.R.T。示例代码...哪种语言适合您?
答案 1 :(得分:0)
纹理只是具有1到4个通道的2D数据阵列。对于矩阵,您可能需要浮点纹理。浮点纹理支持是可选的,但常见的
ext = gl.getExtension("OES_texture_float");
if (!ext) {
// tell the user they can't run your app
所以,你把数据放在纹理
中const width = 5;
const height = 5;
const data = new Float32Array(width * height);
data[0] = ???
data[1] = ???
等
现在制作一个纹理并上传
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
const level = 0;
gl.texImage2D(gl.TEXTURE_2D, level, gl.LUMINANCE, width, height 0,
gl.LUMINANCE, gl.FLOAT, data);
// set the filtering so values don't get mixed
gl.texParameteri(gl.TEXTURE2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
LUMINANCE
是单通道纹理。
要阅读它,您需要知道着色器中的尺寸,您必须自己传递WebGL1
uniform vec2 dataTextureSize;
uniform sampler2D dataTexture;
然后你可以获得这样的任何元素
float row = ??
float col = ??
vec2 uv = (vec2(col, row) + .5) / dataTextureSize;
float value = texture2D(dataTexture, uv).r; // just the red channel
WebGL通常不允许您选择写入的位置(这将需要计算着色器,这是几个版本关闭)。因此,您需要构建应用程序,以便按顺序处理每个目标行和列,或者有一些技巧,例如使用gl.POINT
并设置gl_Position
来选择特定的输出像素。
您可以看到an example of that here。
如果您使用WebGL2
,则无需扩展,您可以使用texelFetch
从纹理中获取特定值。
float value = texelFetch(dataTexture, ivec2(col, row));
使用gl.R32F
作为内部格式
const level = 0;
gl.texImage2D(gl.TEXTURE_2D, level, gl.R32F, width, height 0,
gl.RED, gl.FLOAT, data);