원근감을 표현해 랜더링
zNear와 zFar 사이에 장면의 모든 물체가 들어와야 화면에 보임.
_setupCamera() {
const width = this._app.clientWidth;
const height = this._app.clientHeight;
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 100);
// ddd
camera.position.set(7, 7, 0); // 카메라의 위치
camera.lookAt(0, 0, 0); // 카메라가 바라보는 위치
this._camera = camera;
this._scene.add(camera);
}
원근감 없이 물체의 크기대로 랜더링
import "../scss/common.scss";
import * as THREE from "three";
import webGL from "three/examples/jsm/capabilities/WebGL";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { RectAreaLightUniformsLib } from "three/examples/jsm/lights/RectAreaLightUniformsLib";
import { RectAreaLightHelper } from "three/examples/jsm/helpers/RectAreaLightHelper";
class App {
constructor() {
const scene = new THREE.Scene();
const renderer = new THREE.WebGLRenderer({ antialias: true });
const app = document.getElementById("app");
this._scene = scene;
this._renderer = renderer;
this._app = app;
this._renderer.setPixelRatio(window.devicePixelRatio);
this._renderer.setSize(window.innerWidth, window.innerHeight);
this._app.appendChild(this._renderer.domElement);
this._setupCamera();
this._setupLight();
this._setupModel();
this._setupControls();
window.onresize = this.resize.bind(this);
this.resize();
requestAnimationFrame(this.render.bind(this));
// if (webGL.isWebGLAvailable()) {
// animate();
// } else {
// const warning = webGL.getWebGLErrorMessage();
// document.getElementById("app").appendChild(warning);
// }
}
_setupCamera() {
// const width = this._app.clientWidth;
// const height = this._app.clientHeight;
const camera = new THREE.PerspectiveCamera(
75,
window.innerHeight / window.innerHeight,
0.1,
100
);
// ddd
camera.position.set(7, 7, 0); // 카메라의 위치
camera.lookAt(0, 0, 0); // 카메라가 바라보는 위치
this._camera = camera;
// this._scene.add(camera);
}
_setupLight() {
RectAreaLightUniformsLib.init(); // 광원을 사용하기 위해 초기화 코드 선행
const light = new THREE.RectAreaLight(0xffffff, 10, 6, 1);
// 색상, 세기, 광원의 가로길이, 광원의 세로길이
light.position.set(0, 5, 0);
light.rotation.x = THREE.Math.degToRad(-90); // -90도 방향으로 빛을 비춤
const helper = new RectAreaLightHelper(light);
light.add(helper);
this._scene.add(light);
this._light = light;
}
_setupModel() {
const groundGeometry = new THREE.PlaneGeometry(10, 10);
const groundMaterial = new THREE.MeshStandardMaterial({
color: "#2c3e5a",
roughness: 0.5,
metalness: 0.5,
side: THREE.DoubleSide,
});
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
ground.rotation.x = THREE.Math.degToRad(-90);
this._scene.add(ground);
const bigSphereGeometry = new THREE.SphereGeometry(1.5, 64, 64, 0, Math.PI);
const bigSphereMaterial = new THREE.MeshStandardMaterial({
color: "#fff",
roughness: 0.1,
metalness: 0.2,
});
const bigSphere = new THREE.Mesh(bigSphereGeometry, bigSphereMaterial);
bigSphere.rotation.x = THREE.Math.degToRad(-90);
this._scene.add(bigSphere);
const torusGeometry = new THREE.TorusGeometry(0.4, 0.1, 32, 32);
const torusMaterial = new THREE.MeshStandardMaterial({
color: "#9b59b6",
roughness: 0.5,
metalness: 0.9,
});
for (let i = 0; i < 8; i++) {
const torusPivot = new THREE.Object3D();
const torus = new THREE.Mesh(torusGeometry, torusMaterial);
torusPivot.rotation.y = THREE.Math.degToRad(45 * i);
torus.position.set(3, 0.5, 0);
torusPivot.add(torus);
this._scene.add(torusPivot);
}
const smallSphereGeometry = new THREE.SphereGeometry(0.3, 32, 32);
const smallSphereMaterial = new THREE.MeshStandardMaterial({
color: "#e74c3c",
roughness: 0.2,
metalness: 0.5,
});
const smallSpherePivot = new THREE.Object3D();
const smallSphere = new THREE.Mesh(
smallSphereGeometry,
smallSphereMaterial
);
smallSpherePivot.add(smallSphere);
smallSpherePivot.name = "smallSpherePivot"; // 이름을 부여해주면 scene 객체를 통해 언제든 조회할 수 있다.
smallSphere.position.set(3, 0.5, 0);
this._scene.add(smallSpherePivot);
const targetPivot = new THREE.Object3D();
const target = new THREE.Object3D();
targetPivot.add(target);
targetPivot.name = "targetPivot";
target.position.set(3, 0.5, 0);
this._scene.add(targetPivot);
}
_setupControls() {
new OrbitControls(this._camera, this._app);
}
resize() {
const width = this._app.clientWidth;
const height = this._app.clientHeight;
const aspect = width / height;
if (this._camera instanceof THREE.PerspectiveCamera) {
this._camera.aspect = aspect;
} else {
this._camera.left = -1 * aspect; // xLeft
this._camera.right = 1 * aspect; // xRight
}
this._camera.updateProjectionMatrix();
this._renderer.setSize(width, height);
}
render(time) {
// time : 렌더링이 처음 시작된 이후 경과된 값으로 밀리세컨드
this._renderer.render(this._scene, this._camera);
this.update(time);
requestAnimationFrame(this.render.bind(this));
}
update(time) {
time *= 0.001;
const smallSpherePivot = this._scene.getObjectByName("smallSpherePivot");
if (smallSpherePivot) {
smallSpherePivot.rotation.y = THREE.Math.degToRad(time * 50);
const smallSphere = smallSpherePivot.children[0];
smallSphere.getWorldPosition(this._camera.position);
const targetPivot = this._scene.getObjectByName("targetPivot");
if (targetPivot) {
targetPivot.rotation.y = THREE.Math.degToRad(time * 50 + 10);
const target = targetPivot.children[0];
const pt = new THREE.Vector3();
target.getWorldPosition(pt);
this._camera.lookAt(pt);
}
if (this._light.target) {
const smallSphere = smallSpherePivot.children[0];
smallSphere.getWorldPosition(this._light.target.position);
if (this._lightHelper) this._lightHelper.update();
}
}
}
}
window.onload = () => {
new App();
};