Skybox (procedural sky)

스카이박스(절차적 하늘)

Painting a full sky — that shifts with time of day — from one shader that mimics atmospheric scattering, no image required.

Also known as: Sky domePreetham sky modelTHREE.Sky
···
js
import * as THREE from 'three';
import { Sky } from 'three/addons/objects/Sky.js';
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(55, 1, 0.1, 400);
camera.position.set(0, 1.2, 6);

const sky = new Sky();
sky.scale.setScalar(100);
scene.add(sky);
const sun = new THREE.Vector3();
sky.material.uniforms.turbidity.value = 3.2;
sky.material.uniforms.rayleigh.value = 1.6;
sky.material.uniforms.mieCoefficient.value = 0.006;
sky.material.uniforms.mieDirectionalG.value = 0.8;

const ground = new THREE.Mesh(new THREE.CircleGeometry(30, 48), new THREE.MeshStandardMaterial({ color: 0x33482c, roughness: 1 }));
ground.rotation.x = -Math.PI / 2;
ground.position.y = -0.6;
scene.add(ground);
const dl = new THREE.DirectionalLight(0xffffff, 1.8);
scene.add(dl);
scene.add(new THREE.AmbientLight(0x9fb3d9, 1.1));

const deco = new THREE.Group();
for (let i = 0; i < 7; i++) {
  const m = new THREE.Mesh(new THREE.ConeGeometry(0.3 + Math.random() * 0.3, 1 + Math.random(), 6), new THREE.MeshStandardMaterial({ color: 0x3a5230, roughness: 0.9 }));
  const a = (i / 7) * Math.PI * 2;
  m.position.set(Math.cos(a) * 3.2, -0.1, Math.sin(a) * 3.2 - 2);
  deco.add(m);
}
scene.add(deco);

function resize() { renderer.setSize(innerWidth, innerHeight); camera.aspect = innerWidth / innerHeight; camera.updateProjectionMatrix(); }
addEventListener('resize', resize); resize();
renderer.setAnimationLoop((t) => {
  const time = t * 0.001;
  const elevation = 20 + Math.sin(time * 0.15) * 12;
  const azimuth = time * 8;
  const phi = THREE.MathUtils.degToRad(90 - elevation);
  const theta = THREE.MathUtils.degToRad(azimuth);
  sun.setFromSphericalCoords(1, phi, theta);
  sky.material.uniforms.sunPosition.value.copy(sun);
  if (sky.material.uniforms.time) sky.material.uniforms.time.value = time;
  dl.position.copy(sun).multiplyScalar(20);
  camera.position.x = Math.sin(time * 0.1) * 1.5;
  camera.lookAt(0, 0.6, -2);
  renderer.render(scene, camera);
});

A classic skybox glues photos onto the six faces of a cube, but three/addons/objects/Sky.js computes physically based atmospheric scattering (the Preetham model) in a shader instead. Feed it a single sun direction (sunPosition) and it works out Rayleigh scattering (the blue sky) and Mie scattering (the hazy glow around the sun) together, so the sky reddens automatically when the sun sits low and blues out when it’s high.

The shader is painted on the inside face (side: BackSide) of one large cube (BoxGeometry) sized with sky.scale.setScalar(N), so as long as the camera stays inside that cube, it always reads as sky. The sun’s position is given in spherical coordinates: convert elevation and azimuth to radians with THREE.MathUtils.degToRad, build a direction vector with Vector3.setFromSphericalCoords, and assign it to sky.material.uniforms.sunPosition.value.

This demo sweeps elevation between 8° and 32° over time, drifting from a low golden-hour sky toward a higher midday one. Four values — turbidity (atmospheric haze), rayleigh (sky-blue intensity), and mieCoefficient/mieDirectionalG (the shape of the sun’s glow) — tune everything from a clear day to a hazy one.

When to use

A quick sky backdrop without an external HDRI, or animating a day/night or sunrise/sunset transition.