상세 컨텐츠

본문 제목

WebGL 의 Three.js 활용 관련

WEB/WebGL

by AlrepondTech 2017. 11. 1. 12:07

본문

반응형

 

 

 

=======================

=======================

=======================

 

 

 

출처: https://blog.pigno.se/post/131780373668/threejs%EC%99%80-webgl

 

Three.js를 들어본적이 있는가? 아니면 WebGL을 아는지 묻고싶다. WebGL부터 설명하자면 3D 랜더링을 위한 일반 개발환경의 OpenGL의 ES 2.0을 바탕으로 웹에서 구동 할 수 있게 제공한 기술이다. 물론 WebGL은 브라우저마다 사용이 되는 것도 있고 불가한 브라우저도 존재한다.

http://caniuse.com/#feat=webgl 주소를 들어가 보면 WebGL을 지원하는 브라우저 목록을 확인할 수 있는데 인터넷 익스플로러 같은 경우 11버전부터 지원하기에 윈도우8 사용자 부터 사용이 가능하다고 생각하는게 편하다고 본다. 이는 Canvas 지원 브라우저 중에 일부를 지원한다는 의미로 보면 된다.

그럼 Three.js는 뭘까. Three.js에 간단한 설명으로는 Javascript 3D library이다. 이는 WebGL 기술을 기반으로 랜더링과 카메라, 조명등의 3D 프로그래밍 기술을 간단하게 사용 할 수 있도록 제공한 라이브러리 이며, Three.js를 사용하면 매핑, 카메라 변경, 모델처리 등 간단하게 사용할 수 있는 가이드라인을 제공한다. http://threejs.org

 

필자는 GitHub 오픈소스 프로젝트로 3D Mockup Javascript Plugin을 개발하고 있는데 이는 WebGL Based 기술이기 때문에 Three를 채택했다. 이유는 목업 디바이스에 사용자가 원하는 각도로 데모를 표현하기 위해서는 디바이스 모델을 실시간으로 보여줄 수 있는 웹 스팩이 필요하기 때문이다. https://github.com/KennethanCeyer/MockupJS 이 주소로 들어가 보면 오픈소스 프로젝트를 확인 할 수 있다.

 

위의 데모와 같이 Three.js로 제작한 많은 WebGL 사이트들이 존재하고 있으며 필자가 확인해본 결과 IE11+, OS X의 사파리, 크롬등에서 문제없이 잘 돌아간다.(물론 리소스를 많이 잡아먹는 느낌이 든다.)

Three.js의 Python으로 제공된 컨버터(https://github.com/mrdoob/three.js/blob/master/utils/converters/obj/convert_obj_three.py)를 사용하면 3D MAX나 블렌더에서 제작한 모델을 obj 확장자로 export한 후 해당 py로 Javascript에 맞는 json으로 컨버팅이 가능하다.

더 자세한 사항은 차차 MockupJS를 개발하며 추가로 포스팅 할 예정이다.

 

 

 

=======================

=======================

=======================

 

 

 

 

출처: https://msdn.microsoft.com/ko-kr/library/dn479430(v=vs.85).aspx

 

Three.js를 사용한 기본 3D 그래픽

 

3D 그래픽 및 WebGL 기반 Three.js 라이브러리를 사용한 렌더링의 기본 사항을 알아봅니다.

기본 큐브

셰이더 및 필요한 수학(행렬사원수 등)과 더불어 네이티브 WebGL 그래픽 프로그래밍은 복잡할 수 있습니다. 이러한 복잡성을 줄이는 데 도움이 되도록 Three.js를 비롯한 여러 단순화 라이브러리가 있습니다. 이 라이브러리의 기본 사항에 대해서는 다음에 설명합니다.

OpenGL과 마찬가지로 Three.js는 오른쪽 좌표계를 사용합니다.

 

이 그림에서 컴퓨터 화면은 xy 평면과 일치하며 원점 (0, 0, 0)에 중심이 있습니다. 양의 z축은 화면에서 관찰자 쪽을 가리킵니다.

구형 등의 Three.js 개체를 장면에 추가하면 기본적으로 개체가 xyz 좌표계의 원점에 추가됩니다. 따라서 카메라 개체 및 구형 개체를 장면에 추가하는 경우 둘 다 (0, 0, 0)에 배치되며 안쪽에서 바깥쪽으로 구형을 보게 됩니다. 해결 방법은 z축에서 양의 50단위만큼 아래 등의 적절한 위치로 카메라를 이동하는 것입니다. camera.position.z = 50

다음 코드 예제에서 자세히 설명합니다.

예제 1

 
<!DOCTYPE html>  <html> <head>   <meta charset="utf-8" />   <title>Cube</title>   <style>     body {       text-align: center;     }      canvas {        width: 100%;        height: 100%;       border: 1px solid black;     }   </style> </head>  <body>   <h1>Liquid Three.js Cube</h1>   <p>Change the browser's window size.</p>   <script src="https://rawgithub.com/mrdoob/three.js/master/build/three.js"></script> <!-- Get the latest version of the Three.js library. -->   <script>     var scene = new THREE.Scene(); // Create a Three.js scene object.     var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); // Define the perspective camera's attributes.      var renderer = window.WebGLRenderingContext ? new THREE.WebGLRenderer() : new THREE.CanvasRenderer(); // Fallback to canvas renderer, if necessary.     renderer.setSize(window.innerWidth, window.innerHeight); // Set the size of the WebGL viewport.     document.body.appendChild(renderer.domElement); // Append the WebGL viewport to the DOM.      var geometry = new THREE.CubeGeometry(20, 20, 20); // Create a 20 by 20 by 20 cube.     var material = new THREE.MeshBasicMaterial({ color: 0x0000FF }); // Skin the cube with 100% blue.     var cube = new THREE.Mesh(geometry, material); // Create a mesh based on the specified geometry (cube) and material (blue skin).     scene.add(cube); // Add the cube at (0, 0, 0).      camera.position.z = 50; // Move the camera away from the origin, down the positive z-axis.      var render = function () {       cube.rotation.x += 0.01; // Rotate the sphere by a small amount about the x- and y-axes.       cube.rotation.y += 0.01;        renderer.render(scene, camera); // Each time we change the position of the cube object, we must re-render it.       requestAnimationFrame(render); // Call the render() function up to 60 times per second (i.e., up to 60 animation frames per second).     };      render(); // Start the rendering of the animation frames.   </script> </body> </html>  

코드 주석에서 수행되는 작업을 자세히 설명하지만 5가지 특정 영역을 좀 더 자세히 살펴보겠습니다.

  1.  
    var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);  
    PerspectiveCamera의 매개 변수 4개는 다음과 같습니다.
    • 75
    • window.innerWidth / window.innerHeight
    • 0.1
    • 1000
    이러한 매개 변수를 고려하여 다음 그림을 살펴보겠습니다.
    • 첫 번째 매개 변수(75)는 맨 아래에서 보기의 맨 위까지 카메라의 세로 시야(도)를 정의합니다. 지정된 시점에 화면에 표시되는 관찰 가능한 세계의 범위입니다. 가로 FOV는 세로 FOV를 사용하여 계산됩니다.
    • 두 번째 매개 변수(window.innerWidth / window.innerHeight)는 카메라의 가로 세로 비율을 정의합니다. 일반적으로 뷰포트 요소의 너비를 해당 높이로 나눈 값을 사용하는 것이 좋으며, 그렇지 않으면 이미지가 찌그러져 보일 수도 있습니다.
    • 세 번째 매개 변수(0.1)는 가까운 카메라 절두체 평면을 정의합니다(그림의 "Near"). 이 경우 가까운 절두체 평면은 xy 평면(즉, 화면)과 거의 일치합니다.
    • 마지막 매개 변수(1000)는 먼 카메라 절두체 평면을 정의합니다(그림의 "Far"). 이 경우 개체가 ±1000단위만큼 이동하면 보이는 Three.js 환경 외부에 있는 것으로 간주되며 보기에서 잘립니다.
  2.  
    var renderer = window.WebGLRenderingContext ? new THREE.WebGLRenderer() : new THREE.CanvasRenderer();  
    사용자 브라우저에서 WebGL을 지원하지 않는 경우(Internet Explorer 10 이전), canvas 기반 렌더러가 대신 사용됩니다(THREE.CanvasRenderer()). 이 경우 코드베이스가 여전히 있는 그대로 작동하지만 속도가 느려지며 그래픽 품질도 저하됩니다.
  3.  
    document.body.appendChild(renderer.domElement);  
    div 등의 적절한 요소에 Three.js 렌더러(viewport) 요소를 추가할 수 있습니다. 이 경우 canvas 요소(따라서 위의 canvas CSS)인 Three.js 렌더러를 body 요소에 추가합니다.
  4.  
    var geometry = new THREE.CubeGeometry(20, 20, 20); // Create a 20 by 20 by 20 cube. var material = new THREE.MeshBasicMaterial({ color: 0x0000FF }); // Skin the cube with 100% blue. var cube = new THREE.Mesh(geometry, material); // Create a mesh based on the specified geometry (cube) and material (blue skin).  
    3D 그래픽에서는 일반적으로 메시를 만든 다음 재질(예: 비트맵 질감)을 적용합니다. 보시다시피, 지정한 geometry 및 material을 사용하여 메시(cube)가 만들어집니다.
  5.  
    camera.position.z = 50;  
    Three.js에서 개체를 장면에 추가하면 일반적으로 원점 (0, 0, 0)에 추가됩니다. 이 경우 자동으로 추가된 카메라 개체를 z축에서 관찰자 쪽으로 양의 50단위만큼 아래로 이동하여 큐브와 카메라가 동일한 "실제" 위치에 존재하지 않도록 합니다.

관련된 코드 주석을 검토하면 이 예제(예제 1)의 나머지 코드를 이해할 수 있습니다.

이제 광원 안의 구형인 좀 더 복잡한 시나리오를 살펴보겠습니다.

광원 안의 구형

이 코드 예제에서는 광원을 사용하여 NASA의 행성 비트맵 질감을 가진 반사 구형을 만듭니다.

예제 2

 
<!DOCTYPE html>  <html> <head>   <meta charset="utf-8" />   <title>Sphere</title>   <style>     body {       text-align: center;       color: white;       background-color: black;     }      canvas {        width: 100%;        height: 100%;     }   </style> </head>  <body>   <h1>Liquid Three.js Sphere</h1>   <button id="startButton">Start</button>   <script src="https://rawgithub.com/mrdoob/three.js/master/build/three.js"></script> <!-- Get the latest version of the Three.js library. -->   <script>     var bitmap = new Image();     bitmap.src = 'images/jupiter.jpg'; // Pre-load the bitmap, in conjunction with the Start button, to avoid any potential THREE.ImageUtils.loadTexture async issues.     bitmap.onerror = function () {       console.error("Error loading: " + bitmap.src);     }      var scene = new THREE.Scene(); // Create a Three.js scene object.     var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); // Define the perspective camera's attributes.      var renderer = window.WebGLRenderingContext ? new THREE.WebGLRenderer() : new THREE.CanvasRenderer(); // Fallback to canvas renderer, if necessary.     renderer.setSize(window.innerWidth, window.innerHeight); // Set the size of the WebGL viewport.     document.body.appendChild(renderer.domElement); // Append the WebGL viewport to the DOM.      // Be aware that a light source is required for MeshPhongMaterial to work:     var pointLight = new THREE.PointLight(0xFFFFFF); // Set the color of the light source (white).     pointLight.position.set(100, 100, 250); // Position the light source at (x, y, z).     scene.add(pointLight); // Add the light source to the scene.      var texture = THREE.ImageUtils.loadTexture(bitmap.src); // Create texture object based on the given bitmap path.     var material = new THREE.MeshPhongMaterial({ map: texture }); // Create a material (for the spherical mesh) that reflects light, potentially causing sphere surface shadows.     var geometry = new THREE.SphereGeometry(50, 64, 64); // Radius size, number of vertical segments, number of horizontal rings.      var sphere = new THREE.Mesh(geometry, material); // Create a mesh based on the specified geometry (cube) and material (blue skin).     scene.add(sphere); // Add the sphere at (0, 0, 0).      camera.position.z = 150; // Move the camera away from the origin, down the positive z-axis.      var render = function () {       sphere.rotation.x += 0.002; // Rotate the sphere by a small amount about the x- and y-axes.       sphere.rotation.y += 0.005;        renderer.render(scene, camera); // Each time we change the position of the cube object, we must re-render it.       requestAnimationFrame(render); // Call the render() function up to 60 times per second (i.e., up to 60 animation frames per second).     };      document.getElementById('startButton').addEventListener('click', function () {       render(); // Start the rendering of the animation frames.     }, false);   </script> </body> </html>  

예제 2의 코드 주석도 수행되는 작업을 잘 설명하지만 다음 두 가지 항목을 자세히 살펴보겠습니다.

  1.  
    var bitmap = new Image(); bitmap.src = 'images/jupiter.jpg';  
    페이지가 로드된 후 사용자가 Start 단추를 클릭하는 데 걸리는 시간 후에 비트맵 이미지가 "미리 로드"됩니다. 이렇게 하면 THREE.ImageUtils.loadTexture()에서 발생할 수 있는 비동기 비트맵 로드 문제를 방지하는 데 도움이 됩니다.
  2.  
    var pointLight = new THREE.PointLight(0xFFFFFF); // Set the color of the light source (white). pointLight.position.set(100, 100, 250); // Position the light source at (x, y, z). scene.add(pointLight); // Add the light source to the scene.  
    THREE.MeshPhongMaterial()을 성공적으로 사용하려면 광원이 필요합니다. Phong 음영은 행성 비트맵(texture)에 반사 표면을 제공합니다.
  3.  
    var material = new THREE.MeshPhongMaterial({ map: texture });  

관련된 코드 주석을 검토하면 이 예제(예제 2)의 나머지 코드를 이해할 수 있습니다.

다음에는 질량 1개 관련 문제에서 WebGL 기반 Three.js 응용 프로그램에 대해 설명합니다.

관련 항목

Three.js 설명서
질량 1개 관련 문제
질량 2개 관련 문제
질량 3개 관련 문제
질량 2개 및 질량 3개 관련 문제의 물리학 및 수식

 

 

 

 

=======================

=======================

=======================

 

 

 

출처: https://www.vobour.com/book/view/6AyTPZ7XFt3SQfQ7A

 

 

ThreeJS를 배워보자 – Chapter 1

Packt사에서 나온 괜찮은 ThreeJS 교재를 발견했다. 대충 둘러보니 처음 배우기에 아주 괜찮아 보였다.

그래서 그걸 따라하며 여기에 도큐멘팅을 한다.

Chapter 1 – ThreeJS로 첫번째 씬을 만들어 보자.

우선 기본 html파일부터 작성해보자.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ThreeJS Practice 1</title>
    <script type="text/javascript" src="libraries/three.js"></script>
    <style>
        body { margin: 0; }
        canvas { width: 100%; height: 100% }
    </style>
</head>
<body>
    <!-- Div for the threeJS scene -->
    <div id="threejs_scene"></div>
    <!-- My threeJS Javascript codes here -->
    <script type="text/javascript" src="script.js"></script>
</body>
</html>

head안에 three.js라이브러리를 넣어놨고, 간단하게 css를 써서 웹브라우저 전체를 두루 쓸 수 있도록 body의 마진을 0으로 잡고 threeJS가 보일 canvas를 100%로 잡았다. 그리고나서 body안에 ThreeJS가 보일 div코드에 id를 threejs_scene으로 이름지어서 자리를 만들어놨고 바디가 끝나기 전에 앞으로 만들 script을 실행하도록 넣어놨다.

자! 이제 기본index.html셋팅은 끝났다.

이제 script.js를 열고 멋진 three.js씬을 만들어 나가보자.

처음 ThreeJs 시작하기 포스팅을 하며 배웠던, 3D Scene을 구현하기 위한 최소 세가지, Scene, Camera, 그리고 Renderer부터 정의내려보자.

function init() {
    var scene = new THREE.Scene();
    var camera = new THREE.PerspectiveCamera(80, window.innerWidth/window.innerHeight, 0.1, 1000);
    var renderer = new THREE.WebGLRenderer();
    renderer.setClearColor(0xEEEEEE);
    renderer.setSize(window.innerWidth, window.innerHeight);
    //Show Axis
    var axes = new THREE.AxisHelper(10);
    scene.add(axes);
    //Let's make a plane
    var planeGeometry = new THREE.PlaneGeometry(60,30,1,1);
    var planeMaterial = new THREE.MeshBasicMaterial({color: 0xCCCCCC});
    var plane = new THREE.Mesh(planeGeometry, planeMaterial);
    plane.rotation.x = -0.5 * Math.PI;
    scene.add(plane);
    camera.position.x = 0;
    camera.position.y = 30;
    camera.position.z = 30;
    camera.lookAt(scene.position);
    document.getElementById("threejs_scene").appendChild(renderer.domElement);
    renderScene();
    function renderScene() {
        renderer.render(scene,camera);
    }
}
window.onload = init();

제일 처음 작성한 코드를 보면,

웹페이지에서 모든걸 다 로딩하면 한번에 뜰 수 있게 모든 코드를 function init()안에 묶었고 제일 마지막줄에 window.onload = init; 을 넣었다.

init() 펑션안에서 첫줄부터 세번째줄까지는 ThreeJS의 가장 기본요소 Scene, Camera 그리고 Renderer를 정의하면서, 카메라는 80도의 화각을 가지고 브라우저 창에 맞춘 aspect ratio를 맞추게 한 ThreeJS의 가장 기본카메라인 perspective camera를 썼고, 렌더러는 WebGL랜더러를 사용하도록 했다.

그 다음 6번째 줄에서 씬 전체의 배경색을 아주 약한 그레이로 만들었고, 7번째줄에서는 랜더러의 사이즈를 브라우저 창에 맞게 정했다.

우선 카메라가 어디를 보고있는지를 도와줄 xyz좌표를 넣기위해 10번째 줄에서 ThreeJS의 AxisHelper를 넣었다. AxisHelper괄호안의 숫자는 각 xyz좌표의 길이를 정해준다. 그리고 11번째 줄에서 우리가 볼 수 있게 씬에다가 위에정의한 axes를 추가해주었다. 참고로 좌표의 색은 x축은 Red, y축은 Green 그리고 z축은 Blue이다. xyz = rgb로 외우면 쉽다. 이제 우리가 보는 뷰가 거꾸로 뒤집혔는지, 세로로 보고있는지 쉽게 알 수 있게 됬다.

이제 바닥판 하나를 만들어서 중앙에 위치시켜보자. THREE.PlaneGeometry(60,30,1,1)를 이용해서 가로 60, 세로 30짜리 크기의 가로세로 모두 1의 세그먼트를 가진 Plane 지오메트리를 만들고 MeshBasicMaterial를 사용해서 약한 회색의 메터리얼을 적용시키자. 디폴트로는 플래인이 세로로 벽처럼 서있기때문에 -180도 회전시켜서 바닥에 위치하도록 만들자. 180도가 아니라 -180도로 한 이유는 모든 3D 지오메트리들이 그렇듯, 디폴트로는 한면만 랜더를 하여 보이기때문에 180도로 돌리면 안보이는 면으로 돌리게 되어서 반대로 180도를 돌리자. 만약 양면모두 랜더를 하고싶다면, 메터리얼을 정할 때 다음과 같이 더블사이드로 지정해 주면된다: MeshBasicMaterial({color:0xCCCCCC, side: THREE.DoubleSide}); 하지만 괜히 더블사이드로 랜더를 하게 만들어 괜히 컴터에 부하를 더 주지말고 간단하게 -180도로 돌리도록 하자.

 

 

반응형

 

728x90

 

다음으로 정 중앙에 위치해서 아무것도 못보는 우리의 카메라를 밖으로 위치시켜보자.

20번째부터 22번째 줄까지 카메라를 y축으로 30만큼, 그리고 z축으로 30만큼 이동시켰고 23번째 줄에서 카메라가 쳐다보는 곳은 Scene에서 0,0,0 즉 정중앙을 쳐다보도록 했다.

이제 만든 이 모든것을 HTML에서 만들어놓은 div태그중 id를 threejs_scene이라고 이름지어준 곳에 들어가서 캔버스를 펼 쳐 주도록 25번째 줄처럼 추가시킨다.

그리고 난후 이 모든것을 랜더 시키기 위해 renderScene()이라고 이름지은 function안에 지금까지 만든 scene과 camera를 집어넣은 랜더러를 넣고 renderScene()을 실행시키도록 하자.

 

 

자 이제 기본적인 판이 만들어 졌다.

다음으로 가운데에 빙글빙글 돌고 있는 큐브와 통통 튀는 공 하나를 만들어 보겠다.

//Let's make a cube  
var cubeGeometry = new THREE.BoxGeometry(6,6,6);  
var cubeMeterial = new THREE.MeshBasicMaterial({color: 0x0089A0});  
var cube = new THREE.Mesh(cubeGeometry, cubeMeterial);  
cube.position.x = 0;  
cube.position.y = 10;  
cube.position.z = 10;  
scene.add(cube);
//Let's make a sphere
var sphereGeometry = new THREE.SphereGeometry(4,32,32);
var sphereMeterial = new THREE.MeshBasicMaterial({color: 0xFE98A0});
var sphere = new THREE.Mesh(sphereGeometry, sphereMeterial);
sphere.position.x = -15;
sphere.position.y = 2;
sphere.position.z = 0;
scene.add(sphere);

위와같이 중앙에 큐브하나, 왼쪽편으로 공 하나를 넣었다.

 

내가 쫌 이런 컬러들을 좋아해서 컬러를 다 저렇게 만들어 놨다. 아무튼, 이제 저 큐브는 빙글빙글 돌게 만들어 주도록 하자.

아래의 코드를 renderScene() 펑션안에다가 넣어 주도록 하자.

requestAnimationFrame(renderScene); 
//cube animation    
cube.rotation.x += 0.01;    
cube.rotation.y += 0.01;    
cube.rotation.z += 0.01;

첫줄인 requestAnimationFrame(renderScene); 을 삽입함으로서, 프레임이 계속해서 흘러가도록 만들어주고, 그 다음 코드들을 넣어줌으로서 각각의 방향으로 0.01씩 매 프레임마다 돌게 만들어 줬다. 쉽다!!

 

다음으로 공을 통통 튀겨보도록 하자.

우선, 숫자가 계속해서 더해질 변수를 step이라고 이름짓고 init()펑션 안쪽 처음 시작하는 부분 어딘가에 선언해주고,

var step = 0;

에니메이션이 이루어질 renderScene펑션 안쪽에 다음과 같이 써주자.

step += 0.1;
sphere.position.y = 9 + (5 * Math.cos(step));   

step 은 공이 튈 속도를 정하게 되고, cosine함수 (그렇다. 우리가 수학시간에 배웠던 그 코사인함수이다. 그래프가 어떻게 되는지는 이 사이트를 참조해 보도록 하자!) 를 이용해서 공이 아래위로 스무스하게 튀게 만들어 주는데, 앞에 5를 곱해줌으로서 공이 5만큼 위,아래로 튀게 만들어줬고, 앞에 5만큼 튀어오르니까 5를 더하고, 구의 반지름으로 정한만큼, 그러니까 4만큼 더해서 올려주어서 바닥에서 부터 공이 위로 10까지 튀게 만들어 주었다.

 

 

이제 큐브는 빙글빙글 돌고있고 공은 통통 튀고있다. 하지만 뭔가 그림이 좀 평면적이다. 그림자가 없어서이다.

자 이제 조명을 하나 넣어주고 그림자를 넣어줘서 조금 더 입체감 있게 만들어보자!

우선 Spot조명을 하나 넣어보자.

var spotLight = new THREE.SpotLight(0xFFFFFF);
spotLight.position.set(-40,60,30);  
scene.add(spotLight);   

조명을 넣었지만 아무 변화가 없다. 그이유는 조명을 받아주는 곳, 그림자를 받아주는 곳을 지정해 줘야 하기 때문이다. 그리고 우선 그이전에 우리가 쓴 MeshBasicMaterial은 그림자를 생성하지 못한다. 그래서 매터리얼도 MeshLambertMaterial이나 MeshPhongMaterial타입의 매터리얼로 바꿔줘야 한다. 우리는 여기서 이름이 좀 더 친숙한 Phong매터리얼로 바닥판, 큐브, 그리고 공의 매터리얼들을 바꿔주도록 하자.

 

 

벌써 뭔가 입체감이 생기기 시작한다.

이제 그림자를 생성시키기 위해 필요한 작업들을 해보자.

우선 renderer의 배경색과 사이즈을 정해준 코드 바로 밑에 한줄 더 추가해주자.

renderer.shadowMap.enabled = true;

그리고 그림자를 받을 바닥판에는 receiveShadow를 그림자가 생성될 쉐입인 큐브와 공과 조금전에 만든 spot조명에 모두 castShadow를 지정해주도록 하자.

. . .
plane.receiveShadow = true;  
. . . 
cube.castShadow = true;
. . .
sphere.castShadow = true;  
. . .
spotLight.castShadow = true;

 

 

 

 

자, 이제 그림자가 생기고 훨씬더 삼차원공간같이 느껴진다.

 

 

하지만 그림자가 무슨 깍두기마냥 각지게 생겼다.. 그 이유는 그림자의 mapSize가 디폴트로 512 x 512로 지정되어 있기 때문인데 그 해상도를 높여주면 부드러워지게 된다. 현재는 그리 랜더링에 부하를 주는게 없으니 통크게 10배크기의 mapSize로 지정해서 보도록 하자. 아래의 코드를 아까 spotLight쪽에 추가했던 castShadow 밑에다가 써주도록 하자.

spotLight.shadow.mapSize.width = 5120;
spotLight.shadow.mapSize.height = 5120;

 

 

그림자가 훨씬 부드러워 졌다.

이제 다음편에서는 지금 보고있는 브라우저의 Frame rate을 확인할 수 있는 조그마한 창과 실시간으로 값을 변경할 수 있는 GUI를 추가하는 법을 배워보겠다.

그리고 복습겸 한번 지금까지 위에서 설명했던것을 참조로 하여 혼자 쓸쓸히 튀고있는 공 오른쪽에 엇박자로 튀는 공 하나를 더 만들어 보도록 해보자.

 

 

지금까지 만든 script.js 전체 코드는 아래에 있다.

function init() {
    var scene = new THREE.Scene();
    var camera = new THREE.PerspectiveCamera(80, window.innerWidth/window.innerHeight, 0.1, 1000);
    var renderer = new THREE.WebGLRenderer();
    //For bouncing balls;
    var step = 0;
    renderer.setClearColor(0xEEEEEE);
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    //Show Axis
    var axes = new THREE.AxisHelper(10);
    scene.add(axes);
    //Let's make a plane
    var planeGeometry = new THREE.PlaneGeometry(60,30,1,1);
    var planeMaterial = new THREE.MeshPhongMaterial({color: 0xCCCCCC});
    var plane = new THREE.Mesh(planeGeometry, planeMaterial);
    plane.receiveShadow = true;
    plane.rotation.x = -0.5 * Math.PI;
    scene.add(plane);
    //Let's make a cube
    var cubeGeometry = new THREE.BoxGeometry(6,6,6);
    var cubeMeterial = new THREE.MeshPhongMaterial({color: 0x0089A0});
    var cube = new THREE.Mesh(cubeGeometry, cubeMeterial);
    cube.castShadow = true;
    cube.position.x = 0;
    cube.position.y = 10;
    cube.position.z = 10;
    scene.add(cube);
    //Let's make a spheres
    var sphereGeometry = new THREE.SphereGeometry(4,32,32);
    var sphereMeterial = new THREE.MeshPhongMaterial({color: 0xFE98A0});
    var sphere = new THREE.Mesh(sphereGeometry, sphereMeterial);
    sphere.castShadow = true;
    sphere.position.x = -15;
    sphere.position.y = 4;
    sphere.position.z = 0;
    scene.add(sphere);  
    var sphereMeterial2 = new THREE.MeshPhongMaterial({color: 0xFEE721});
    var sphere2 = new THREE.Mesh(sphereGeometry, sphereMeterial2);
    sphere2.castShadow = true;
    sphere2.position.x = 15;
    sphere2.position.y = 4;
    sphere2.position.z = 0;
    scene.add(sphere2);  
    var spotLight = new THREE.SpotLight(0xFFFFFF);
    spotLight.position.set(-40,60,30);
    spotLight.castShadow = true;
    spotLight.shadow.mapSize.width = 5120;
    spotLight.shadow.mapSize.height = 5120;
    scene.add(spotLight);
    camera.position.x = 0;
    camera.position.y = 30;
    camera.position.z = 30;
    camera.lookAt(scene.position);  
    document.getElementById("threejs_scene").appendChild(renderer.domElement);
    // renderScene();
    var renderScene = new function renderScene() {
        requestAnimationFrame(renderScene);
        //cube animation
        cube.rotation.x += 0.01;
        cube.rotation.y += 0.01;
        cube.rotation.z += 0.01;
        //sphere animation  
        step += 0.1;
        sphere.position.y = 9 + (5 * Math.cos(step));
        sphere2.position.y = 9 + (5 * Math.cos(step+3));
        renderer.render(scene,camera);
    }
}
window.onload = init();

 

 

 

 

=======================

=======================

=======================

 

 

 

반응형


관련글 더보기

댓글 영역