1. 만들 것
- 태양계
- 태양계의 라벨
2. 코드
import * as THREE from "../build/three.module.js";
import { OrbitControls } from "../examples/jsm/controls/OrbitControls.js";
import {
CSS2DRenderer,
CSS2DObject,
} from "../examples/jsm/renderers/CSS2DRenderer.js";
class App {
#domContainer;
#renderer;
#scene;
#camera;
#control;
#solarSystem;
#earthOrbit;
#moonOrbit;
#labelRenderer;
constructor() {
const domContainer = document.querySelector("#webgl-container");
this.#domContainer = domContainer;
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
domContainer.appendChild(renderer.domElement);
this.#renderer = renderer;
const labelRenderer = new CSS2DRenderer();
labelRenderer.domElement.style.cssText = `
position: absolute;
top: 0px;
`;
domContainer.appendChild(labelRenderer.domElement);
this.#labelRenderer = labelRenderer;
const scene = new THREE.Scene();
this.#scene = scene;
this.#setupCamera();
this.#setupLight();
this.#setupModel();
this.#setupControls();
window.onresize = this.resize.bind(this);
this.resize();
requestAnimationFrame(this.render.bind(this));
}
resize() {
const width = this.#domContainer.clientWidth;
const height = this.#domContainer.clientHeight;
this.#camera.aspect = width / height;
this.#camera.updateProjectionMatrix();
this.#renderer.setSize(width, height);
this.#labelRenderer.setSize(width, height);
}
#setupCamera() {
const width = this.#domContainer.clientWidth;
const height = this.#domContainer.clientHeight;
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 100);
camera.position.set(0, 0, 10);
this.#camera = camera;
}
#setupLight() {
const color = 0xfffffff;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(-1, 2, 4);
this.#scene.add(light);
}
#setupModel() {
const solarSystem = new THREE.Object3D();
this.#scene.add(solarSystem);
solarSystem.add(new THREE.AxesHelper(20));
const sphereGeometry = new THREE.SphereGeometry(1, 7, 7);
const sunMaterial = new THREE.MeshPhongMaterial({
emissive: 0xffff00,
flatShading: true,
opacity: 0.5,
transparent: true,
});
const sunMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
solarSystem.add(sunMesh);
sunMesh.add(new THREE.AxesHelper(1));
sunMesh.scale.set(5, 5, 5);
const sunDiv = document.createElement("div");
sunDiv.className = "label";
sunDiv.textContent = "태양";
const sunLabel = new CSS2DObject(sunDiv);
sunLabel.position.set(0, 1.2, 0);
sunMesh.add(sunLabel);
const earthOrbit = new THREE.Object3D();
earthOrbit.position.x = 10;
solarSystem.add(earthOrbit);
const earthMaterial = new THREE.MeshPhongMaterial({
color: 0x2233ff,
emissive: 0x112244,
flatShading: true,
opacity: 0.5,
transparent: true,
});
const earthMesh = new THREE.Mesh(sphereGeometry, earthMaterial);
earthMesh.add(new THREE.AxesHelper(1));
earthOrbit.add(earthMesh);
const earthDiv = document.createElement("div");
earthDiv.className = "label";
earthDiv.textContent = "지구구구";
const earthLabel = new CSS2DObject(earthDiv);
earthLabel.position.set(0, 3, 0);
earthMesh.add(earthLabel);
const moonOrbit = new THREE.Object3D();
moonOrbit.position.x = 2;
earthOrbit.add(moonOrbit);
const moonMaterial = new THREE.MeshPhongMaterial({
color: 0x888888,
emissive: 0x222222,
flatShading: true,
opacity: 0.5,
transparent: true,
});
const moonMesh = new THREE.Mesh(sphereGeometry, moonMaterial);
moonOrbit.add(moonMesh);
moonMesh.scale.set(0.5, 0.5, 0.5);
moonMesh.add(new THREE.AxesHelper(1));
const moonDiv = document.createElement("div");
moonDiv.className = "label";
moonDiv.textContent = "달달달달달달";
const moonLabel = new CSS2DObject(moonDiv);
moonLabel.position.set(0, 3, 0);
moonMesh.add(moonLabel);
this.#scene.add(new THREE.AxesHelper(20));
this.#solarSystem = solarSystem;
this.#earthOrbit = earthOrbit;
this.#moonOrbit = moonMesh;
}
#setupControls() {
const control = new OrbitControls(this.#camera, this.#domContainer);
this.#control = control;
}
update(time) {
time *= 0.001;
this.#solarSystem.rotation.y = time / 2;
this.#earthOrbit.rotation.y = time * 2;
this.#moonOrbit.rotation.y = time * 6;
this.#control.update();
}
render(time) {
this.#renderer.render(this.#scene, this.#camera);
this.#labelRenderer.render(this.#scene, this.#camera);
this.update(time);
requestAnimationFrame(this.render.bind(this));
}
}
window.onload = function () {
new App();
};