在片段着色器中处理大 arrays/textures

handle large arrays/textures in fragment shader

我正在尝试将大量信息传递到我的片段着色器,但我总是达到限制(绑定的纹理太多、纹理太大等、数组太大等)。我使用 ThreeJS 自定义着色器。

我有一个 256*256*256 的 rgba 体积,我想传递给我的着色器。

在我的着色器中,我想将片段的世界位置映射到这个 256*256*256 体积中的体素。

有没有好的策略来处理这么多的信息?哪个是最好的实践?有什么好的解决方法吗?

我目前的方法是生成 4 个不同的 2048x2048 rgba 纹理,其中包含我需要的所有数据。

为了创建每个 2048x2048 纹理,我只是将每个切片的每一行按顺序推入一个大数组,并将该数组分成 2048x2048x4 块,这是我的纹理:

  var _imageRGBA = new Uint8Array(_dims[2] *_dims[1] * _dims[0] * 4);
  for (_k = 0; _k < _dims[2]; _k++) {
    for (_j = 0; _j < _dims[1]; _j++) {
      for (_i = 0; _i < _dims[0]; _i++) {
      _imageRGBA[4*_i + 4*_dims[0]*_j + 4*_dims[1]*_dims[0]*_k] = _imageRGBA[4*_i + 1 + 4*_dims[0]*_j + 4*_dims[1]*_dims[0]*_k] = _imageRGBA[4*_i + 2 + 4*_dims[0]*_j + 4*_dims[1]*_dims[0]*_k] = _imageN[_k][_j][_i];//255 * i / (_dims[2] *_dims[1] * _dims[0]);
      _imageRGBA[4*_i + 3 + 4*_dims[0]*_j + 4*_dims[1]*_dims[0]*_k] = 255;
      }
    }
  }

每个纹理看起来像这样:

在着色器方面,我尝试将片段的世界位置映射到纹理中的实际颜色:

顶点着色器:

uniform mat4 rastoijk;

varying vec4 vPos;
varying vec2 vUv;

void main() {
    vPos = modelMatrix * vec4(position, 1.0 );
    vUv = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0 );

}
</script>

片段着色器:

<script id="fragShader" type="shader">

vec4 getIJKValue( sampler2D tex0, sampler2D tex1, sampler2D tex2, sampler2D tex3, vec3 ijkCoordinates, vec3 ijkDimensions) {

    // IJK coord to texture
    float textureSize = 2048.0;
    float index = ijkCoordinates[0] + ijkCoordinates[1]*ijkDimensions[0] + ijkCoordinates[2]*ijkDimensions[0]*ijkDimensions[1];

    // map index to right 2048 x 2048 slice
    float sliceIndex = floor(index / (textureSize*textureSize));
    float inTextureIndex = mod(index, textureSize*textureSize);

    // get row in the texture
    float rowIndex = floor(inTextureIndex/textureSize);
    float colIndex = mod(inTextureIndex, textureSize);

    // map indices to u/v
    float u = colIndex/textureSize;
    float v =1.0 - rowIndex/textureSize;

    vec2 uv = vec2(u,v);
    vec4 ijkValue = vec4(0, 0, 0, 0);
    if(sliceIndex == float(0)){
      ijkValue = texture2D(tex0, uv);
    }
    else if(sliceIndex == float(1)){
      ijkValue = texture2D(tex1, uv);
    }
    else if(sliceIndex == float(2)){
      ijkValue = texture2D(tex2, uv);
    }
    else if(sliceIndex == float(3)){
      ijkValue = texture2D(tex3, uv);
    }

    return ijkValue;
  }

uniform mat4 rastoijk;
uniform sampler2D ijk00;
uniform sampler2D ijk01;
uniform sampler2D ijk02;
uniform sampler2D ijk03;
uniform vec3 ijkDimensions;

varying vec4 vPos;
varying vec2 vUv;

void main(void) {
    // get IJK coordinates of current element
    vec4 ijkPos = rastoijk * vPos;
    // show whole texture in the back...
    vec3 color = texture2D(ijk00, vUv).rgb;
    //convert IJK coordinates to texture coordinates
    if(int(floor(ijkPos[0])) > 0
      && int(floor(ijkPos[1])) > 0
      && int(floor(ijkPos[2])) > 0
      && int(floor(ijkPos[0])) < int(ijkDimensions[0])
      && int(floor(ijkPos[1])) < int(ijkDimensions[1])
      && int(floor(ijkPos[2])) < int(ijkDimensions[2])){

      // try to map IJK to value...
      vec3 ijkCoordinates = vec3(floor(ijkPos[0]), floor(ijkPos[1]), floor(ijkPos[2]));
      vec4 ijkValue = getIJKValue(ijk00, ijk01, ijk02, ijk03, ijkCoordinates, ijkDimensions);
      color = ijkValue.rgb;
    }

    gl_FragColor = vec4(color, 1.0);
    // or discard if not in IJK bounding box...
  }
</script>

效果不佳。我现在得到一张带有奇怪伪像的图像(奈奎斯特香农效应?)。当我放大时,图像出现了。 (虽然不完美,有些黑点)

任何帮助建议将不胜感激。我还计划使用这种方法为体积渲染做一些光线投射(在医学领域非常需要)

最佳,

使用多个纹理处理大型数组的方法很好。

问题是我如何使用 THREE.js 生成纹理。

纹理是使用默认线性插值生成的:http://threejs.org/docs/#Reference/Textures/DataTexture

我需要的是最近邻插值。这是,纹理仍然是像素化的,我们可以访问真实的 IJK 值(不是插值) 在那里找到它:http://www.html5gamedevs.com/topic/8109-threejs-custom-shader-creates-weird-artifacts-space-between-faces/

texture = new THREE.DataTexture( textureData, tSize, tSize, THREE.RGBAFormat, THREE.UnsignedByteType, THREE.UVMapping,
      THREE.ClampToEdgeWrapping, THREE.ClampToEdgeWrapping, THREE.NearestFilter, THREE.NearestFilter );

谢谢