2015-01-28 4 views
0

Я пытаюсь передать большой объем информации в свой шейдер фрагмента, но я всегда достигаю предела (слишком много текстур привязано, слишком много текстур и т. Д., Массив слишком большой и т. Д.).). Я использую настраиваемый шейдер ThreeJS.обрабатывать большие массивы/текстуры в фрагменте шейдера

У меня есть том объемом 256 * 256 * 256 rgba, который я хочу передать моему шейдеру.

В моем шейдере я хочу сопоставить мировое положение фрагментов с вокселом в этом объеме 256 * 256 * 256.

Есть ли хорошая стратегия для решения такого количества информации? Что было бы лучшим пратисом? Есть ли хорошее обходное решение?

Мой текущий подход заключается в создании 4 различных текстур rgba 2048x2048, содержащих все необходимые мне данные.

Для создания каждого 2048x2048 текстуры, я просто нажать каждую строку каждого ломтика sequencially к большому массиву и разделить этот массив в 2048x2048x4 chuncks, которые мои текстуры:

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; 
     } 
    } 
    } 

Каждая текстура выглядит так: enter image description here

на стороне шейдера, я пытаюсь отобразить worldposition фрагмент, чтобы реальный цвет от текстуры:

Vertex Shader:

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> 

Это не очень хорошо работает. Теперь я получаю изображение с необычными артефактами (эффект nyquist shannon?). Когда я увеличиваю масштаб, изображение появляется. (хотя и не идеально, некоторые черные точки)

enter image description here

Любые советы помощь будет весьма признателен. Я также планирую сделать некоторые raycasting для объемного рендеринга с использованием этого подхода (очень необходимо в медицинской сфере)

Беста,

+0

ли эта помощь? http://stackoverflow.com/a/23040903/128511 – gman

+0

Это действительно помогает немного да, но я не вижу, как применить это к моей текущей проблеме ... См. обновленный вопрос.Я не знаком с webgl, и я не знаю, имеет ли смысл мой подход. спасибо – Nicolas

ответ

1

подход для обработки больших массивов с помощью нескольких текстур было прекрасно.

Проблема заключалась в том, как я генерировал текстуру с помощью THREE.js.

текстуры был сгенерирован с использованием линейной интерполяции по умолчанию: http://threejs.org/docs/#Reference/Textures/DataTexture

Что мне нужно был ближайшим neighboor интерполяцией. Это было, текстура еще пикселизированная и мы можем получить доступ к реальной стоимости 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); 

enter image description here

Благодарность

Смежные вопросы