스케칭이된 표면을 만들기 까지는 성공했으나..

가장 큰 숙제로 남아 있던 문제가 표면의 각도에 따라 해칭이 이루어지지 않아서 동적인 화면에 스케치 쉐이더필터를 적용했을때 화면에 스크레치가 생긴듯한 현상을 일으키는 문제였다.

이를 해결하기 위한 방법으로 각 표면의 각도에 맞게 텍스쳐를 회전시키는 것을 생각해봤지만.. 그 표면의 각도를 알기 위해선 표면의 법선 벡터 (Normal Vector)를 알아야 한다. 그 정보는 Rasterize 되기전의 정보이므로 Fragment Shader에서나 가능한 내용이다. 결국 PV3D 에서 출력해낸 2D 이미지에 Pixel Bender를 적용해야하므로 한계가 있다는 말이다.

그래서 짱구를 굴리고 굴려서 생각해낸 방법이...

생상정보 RGBA 중에서 A는 Light에 관한 정보를 담고, RGB에 Normal Vector를 담는 방법이겠다. 즉 R에는 Normal Vector의 x 값을, G에는 y값을, B에는 z값을 넣어 Pixel Bender에서 각 픽셀에서의 법선 정보를 알 수 있게끔 하고, 음영정보는 A에 담긴 정보를 사용한다는 뜻!

그러나 그런 방법은 있지만 PV3D에는 그렇게 렌더링 할 수 있는 방법이 없다.. 그런 이유로 Pixel Bender에 불탔던 열정이 잠시 식었었으나! 방법을 찾았다.

AbstractSmoothShadeMaterial 클래스를 상속받은 Custom Material을 만들면 되는것. 어렵지 않을까해서 EnvMapMaterial 이나 CellMaterial을 열어봤지만 크게 복잡한건 없는것 같다. 둘다 AbstractSmoothShadeMaterial의 서브클래스. 물론 EnvMapMaterial은 수식 자체가 뭘 하겠다는건지 알아먹을 수 없었으나 Custom Material을 만드는데에 문제가 있어보이지는 않는다.

 package org.papervision3d.materials.shadematerials

{

import fl.motion.Color;

import flash.display.BitmapData;

import flash.display.Graphics;

import flash.geom.Matrix;

import org.papervision3d.cameras.Camera3D;

import org.papervision3d.core.math.Number3D;

import org.papervision3d.core.proto.CameraObject3D;

import org.papervision3d.core.geom.renderables.Triangle3D;

import org.papervision3d.core.geom.renderables.Vertex3DInstance;

import org.papervision3d.core.material.AbstractSmoothShadeMaterial;

import org.papervision3d.core.math.Matrix3D;

import org.papervision3d.core.proto.LightObject3D;

import org.papervision3d.core.render.data.RenderSessionData;

import org.papervision3d.core.render.draw.ITriangleDrawer;

/**

* @Author Buzzler

*/

public class NormalMaterial extends AbstractSmoothShadeMaterial implements ITriangleDrawer

{

private static var x1:Number;

private static var x0:Number;

private static var x2:Number;

private static var y0:Number;

private static var y1:Number;

private static var y2:Number;

private var camera:CameraObject3D;

private var tmpN:Number3D;

private var tmpL:Number3D;

private var tmpR:uint;

private var tmpG:uint;

private var tmpB:uint;

private var tmpRGB:uint;

public function NormalMaterial(light:LightObject3D, camera:CameraObject3D)

{

super();

this.light = light;

this.camera = camera;

}

private static var useMap:BitmapData;

override public function drawTriangle(face3D:Triangle3D, graphics:Graphics, renderSessionData:RenderSessionData, altBitmap:BitmapData = null, altUV:Matrix = null):void

{

x0 = face3D.v0.vertex3DInstance.x;

   y0 = face3D.v0.vertex3DInstance.y;

x1 = face3D.v1.vertex3DInstance.x;

y1 = face3D.v1.vertex3DInstance.y;

x2 = face3D.v2.vertex3DInstance.x;

y2 = face3D.v2.vertex3DInstance.y;

triMatrix.a = x1 - x0;

triMatrix.b = y1 - y0;

triMatrix.c = x2 - x0;

triMatrix.d = y2 - y0;

triMatrix.tx = x0;

triMatrix.ty = y0;


tmpN = face3D.faceNormal.clone();

tmpL = new Number3D(-light.x,-light.y,-light.z);

tmpR = uint((tmpN.x + 1.0) * 127.5);

tmpG = uint((tmpN.y + 1.0) * 127.5);

tmpB = uint((tmpN.z + 1.0) * 127.5);

tmpRGB = (tmpR << 16) | (tmpG << 8) | (tmpB);

graphics.beginFill(tmpRGB, brightness(tmpN, tmpL));

   graphics.moveTo( x0, y0 );

graphics.lineTo( x1, y1 );

graphics.lineTo( x2, y2 );

graphics.lineTo( x0, y0 );

graphics.endFill();

renderSessionData.renderStatistics.shadedTriangles++;

}

private function brightness(n1:Number3D, n2:Number3D):Number

{

n1.normalize();

n2.normalize();

var result:Number = Math.acos(Number3D.dot(n1, n2)) - Math.PI / 2;

result = Math.max(result, 0) / (Math.PI / 2);

return 1 - result;

}

}

}

 

이게 NormalMaterial 이라는 직접 만든 재질을 입혀 많은 구(Sphere)이다.
알파값으로 Light와의 관계를 알 수 있고, 색상으로 면의 방향을 나타내는 법선 벡터를 알 수 있다.

자.. 숙제가 또 남았다. Face3D 단위가 아닌 Vertex 단위로 Color Interpolation이 필요해 보인다. 그래야 더욱 자연스러운 법선 백터가 생성되지 않을까. 안그럼 엄청나게 폴리곤이 많은 모델이어야 자여스럽게 보이는 상황이 발생 할 테니. 어쨌거나 당장 필요한 수준의 Material을 만들었으니 일단 만족.

추가: 3포인트 그래디언트를 만들어주는 픽셀벤더 필터가 있으니 도움이 되지 않을까

'Pixel Bender' 카테고리의 다른 글

PixelBender Outline View  (0) 2008.11.05
Flex와 Pixel Bender로 iChat 흉내내기  (0) 2008.09.25
Human Detector!  (2) 2008.09.25
Sketch Shader  (0) 2008.09.18
Sobel Operation 의 간단한 응용  (0) 2008.09.18

WRITTEN BY
buzzler

,