Edited at

Alternativa3DでAGALの適用とアルファブレンド

More than 5 years have passed since last update.

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 で反映させる旨を指定する必要があります。

- Context3DBlendFactor - help.adobe.com

- Context3D#setBlendFactors - help.adobe.com

Alternativa3Dでは先のDrawUnitblendSourceblendDestinationに指定することで適用できます。


サンプル

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);
}
}
}