Pixel Bender 3Dの勉強 その4 | Photoshop CC Tutorials
今回はPixelBender3Dでフラットシェーディングを記述してみました。
下図をご覧いただくとAGALと比べて一目で内容が理解できると思います。

$ピック社長のブログ

◆【できあがりはこちらをクリック】(要:FlashPlayer11、ビデオカード等GPU搭載PC)
$ピック社長のブログ

Triangle.pbvk

vertex kernel Triangle
<
namespace: "Pixel Bender 3D examples";
vendor: "Adobe";
version: 1;
>
{
parameter float4x4 objectToClipSpaceTransform;

input vertex float4 vertexPosition
<
id: "PB3D_POSITION";
>;
output float4 vertexClipPosition;

void evaluateVertex()
{
vertexClipPosition = vertexPosition * objectToClipSpaceTransform;
}
}


Triangle.pbmk

material kernel phong
<
namespace : "AIF Test";
vendor : "Adobe";
version : 1;
>
{
input vertex float4 vertexPosition
<
id : "PB3D_POSITION";
>;
input vertex float4 UVCoord
<
id : "PB3D_UV";
>;
input vertex float4 vertexNormal
<
id : "PB3D_NORMAL";
>;

parameter float4x4 worldMatrix;

input image4 inputImage;

interpolated float4 interpolatedCoord;
interpolated float4 interpolatedNormal;
interpolated float4 interpolatedVertex;

output float4 result;

void evaluateVertex()
{
float4 vertexWorld = vertexPosition * worldMatrix;
float4 normalWorld = vertexNormal * worldMatrix;
interpolatedCoord = UVCoord;
interpolatedVertex = vertexWorld;
interpolatedNormal = normalWorld;
}

parameter float4 lightPosition;
parameter float4 eyePosition;

void evaluateFragment()
{
result = float4(0,0,0,0);
float4 color = sample(inputImage, float2(interpolatedCoord.x, interpolatedCoord.y));
float4 lightDir = lightPosition - interpolatedVertex;
lightDir = normalize(lightDir);
float diffuseRef = dot(interpolatedNormal, lightDir);
color = color * diffuseRef;
result += color;
result.w = 1. ;
}
}


Main.as
package 
{
import com.adobe.pixelBender3D.AGALProgramPair;
import com.adobe.pixelBender3D.PBASMCompiler;
import com.adobe.pixelBender3D.PBASMProgram;
import com.adobe.pixelBender3D.RegisterMap;
import com.adobe.pixelBender3D.utils.VertexBufferHelper;
import com.adobe.pixelBender3D.utils.ProgramConstantsHelper;
import com.adobe.pixelBender3D.VertexRegisterInfo;

import com.adobe.utils.PerspectiveMatrix3D;

import flash.display.Bitmap;
import flash.display.Sprite;
import flash.display.Stage3D;
import flash.display3D.Context3D;
import flash.display3D.Context3DCompareMode;
import flash.display3D.Context3DTriangleFace;
import flash.display3D.IndexBuffer3D;
import flash.display3D.Program3D;
import flash.display3D.VertexBuffer3D;
import flash.display3D.Context3DRenderMode;
import flash.display3D.Context3DProgramType;
import flash.display3D.Context3DBlendFactor;
import flash.display3D.Context3DTextureFormat;
import flash.display3D.textures.Texture;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.geom.Vector3D;
import flash.geom.Matrix3D;
import flash.utils.getTimer;
import flash.utils.Timer;

import net.hires.debug.Stats;

import ExampleUtils;

public class Main extends Sprite
{
[Embed (source="./vp_triangle.pbasm", mimeType="application/octet-stream")]
protected static const VertexPositionProgram : Class;

[Embed (source="./mv_triangle.pbasm", mimeType="application/octet-stream")]
protected static const VertexMaterialProgram : Class;

[Embed (source="./mf_triangle.pbasm", mimeType="application/octet-stream")]
protected static const FragmentMaterialProgram : Class;

[Embed( source = "FlashLogo.png" )]
private static var TextureImg:Class;

public static const WIDTH:int = 400;
public static const HEIGHT:int = 400;

// molehill-related variables
private var context3D_ : Context3D;
private var indexBuffer_ : IndexBuffer3D;
private var rendertimer_ : Timer;
private var shaderProgram_ : Program3D;
private var vertexBuffer_ : VertexBuffer3D;
private var _stage3D:Stage3D;

// PB3D-related variables
private var vertexRegisterMap_ : RegisterMap;
private var fragmentRegisterMap_ : RegisterMap;
private var vertexBufferMap_ : VertexBufferHelper;
public var parameterBufferHelper_ : ProgramConstantsHelper;

private var _texture:Texture;

private var _matProjection:PerspectiveMatrix3D;
private var _camera:Camera;

private var lightPosition_ : Vector3D = new Vector3D( 0.0, 0.0, -3.0 );
private var eyePosition_ : Vector3D = new Vector3D( 0.0, 0.0, -3.0 );

public function Main()
{
_stage3D = stage.stage3Ds[0];
_stage3D.addEventListener( Event.CONTEXT3D_CREATE, Context3DCreateHandler );
_stage3D.requestContext3D( Context3DRenderMode.AUTO );
}

private function Context3DCreateHandler(e:Event) : void
{
context3D_ = _stage3D.context3D;
init();
addChild(new Stats);
}

public function init():void
{
context3D_ = _stage3D.context3D;
context3D_.enableErrorChecking = true;
context3D_.configureBackBuffer(WIDTH, HEIGHT, 4, true);
context3D_.setCulling(Context3DTriangleFace.BACK);
context3D_.setBlendFactors(Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA );
context3D_.setDepthTest(false, Context3DCompareMode.ALWAYS);

setupShadingPrograms();
setupGeometry();
InitCamera();
InitProjection();

vertexBufferMap_ = new VertexBufferHelper(context3D_,
vertexRegisterMap_.inputVertexRegisters,
vertexBuffer_
);

// at this point, our Triangle object has sufficient information to do
// its job when the render calls start coming in, so let's get them
// going

rendertimer_ = new Timer(1);
rendertimer_.addEventListener(TimerEvent.TIMER, frameEventHandler);
rendertimer_.start();
}

private function frameEventHandler(event : Event) : void
{
render(getTimer());
}

private var cnt:int = 0;
public function render(time : Number) : void
{
context3D_.clear(0, 0, 0, 0);

var mat:Matrix3D = new Matrix3D();
var worldMat:Matrix3D = new Matrix3D();
worldMat.appendRotation(cnt++, new Vector3D(0, 1, 0)); // ワールド座標変換
worldMat.appendRotation(cnt, new Vector3D(1, 0, 0)); // ワールド座標変換
worldMat.appendRotation(cnt, new Vector3D(0, 0, 1)); // ワールド座標変換
mat.append(worldMat);
mat.append(_camera.matrix); // ビュー座標変換
mat.append(_matProjection); // プロジェクション座標変換

parameterBufferHelper_.setMatrixParameterByName(
Context3DProgramType.VERTEX,
"objectToClipSpaceTransform",
mat,
true
);

parameterBufferHelper_.setMatrixParameterByName(
Context3DProgramType.VERTEX,
"worldMatrix",
worldMat,
true
);

parameterBufferHelper_.setNumberParameterByName(
Context3DProgramType.FRAGMENT,
"lightPosition",
Vector.([lightPosition_.x, lightPosition_.y, lightPosition_.z, 0])
);

parameterBufferHelper_.setNumberParameterByName(
Context3DProgramType.FRAGMENT,
"eyePosition",
Vector.([eyePosition_.x, eyePosition_.y, eyePosition_.z, 0])
);

parameterBufferHelper_.update();
context3D_.setTextureAt(0, _texture);
context3D_.setProgram(shaderProgram_);
vertexBufferMap_.setVertexBuffers();
context3D_.drawTriangles(indexBuffer_, 0, indexNum / 3);

context3D_.present();
}

private var indexNum:int;
private function setupGeometry() : void
{
var size:Number = 0.5;

var vertices:Vector. = Vector.([
// forward
//x y z w u v z w nx ny nz nw
1 * size, -1 * size, -1 * size, 1, 1, 1, 0, 0, 0, 0, -1, 0,
-1 * size, -1 * size, -1 * size, 1, 0, 1, 0, 0, 0, 0, -1, 0,
-1 * size, 1 * size, -1 * size, 1, 0, 0, 0, 0, 0, 0, -1, 0,

1 * size, -1 * size, -1 * size, 1, 1, 1, 0, 0, 0, 0, -1, 0,
-1 * size, 1 * size, -1 * size, 1, 0, 0, 0, 0, 0, 0, -1, 0,
1 * size, 1 * size, -1 * size, 1, 1, 0, 0, 0, 0, 0, -1, 0,

// right
//x y z w u v z w nx ny nz nw
1 * size, -1 * size, 1 * size, 1, 1, 1, 0, 0, 1, 0, 0, 0,
1 * size, -1 * size, -1 * size, 1, 0, 1, 0, 0, 1, 0, 0, 0,
1 * size, 1 * size, -1 * size, 1, 0, 0, 0, 0, 1, 0, 0, 0,

1 * size, -1 * size, 1 * size, 1, 1, 1, 0, 0, 1, 0, 0, 0,
1 * size, 1 * size, -1 * size, 1, 0, 0, 0, 0, 1, 0, 0, 0,
1 * size, 1 * size, 1 * size, 1, 1, 0, 0, 0, 1, 0, 0, 0,

// left
//x y z w u v z w nx ny nz nw
-1 * size, -1 * size, -1 * size, 1, 1, 1, 0, 0, -1, 0, 0, 0,
-1 * size, -1 * size, 1 * size, 1, 0, 1, 0, 0, -1, 0, 0, 0,
-1 * size, 1 * size, 1 * size, 1, 0, 0, 0, 0, -1, 0, 0, 0,

-1 * size, -1 * size, -1 * size, 1, 1, 1, 0, 0, -1, 0, 0, 0,
-1 * size, 1 * size, 1 * size, 1, 0, 0, 0, 0, -1, 0, 0, 0,
-1 * size, 1 * size, -1 * size, 1, 1, 0, 0, 0, -1, 0, 0, 0,

// back
//x y z w u v z w nx ny nz nw
-1 * size, -1 * size, 1 * size, 1, 1, 1, 0, 0, 0, 0, 1, 0,
1 * size, -1 * size, 1 * size, 1, 0, 1, 0, 0, 0, 0, 1, 0,
1 * size, 1 * size, 1 * size, 1, 0, 0, 0, 0, 0, 0, 1, 0,

-1 * size, -1 * size, 1 * size, 1, 1, 1, 0, 0, 0, 0, 1, 0,
1 * size, 1 * size, 1 * size, 1, 0, 0, 0, 0, 0, 0, 1, 0,
-1 * size, 1 * size, 1 * size, 1, 1, 0, 0, 0, 0, 0, 1, 0,

// top
//x y z w u v z w nx ny nz nw
1 * size, 1 * size, -1 * size, 1, 1, 1, 0, 0, 0, 1, 0, 0,
-1 * size, 1 * size, -1 * size, 1, 0, 1, 0, 0, 0, 1, 0, 0,
-1 * size, 1 * size, 1 * size, 1, 0, 0, 0, 0, 0, 1, 0, 0,

1 * size, 1 * size, -1 * size, 1, 1, 1, 0, 0, 0, 1, 0, 0,
-1 * size, 1 * size, 1 * size, 1, 0, 0, 0, 0, 0, 1, 0, 0,
1 * size, 1 * size, 1 * size, 1, 1, 0, 0, 0, 0, 1, 0, 0,

// bottom
//x y z w u v z w nx ny nz nw
1 * size, -1 * size, 1 * size, 1, 1, 1, 0, 0, 0, -1, 0, 0,
-1 * size, -1 * size, 1 * size, 1, 0, 1, 0, 0, 0, -1, 0, 0,
-1 * size, -1 * size, -1 * size, 1, 0, 0, 0, 0, 0, -1, 0, 0,

1 * size, -1 * size, 1 * size, 1, 1, 1, 0, 0, 0, -1, 0, 0,
-1 * size, -1 * size, -1 * size, 1, 0, 0, 0, 0, 0, -1, 0, 0,
1 * size, -1 * size, -1 * size, 1, 1, 0, 0, 0, 0, -1, 0, 0
])

indexNum = 36;

vertexBuffer_ = context3D_.createVertexBuffer(indexNum, 12);
vertexBuffer_.uploadFromVector(vertices, 0, indexNum);

indexBuffer_ = context3D_.createIndexBuffer(indexNum);
indexBuffer_.uploadFromVector(Vector.([0, 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]), 0, indexNum);

var texture:Bitmap = Bitmap(new TextureImg());
trace(texture.bitmapData.width);
_texture = context3D_.createTexture(texture.bitmapData.width, texture.bitmapData.height, Context3DTextureFormat.BGRA, false);
_texture.uploadFromBitmapData(texture.bitmapData);
}

private function setupShadingPrograms() : void
{
var vertexPositionProgram : PBASMProgram;
var vertexMaterialProgram : PBASMProgram;
var fragmentMaterialProgram : PBASMProgram;

vertexPositionProgram = ExampleUtils.resourceToPBASMProgram(VertexPositionProgram);
vertexMaterialProgram = ExampleUtils.resourceToPBASMProgram(VertexMaterialProgram);
fragmentMaterialProgram = ExampleUtils.resourceToPBASMProgram(FragmentMaterialProgram);

var translatedPrograms : AGALProgramPair;

translatedPrograms = PBASMCompiler.compile(vertexPositionProgram,
vertexMaterialProgram,
fragmentMaterialProgram
);

// we'll need these in order to set variables without resorting to low
// level molehill calls. A later example will show PB3D use
// without use of RegisterMap objects.

vertexRegisterMap_ = translatedPrograms.vertexProgram.registers;
fragmentRegisterMap_ = translatedPrograms.fragmentProgram.registers;

// we've now translated everything to AGAL, the binary format that
// molehill accepts, so let's create a Molehill shader program and upload
// our binaries

parameterBufferHelper_ = new ProgramConstantsHelper( context3D_, vertexRegisterMap_, fragmentRegisterMap_ );

shaderProgram_ = context3D_.createProgram();
shaderProgram_.upload(translatedPrograms.vertexProgram.byteCode,
translatedPrograms.fragmentProgram.byteCode
);
}

private function InitProjection() : void
{
_matProjection = new PerspectiveMatrix3D();
_matProjection.perspectiveFieldOfViewLH( 45 * Math.PI / 180, WIDTH / HEIGHT, 0.1, 3000 );
}

/**
* カメラの初期化を行う
*/
private function InitCamera() : void
{
_camera = new Camera();
// カメラ位置、注視点
_camera.InitView( new Vector3D(eyePosition_.x, eyePosition_.y, eyePosition_.z), new Vector3D(0, 0, 0), new Vector3D(0, 1, 0) );
}

}

}

import flash.display.BitmapData;
import flash.display.Shape;
import flash.display3D.Context3D;
import flash.display3D.textures.Texture;
import flash.display3D.IndexBuffer3D;
import flash.display3D.VertexBuffer3D;
import flash.display3D.Context3DTextureFormat;
import flash.geom.Matrix;
import flash.geom.Matrix3D;
import flash.geom.Vector3D;

class Camera
{
private var _view:Matrix3D;
private var _from:Vector3D;
private var _at:Vector3D;
private var _up:Vector3D;

public function Camera()
{
_view = new Matrix3D();
}

/**
* ビュー行列の設定を行う
*/
public function InitView( from:Vector3D, at:Vector3D, up:Vector3D ) : void
{
var vz:Vector3D = at.subtract( from );
vz.normalize();
var vx:Vector3D = up.crossProduct( vz );
vx.normalize();
var vy:Vector3D = vz.crossProduct( vx );
vy.normalize();
var vtx:Number = vx.dotProduct( from ) * -1;
var vty:Number = vy.dotProduct( from ) * -1;
var vtz:Number = vz.dotProduct( from ) * -1;

_view.identity();
_view.rawData = Vector.([
vx.x, vy.x, vz.x, 0,
vx.y, vy.y, vz.y, 0,
vx.z, vy.z, vz.z, 0,
vtx, vty, vtz, 1,
]);

_from = from;
_at = at;
_up = up;
}

public function get matrix():Matrix3D
{
return _view;
}

public function get from() : Vector3D
{
return _from;
}

public function get at() : Vector3D
{
return _at;
}
}