Alternativa3D(AlternativaPlatform)にて
- テクスチャマテリアルに独自のAGALを適用
- アルファ値を反映
...する解説です。
共通
Materialクラスを継承して fillResources()
と collectDraws()
をoverrideします。
-
fillResources()
で必要なGPUリソースをアップロードします。 -
collectDraws()
で描画の準備と予約をする様です。
AGALの適用
camera:Camera3D
から DrawUnit
を生成し、vertexBuffer, indexBuffer, texture, shaderを準備します。
サンプルでは
- vertexShader
- 頂点にprojectionMatrixを反映
- uvをfragmentShaderへ渡す
- fragmentShader
- 輝度を計算してRGBへ格納
- アルファ値は指定の値を格納
としています。
アルファ値の反映
fragmentShaderで oc.w(oc.a)
にアルファ値を代入しても反映されません。
Context3D#setBlendFactors
で反映させる旨を指定する必要があります。
Alternativa3Dでは先のDrawUnit
のblendSource
とblendDestination
に指定することで適用できます。
サンプル
LuminanceAndAlphaTextureMaterial.as - github にもあります。
LuminanceAndAlphaTextureMaterial.as
package
{
import alternativa.engine3d.alternativa3d;
import alternativa.engine3d.core.Camera3D;
import alternativa.engine3d.core.DrawUnit;
import alternativa.engine3d.core.Light3D;
import alternativa.engine3d.core.Object3D;
import alternativa.engine3d.core.Renderer;
import alternativa.engine3d.core.VertexAttributes;
import alternativa.engine3d.materials.Material;
import alternativa.engine3d.materials.ShaderProgram;
import alternativa.engine3d.objects.Surface;
import alternativa.engine3d.resources.Geometry;
import alternativa.engine3d.resources.TextureResource;
import com.adobe.utils.AGALMiniAssembler;
import flash.display3D.Context3D;
import flash.display3D.Context3DBlendFactor;
import flash.display3D.Context3DProgramType;
import flash.display3D.VertexBuffer3D;
import flash.utils.Dictionary;
use namespace alternativa3d;
/**
* ...
* @author Toshiyuki Suzumura / @suzumura_ss
*/
public class LuminanceAndAlphaTextureMaterial extends Material
{
private var _texture:TextureResource;
private var _alpha:Number;
private var _context3d:Context3D;
private var _program:ShaderProgram = new ShaderProgram(null, null);
private var _vertexShaderAssembler:AGALMiniAssembler = new AGALMiniAssembler();
private var _fragmentShaderAssembler:AGALMiniAssembler = new AGALMiniAssembler();
public function LuminanceAndAlphaTextureMaterial(texture:TextureResource, alpha:Number, context3d:Context3D)
{
_texture = texture;
_alpha = alpha;
_context3d = context3d;
_vertexShaderAssembler.assemble(Context3DProgramType.VERTEX, [
// op = va0[pos] * vc0[projection]
"m44 op, va0, vc0",
// v0 = va1[uv]
"mov v0, va1",
].join("\n"));
_fragmentShaderAssembler.assemble(Context3DProgramType.FRAGMENT, [
// ft0 = sampler2d(fs0, v0[uv])
"tex ft0, v0, fs0 <2d,linear,repeat>",
// lum = 0.299r
"mul ft0.x, ft0.x, fc0.x",
// lum += 0.587g
"mul ft0.y, ft0.y, fc0.y",
"add ft0.x, ft0.x, ft0.y",
// lum += 0.114b
"mul ft0.z, ft0.z, fc0.z",
"add ft0.x, ft0.x, ft0.z",
// g = lum, b = lum
"mov ft0.y, ft0.x",
"mov ft0.z, ft0.x",
// a = <_alpha>
"mov ft0.w, fc0.w",
"mov oc, ft0",
].join("\n"));
}
override alternativa3d function fillResources(resources:Dictionary, resourceType:Class):void
{
super.fillResources(resources, resourceType);
if (_texture != null) {
resources[_texture] = true;
}
_program.program = _context3d.createProgram();
_program.program.upload(_vertexShaderAssembler.agalcode, _fragmentShaderAssembler.agalcode);
}
override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean, objectRenderPriority:int = -1):void
{
var object:Object3D = surface.object;
var posBuffer:VertexBuffer3D = geometry.getVertexBuffer(VertexAttributes.POSITION);
var uvBuffer:VertexBuffer3D = geometry.getVertexBuffer(VertexAttributes.TEXCOORDS[0]);
var drawUnit:DrawUnit = camera.renderer.createDrawUnit(object, _program.program, geometry._indexBuffer, surface.indexBegin, surface.numTriangles, _program);
drawUnit.setProjectionConstants(camera, 0, object.localToCameraTransform); // = vc0
drawUnit.setVertexBufferAt(0, posBuffer, 0, "float3"); // = va0
drawUnit.setVertexBufferAt(1, uvBuffer, 3, "float2"); // = va1
drawUnit.setFragmentConstantsFromNumbers(0, 0.299, 0.587, 0.114, _alpha); // = fc0
drawUnit.setTextureAt(0, _texture._texture); // = fs0
drawUnit.blendSource = Context3DBlendFactor.SOURCE_ALPHA;
drawUnit.blendDestination = Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA;
camera.renderer.addDrawUnit(drawUnit, (objectRenderPriority >= 0)? objectRenderPriority: Renderer.OPAQUE);
}
}
}