Matrix 如何将大型矩阵发送到着色器?

Matrix 如何将大型矩阵发送到着色器?,matrix,textures,webgl,Matrix,Textures,Webgl,我想在顶点着色器中发送大于4*4(mat4)的矩阵。我想把矩阵放在一个纹理中,然后把纹理发送给着色器 问题是我不知道该怎么做。 你能帮我举一个关于如何在纹理中设置矩阵以及如何从着色器中的纹理中获取元素的基本示例吗 以下是我的代码的一些部分: 有两个矩阵:m1和m2: r1 = m1.rows, r2 = m2.rows, c1 = m1.cols, c2 = m2.cols, d1 = m1.data, d2 = m2.data; 要放入纹理中的数据: count = Math.max(r1,

我想在顶点着色器中发送大于4*4(mat4)的矩阵。我想把矩阵放在一个纹理中,然后把纹理发送给着色器

问题是我不知道该怎么做。 你能帮我举一个关于如何在纹理中设置矩阵以及如何从着色器中的纹理中获取元素的基本示例吗

以下是我的代码的一些部分: 有两个矩阵: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); 
    }
片段着色器:

#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); 
    }
\ifdef glu
高精度浮点;
#恩迪夫
 
//从顶点着色器传入。
可变vec2-vTex;//要计算的行、列
均匀取样器;     
均匀长度;      
均匀浮球;//源纹理上的增量
均匀浮球;//向下递增源纹理
均匀浮球;     
均匀浮球;     
      
//求和行r x列c
浮点sumrowcol(浮点行,浮点列){
浮点和=0;//sum
浮点ss=0;//源纹理上的列
浮点tt=0;//源纹理上的行
float r=row*uStepT;//移动纹理坐标
float c=col*uStepS;//移动纹理坐标
for(int pos=0;pos=uLength)break;//当我们将一行乘以一列时停止
浮点m1=纹理2d(usampler,vec2(r,ss)).r;
float m2=纹理2d(usampler,vec2(tt,c)).g;
总和+=(m1*m2);
ss+=uStepS;
tt+=uStepT;
        } 
回报金额;
    } 
      
浮动移位_右(浮动v,浮动金额){
v=地板(v)+0.5;
返回楼层(v/exp2(金额));
   }
      
浮动左移(浮动v,浮动金额){
返回层(v*exp2(金额)+0.5);
   }
      
浮动掩码\u最后(浮动v,浮动位){
返回模式(v,左移位(1.0,位));
   }
      
浮点提取_位(float num、float from、float to){
from=楼层(from+0.5);to=楼层(to+0.5);
最后返回掩码(向右移位(num,from),到-from);
   }
      
vec4编码_浮点(float val){
if(val==0.0)返回vec4(0,0,0,0);
浮动符号=val>0.0?0.0:1.0;
val=abs(val);
浮动指数=下限(log2(val));
浮点数指数=指数+127.0;
浮点数=((val/exp2(指数))-1.0)*8388608.0;
浮点数t=有偏指数/2.0;
浮动有偏指数的最后一位=fract(t)*2.0;
浮动\u偏置\u指数的剩余\u位\u=floor(t);
浮点字节4=提取字节(分数,0.0,8.0)/255.0;
浮点字节3=提取字节(分数,8.0,16.0)/255.0;
浮点字节2=(有偏指数的最后一位*128.0+提取位(分数,16.0,23.0))/255.0;
浮点字节1=(符号*128.0+有偏指数的剩余字节)/255.0;
返回vec4(字节1、字节2、字节3、字节4);
    } 
无效主(无效){
          
//从传递的texel的.s和.t中获取隐含的行和列
浮动柱=地板((vTex.s*uOutRows));
浮动行=地板((vTex.t*uOutCols))
 
//对传递的像素的行x列求和
浮点v=sumrowcol(行,列);
 
gl_FragColor=编码浮点数(v);
    }

这是您需要做的:

  • 创建任务可能的最大大小的2D纹理,因为重新分配纹理比重新分配RAM困难一个数量级
  • 根据每个纹理所需的通道数,将纹理类型设置为
    GL\u RED
    GL\u RG
    GL\u RGB
    GL\u RGBA
    。通道类型当然应该是
    GL\u FLOAT
  • 将新创建的纹理传递给着色器,然后在每次算法需要时更新它
  • 帮助更新2D纹理中任意矩形区域的函数是
  • 还请记住,您最好将放大模式设置为
    GL_NEAREST
    ,因为除
    texelFetch
    系列之外的任何纹理采样函数都会近似于相邻颜色,这很可能不是您想要的

  • W.R.T.示例代码…哪种语言更适合您?

    纹理只是一个具有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);
    
    亮度
    是单通道纹理

    要阅读它,您需要知道着色器中的尺寸,在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\u位置来选择特定的输出像素

    你可以看到

    如果使用,则不需要扩展,可以使用
    texelFetch
    从纹理中获取特定值

    float value = texelFetch(dataTexture, ivec2(col, row));
    
    可能是m