从 tilemap 制作三个.js 天空盒 [英] make three.js skybox from tilemap

查看:29
本文介绍了从 tilemap 制作三个.js 天空盒的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我可以使用 6 个单独的图像文件制作一个 Three.js 天空盒.但我希望能够从由瓷砖组成的单个图像构建一个天空盒.

I can make a three.js skybox using 6 separate image files. But I want to be able to build a skybox from a single image made up of tiles.

例如,如果我有一个复合平铺图像作为源(请参阅 (http://www.zen226082.zen.co.uk/STACK_EXCHANGE/Giant_A.jpg)...我没有足够的代表在这里发布它:-(.

For example if I have a composite tiled image as source (see (http://www.zen226082.zen.co.uk/STACK_EXCHANGE/Giant_A.jpg)... i dont have enough rep to post it here :-(.

我可以将合成图像加载到画布中并将每个图块复制到缓存缓冲区中,然后将它们发送到 Three.js 材料数组中.然后使用这些材料制作天空盒.

I can load the composite image into a canvas and copy each tile into a cache buffer and then send them into a Three.js materials array. The materials are then used to make a skybox.

但是有两个问题.

问题1是合成图像需要翻转.我可以在像 Paint.net 这样的图形应用程序中轻松地做到这一点,但能够在 javascript/three.js 中以编程方式做到这一点会很好.

Problem 1 is that the composite image needs to be flipped. I can do this easilly in a graphics app like Paint.net but it would be nice to be able to do it programmatically in javascript/three.js.

问题 2 是 Three.js 要求 Y+ 和 Y- 的瓷砖也需要旋转 180 度.这在图形应用程序中(对我来说)很难做到.例如,这是修改后的合成平铺图像以适应我一直在使用的 Three.js 代码 (http://www.zen226082.zen.co.uk/STACK_EXCHANGE/Giant_B.jpg)(可怕!)

Problem 2 is that Three.js requires that the tiles for Y+ and Y- also need to be rotated 180 degrees. This is difficult (for me) to do in a graphics application. For example here is a composite tiled image after modification to suit the Three.js code which I have been using (http://www.zen226082.zen.co.uk/STACK_EXCHANGE/Giant_B.jpg) (Horrible!)

我的问题 = 在从合成图像中提取两个图块之后,在将它们传递到天空盒构造之前,我是否可以对它们执行 180 度旋转.

My Question = Is there some way that I can perform a 180 degree rotation on the two tiles after extracting them from the composite image and before passing them into the skybox construction.

编辑(2014 年 8 月 10 日)问题应该是如何从由 12 个相同大小的图块组成的单个图像文件制作一个 Three.js skyBox".

EDIT (10th August 2014) The Question should be "How to make a three.js skyBox from a single image file made up of 12 equal-sized tiles".

这是我一直在使用的代码:-

Here is the code I have been using:-

    var skyBoxGeometry = new THREE.CubeGeometry(skybox_sidelength,skybox_sidelength,skybox_sidelength); 
    var skyBoxMaterialArray = [];

    var widthOfOnePiece  = 2048/4;//...i.e. 512
    var heightOfOnePiece = 1536/3;//...i.e. 512
    var numColsToCut = 4;
    var numRowsToCut = 3;

    var image = new Image();
    image.src = "TRI_VP_files/images/SOW_skybox_2048_1536_v7.jpg";
    image.onload = SOW_F_cutImageUp;
    //... NB canvas origin is Top Left corner, X is left to right, Y is top to bottom

    function SOW_F_cutImageUp() {
        var imagePieces = [];

        for(var xxx = 0; xxx < numColsToCut; ++xxx) 
        {
            for(var yyy = 0; yyy < numRowsToCut; ++yyy) 
            {
                var canvas = document.createElement('canvas');
                canvas.width = widthOfOnePiece;
                canvas.height = heightOfOnePiece;
                var context = canvas.getContext('2d');
                context.drawImage(image, 
                xxx * widthOfOnePiece, yyy * heightOfOnePiece, widthOfOnePiece, heightOfOnePiece, 0, 0, canvas.width, canvas.height);

                imagePieces.push(canvas.toDataURL());

            }
        }
        //...  expected sequence of face view directions  = ["xpos", "xneg", "ypos", "yneg", "zpos", "zneg"];

        for (var iii = 0; iii < 6; iii++)
        {
                 if (iii == 0) imagePiece_num = 4 //... xpos
            else if (iii == 1) imagePiece_num = 10//... xneg
            else if (iii == 2) imagePiece_num = 6 //... ypos
            else if (iii == 3) imagePiece_num = 8 //... yneg
            else if (iii == 4) imagePiece_num = 1 //... zpos
            else if (iii == 5) imagePiece_num = 7 //... zneg

            skyBoxMaterialArray.push
            ( new THREE.MeshBasicMaterial
                (   {map: THREE.ImageUtils.loadTexture(imagePieces[imagePiece_num]),
                    side: THREE.BackSide}));

            //window.open(imagePieces[imagePiece_num], "Here is the toDataURL() cached image", "width=512, height=512");
            //alert ("Continue");
        }
    }//... end of function.

    var skyBoxMaterial = new THREE.MeshFaceMaterial( skyBoxMaterialArray );
    var skyBox = new THREE.Mesh( skyBoxGeometry, skyBoxMaterial );
    scene222.add( skyBox );

推荐答案

问题应该是如何从由 12 个相同大小的图块组成的单个图像文件制作一个 Three.js skyBox".

The Question should be "How to make a three.js skyBox from a single image file made up of 12 equal-sized tiles".

(这个答案得到了 WestLangley 的大力帮助.

(This answer achieved with greatly appreciated assistance from WestLangley).

一些关键点:-

  • 假设源图像中的图块是这样排列和引用的:-

  • Assume the tiles in the source image are arranged and referenced thus:-

//... Personal             Source image               Desired in-scene        Required
//... tile numbering       [column, row]              xyz positions of 6      sequence numbers in 
//... scheme               tile coordinates            tiles to be used.      Three.js material array 

//... [ 0] [ 3] [ 6] [ 9]  [0,0] [1,0] [2,0] [3,0]   [  ] [py] [  ] [  ]      [ ] [2] [ ] [ ]     
//... [ 1] [ 4] [ 7] [10]  [0,1] [1,1] [2,1] [3,1]   [nx] [pz] [px] [nz]      [1] [4] [0] [5]     
//... [ 2] [ 5] [ 8] [11]  [0,2] [1,2] [2,2] [3,2]   [  ] [ny] [  ] [  ]      [ ] [3] [ ] [ ]     

  • 十字"中心的图块对应于从天空盒原点沿 Z_positive 方向看的视图.

  • The tile at the centre of the "cross" corresponds to the view looking from the skyBox origin in the Z_positive direction.

    (这样就不需要旋转 180 度了).

    (That makes spinning by 180 degrees unneccessary).

    在材料用途的定义中... side: THREE.FrontSide

    In definition of material use... side: THREE.FrontSide

    为了防止源图块的镜像,请使用... skyBox.scale.set( -1, 1, 1 )

    To prevent mirror images of the source tiles, "flip" them using... skyBox.scale.set( -1, 1, 1 )

    为了确保图像得到完全处理,函数 F_cutImageUp 扩展以包括创建 skyBox 网格

    To ensure that images are fully processed the function F_cutImageUp extends to include creation of the skyBox mesh

    这适用于当前最新的 Three.js 版本 (R.68).

    This works for the current latest Three.js release (R.68).

    此代码不使用 MeshShaderMaterial,更强大(但要求更高)的 WebGL 代码示例可在 http://threejs.org/examples/webgl_shaders_ocean.html

    This code does not use MeshShaderMaterial, more powerful (but demanding) WebGL code example is available at http://threejs.org/examples/webgl_shaders_ocean.html

    webgl_shaders_ocean.html 代码示例还包括更高效的切片切割和排序算法.

    The webgl_shaders_ocean.html code example also includes a more efficient tile-cutting and sequencing algorithm.

    SkyBox 生成代码(要插入到 THREE.js 初始化函数中).

    SkyBox Generation Code (to be inserted in the THREE.js Initialisation function).

    var skybox_sidelength = 10000;
    var skyBoxGeometry = new THREE.BoxGeometry( skybox_sidelength, skybox_sidelength, skybox_sidelength); 
    
    var skyBoxMaterialArray = [];
    
    var numCols = 4, numRows = 3; //... assume any source image is tiled 4 columns(x) by 3 rows(y)
    //... NB canvas origin is Top Left corner, X is left to right, Y is top to bottom
    
    //... We use the following mapping scheme to reference the tiles in the source image:-
    //...
    //... Personal             [x,y] tile coordinates    xyz positions            Required tile       
    //... tile numbering                                 of tiles in scene        sequence in Three.js 
    //...                                                                         array 
    
    //... [ 0] [ 3] [ 6] [ 9]  [0,0] [1,0] [2,0] [3,0]   [  ] [py] [  ] [  ]      [ ] [2] [ ] [ ]     
    //... [ 1] [ 4] [ 7] [10]  [0,1] [1,1] [2,1] [3,1]   [nx] [pz] [px] [nz]      [1] [4] [0] [5]     
    //... [ 2] [ 5] [ 8] [11]  [0,2] [1,2] [2,2] [3,2]   [  ] [ny] [  ] [  ]      [ ] [3] [ ] [ ]                           
    
    var image_file = "3D_Skybox_files/Giant_A.jpg", tile_width = 512, tile_height = 512;    
    var IP_image = new Image();
    IP_image.onload = F_cutImageUp; 
    IP_image.src = image_file; //... horizontal cross of 6 WYSIWYG tiles in a 4x3 = 12 tile layout.
    
    function F_cutImageUp() 
    { //... cut up source image into 12 separate image tiles, numbered 0..11
    
        var imagePieces = [];
        var item_num = -1;
    
        for(var xxx = 0; xxx < numCols; ++xxx) 
        {
            for(var yyy = 0; yyy < numRows; ++yyy) 
            {
                var tileCanvas = document.createElement('canvas');
                tileCanvas.width  = tileWidth;
                tileCanvas.height = tileHeight;
    
                var tileContext = tileCanvas.getContext('2d');
    
                tileContext.drawImage( 
                    IP_image, 
                    xxx * tileWidth, yyy * tileHeight, 
                    tileWidth, tileHeight, 
                    0, 0, tileCanvas.width, tileCanvas.height);
    
                imagePieces.push(tileCanvas.toDataURL());
    
            }
        }
    
        //... Required sequence of tile view directions  = ["xpos", "xneg", "ypos", "yneg", "zpos", "zneg"];
    
        for (var iii = 0; iii < 6; iii++) //... select the right tiles for the 6 different faces of the sky box
        {
    
            //... we associate the centre tile (4) of the cross with the zpos direction
                 if (iii == 0) imagePiece_num =  7;//... xpos
            else if (iii == 1) imagePiece_num =  1;//... xneg
            else if (iii == 2) imagePiece_num =  3;//... ypos
            else if (iii == 3) imagePiece_num =  5;//... yneg                                       
            else if (iii == 4) imagePiece_num =  4;//... zpos
            else if (iii == 5) imagePiece_num = 10;//... zneg
    
            skyBoxMaterialArray.push
            ( new THREE.MeshBasicMaterial
                ({      map: THREE.ImageUtils.loadTexture(imagePieces[imagePiece_num]),
                        side: THREE.FrontSide // <== not intuitive
                })
            );
    
            //... Just for checking image pieces are created OK
            //window.open(imagePieces[imagePiece_num], "Here is the toDataURL() cached image " + //imagePiece_num, "width=512, height=512");
            //alert ("Displayed imagePiece_num: " + imagePiece_num);
    
        }  //... end of tile selection
    
    var skyBoxMaterial = new THREE.MeshFaceMaterial( skyBoxMaterialArray );                         
    var skyBox = new THREE.Mesh( skyBoxGeometry, skyBoxMaterial );
    skyBox.scale.set( -1, 1, 1 ); // <== not intuitive
    scene.add( skyBox ); 
    
    }//... end of F_cutImageUp function <== note function includes skyBox mesh creation.
    

    这篇关于从 tilemap 制作三个.js 天空盒的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆