Skip to content Skip to sidebar Skip to footer

Make Three.js Skybox From Tilemap

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. For example if I have a composite tiled i

Solution 1:

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

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

Some key points:-

  • 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][ ][ ]
  • The tile at the centre of the "cross" corresponds to the view looking from the skyBox origin in the Z_positive direction.

  • (That makes spinning by 180 degrees unneccessary).

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

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

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

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

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

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

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

varskybox_sidelength=10000;
varskyBoxGeometry=newTHREE.BoxGeometry( skybox_sidelength, skybox_sidelength, skybox_sidelength); 

varskyBoxMaterialArray= [];

varnumCols=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] [ ] [ ]                           varimage_file="3D_Skybox_files/Giant_A.jpg", tile_width = 512, tile_height = 512;    
varIP_image=newImage();
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..11varimagePieces= [];
    varitem_num= -1;

    for(varxxx=0; xxx < numCols; ++xxx) 
    {
        for(varyyy=0; yyy < numRows; ++yyy) 
        {
            vartileCanvas= document.createElement('canvas');
            tileCanvas.width  = tileWidth;
            tileCanvas.height = tileHeight;

            vartileContext= 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 (variii=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 directionif (iii == 0) imagePiece_num =  7;//... xposelseif (iii == 1) imagePiece_num =  1;//... xnegelseif (iii == 2) imagePiece_num =  3;//... yposelseif (iii == 3) imagePiece_num =  5;//... yneg                                       elseif (iii == 4) imagePiece_num =  4;//... zposelseif (iii == 5) imagePiece_num = 10;//... zneg

        skyBoxMaterialArray.push
        ( newTHREE.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 selectionvarskyBoxMaterial=newTHREE.MeshFaceMaterial( skyBoxMaterialArray );                         
varskyBox=newTHREE.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.

Post a Comment for "Make Three.js Skybox From Tilemap"