Warning: opendir(/var/www/html/wp-content/mu-plugins): Failed to open directory: Permission denied in /var/www/html/wp-includes/load.php on line 981
이중 후자의 경우 현재 PV3D 에서 구현할 수 있는 포멧은 Collada의 .dae 와 Quake II의 .md2 가 있다. 오늘은 이 두가지 포멧에 대해서 알아 보겠다.
DAE
[파일정보]
people_ani_max.dae : 1,541 KB
texture_1.png : 106KB
texture_2.png : 109KB
totalFrame : 30
먼저 Collada 의 .dae 포멧이다. Collada는 3D 데이터를 XML 로 저장하는 포멧이다. 오픈소스로 진행되고 있으며 최근 가장 많이 사용 되어지고 있다. 다만 각 어플리케이션에서 저장하는 방법이 약간씩 다른데 이 때문에 PV3D 에서 제대로 읽어오지 못하는 경우가 종종있다. 현재까지 테스트 해 본 바로는 3ds Max 에서 ColladaMAX 로 export 하는 방법이 가장 이상적이다. 다만 ColladaMAX 가 3.05C 이후 업데이트가 없으며 Max 2009 를 지원하지 않는다는 문제가 있다. 누군가 2009용으로 빌드한 것이 있으나 모든 시스템에서 정상적으로 작동되지는 않는다.
.dae 의 경우 3D 데이터에 대한 범용적인 저장 방법이다. 그러므로 대부분의 데이터를 저장 할 수 있다. 현재로서는 가장 현실적인 방법이기는 하나 텍스트인 XML 을 파싱해야하므로 퍼포먼스가 상당히 나쁘다. 위의 샘플에서 볼 수 있드시 30프레임 애니메이션을 로드하는데 상당한 시간이 필요하다.
MD2
[파일정보]
tris.md2 : 378 KB
blade_blue.png : 57 KB
totalFrame : 200
.md2 는 본래 Quake II 용 캐릭터 모델링 데이터 포멧이다. 많은 Quake 유저들을 통해서 많은 캐릭터 파일이 공개 되어있을 뿐 아니라 다른 게임등에도 사용되는 듯 하다. .md2의 특징은 ByteArray 를 통해서 파싱하는데 거의 시간이 걸리지 않는 다는 점이다. 위 md2 샘플을 보면 무려 200프레임의 애니메이션 정보를 담고 있으나 .md2 파일의 용량은 378 KB 밖에 되지 않는다. 30프레임에 1.5 MB 인 .dae 와는 큰 차이를 보인다. 물론 두 파일의 포멧적 특성상 이러한 차이가 나는 것은 당연하겠으나 PV3D에서 에니메이션을 구현할때 확실히 큰 장점이 아닐 수 없다. 하지만 아쉽게도 치명적인 단점이 존재하는데 그것은 파일의 태생상 한 파일에 여러 오브젝트와 메터리얼, 라이트 등에 대한 정보를 담을 수 없다는 것이다.
결과적으로 현시점에서 PV3D 를 웹사이트에 적용 시킨 다면 DAE 이 외는 대안이 없어 보인다. 하지만 이 또한 낮은 퍼포먼스라는 걸림돌 때문에 쉽게 적용시키기 어렵다. 결국 최소화된 모델링 데이터를 통한 최적화 밖에 답이 없어 보인다. Flash Player 10 이 보편화 되고 CS4 를 통한 3D 작업에 대한 정보가 더 많아지면 3D 작업은 CS4 에서 구현하는 것이 가장 좋을 것 같다.
]]>채널을 로드하는데 시간이 조금 걸리니 잠시만 기다려주시기 바랍니다. #channels: 155 #frames: 30, startTime: 0 endTime: 0.966667 애니메이션을 로드 하는데 시간이 상당히 걸리는데 아직까지는 줄이는 법을 모르겠다. 실작업에 사용하기에는 참 부담스러운 시간이다.
지금까지 공부한 여러가지를 복합적으로 적용시켜보았다. 가장 어려웠던건 카메라 돌리기였다. 일단 lookAt 이 센터로 잡혀 있어서 x, y, z 만 이동 시켜 주면 된느데 이걸 원으로 그리는 게 무지 힘들었다. 원은 어떻게든 그리겠는데 구는 아직도 제대로 구현이 안되고 있다.
W, A, S, D 를 누르면 캐릭터가 걷는데 핵심은 W를 눌러서 앞으로 갈때 걷는 애니메이션을 보여주는 부분이다. 나머지 키로 방향 전환을 하는데 정확하게 컨트롤을 하지 않아서 가끔 문워크를 한다. 이럴때는 S 키를 한번 눌러주면 해결된다.
]]>Papervision3D 2 Great White 의 재질 테스트이다.
기본 소스는 http://dev.papervision3d.org/2008/06/25/pv3d-20-materials/ 를 참고하였다.
특이점은 Environmental Map 과 BitmapFileMaterial 인데 전자는 lightmap이 제대로 만들어지지 않는 것 같고 [ 추가 – lightmap 보다는 pointLight 가 정상 작동 하지 않는 것 같다. Goraud 매터리얼 만 해도 그림자가 고정적으로 보여 하는데 맵핑 되어진 상태로 있다. ] 후자는 이미지 색이 빠진다. 후자는 목록에서 Select Material 를 누르면 다시 볼 수 있다.
일단 이 소스에서는 단일 맵핑만 되어있는데 실제 3D에서는 여러 맵핑이 공존해야 하는데 이게 가능한지의 여부는 아직 모르겠다. 추가 – 혹시 해서 다시 확인해 봤는데 Composite Material 에 여러 재질을 추가 할 수 있다.
light 에 관련한 material 들이 제대로 동작하지 않는건 본 예제에 사용한 collada와 관련 있는 듯하다. 단순한 collada 에서는 light 가 제대로 작동해서 이에 관련 된 material 도 정상작동한다.
]]>Collada를 이용한 애니메이션이다. 이것을 테스트 하기 위해서 로우폴리곤 소스를 열심히 찾았는데 결국 국내에서는 쓸만한 것을 찾을 수가 없었다. 어찌어찌 하다가 재미난 프로젝트를 발견했는데 FFX Project 이다. FFX 에서 나오는 모델링 데이터를 뽑아내는 프로젝트 인거 같은데 스퀘어에서 만들어낸 양질의 모델링 데이터를 가져다 쓸 수 있어서 완전 좋았다. 이 프로젝트에 대해서는 추후에 한번 더 포스트 할 기회가 있을 것 같다.
위의 테스트 플래쉬에서 사용된 소스는 총 3030 triangles 와 2 png 로 이루어져있다. 테스트 해 본 결과 3000개 까지는 어느 정도 소화 하는 것 같지만 더 많아지면 스크립트를 파싱하는 시간 15초를 초과 하게 되서 플래시플레이어가 스크립을 강제종료시켜 버리는 문제가 있었다. 그렇지 않고 로드가 된다고 해도 위에서 처럼 퍼포먼스가 너무 떨어져서 1000개 이상의 폴리곤은 사용은 좀 어려울 것 같다.

위 이미지는 똑같은 Collada 파일을 3D MAX에서 렌더링 한 것으로 확실히 광원효과와 하드웨어 가속을 받는 3D 프로그램이 더 좋은 퀄리티를 보여준다. 당연한건가? ㅡ.ㅡa ㅋㅋㅋ
요청으로 위의 작업물 소스를 올립니다. 이 소스에는 Papervision3D가 없습니다. Papervision3D는 다음의 주소에서 받으 실 수 있습니다. http://pv3d.org/2007/12/12/1-downloading-papervision3d-20-alpha-great-white/ 버전은 반드시 2.0 GreattWhite로 사용하셔야 합니다.
]]>현재 널리 알려져 있는 라이브러리로는 Sandy3D, Papervision3D, Away3D 등이 있는데 각각 장단점이 있는 것 같으나 전부 속속들이 들여다 보지는 못해서 아직 정확한 성능의 차이나 사용상의 용이성등의 평가는 어렵다. 이번 글에서는 셋중 실제 홈페이지에 가장 많이 적용되고 있는 Papervision3D (PV3D)를 기준으로 작성하였다. PV3D는 실무에서도 많이 쓰이고 있을 뿐 아니라 개발 또 한 활발히 이뤄지고 있어 앞으로 더욱 기대되는 라이브러리 이다. 참고로 사용된 PV3D의 버전은 2.0a GreatWhite 이다.
II. Object Build Solution
이번에 테스트 해본 오브젝트 생성 방법은 총 4가지 이다. 첫번째는 PV3D에 기본으로 있는 Object Class를 이용한 방법이고, 두번째는 AS3 Geom Class Exporter를 이용한 방법, 세번째는 DAE 파일을 PV3D의 기본 collada 클래스로 생성한 방법이고 마지막은 같은 DAE 파일을 ASCollada의 DAE 클래스로 생성한 방법이다.
1. 기본 내장 클래스
PV3D는 기본적으로 org.papervision3d.objects 패키지에서 오브젝트를 선언하고 있다. 하위로 종류별로 parsers, primitives, spceial로 구분되며 이 구문에서는 primitives 안의 기본 오브젝트들로 생성하였다.
[sourcecode language=”as3″]var cube:Cube = new Cube(materialList, 100, 100, 100);
var cone:Cone = new Cone(new WireframeMaterial(0xFF0000));
var sphere:Sphere = new Sphere(new WireframeMaterial(0xFF0000));[/sourcecode]
가장 빠른 성능을 보이지만 기본으로 제공하는 이외의 형태를 만들지 못하기 때문에 UI 나 Navigation 이 외에는 활용성 면에서는 조금 부족하지 않나 싶다. 결국 사용자화된 오브젝트를 쓰기 위해서는 외부파일을 로드 해야만 한다.
2. AS3 Geom Class Exporter
이는 3D MAX 에서 AS3 Geom Exporter라는 Max Script를 설치하여서 각 라이브러리 별 .as파일로 바로 export하는 방법이다. 이 방법 또한 각 라이브러리에 맞게 .as파일을 만들어 주기 때문에 성능면에서는 좋지만 이름에서 처럼 Geom 에 대한 데이터만 만들어 주기 때문에 위치나 맵핑에 관한 정보없이 단순한 오브젝트만 만들어 주는 것같다. 결국 애니메이션과 맵핑을 위해서 손이 한번 더 가야 한다.
[sourcecode language=”as3″]test = new Test(new WireframeMaterial(0xFF0000));[/sourcecode]
3. Collada
collada 는 뒤에 좀 더 자세히 설명하겠지만 간단히 말해서 3D데이터를 표준 XML 로 만들어주는 프로젝트이다. 확장자는 .dae 를 사용한다. 이 방법은 PV3D에서 기본으로 지원하던 collada 클래스를 이용하는 방법이다.
[sourcecode language=”as3″]collada = new Collada(“test.DAE” , materialList);[/sourcecode]
4. DAE
이 방법은 위의 방법과 .dae 파일을 사용한다는 점에서 동일하나 .dae 파일을 파싱하는 클래스가 Collada 가 아닌 DAE 이다. 두 파일의 차이는 DAE는 ASCollada 프로젝트의 파일을 PV3D에 합친것으로 이는 PV3D 2.0a 이후 버전에 적용되었다. 또한 위의 방법과 결정적 차이는 .dae파일의 Animation 을 컨트롤 할 수 있다는 점이다.
[sourcecode language=”as3″]dae = new DAE();
dae.animate = true;
dae.load(“test.DAE”, materialList);[/sourcecode]
III. Collada
collada의 정의를 홈페이지에서 보면 다음과 같이 규정하고 있다. ‘COLLADA is an open digital-asset exchange schema for the interactive 3D industry’ collada 에는 대부분의 3D 데이터가 저장되는데 특히 맵핑과 애니메이션이 매우 유용하다. 3D MAX 와 같은 프로그램에서 모델링과 맵핑을 하고 이를 collada로 export 한 후 PV3D 를 통해 Flash 에 바로 적용 할 수 있기 때문이다. 참고로 3D MAX 에서 collada 파일을 export 하기 위해서는 ColladaMax 같은 플러그인을 별도로 설치 해야한다.
IV. Example
위에서 말한 4가지 방법으로 예제를 만들어 보았다. 아래 소스를 보면 알 수 있겠지만 똑같은 조건하에 오브젝트만 생성하고 있는데 생성되어지는 기본값이 조금씩 상이한 것을 알 수 있다. 특히 같은 .dae 파일을 사용하는 Collada 와 DAE 클래스의 다른 점을 눈여겨 볼 필요가 있을 것 같다.
[sourcecode language=”as3″]
package {
import fl.events.ScrollEvent;
import fl.events.SliderEvent;
import flash.display.*;
import flash.filters.*;
import flash.display.Stage;
import flash.events.*;
import flash.ui.Mouse;
import org.papervision3d.core.proto.DisplayObjectContainer3D;
import org.papervision3d.objects.parsers.Collada;
import org.papervision3d.objects.parsers.DAE;
// Import Papervision3D
import org.papervision3d.cameras.*;
import org.papervision3d.scenes.*;
import org.papervision3d.objects.*;
import org.papervision3d.objects.special.*;
import org.papervision3d.objects.primitives.*;
import org.papervision3d.materials.*;
import org.papervision3d.materials.special.*;
import org.papervision3d.materials.shaders.*;
import org.papervision3d.materials.utils.*;
import org.papervision3d.materials.utils.MaterialsList;
import org.papervision3d.lights.*;
import org.papervision3d.render.*;
import org.papervision3d.view.*;
import org.papervision3d.events.*;
import org.papervision3d.core.utils.*;
import org.papervision3d.core.utils.virtualmouse.VirtualMouse;
import Test;
public class TestObject extends MovieClip {
public var viewport :Viewport3D;
public var scene :Scene3D;
public var camera :Camera3D;
public var renderer :BasicRenderEngine;
private var materialList : MaterialsList;
private var cont:DisplayObject3D;
private var test:Test;
private var collada:Collada;
private var dae:DAE;
public function TestObject() {
init();
}
public function init():void {
stage.scaleMode = “noScale”
stage.showDefaultContextMenu = false;
init3D();
addEventListener( Event.ENTER_FRAME, loop );
for (var i:int = 1; i < 5; i++) {
this.getChildByName("btn"+i).addEventListener( MouseEvent.CLICK, clickHandler );
}
function clickHandler( e:MouseEvent ):void {
changeObject( e.currentTarget.name );
}
this.getChildByName("carZoom").addEventListener( SliderEvent.CHANGE, carZoomHandler );
function carZoomHandler( e:SliderEvent ):void {
camera.zoom = e.currentTarget.value - 100;
doTrace( String( "camera.zoom : "+camera.zoom ));
}
}
public function doTrace( val:String ):void {
var temp:String = TextArea(this.getChildByName("traceTA")).text;
temp = val + "n" + temp;
TextArea(this.getChildByName("traceTA")).text = temp;
}
private function changeObject( _name:String ):void {
removeObject();
switch (_name) {
case "btn1" :
cont = new DisplayObject3D();
var cube:Cube = new Cube(materialList, 100, 100, 100);
var cone:Cone = new Cone(new WireframeMaterial(0xFF0000));
var sphere:Sphere = new Sphere(new WireframeMaterial(0xFF0000));
cube.x = 400;
cone.z = 400;
sphere.z = -100
cont.addChild( cube );
cont.addChild( cone );
cont.addChild( sphere );
scene.addChild(cont);
doTrace("-------------------------");
doTrace("var cube:Cube = new Cube(materialList, 100, 100, 100);nvar cone:Cone = new Cone(new WireframeMaterial(0xFF0000));nvar sphere:Sphere = new Sphere(new WireframeMaterial(0xFF0000));");
doTrace("-------------------------");
break;
case "btn2" :
//Create Test
test = new Test(new WireframeMaterial(0xFF0000));
scene.addChild(test);
doTrace("-------------------------");
doTrace("test = new Test(new WireframeMaterial(0xFF0000));");
doTrace("-------------------------");
break;
case "btn3" :
//Create Collada
collada = new Collada("https://sewonist.com/examples/TestObject/test.DAE” , materialList);
scene.addChild(collada);
doTrace(“————————-“);
doTrace(“collada = new Collada(“test.DAE” , materialList);”);
doTrace(“————————-“);
break;
case “btn4” :
//Create DAE
dae = new DAE();
dae.animate = true;
dae.load(“https://sewonist.com/examples/TestObject/test.DAE“, materialList);
scene.addChild(dae);
doTrace(“————————-“);
doTrace(“dae = new DAE();ndae.animate = true;ndae.load(“test.DAE”, materialList);”);
doTrace(“————————-“);
break;
}
}
private function removeObject():void {
scene.removeChild( cont );
scene.removeChild( test );
scene.removeChild( collada );
scene.removeChild( dae );
}
// ___________________________________________________________________ Init3D
public function init3D():void {
// Create viewport
viewport = new Viewport3D();
addChild( viewport );
// Create Renderer
renderer = new BasicRenderEngine();
// Create scene
scene = new Scene3D(true);
// Create Material
materialList = new MaterialsList();
materialList.addMaterial( new WireframeMaterial(0xFF0000), “ColorMaterial” );
materialList.addMaterial( new WireframeMaterial(0xFF0000), “all” );
// Create camera
camera = new Camera3D();
renderer.renderScene(scene, camera, viewport);
}
// ___________________________________________________________________ Loop
public function loop(event:Event = null):void
{
if ( cont ) {
cont.yaw(1);
}
if ( test ) {
test.yaw(1);
}
if ( collada ) {
collada.yaw(1);
}
if ( dae ) {
dae.yaw(1);
}
renderer.renderScene(scene, camera, viewport);
}
}
}
[/sourcecode]
V. Results
위의 결과표는 매우 주관적인 견해라는 것을 꼭 기억해주기 바란다. 기본클래스를 이용한 경우에도 따로 추가해주면 맵핑과 애니메이션이 가능하다. 또 한 COLLADA를 이용하는 클래스도 사용성이 꼭 나쁘다고 할 수는 없다. 다만 위의 표는 각 방법에 대한 차이를 좀더 쉽게 이해하기 위해서 만들었으니 차이에 대해 참고 정도의 역활이었으면 한다.
확실히 플래쉬에서 구현되는 3D는 많은 제약을 가지고 있다. 특히 하드웨어 가속을 받지 않기 때문에 성능이나 기능 면에서 현란한 3D게임 같은 화면을 기대 하는 것은 무리가 있다. 하지만 날로 좋아지는 컴퓨터의 성능과 AS3의 성능 향상으로 플래쉬에서 3D를 이용한 다양한 시도가 가능 할 것으로 기대 된다. 조만간 웹에서 Coverflow 와 같은 화려한 UI 나 스페셜포스 같은 FPS 게임을 경험하게 될 지도 모른다.
VI. Links
Papervision3D : http://pv3d.org/
Collada : http://www.collada.org/mediawiki/index.php/Main_Page
ColladaMax : http://www.feelingsoftware.com/content/view/65/79/lang,en/
AS3 Geom Exporter : http://seraf.mediabox.fr/showcase/as3-geom-class-exporter-for-3ds-max-english/
ASCollada : http://ascollada.org/