three.js 버전이 변경되어 작동되지 않는 문제로 소스를 개조하였습니다.
본문과 좀 일치하지 않는 부분이 있을수 있으며 아래 URL 에서 정상작동됩니다.
http://dreamplan7.cafe24.com/canvas2/three011.html
3차원 웹 가상세계에서도 시계는 돌아갑니다.
똑딱똑딱-
마치 디즈니 애니메이션 겨울왕국에서 엘사와 함께 할 수 없어 시계만 마냥 바라보며 소리내는 안나처럼 말입니다 :)
과거에는 시간을 측정하는 도구로서 해시계가 있었지요.
비록 비오는 날이면 무용지물이긴 하지만, 그래도 햇볓의 그림자로 시간을 알아낼 수 있었던 것은 조상들의 지혜가 아닌가 생각됩니다.
모두가 태앙이 지구 주위를 회전한다는 천동설을 주장할 때에
갈릴레오 갈릴레이는 지구가 회전한다는 지동설을 주장하였지요.
협박에 못 이겨서 자신의 주장을 굽히면서도 '그대로 지구는 돈다'라고 되뇌이던 갈릴레오 갈릴레이의 주장은 지금에 와서야 그 사실이 더욱 확고해졌습니다.
하지만, HTML5 3차원 웹 캔버스의 세계에서는 약간 다른 원리가 작동합니다.
바로 천동설이지요 :) 3차원 웹 공간에서 바다와 대륙을 중심으로 태양이 도는 것입니다.
실제 이 지구의 원리와는 어쩌면 다른 세계이고,
갈릴레오 갈릴레이가 들으면 화를 낼 법하기도 한데요.
그렇게 될 수 밖에 없는 이유는 바로 지동설의 세계를 만드는 것은 어렵기 때문입니다. :)
그냥 XYZ축으로 구성된 3차원 공간에서 XZ 축으로 휘어지지 않은 평면이 쫙 뻗어있고
태양이 세계를 빙글빙글 회전하는 것이 더욱 구현하기가 쉽기 때문이지요 :)
이번 시간에는 태양이 캔버스의 세계를 빙글빙글 돌면서 새벽부터 자정까지, 자정부터 다시 다음날 새벽까지 시간이 무한 반복되는 세계를 표현해보겠습니다.
맨 앞에서 보셨던 영상처럼 말이죠 :)
우선 지난 번에 소스를 나누었기 때문에 일부 소스만 수정해주시면 됩니다.
먼저 모델을 불러들이는 부분에 약간의 문제가 있었으며 수정하였습니다.
바로 자바스크립트의 특성 때문인데요.
관련 정의는 아래와 같습니다.
< 자바스크립트 call by value, call by reference 특성 >
자바스크립트에서는
함수 안에서 변수자체에 값을 개입하면,
함수가 종료될 경우 변수를 사용할 수 없는 특성이 있습니다.
대신 함수 안에서 변수의 속성에 값을 할당하면
함수가 종료되어도 변수의 속성을 사용할 수 있는데요.
이를 위해서 변수를 함수 밖에서 먼저 Object() 형으로 선언하여야 합니다.
변경된 소스는 아래와 같은데요.
세세한 원리까지 설명드리자면, 너무 깊이 들어가니까 차후에 기회가 되면 다뤄보도록 하겠습니다.
< js/LoadModel.js >
// 집 모델
var home_mesh = new Object();
loadDAE(
'http://dreamplan7.cafe24.com/canvas/img/homeK.dae',
home_mesh,
function(obj){
scene.add( obj );
obj.rotation.set(-90 * PI_PER_180, 0, -90 * PI_PER_180);
obj.position.set(0,3,0);
}
);
// 섬 모델
var land_mesh = new Object();
loadDAE(
'http://dreamplan7.cafe24.com/canvas/dae/island3.dae',
land_mesh,
function(obj){
scene.add( obj );
obj.rotation.set(-90 * PI_PER_180, 0, 0);
obj.position.set(0,-50,50);
obj.scale.set(300,300,300);
}
);
// 바닥
var floor;
loader.load(
'http://dreamplan7.cafe24.com/canvas/img/floor1.jpg',
function ( texture ) {
floor = new THREE.Mesh(
new THREE.BoxGeometry(10, 10, 10)
);
floor.material = new THREE.MeshStandardMaterial({map: texture});
floor.material.map.repeat.x=3;
floor.material.map.repeat.y=3;
floor.material.map.wrapS=THREE.RepeatWrapping;
floor.material.map.wrapT=THREE.RepeatWrapping;
floor.position.set(0, -3, 0);
floor.receiveShadow=true;
scene.add(floor);
}
);
<CrayCommon.js>
// 3차원 세계
var scene = new THREE.Scene();
const PI_PER_180 = Math.PI / 180;
var loader = new THREE.TextureLoader();
var loaderMesh = new THREE.ColladaLoader();
function loadDAE(file, obj, callback)
{
if(obj == undefined)obj=new Object();
loaderMesh.load(
file,
function ( collada ){
obj.obj = collada.scene;
var i;
for(i=0;i<obj.obj.children.length;++i)
obj.obj.children[i].castShadow=true;
callback(obj.obj);
});
}
// 렌더러 정의 및 크기 지정, 문서에 추가하기
var renderer = new THREE.WebGLRenderer( { antialias: true, preserveDrawingBuffer: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFShadowMap; // <-- 속도가 빠르다
renderer.gammaInput = true;
renderer.gammaOutput = true;
그리고 금번 강좌에 해당하는 새로운 버전의 HTML 파일인데
변경된 부분은 <script src="js/three011.js"></script> 밖에는 없습니다.
<three011.html>
<html>
<head>
<title>3차원웹 캔버스</title>
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
</style>
</head>
<body>
<script src="https://threejs.org/build/three.min.js"></script>
<script src="js/OrbitControls.js"></script>
<script src="js/ColladaLoader.js"></script>
<script src="js/Sky.js"></script>
<script src="js/Water.js"></script>
<!-- 이 위쪽은 three.js 라이브러리 -->
<script src="js/CrayCommon.js"></script>
<script src="js/LoadCamera.js"></script>
<script src="js/LoadLight.js"></script>
<script src="js/LoadSkySea.js"></script>
<script src="js/LoadModel.js"></script>
<script src="js/three011.js"></script>
</body>
</html>
그리고 변경된 three011.js 파일의 내용은 아래와 같은데요.
var framesPerSecond=30;
// 에니메이션 효과를 자동으로 주기 위한 보조 기능입니다.
var animate = function () {
// 프레임 처리
setTimeout(function() {
requestAnimationFrame(animate);
}, 1000 / framesPerSecond);
if(home_mesh.obj != undefined)
{
home_mesh.obj.rotation.set(-90 * PI_PER_180, 0, -45 * PI_PER_180);
}
water.material.uniforms[ 'time' ].value += 1.0 / 60.0;
parameters.azimuth+=0.001;
phi = 2 * Math.PI * ( parameters.azimuth - 0.5 );
light_sun.position.x = parameters.distance * Math.cos( phi );
light_sun.position.y = parameters.distance * Math.sin( phi ) * Math.sin( theta );
light_sun.position.z = parameters.distance * Math.sin( phi ) * Math.cos( theta );
sky.material.uniforms['sunPosition'].value = light_sun.position.copy( light_sun.position );
water.material.uniforms['sunDirection'].value.copy( light_sun.position ).normalize();
cubeCamera.update( renderer, sky );
// 랜더링을 수행합니다.
renderer.render( scene, camera );
};
// animate()함수를 최초에 한번은 수행해주어야 합니다.
animate();
우선 집 모형의 로딩이 완료될 경우 45도로 틀어서 보여주도록 하였습니다.
큰 의미는 없고요. 그림자가 더욱 확연하게 돋보이도록 하기 위함입니다.
if(home_mesh.obj != undefined)
{
home_mesh.obj.rotation.set(-90 * PI_PER_180, 0, -45 * PI_PER_180);
}
그리고 태양의 좌표를 조정하는 부분입니다.
사실 외국 소스를 가져온 거라서, 100% 이해가 되지는 않지만,
여러모로 이것 저것 시험해본 결과를 반영한 것이지요.
parameters.azimuth+=0.001;
phi = 2 * Math.PI * ( parameters.azimuth - 0.5 );
light_sun.position.x = parameters.distance * Math.cos( phi );
light_sun.position.y = parameters.distance * Math.sin( phi ) * Math.sin( theta );
light_sun.position.z = parameters.distance * Math.sin( phi ) * Math.cos( theta );
sky.material.uniforms['sunPosition'].value = light_sun.position.copy( light_sun.position );
water.material.uniforms['sunDirection'].value.copy( light_sun.position ).normalize();
cubeCamera.update( renderer, sky );
먼저 parameters.azimuth 는 태양의 위치를 의미합니다.
여기서는 0이 새벽 6시이고, 0.5가 오후 6시입니다.
0.75면 밤 12시이고, 0.75부터 1까지는 한 밤중이지요
그 값을 계속 0.001 씩 추가 갱신하면서,
태양의 위치값을 삼각함수를 이용해서 산출해주고,
light_sun.position.x = parameters.distance * Math.cos( phi );
light_sun.position.y = parameters.distance * Math.sin( phi ) * Math.sin( theta );
light_sun.position.z = parameters.distance * Math.sin( phi ) * Math.cos( theta );
계산된 결과를 하늘과 바다에 투영해 주는 겁니다 :)
sky.material.uniforms['sunPosition'].value = light_sun.position.copy( light_sun.position );
water.material.uniforms['sunDirection'].value.copy( light_sun.position ).normalize();
cubeCamera.update( renderer, sky );
그래서 시간이 점점 흘러갈수록 태양의 위치와 그림자의 위치도 바뀌는 것이지요.
실제 반영 예제는 아래 URL에서 확인해보실 수 있습니다.
http://dreamplan7.cafe24.com/canvas2/three011.html\
여기까지 읽어주셔서 감사드립니다.
수고하셨습니다 :)
다음강좌 보러 가기 / https://itadventure.tistory.com/63
'자바스크립트와 캔버스' 카테고리의 다른 글
3차원 웹, 창공을 누비는 카메라! - 25번째 시간 (5) | 2019.07.20 |
---|---|
3차원 웹 캔버스, 원터치 버튼 이동! - 24번째 시간 (14) | 2019.07.17 |
3차원 웹, 소스의 체계적 정리, 22번째 시간 (2) | 2019.07.15 |
3차원 웹, 땅아 드러나라!, 캔버스와 함께하는 자바스크립트, 21번째 시간 (2) | 2019.07.13 |
3차원 웹, 하늘과 바다를 만들어 봐, 캔버스와 함께하는 자바스크립트, 20번째 시간 (6) | 2019.07.07 |