2015-06-15 55 views
0

我有一个应用程序,我加载一系列医学图像(jpg),为每个图像创建纹理对象并在3D平面上显示这些纹理。图像数量取决于CT扫描仪的分辨率,但我的原型最多可以使用512.从现有的纹理创建2D纹理

作为一项额外的任务,我希望使用这些纹理在单独的3D画布上执行体积渲染。

解决WebGL中缺乏3D纹理的所有算法都有一个“无声”的先决条件,即图像格式的纹理图集已经存在。

但在我的情况下,我没有这样的图集。

  1. 假设硬件支持所产生的这个2D纹理图集的大小,我怎么能定制已经载入纹理到一个单一的2D纹理和饲料它的着色器?

  2. 我想过将每个图像的数据合并到一个数组中,并创建THREE.DataTexture。但是我找不到从使用它的纹理读取图像数据的方法。有没有另外一种方法来提取加载的图像的数据?

+3

实际上,您不必创建2D地图,但可以模拟3D纹理的存在。 http://stackoverflow.com/questions/19939557/a-3-dimensional-array-represented-by-a-2-dimensional-array和https://www.youtube.com/watch?v=rfQ8rKGTVlg#t= 25m03s – gaitat

+0

谢谢您的回答Peter O.然而,您所描述的是我的过程中的下一步。它假定我已经加载了sampler2D tex中所有图像的数组。考虑到我的项目条件,我要问的是如何做到这一点。 –

回答

0

最简单的方法可能是将纹理加载到2d画布中以构建您的图集。

假设我们有一个下载512个纹理的功能,我们希望通过16个

var width = 128; // just assuming this is the size of a single texture 
var height = 128; 
var across = 32; 
var down = 16; 

asyncLoad512Images(useLoaded512Images); 

function useLoaded512Images(arrayOfImages) { 
    var canvas = document.createElement("canvas"); 
    canvas.width = width * across; 
    canvas.height = height * down; 
    var ctx = canvas.getContext("2d"); 

    // draw all the textures into the canvas 
    arrayOfImagess.forEach(function(image, ndx) { 
    var x = ndx % across; 
    var y = Math.floor(ndx/across); 

    ctx.drawImage(image, x * width, y * height); 
    } 

    // now make a texture from canvas. 
    var atlasTex = gl.createTexture(); 
    gl.bindTexture(gl.TEXTURE_2D, atlasTex); 
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, 
       canvas); 
} 

一些优化,把他们在32个网格:所以你让画布一开始你可能更改代码并在每个图像加载到正确位置的2D画布中。优点是浏览器不需要在内存中保存所有512个图像。它可以在你绘制完成后立即丢弃它们。

var width = 128; // just assuming this is the size of a single texture 
var height = 128; 
var across = 32; 
var down = 16; 
var numImages = 32 * 16; 
var numImagesDownloaded = 0; 

// make a canvas to hold all the slices 
var canvas = document.createElement("canvas"); 
canvas.width = width * across; 
canvas.height = height * down; 
var ctx = canvas.getContext("2d"); 

// assume the images are named image-x.png 
for (var ii = 0; ii < numImages; ++ii) { 
    loadImage(ii); 
} 

function loadImage(num) { 
    var img = new Image(); 
    img.onload = putImageInCanvas(img, num); 
    img.src = "image-" + num + ".png"; 
} 

function putImageInCanvas(img, num) { 
    var x = num % across; 
    var y = Math.floor(num/across); 

    ctx.drawImage(img, x * width, y * height); 

    ++numImagesDownloaded; 
    if (numImagesDownloaded === numImages) { 
    // now make a texture from canvas. 
    var atlasTex = gl.createTexture(); 
    gl.bindTexture(gl.TEXTURE_2D, atlasTex); 
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, 
        canvas); 
    .... 
    } 
} 

或者,也可以将每个图像划分成纹理,并使用附连到帧缓冲器的纹理要呈现的图像的纹理到图谱质地。这是更多的工作。你需要制作一个简单的2d着色器,然后在正确的位置渲染每个图像纹理到atlas纹理。

这样做的唯一理由就是如果纹理有4个通道的数据而不是3个或更少,因为2d画布无法使用所有4个通道,因为2d画布始终使用预乘alpha 。

将纹理绘制到纹理中与绘制周期相同。 See any example that draws into a texture

在three.js所短的版本是,

进行渲染目标

rtTexture = new THREE.WebGLRenderTarget( 
     width * across, height * down, { 
     minFilter: THREE.LinearFilter, 
     magFilter: THREE.NearestFilter, 
     format: THREE.RGBFormat, 
     depthBuffer: false, 
     stencilBuffer: false, 
    }); 
rtTexture.generateMipmaps = false; 

建立一个平面和渲染,把它放在一个场景的材料。对于每个图像纹理,将材质设置为使用该图像纹理,并设置任何其他参数以使其绘制四边形,然后将其绘制到图集纹理中。 I'm guessing an orthographic camera would make that easiest。然后用渲染目标调用渲染。

renderer.autoClear = false; 
renderer.render(sceneRTT, cameraRTT, rtTexture, false); 

这将渲染到rtTexture

当你完成rtTexture是你的图谱纹理。只要使用像任何纹理的纹理。将其分配给材料。

+0

谢谢你的回复你gman。第一种方法似乎更合适,因为我使用Three.js函数中的构建将图像加载到纹理上。内存使用不成问题(至少暂时)。我主要关心的是速度。 我说,因为我试图在画布上分别绘制每个图像,然后使用context.getImageData(0,0,imageWidthOfCut,imageHeightOfCut).data; 获取数组。但是这对于512张图像来说非常缓慢。然而你所描述的看起来更快。我会尝试一下并回馈。 –

+0

如果你能提供给我一些链接,我也会对你提到的方法感兴趣。 –

+0

事实上,当他们到达时使用纹理的中间方法可能是最好的,因为它会使图像纹理下载,这将不太可能冻结浏览器,因为一次画出512张图像可能会冻结浏览器一秒或2或3或4取决于机器的功率。另外,我不确定为什么你叫'ctx.getImageData'。您可以直接将画布传递给'gl.texImage2D' – gman