Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for How to Create a Skybox With Three.js
Cody Pearce
Cody Pearce

Posted on • Originally published atcodinhood.com

     

How to Create a Skybox With Three.js

This was originally published oncodinhood.com

Skyboxes are typically used in video games to create the illusion of far off three-dimensional backgrounds. A skybox is essentially a cube with textures on each side of the cube. The player or camera is then placed within the cube so that all six textures surround them giving them the illusion that they're within a much larger environment.reactnativeinfinity.com makes use of this technique to create the illusion of spinning in space. The Codepen below has a few different skyboxes you can try out. Click and drag the screen to move around.

Three.js setup

First, set up ascene,camera, andrenderer within aninit function we will call to initialize Three.js. We'll use aPerspectiveCamera with a position that is zoomed out pretty far so we can see the box before jumping in. We'll also use theTHREE.WEbGLRenderer and append it to the body of the page. Finally, theanimate function will handle rerendering the scene with any updates we add.

letscene,camera,renderer,skyboxGeo,skybox;functioninit(){scene=newTHREE.Scene();camera=newTHREE.PerspectiveCamera(55,window.innerWidth/window.innerHeight,45,30000);camera.position.set(1200,-250,20000);renderer=newTHREE.WebGLRenderer({antialias:true});renderer.setSize(window.innerWidth,window.innerHeight);renderer.domElement.id="canvas";document.body.appendChild(renderer.domElement);animate();}functionanimate(){renderer.render(scene,camera);requestAnimationFrame(animate);}init();

Import the core Three.js library.

<scriptsrc="https://threejs.org/build/three.min.js"></script>

Set the body height to the viewport height and add a grey background to the body so we can see the cube.

body{margin:0;height:100vh;background:#bdc3c7;}

Since we haven't added any objects we'll only see a grey background right now.

Add Three.js box

We can add a box withTHREE.BoxGeometry withwidth,height, anddepth set to10000. Then useTHREE.Mesh to apply a texture to it, in this case, it will default to a purewhite texture. Finally, add the object to the scene before calling theanimate function within theinit function.

functioninit(){...skyboxGeo=newTHREE.BoxGeometry(10000,10000,10000);skybox=newTHREE.Mesh(skyboxGeo);scene.add(skybox);animate();

Simple Box

Even though it's a cube, it looks like a square because we're viewing it straight on. To verify it is a cube we can add a rotation animation within theanimate function:

functionanimate(){skybox.rotation.x+=0.005;skybox.rotation.y+=0.005;renderer.render(scene,camera);requestAnimationFrame(animate);}

Simple cube

Skybox Mesh Material

You can find free skybox images onopengameart.org or you can search Google for "free skybox images". There should be six images that correspond to each side of the cube that seamlessly mesh together. For example, for React Native Infinity, the six space images correspond to different sides as shown below.

Skybox Names

Each image should be named according to the side which they correspond to, for example,purplenebula_ft.png is the front image,purplenebula_rt.png is the right image, andpurplenebula_dn.png is the bottom image. There are three steps we need to follow to add these images to our cube:

  1. Load each image as a Texture
  2. Map each Texture to a Material array
  3. Add Material array to the Skybox cube

1. Load Images as Textures

Textures can be loaded in Three.js using theTextureLoader().load() function. Theload() method takes the path of the image as a parameter. We could load each image by creating sixTextureLoader() functions, like this:

constft=newTHREE.TextureLoader().load("purplenebula_ft.jpg");constbk=newTHREE.TextureLoader().load("purplenebula_bk.jpg");constup=newTHREE.TextureLoader().load("purplenebula_up.jpg");constdn=newTHREE.TextureLoader().load("purplenebula_dn.jpg");constrt=newTHREE.TextureLoader().load("purplenebula_rt.jpg");constlf=newTHREE.TextureLoader().load("purplenebula_lf.jpg");

But it would be better to create a reusable function that loops through all of our images for us. Create a functioncreatePathStrings() that will create an array of path strings from a file image name,filename.

functioncreatePathStrings(filename){constbasePath="./static/skybox/";constbaseFilename=basePath+filename;constfileType=".png";constsides=["ft","bk","up","dn","rt","lf"];constpathStings=sides.map(side=>{returnbaseFilename+"_"+side+fileType;});returnpathStings;}

This should create an array of strings that represent the path to each image:

['./static/skybox/purplenebula_ft.jpg','./static/skybox/purplenebula_bk.jpg',...]

Next, load each texture usingTextureLoader().load() by mapping over the array above. Let's create another function,createMaterialArray(), to generate a new array of loaded textures. We will also pass in thefilename parameter into thecreatePathStrings function.

letskyboxImage="purplenebula";functioncreateMaterialArray(filename){constskyboxImagepaths=createPathStrings(filename);constmaterialArray=skyboxImagepaths.map(image=>{lettexture=newTHREE.TextureLoader().load(image);returntexture;});returnmaterialArray;}

2. Map each Texture to a Mesh array

TheMeshBasicMaterial() Three.js method will allow us to map our textures above to a Three.js material. Instead of creating another function to do this, we can simply modify thecreateMaterialArray() function to return a Three.js material instead of the loaded texture.

functioncreateMaterialArray(filename){constskyboxImagepaths=createPathStrings(filename);constmaterialArray=skyboxImagepaths.map(image=>{lettexture=newTHREE.TextureLoader().load(image);returnnewTHREE.MeshBasicMaterial({map:texture,side:THREE.BackSide});// <---});returnmaterialArray;}

3. Add Mesh array to the Skybox cube

We're finally ready to add our mesh array to the cube we created above. First, create a variable,skyboxImage, with the base file name. Pass that variable into thecreateMaterialArray to generate our mesh array. Finally, pass that array into the second parameter of thenew Three.Mesh() function.

constskyboxImage='purplenebula';functioninit(){...constmaterialArray=createMaterialArray(skyboxImage);skyboxGeo=newTHREE.BoxGeometry(10000,10000,10000);skybox=newTHREE.Mesh(skyboxGeo,materialArray);scene.add(skybox);animate();}

Our cube should now have the mesh array, click the "Outside Box" button to see how this should look.

Place camera inside the cube

We can change thecamera'sz position from20000 to2000 to put the camera inside the cube.

functioninit()...camera.position.set(1200,-250,2000);...}

Inside the cube

Orbit Controls

While the above works to put us inside the cube, it would be better if could control the camera with the mouse and look around the environment. The Orbit Controls package for Three.js allows us to do that add a<script> import:

<scriptsrc="https://threejs.org/build/three.min.js"></script><scriptsrc="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

First, add another variable namedcontrols to the initialization at the top. Then assign that variable to theOrbitControls method while passing in thecamera anddomElement. Enable the controls by settingcontrols.enabled totrue. Finally, set aminDistance andmaxDistance so that the user cannot zoom outside of the cube.

letscene,camera,renderer,skyboxGeo,skybox,controls;functioninit(){...controls=newTHREE.OrbitControls(camera,renderer.domElement);controls.enabled=true;controls.minDistance=700;controls.maxDistance=1500;...animate();}

Next, remove the rotation in theanimate() function and addcontrols.update();

functionanimate(){controls.update();renderer.render(scene,camera);requestAnimationFrame(animate);}

You should now be able to click and drag the environment around to see whatever part you want. If you want the environment to rotate again, like you're in space rotating, you can use theautoRotate property:

functioninit(){...controls=newTHREE.OrbitControls(camera,renderer.domElement);controls.enabled=true;controls.minDistance=700;controls.maxDistance=1500;controls.autoRotate=true;controls.autoRotateSpeed=1.0;...animate();}

Resize window

If you resize your browser window after initialization the canvas will not resize to fit the new window size. To fix this create a function to redefine thecamera.aspect andrenderer size to the height and width of thewindow:

functiononWindowResize(){camera.aspect=window.innerWidth/window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth,window.innerHeight);}

Then add an event listener on thewindowresize event and pass this new function. Add this event listener to theinit() function right above theanimate() call.

functioninit(){...window.addEventListener('resize',onWindowResize,false);animate();}

The canvas will now resize with the window.

Conclusion

Skyboxes are a neat way to create the illusion of a 3d environment quickly. Although generally used for video games, there might be some creative ways you could implement them in a web project.

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Front end developer working with React, React Native, and CSS.
  • Location
    Washington
  • Work
    Front End Developer at Fullstack Labs
  • Joined

More fromCody Pearce

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp