공부도 할겸 겸사겸사 분석하면서 PV3D의 기본적인 사용법에 대한 튜토리얼을 해볼까 한다. 많이 찾아보았지만 PV3D가 인기가 별로 없고, 코드가 상당히 유동적이여서 사람들에게 반감을 사는 내용을 많이 보았다. 그래서 Away3D를 사용하는 사람이 많은것으로 보인다. 퍼포먼스에 대해서는 PV3D가 타 3D 엔진보다는 좀 떨어진다고 생각한다. 하지만 구조는 그래도 AS3.0에 가장 가깝지 않을까 조심스럽게 주장해 본다. 좀 더 파헤쳐 보고 경우에 따라 엔진을 사용하면 된다고 생각하기 때문에 우선 PV3D 2.0 Great White를 선택하였다.
현존하는 상당히 많은 오픈 소스들이 존재한다. 그 소스들을 갖고 어떻게 익히고, 응용하고, 창조해 내느냐는 개인의 역량에 달려있다고 본다. 내가 알고 싶은 것들에 대해서 튜토리얼을 하는 것이니 필요한 사람에게만 도움이 될 것이라고 생각이 든다. 어쨌든, 기존의 소스를 변경까지도 하기 때문에 업데이트를 받을때 백업을 해두어야 할 지도 모른다. ㅡㅡ;
요번 튜토리얼트는 기본적인 마우스 이벤트 처리에 대해서 알아 볼 것이고, 최종 목표는 마우스가 플래시 플레이어를 벗어났을때 PV3D 이벤트와 연동시키는 것이 목표다. 현재 마우스가 객체에 오버한 상태에서 플래시 컨텐츠 벗어 났을때 체크를 할 수가 없다. 이 부분에 대해서 기존 코드에 추가 및 수정을 좀 할 것이다.
우선, 시작에 앞서 기본적인 셋팅(viewport, scene, camera, renderer)에 대한 지식은 있어야 한다. 솔직히 아직 나도 정확히 알고 있지 않다. 내부 구조를 보았지만 상당한 구조를 갖고 있어 완벽하게 알지 못한다. 완벽하게 알지 못해도 사용하는데는 전혀 문제가 되지 않으니 염려하지 않아도 된다. 자 일단 시작해 보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | package { import org.papervision3d.view.Viewport3D; import org.papervision3d.scenes.Scene3D; import org.papervision3d.cameras.Camera3D; import org.papervision3d.render.BasicRenderEngine; ... public class ModifyVirtualMouse extends Sprite { private var viewport:Viewport3D; private var scene:Scene3D; private var camera:Camera3D; private var renderer:BasicRenderEngine; public function ModifyVirtualMouse():void { this.init(); } private function init():void { // 화면 렌더링 영역 생성. this.viewport = new Viewport3D(600, 400, false, true); addChild(this.viewport); // 기본적으로 필요한 인스턴스로 각각의 파트를 담당한다. // 순서대로 화면, 카메라, 화면 랜더링 임. this.scene = new Scene3D(); this.camera = new Camera3D(); this.renderer = new BasicRenderEngine(); // 컨텐츠 셋팅. this.setContent(); } ... private function onEnterFrame(e:Event):void { ... // 화면 랜더링 this.renderer.renderScene(this.scene, this.camera, this.viewport); } } |
이것이 기본 골격이다. 많이 보았을 것이라 예상된다. 이제 본격적으로 마우스 이벤트에 대해서 알아보자.
org.papervision3d.events 패키지에 있는 InteractiveScene3DEvent.as 이벤트들을 사용할 수 있다. 이벤트는 아래와 같이 정의되어 있다.
1 2 3 4 5 6 7 8 9 | public static const OBJECT_CLICK:String = "mouseClick"; public static const OBJECT_DOUBLE_CLICK:String = "mouseDoubleClick"; public static const OBJECT_OVER:String = "mouseOver"; public static const OBJECT_OUT:String = "mouseOut"; public static const OBJECT_MOVE:String = "mouseMove"; public static const OBJECT_PRESS:String = "mousePress"; public static const OBJECT_RELEASE:String = "mouseRelease"; public static const OBJECT_RELEASE_OUTSIDE:String = "mouseReleaseOutside"; public static const OBJECT_ADDED:String = "objectAdded"; |
많인 본듯한? 문자들이 보인다. 맞다 바로 AS1.0에서 사용하였던 이벤트 문자를 사용하였다. 액션스크립트의 기본적인 지식은 가추고 있다고 판단하고 설명은 넘어가겠다. AS3.0에서는 “MouseEvent.MOUSE_OVER” 라고 사용한다면 PV3D에서는 “InteractiveScene3DEvent.OBJECT_OVER” 라고 사용해야 한다. 그럼 간단하게 아래와 같이 코드를 작성해 보자. 필요한 부분에 한해서 주석을 달아두었다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | package { /** * @author jin_u EUM (jin_u@jinustudio.com) * @since 28/11/2008 */ import flash.display.MovieClip; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import org.papervision3d.events.InteractiveScene3DEvent; import org.papervision3d.materials.ColorMaterial; import org.papervision3d.view.Viewport3D; import org.papervision3d.scenes.Scene3D; import org.papervision3d.cameras.Camera3D; import org.papervision3d.materials.ColorMaterial; import org.papervision3d.objects.primitives.Plane; import org.papervision3d.render.BasicRenderEngine; public class ModifyVirtualMouse extends Sprite { private var viewport:Viewport3D; private var scene:Scene3D; private var camera:Camera3D; private var renderer:BasicRenderEngine; private var colorMaterial:ColorMaterial; private var primitive:Plane; public function ModifyVirtualMouse():void { this.init(); } private function init():void { // 화면 렌더링 영역 생성. this.viewport = new Viewport3D(600, 400, false, true); addChild(this.viewport); // 기본적으로 필요한 인스턴스로 각각의 파트를 담당한다. // 순서대로 화면, 카메라, 화면 랜더링 임. this.scene = new Scene3D(); this.camera = new Camera3D(); this.renderer = new BasicRenderEngine(); // 컨텐츠 셋팅. this.setContent(); } private function setContent():void { // 컬러 메티어리얼 크기 var value:Number = 100 // 컬러 메티어리얼을 생성한 후 인터랙티브를 사용할 것을 선언한다. this.colorMaterial = new ColorMaterial (0xFFFFFF); this.colorMaterial.interactive = true; // Plane 객체를 생성하여 화면에 붙여 넣는다. this.primitive = new Plane(colorMaterial, value, value, 2, 2); this.scene.addChild(this.primitive); // Plane 객체에 인터랙티브 마우스 오버, 아웃 이벤트를 선언한다. this.primitive.addEventListener(InteractiveScene3DEvent.OBJECT_OVER, this.onOverObject, false, 0, true); this.primitive.addEventListener(InteractiveScene3DEvent.OBJECT_OUT, this.onOutObject, false, 0, true); // 카메라를 앞으로 -250 당긴다. 기본값은 -1000 임. this.camera.z = -250; // 기본적으로 사용할 이벤트를 생성한다. this.setListener(); } private function setListener():void { // 반복 이벤트 설정. addEventListener(Event.ENTER_FRAME, this.onEnterFrame, false, 0, true); } private function onEnterFrame(e:Event):void { // 카메라 이동을 위한 설정. var freeX:Number = mouseX - stage.stageWidth * .5; var freeY:Number = mouseY - stage.stageHeight * .5; var sp:Number = .05 this.camera.x += (freeX - this.camera.x) * sp; this.camera.y += (freeY - this.camera.y) * sp; // 화면 랜더링 this.renderer.renderScene(this.scene, this.camera, this.viewport); } /** 인터랙티브 오브젝트 오버, 아웃 이벤트 정의. */ private function onOverObject(e:InteractiveScene3DEvent = null):void { this.viewport.containerSprite.buttonMode = true; this.colorMaterial.fillColor = 0x6D4201 } private function onOutObject(e:InteractiveScene3DEvent = null):void { this.viewport.containerSprite.buttonMode = false; this.colorMaterial.fillColor = 0xFFFFFF; } } } |
샘플 1 :
위와 같이 마우스 반응에 따라 버튼 이벤트가 발생하는 것을 볼 수 있다. 여기서 하나 집고 넘어가자. PV3D의 마우스 이벤트는 결점?이라고 해야 할지 모르겠지만 마우스 손모양에 대한 처리가 조금 난해한 점이 있다.
아래와 같은 코딩을 했을 경우
109 110 111 112 113 114 115 116 117 118 119 120 121 | /** 인터랙티브 오브젝트 오버, 아웃 이벤트 정의. */ private function onOverObject(e:InteractiveScene3DEvent = null):void { this.viewport.containerSprite.buttonMode = true; this.colorMaterial.fillColor = 0x6D4201 } private function onOutObject(e:InteractiveScene3DEvent = null):void { this.viewport.containerSprite.buttonMode = false this.colorMaterial.fillColor = 0xFFFFFF; } |
샘플 1에서 마우스를 움직여 보면 알겠지만 객체에 마우스로 올때 마우스를 움직이지 않고 있으면 손모양으로 변하지 않을 것이다. 샘플 1은 마우스가 객체에 오버 했을 경우 마우스가 이동해야 손모양이 나오게 설정이 되어있기 때문이다. 인터랙티브 이벤트가 오버시에 “this.viewport.containerSprite.buttonMode = true, false“를 하였기 때문이다. 만약 손 모양을 무조건 보이게 할려고 한다면 핸들러에서 “this.viewport.containerSprite.buttonMode = true, false“를 삭제한 후에 “init()” 메소드에 “buttonMode” 를 추가 하면 된다. 아래 코드는 변경된 부분만을 보여주고 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | package { ... public class ModifyVirtualMouse extends Sprite { ... public function ModifyVirtualMouse():void { this.init(); } private function init():void { ... // 버튼 모드 활성. this.viewport.containerSprite.buttonMode = true; ... } ... /** 인터랙티브 오브젝트 오버, 아웃 이벤트 정의. */ private function onOverObject(e:InteractiveScene3DEvent = null):void { this.colorMaterial.fillColor = 0x6D4201 } private function onOutObject(e:InteractiveScene3DEvent = null):void { this.colorMaterial.fillColor = 0xFFFFFF; } } } |
샘플 2 :
샘플 2에서 보는 것과 같이 마우스를 이동하고 객체가 마우스에 오버되자마자 바로 손모양이 나오게 될 것이다. 자, 이와 같이 두가지의 경우를 사용하는데 이것은 작업자가 결정해야 할 문제인 것이다. 만약 샘플 2와 같이 한다면, 내가 원하지 않는 곳까지 마우스 오버가 되는 경우가 발생 할 수도 있다는 점을 인지하여야 한다.
마지막으로, 최종 목표인 마우스가 플래시 플레이어 밖으로 나갔을 때 PV3D 이벤트와 연동하는 것을 만들어 보겠다. 우선 위 샘플 2에서 중심점에서 아래로 마우스를 내려보길 바란다. 어떤가? 마우스가 플레이어 밖으로 나갔는데도 비활성화인 흰색으로 컨텐츠가 변하지 않는 것을 확인 할 수 있을 것이다. 이것은 PV3D의 마우스 이벤트의 오류라고 할 수는 없다. 그 기능이 없기 때문이다. 그래서 이 튜토리얼을 만든 것이다. 그럼 이제 코드를 변경 하겠다.
우선 추가 및 수정을 해야 하는 부분이 있다. 아래 파일을 열어 “mouseLeave” 라는 public 프로퍼티를 하나 추가하고 “handleEnterFrame(e:Event)” 메소드에 “mouseLeave” 에 대해서 추가 및 변경을 한다.
open file : org.papervision3d.core.utils.InteractiveSceneManager
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | package org.papervision3d.core.utils { import ... /** * @author John Grden */ /** * @modifier jin_u EUM : jinustudio.com : 30/11/2008 * * @added property * - mouseLeave:Boolean * * @modify method * - handleEnterFrame(e:Event):void */ public class InteractiveSceneManager extends EventDispatcher { ... public var mouseLeave:Boolean = false; public function InteractiveSceneManager(viewport:Viewport3D) { ... } ... protected function handleEnterFrame(e:Event):void { if (mouseLeave) { handleMouseOut(currentMouseDO3D); return } ... } ... } } |
위 코드에서 변경 된 부분만을 보여준것이다. 자 이제 준비는 되었다. 위의 “InteractiveSceneManager.as” 클래스의 역할은 네이밍으로도 충분히 알 수 있듯이 인터랙티브를 담당하는 클래스이다. “handleEnterFrame(e:Event)” 메소드는 반복 수행을 하면서 가상 마우스와 컨텐츠들간의 인터렉션을 적용시키는데 그 부분을 마우스 이벤트에서 아웃 이벤트만을 따로 제어하게 한 것이다. 이러므로써 마우스가 컨텐츠에 플래시 컨텐츠 마지막 부분에 걸여있는 상태에서 아웃을 하여도 이벤트를 전달하여 처리하게 된다. 또는 컨텐츠가 영역 밖에 있을 경우 플레이어를 나가게 되면 가상 마우스가 그 위치에 존재해서 다른 객체들에게 영향을 끼치게 되는데 그 부분도 해결을 해주게 된다.
그럼 이제 마무리 코드를 보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | package { /** * @author jin_u EUM (jin_u@jinustudio.com) * @since 30/11/2008 */ import flash.display.MovieClip; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import org.papervision3d.events.InteractiveScene3DEvent; import org.papervision3d.materials.ColorMaterial; import org.papervision3d.view.Viewport3D; import org.papervision3d.scenes.Scene3D; import org.papervision3d.cameras.Camera3D; import org.papervision3d.materials.ColorMaterial; import org.papervision3d.objects.primitives.Plane; import org.papervision3d.render.BasicRenderEngine; public class ModifyVirtualMouse extends Sprite { private var viewport:Viewport3D; private var scene:Scene3D; private var camera:Camera3D; private var renderer:BasicRenderEngine; private var colorMaterial:ColorMaterial; private var primitive:Plane; private var isLeave:Boolean; public function ModifyVirtualMouse():void { this.init(); } private function init():void { // 마우스가 플레이어를 벗어났는지를 살핀다. ( true = 벗어남 ) this.isLeave = true; // 화면 렌더링 영역 생성. this.viewport = new Viewport3D(600, 400, false, true); addChild(this.viewport); // 기본적으로 필요한 인스턴스로 각각의 파트를 담당한다. // 순서대로 화면, 카메라, 화면 랜더링 임. this.scene = new Scene3D(); this.camera = new Camera3D(); this.renderer = new BasicRenderEngine(); // 버튼 모드 활성. this.viewport.containerSprite.buttonMode = true; // 컨텐츠 셋팅. this.setContent(); } private function setContent():void { // 컬러 메티어리얼 크기 var value:Number = 100 // 컬러 메티어리얼을 생성한 후 인터랙티브를 사용할 것을 선언한다. this.colorMaterial = new ColorMaterial (0xFFFFFF); this.colorMaterial.interactive = true; // Plane 객체를 생성하여 화면에 붙여 넣는다. this.primitive = new Plane(colorMaterial, value, value, 2, 2); this.scene.addChild(this.primitive); // Plane 객체에 인터랙티브 마우스 오버, 아웃 이벤트를 선언한다. this.primitive.addEventListener(InteractiveScene3DEvent.OBJECT_OVER, this.onOverObject, false, 0, true); this.primitive.addEventListener(InteractiveScene3DEvent.OBJECT_OUT, this.onOutObject, false, 0, true); // 카메라를 앞으로 -200 당긴다. 기본값은 -1000 임. this.camera.z = -200; // 기본적으로 사용할 이벤트를 생성한다. this.setListener(); } private function setListener():void { // 반복 이벤트 설정. addEventListener(Event.ENTER_FRAME, this.onEnterFrame, false, 0, true); // 플레이어를 벗어나면 발생하는 이벤트 설정. stage.addEventListener(Event.MOUSE_LEAVE, this.onLeaveStage, false, 0, true); // 마우스 이동 이벤트 설정. stage.addEventListener(MouseEvent.MOUSE_MOVE, this.onMoveStage, false, 0, true); } private function onEnterFrame(e:Event):void { // 카메라 이동을 위한 설정. var freeX:Number = mouseX - stage.stageWidth * .5; var freeY:Number = mouseY - stage.stageHeight * .5; var centerValue:Number = (stage.stageWidth / 2 - stage.stageWidth * .5 ); var sp:Number = .05 if (!this.isLeave) { // 마우스가 플레이어를 벗어나지 않았다면 카메라 이동. this.camera.x += (freeX - this.camera.x) * sp; this.camera.y += (freeY - this.camera.y) * sp; } else { // 마우스가 벗어나면 카메라를 가운데로 이동. this.camera.x += (centerValue - this.camera.x) * sp; this.camera.y += (centerValue - this.camera.y) * sp; } // 화면 랜더링 this.renderer.renderScene(this.scene, this.camera, this.viewport); } /** 인터랙티브 오브젝트 오버, 아웃 이벤트 정의. */ private function onOverObject(e:InteractiveScene3DEvent = null):void { this.colorMaterial.fillColor = 0x6D4201; } private function onOutObject(e:InteractiveScene3DEvent = null):void { this.colorMaterial.fillColor = 0xFFFFFF; } /** 마우스가 플레이어를 벗어나면 발생하는 이벤트. */ private function onLeaveStage(e:Event):void { // 마우스가 벗어남을 입력. this.isLeave = true; this.viewport.interactiveSceneManager.mouseLeave = true; // 마우스 이동 이벤트 설정. stage.addEventListener(MouseEvent.MOUSE_MOVE, this.onMoveStage, false, 0, true); } /** 마우스가 이동하면 발생하는 이벤트. */ private function onMoveStage(e:MouseEvent):void { // 마우스가 벗어나지 않음을 입력. this.isLeave = false; this.viewport.interactiveSceneManager.mouseLeave = false; // 마우스 이동 이벤트 제거. stage.removeEventListener(MouseEvent.MOUSE_MOVE, this.onMoveStage); } } } |
샘플 3 :
위 소스에서 추가된 것들을 살펴 보길 바란다. 샘플 3에서 마우스를 가운데 아래쪽으로 이동을 한 후에 객체에 마우스 오버시에 컨텐츠 밖으로 빠져나가 보고, 마우스를 가운데 하단 마지막 아슬아슬하게 둔 상태에 두면 객체가 하단으로 사라지는데 그때, 마우스를 밖으로 나가면 가상 마우스의 위치가 기존 같았으면 거기에 존재해서 오버 이벤트를 발생하였으나 그 부분까지 처리가 된 것을 확인 할 수 있을 것이다.
정리를 해보면, PV3D는 인터랙티브를 설정했을 경우 가상마우스(VirtualMouse)가 마우스를 따라 다니면서 Hit 영역을 찾아서 처리를 한다. 그래서 마우스를 확~ 움직여서 컨텐츠 밖으로 벗어났을 경우 이 부분에 대해서 처리가 안되는 것이다. 플래시 역시 마우스 작동이 그와 비슷한 경우를 발생 시킬 수 있는데, 이것은 작업자가 처리를 해줘야 하는 이벤트인것이다.
이 튜토리얼로 이벤트 처리에 도움이 되길 바란다. 마지막으로 이미지를 적용한 샘플을 보자.
PV3D 2.0 Great White 업데이트가 되었다.














1. Trackback by blogring.org
25/Dec/2008 at 12:02 pm
tutorial-으로 이어질 블로그링…
tutorial-에 관한블로그를 요약한 것입니다….
2. Comment by 선웅이
23/Jan/2009 at 4:06 pm
안녕하세요 PV3D검색하다 들렸습니다
간간히 pv3d에 관심갔고 보고있는중인데 유용한 정보감사합니다
2월달엔 시간이 널널할꺼 같으니 꼼꼼히 공부해봐야겠네요^^
설 재밋게 보내세요~
3. Comment by jin_u
26/Jan/2009 at 11:52 am
여러가지 테스트를 하면서 작업 한 결과물도 있는데 그것도 정리해서 한번 튜토리얼해야 겠네요.
방문해 주셔서 감사합니다. ^^
4. Comment by 끄니
30/Jun/2009 at 3:38 am
좋은거야….
우리회사 3d 엔진은 지원 안되는게 너무많아..
벡터며 삼각함수며.. 공부하고 있어..ㅠ..ㅠ난 문과인데…
난 수학이 젤 싫은데..ㅠ.ㅠ
5. Comment by jin_u
30/Jun/2009 at 12:04 pm
못하는걸 억지로 할려고 하냐. 잘하는거 해라 잘하는거~ ㅋㅋ
6. Comment by Stefan
19/Feb/2010 at 4:56 am
This is exactly what i´m looking for, but i do not even know in what language … it would be real cool to translate it to english! thanks
7. Comment by jin_u
19/Feb/2010 at 1:53 pm
welcome to my blog ^^