안드로이드 jPCT-AE를 활용해 간단한 기하구조를 만들어 Object3D를 다뤄보기

2012/06/29 02:31

jPCT-AE를 사용하여 안드로이드 3D 앱을 만들 수 있다. OpenGL ES기반으로 Java로 개발할 수 있으면서도 비교적 익숙한 API로 쉽게 테스트 해볼 수 있는게 매력인 것 같다. 그리고 안정적이면서 속도도 빠른 편이라 좋다. 아무튼 이것을 파는 작업을 시작했다. 


첫번째로 기본적인 버텍스 버퍼(Vertices), UV버퍼, 인덱스 버퍼(indices) 정보를 아우르는 기하구조(Geometry) 정보를 가지고 하나의 3D 객체를 만들어 보았다. 간단히 사각형(삼각폴리곤 2개 구성)을 그려본다. 


참고로 기반소스는 아래 링크를 참고하자. 아래 코드는 약간 수정했을 뿐이다.

http://www.jpct.net/wiki/index.php/Hello_World_for_Android



Texture texture = new Texture(BitmapHelper.rescale(BitmapHelper.convert(getResources().getDrawable(R.raw.mybaby)), 64, 64));
TextureManager.getInstance().addTexture("texture", texture);

float[] coordinates = {
		  -10.0f,  -10.0f, 0.0f //TL 0
		,  10.0f,  -10.0f, 0.0f //TR 1
		, -10.0f,   10.0f, 0.0f //BL 2
		,  10.0f,   10.0f, 0.0f //BR 3
};
float[] uvs = {
		  0.0f, 0.0f
		, 1.0f, 0.0f 
		, 0.0f, 1.0f 
		, 1.0f, 1.0f
};
int[] indices = {
		  0, 2, 1
		, 1, 2, 3
		
};
int textureId = TextureManager.getInstance().getTextureID("texture");
plane = new Object3D(coordinates, uvs, indices, textureId);
world.addObject(plane);

위 코드는 가장 기본적인 소스이다. 정점배열(coordinates), 인덱스배열(indices), UV배열(uvs)를 가지고 mybaby를 텍스쳐 삼아 1개의 3D 객체를 만들어 World에 추가한다. 결과는 다음 화면과 같다.


jPCT-AE Object3D 테스트



결국 Object3D 생성자는 총 4가지 종류가 있는데 그 중 하나가 기하구조를 담은 Raw한 데이타를 직접 입력받아 생성하게 되어있다. 참고로 Object3D 생성자를 확인해본다. 뭐, 여기까지는 쉽게 만들 수 있다. 


Mesh라는 객체를 만들어 Object3D에 참조하도록 하는게 일반적이다라고 생각했지만 jPCT는 약간 다르게 Object3D내부에 Mesh객체를 포함하고 있어서 object3d.getMesh(), object3d.setMesh(mesh) 인터페이스를 제공한다. 그래서 다음과 같은 실험을 해보았다. 


Mesh mesh = plane.getMesh();
int maxTriangles = mesh.getTriangleCount();
Object3D plane2 = new Object3D(maxTriangles);
plane2.setMesh(mesh);
plane2.setTexture("texture");
plane2.translate(0.0f, -15.0f, 0);
world.addObject(plane2);


하지만 결과는 예상외다. 기하구조를 담은 Mesh라면 텍스쳐도 잘 입혀져야 하는데 입혀지지 않는다. 실제로 API문서에서 Mesh를 보면 UV에 관련된 API가 존재하지 않는다. 


jPCT-AE Mesh 테스트


Object3D의 생성자를 보면 4가지 중에 Object3D( Object3D obj, boolean reuseMesh ) 인터페이스가 존재한다. 즉, 기존 3D객체를 가지고 3D 객체를 새로 만들되 기존 3D 객체에 저장되어 있는 Mesh정보를 재사용할지 결정하는 것이다. 활용하면 다음과 같은 코드가 된다.

Object3D plane2 = new Object3D(plane, true);
plane2.setTexture("texture");
plane2.translate(0.0f, -15.0f, 0);
world.addObject(plane2);

결과는 예상대로 잘된다.


jPCT-AE Object3D Clone 테스트



그럼 여기서 궁금해지는 점은 도대체 Mesh는 무엇이란 말인가? Mesh는 기하구조를 담고 있어야 한다는 것인 나의 일반적인 생각이였지만 그렇지 않다. jPCT에서는 Mesh객체를 Object3D를 통해 얻고 셋팅할 수 있다는 것은 무엇을 의미하는 것일까? Mesh에 UV맵 정보만 제외하고 정점정보 및 인덱스정보만 있는 것은 결국 이것을 이용해 정점 변환을 하는 컨트롤러 인터페이스가 있기 때문이였다. 백문의 불여일견이니 다음 코드를 보자. 


package com.threed.jpct.example01;

import com.threed.jpct.GenericVertexController;
import com.threed.jpct.Matrix;
import com.threed.jpct.SimpleVector;

public class TestController extends GenericVertexController {
	private static final long serialVersionUID = 1L;
	
	private float _scaleX;
	private float _scaleY;
	private float _scaleZ;
	private Matrix _matrix;
	
	public TestController() {
		_scaleX = 1.0f;
		_scaleY = 1.0f;
		_scaleZ = 1.0f;
		_matrix = new Matrix();
		_matrix.setIdentity();
	}
	@Override
	public void apply() {
		// TODO Auto-generated method stub
		SimpleVector[] s = getSourceMesh();
		SimpleVector[] d = getDestinationMesh();
		for( int i = 0; i < s.length; i++ ){
			d[i].set( s[i] );
			d[i].matMul(_matrix);
		}
	}
	public void scale(float scaleX, float scaleY, float scaleZ){
		_scaleX = scaleX;
		_scaleY = scaleY;
		_scaleZ = scaleZ;
		_matrix.set(0, 0, _scaleX);
		_matrix.set(1, 1, _scaleY);
		_matrix.set(2, 2, _scaleZ);
	}
	public float getScaleX(){
		return _scaleX;
	}
	public float getScaleY(){
		return _scaleY;
	}
	public float getScaleZ(){
		return _scaleZ;
	}
}

GenericVertexController가 바로 정점 정보를 제어하는 추상클래스로 이것을 상속해서 원하는 정점변환 기능을 만들면 된다. 위에서 만들어진 컨트롤러 클래스는 스케일을 조절해준다. 이 클래스를 사용해 스케일을 조정해보자. 


Mesh mesh = plane2.getMesh();
TestController controller = new TestController();
controller.scale(0.5f, 3.0f, 1.0f);
mesh.setVertexController(controller, true);
mesh.applyVertexController();


결과는 다음과 같다. 



jPCT-AE GenericVertexController 활용



이 결과는 2가지를 시사한다. 첫째는 Mesh는 기존에 알고 있던 기하구조를 가지는 정보라기 보다 정점을 변경하기 위한 인터페이스 정도라는 점이고, 두번째는 3D객체를 가지고 다른 3D 객체를 만들어 reuseMesh를 true하면 같은 기하정보를 공유하게 되어 두개 3D객체의 정점정보가 같이 변한다는 점이다. 당연히 reuseMesh를 false처리하면 Mesh는 clone처리 되어 별도의 기하정보가 새로운 3D 객체 내부에 생성되므로 한쪽의 정점변환이 일어나도 다른 한쪽은 변하지 않는다. 아래처럼 말이다. 



jPCT-AE reuseMesh=false


음 그래도 이제 정점변환은 자유스럽게 할 수 있게 되었다. 하지만 더 jPCT와 친해져야 한다는 여전히 모르는게 투성... ^^


참고글

jPCT-AE : http://www.jpct.net/jpct-ae/

jPCT-AE API Docs : http://www.jpct.net/jpct-ae/doc/index.html

jPCT Wiki : http://www.jpct.net/wiki/ 


글쓴이 : 지돌스타(http://blog.jidolstar.com/825)

저작자 표시 비영리 동일 조건 변경 허락

Android , , , , , , , ,