我有一个应用程序,我加载一系列医学图像(jpg),为每个图像创建纹理对象,并在3D平面上显示这些纹理。图像数量取决于CT扫描仪的分辨率,但我的原型最多可以使用512。
作为一项额外任务,我想使用这些纹理在单独的3D画布上执行体积渲染。
所有解决WebGL缺乏3D纹理的算法都具有静音"已经存在图像格式的纹理图集的先决条件。
但就我而言,我没有这样的地图集。
假设硬件支持这个2D纹理图集的最终尺寸,我怎么能将已经加载的纹理定制成一个单独的2D纹理并将其提供给着色器?
我考虑过将每个图像的数据合并为一个数组,然后创建THREE.DataTexture。但是我找不到从使用它的纹理中读取图像数据的方法。是否有其他方法来提取加载图像的数据?
答案 0 :(得分:0)
最简单的方法可能是将纹理加载到2D画布中以构建地图集。
假设我们有一个下载512个纹理的函数,我们希望将它们放在32 x 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);
}
一些优化:您可以更改代码,以便在开始时制作画布,并在每个图像加载时将其绘制到正确位置的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
是你的地图集纹理。只需像任何纹理一样使用纹理。将其分配给材料。