最简单的方法可能是将纹理加载到 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 画布始终使用预乘 alpha,因此无法将所有 4 个通道与 2d 画布一起使用。
将纹理绘制成纹理与绘制周期相同。查看任何绘制到纹理中的示例。
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;
设置要渲染的平面和材质,将其放入场景中。对于每个图像纹理,设置材质以使用该图像纹理并设置任何其他参数以使其在您希望将其绘制到图集纹理的位置绘制四边形。我猜正交相机会让这变得最简单。然后使用渲染目标调用渲染。
renderer.autoClear = false;
renderer.render( sceneRTT, cameraRTT, rtTexture, false );
这将呈现为rtTexture
.
完成后rtTexture
就是您的地图集纹理。只需像使用任何纹理一样使用纹理。将其分配给材质。