Scene Graph를 이용한 공간구성
Object3D의 파생클래스
-
Mesh : 3차원 면으로 구성된 객체 표현
-
Line : 선형 객체를 표현
- LineSegments : 두 개의 점을 이어 한 선을 만듬
- LineLoop : Line 처럼 순서대로 이어오다 마지막 좌표와 첫번째 좌표를 이음
-
Points : 점 표현
이러한 Mesh, Line, Points에 대한 3차원 객체는 3차원 공간 상에 놓여지게됨._
-
3D Object가 3차원 공간 상에 놓여지기 위해서는 위치, 회전, 크기 값이 필요
-> Object 3D는 position(위치), rotation(회전), scale(크기)이라는 속성 가짐
- position : xyz 축에 대한 위치 값. (모든 기본값 : 0)
- rotation : xyz 축에 대한 회전 값. (모든 기본값 : 0)
- scale : xyz 축에 대한 크기의 배수 값.(모든 기본값 : 1 = 원래크기)
- position, rotation, scale은 4x4 크기의 행렬 정보로 변환
- 모니터 기준으로 X축은 화면의 오른쪽이 +, 왼쪽이 -
- 모니터 기준으로 Y축은 화면의 위쪽이 +, 아래쪽이 -
- 모니터 기준으로 Z축은 모니터의 바깥 방향이 +, 안쪽 방향이 -
3차원 공간 상의 장면 구성 : Scene Graph를 코드로 작성
태양, 지구, 달에 대한 scene graph
- 검은 글자 : 오른쪽 클래스로 생성된 객체의 이름
- 회색 글자 : 클래스 타입
- 화살표 : 자식을 가리킴
/*three.js 라이브러리를 module 버전으로 import*/
import * as THREE from '../build/three.module.js';
/*three.module.js에 App이 정의되어 있음*/
class App{
constructor(){
/*divContainer*/
const divContainer = document.querySelector("#webgl-container");
this._divContainer = divContainer;/*다른 method에서 참조할 수 있도록 필드로 정의*/ //밑줄로 시작:이 App 클래스 내부에서만 사용되는 private field, private method라는 의미(개발자들간의 약속-밑줄로 시작하는 것은 외부에서 호출해서는 안됨)
/*rederer*/ //THREE = three.js WebGLRenderer = three.js의 클래스 중 하나
const renderer = new THREE.WebGLRenderer({ antialias: true });//생성할 때 옵션 - 3차원 장면이 렌더링 될 때 오브젝트들의 경계선이 계단 현상 없이 부드럽게 표현
renderer.setPixelRatio(window.devicePixelRatio);//픽셀의 ratio 값 정의(pixel ratio 값은 window의 devicePixelRatio 속성으로 쉽게 얻을 수 있음) 150%일때 1.5 등
divContainer.appendChild(renderer.domElement);//생성된 renderer의 domElement를 webjl-container인 divContainer의 자식으로 추가 renderer.domElement : canvas 타입의 dom 객체
this._renderer = renderer;//rederer가 다른 method에서 참조할 수 있도록 this._renderer로 정의
/*scene*/
const scene = new THREE.Scene();//Scene 객체 생성하는 코드 Scene 클래스 불러옴
this._scene = scene;//scene객체 필드화
/*하위 3개 코드 따로 정의해야하는 것임*/
this._setupCamera();//camera 객체 구성
this._setupLight();//light를 설정하는 메서드
this._setupModel();//3차원 모델 설정하는 메서드
window.onresize = this.resize.bind(this);//창 크기가 변경되면 발생하는 onresize 이벤트에 이 클래스의 resize method 지정 : renderer나 camera는 창 크기 변경될 때마다 그 크기에 맞게 속성 값 재설정해야하기 때문에 필요 //bind : resize method 안에서 this가 가르치는 객체가 아닌 이 App 클래스의 객체가 되도록 하기 위함
this.resize();//창 크기에 맞게 설정
requestAnimationFrame(this.render.bind(this));//적당한 시점에 또한 최대한 빠르게 renderer method를 호출
}
_setupCamera(){/*Camera 생성하는 코드*/
/*three.js가 3차원 그래픽 출력할 영역에 대한 가로와 세로에 대한 크기 얻어옴 */
const width = this._divContainer.clientWidth;
const height = this._divContainer.clientHeight;
/*얻어온 크기를 이용해 카메라 객체 생성*/
const camera = new THREE.PerspectiveCamera(
75,
width / height,
0.1,
100
);
camera.position.z = 25;
this._camera = camera;//또 다른 method에서 사용할 수 있도록 함
}
_setupLight(){/*Light(광원) 생성하는 코드*/
const color = 0xffffff;//광원 색상
const intensity = 1;//광원 세기 값
const light = new THREE.DirectionalLight(color,intensity);//위 두가지 값으로 광원 생성
light.position.set(-1,2,4);//광원 위치 설정
this._scene.add(light); //생성한 광원을 scene 객체의 구성요소로 추가
}
_setupModel(){
//Object3D 타입의 SolarSystem 객체 생성 후 scene에 추가
const solarSystem = new THREE.Object3D();
this._scene.add(solarSystem);
//구 모양의 지오메트리 생성
const radius = 1; //반지름 1
const widthSegments = 12;
const heightSegments = 12;
const sphereGeometry = new THREE.SphereGeometry(radius,widthSegments,heightSegments);
//태양의 재질 생성
const sunMaterial = new THREE.MeshPhongMaterial({
emissive : 0xffff00, flatShading: true});
//지오메트리와 태양의 재질을 이용해 sunMesh 객체 생성, solarSystem에 추가
const sunMesh = new THREE.Mesh(sphereGeometry,sunMaterial);
sunMesh.scale.set(3,3,3);//원래 지오메트리가 갖는 크기보다 xyz축에 대해 3배의 크기로 표시하기 위함
solarSystem.add(sunMesh);
/*지구*/
const earthOrbit = new THREE.Object3D();
solarSystem.add(earthOrbit);
const earthMaterial = new THREE.MeshPhongMaterial({
color:0x2233ff, emissive:0x112244, flatShading:true
});
const earthMesh = new THREE.Mesh(sphereGeometry,earthMaterial);
earthOrbit.position.x = 10;//태양에서 x축으로 거리 10만큼 떨어진 위치에 지구가 배치 되도록 하기 위함
earthOrbit.add(earthMesh);
/*달*/
const moonOrbit = new THREE.Object3D();
moonOrbit.position.x = 2;//지구로부터 2만큼 떨어지고 태양으로부터 12만큼 떨어짐
earthOrbit.add(moonOrbit);
const moonMaterial = new THREE.MeshPhongMaterial({
color:0x888888, emissive:0x222222, flatShading:true });
const moonMesh = new THREE.Mesh(sphereGeometry, moonMaterial);
moonMesh.scale.set(0.5,0.5,0.5);
moonOrbit.add(moonMesh);
this._solarSystem = solarSystem;
this._earthOrbit = earthOrbit;
this._moonOrbit = moonOrbit;
}
resize(){
const width = this._divContainer.clientWidth;
const height = this._divContainer.clientHeight;
this._camera.aspect = width / height;
this._camera.updateProjectionMatrix();
this._renderer.setSize(width, height);
}
render(time){//time:렌더링 시작 후 경과된 시간 값(밀리 초) - scene의 애니메이션에 이용할 수 있음. requestAnimationFrame 함수가 render 함수에 전달해주는 값.
this._renderer.render(this._scene, this._camera);//renderer가 scene을 카메라 시점으로 렌더링 하는 코드
this.update(time);//속성 값 변경 : 애니메이션 효과
requestAnimationFrame(this.render.bind(this)); //render method 반복해 호출 되도록 함(무조건은 아니고 적당한 시점에 최대한 빠르게)
}
update(time){
time *= 0.001; // second unit:전달받은 time에 0.001을 곱해서 second 단위로 변환
this._solarSystem.rotation.y = time / 2;
this._earthOrbit.rotation.y = time * 2;
this._moonOrbit.rotation.y = time *5;
}
}//class
window.onload = function(){
new App();
}
Author And Source
이 문제에 관하여(Scene Graph를 이용한 공간구성), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@mh0223/Scene-Graph를-이용한-공간구성저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)