Creating a skybox in three.js from a tilemap

Creating a skybox in three.js using 6 separate image files is possible, but what if we want to construct a skybox from a single image composed of tiles?

For instance, if we have a composite tiled image as the source (), it presents a challenge due to the need for flipping and rotating the tiles to fit the Three.js requirements.

The current approach involves loading the composite image into a canvas, copying each tile into a cache buffer, and then passing them into a Three.js materials array for constructing the skybox.

However, there are two main issues to address:

Issue 1: The composite image needs to be flipped, which is currently done manually in a graphics software. It would be beneficial to achieve this flip programmatically using JavaScript or Three.js.

Issue 2: Three.js specifies that the tiles for Y+ and Y- also require a 180-degree rotation, posing difficulty when handling this task in a graphical application.

Considering these challenges, the primary question arises: Is there an effective method to perform a 180-degree rotation on the necessary tiles after extracting them from the composite image, prior to their implementation in building the skybox?

UPDATE (10th August 2014): Revised question - "How can we create a three.js skyBox utilizing a single image file consisting of 12 equal-sized tiles?"

Below is the code snippet currently employed for reference:

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

    // Additional code truncated for brevity

Answer №1

The Question should be "Creating a skyBox in three.js using a single image file with 12 equal-sized tiles".

(Special thanks to WestLangley for their assistance in achieving this answer).

Here are some important points to consider:

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

    //... Personal             Source image               Desired positions           Required
    //... tile numbering       [column, row]              of tiles in scene            sequence numbers in 
    //... scheme               tile coordinates            xyz positions of 6          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 center of the "cross" represents the view from the skyBox origin in the Z_positive direction.

  • No need to spin by 180 degrees to achieve this.

  • When defining the material, use... side: THREE.FrontSide

  • To avoid mirror images of the source tiles, use... skyBox.scale.set( -1, 1, 1 )

  • To ensure complete processing of images, the function F_cutImageUp now includes creating the skyBox mesh.

  • This method is compatible with the latest version of Three.js (R.68).

  • This code does not utilize MeshShaderMaterial, for a more advanced example check out http://threejs.org/examples/webgl_shaders_ocean.html

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

SkyBox Generation Code (to be added to 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; //... assuming tiled source image has 4 columns(x) by 3 rows(y)

//... 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() 
{ //... dividing 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++) //... selecting the correct tiles for the 6 different faces of the sky box
    {

        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 // <== required
            })
        );

    } 

var skyBoxMaterial = new THREE.MeshFaceMaterial( skyBoxMaterialArray );                         
var skyBox = new THREE.Mesh( skyBoxGeometry, skyBoxMaterial );
skyBox.scale.set( -1, 1, 1 ); // <== required
scene.add( skyBox ); 

}//... end of F_cutImageUp function <== note function includes skyBox mesh creation.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Adjust the size of the input field as text is being typed in

Can a text input box be automatically resized as text is entered? I've been looking online but haven't come across any solutions. ...

Tips for effectively utilizing Timelinemax and Tween for object animation

Hello Amazing Stackoverflow community, I've been attempting to move my object in three.js to a specific point. I believe I need to utilize Tween.js for this task. However, in the tutorial I followed, they imported Tween Js but used 'timelinemax& ...

Tips for removing or changing the X-Powered-By header in a Sails.js application

Running a Sails.js application results in the automatic addition of the HTTP header X-Powered-By: "Sails <sailsjs.org>" to every response. Is there a way to prevent or modify this header? ...

Display the output based on checkbox selection using JavaScript

I am working on a feature where I need to capture checkbox inputs using JavaScript and then store them in a PHP database. Each checkbox corresponds to a specific column in the database. If a checkbox is checked, I want to insert its value into the databa ...

Adjust focus dynamically on pressing enter in an HTML form

I am currently working on adjusting the functionality of my HTML input form to change focus upon pressing the enter key. I need to trigger the saveValue() function from the input field when the enter key is pressed and then move the focus to the next input ...

Despite population, MongooseJS still renders blank array

Currently in the process of developing an application using Node.js with MongooseJS as the middleware for handling database operations. Encountering an issue with nested schemas, specifically with one of them being populated incorrectly. Despite tracking ...

Setting up a new directory with specific permissions using Node.js

I am facing an issue while using the mkdirp node module to create a folder. It is being created with permissions set at 0775 instead of the required 0777. The official documentation states that it should default to 0777, but in my case, it is showing up ...

Different varieties of responsive calendars with built-in memos for various device displays

I developed a responsive calendar with memos for each day. Everything seems to be working fine, but only on two different screen resolutions. When viewing it on my small monitor with the resolution of 1024x768, it displays like this: https://i.sstatic.net ...

What is the best way to send a variable to an Angular library?

I'm currently working on an Angular library that includes a service installed on my main project. I'm curious to find out if there's a way to access either a global URL variable or a specific field from the config.json file that I've se ...

Implementing two-dimensional orientation on particles in three.js

My first attempt at using three.js involves a basic particle animation with 4 different textures mapped onto them. Everything is working smoothly so far, except for one issue - I can't seem to rotate the particles randomly for different orientations ( ...

Filtering integer columns in a Kendo grid based on user input

I am facing an issue with the grid I have set up, which includes multiple columns such as Id(integer) and Name(string). The change event is functioning properly for the Name column, but not for the ID column. I would like this functionality to be implemen ...

Tips for utilizing a variable selector with jQuery's .attr() method

In a jQuery DataTable, there is a scenario where some values can be modified by clicking an edit button. When clicked, a modal popup appears with a form to enter new values for notes and status: ... "columnDefs": [ { ...

An error in Coffeescript and Express.js: attempting to call the 'sliced' method on an undefined object

Currently working on my debut app using express.js and coffeescript. Want to take a look? Find the code here: https://github.com/findjashua/contactlist However, upon attempting to run it, I encountered the following error: /Users/jashua/local/lib/node_mo ...

Turning off and on CSS transitions to set the initial position

Is there a way in javascript to position divs with rotations without using transitions initially for an animation that will be triggered later by css transition? I have tried a codepen example which unfortunately does not work on the platform but works fin ...

Utilize MaterialUI Grid to define custom styles for the ::after pseudo-element

I came across a helpful article on Stack Overflow about Flex-box and how to align the last row to the grid. I'm interested in implementing it in my project: .grid::after { content: ""; flex: auto; } However, I'm not sure how to inc ...

Navigating through Node's asynchronous behavior

I am currently developing a web scraper that gathers data about various shirts from a specific website. I have successfully set up all the necessary NPM packages in Node.js to scrape the information and save it to a CSV file. However, I have encountered ...

Insert multiple text box values as a new entry in an SQL database

Currently, I am implementing a code snippet to incorporate additional text boxes within a form. The main purpose is to enable users to input multiple languages they are proficient in. <script> jQuery(function($) { var i = 0; ...

"The ng-route feature is not working as expected; instead of displaying the template url, it is showing

I'm currently developing a voting application as part of my freecodecamp project using the MEAN stack. I have completed the backend portion, but without user authentication for now. My focus now is on the frontend. I have created an HTML page that li ...

d3: It appears that my routes are replicating themselves, and I am unable to ascertain the cause

I've been diving deep into D3, studying the works of Mike Bostock and other experts in the field. I'm also going through Scott Murray's book on Interactive Data Visualization specifically focusing on D3. At the moment, my project involves c ...

Challenges with navigating in a compact JavaScript application utilizing only a library called page.js

Currently, I am delving into the workings of a small routing library designed for javascript applications called page.js. To better understand how it operates, I created a very basic app for personal learning. However, I am facing issues making it function ...