Outline material alternativa3d
Whilst I was experimenting with Toon/Cell shading materials I started looking into outlining objects as this is part of some of these materials. There are various different ways to do outlining, one of the first and simplest examples I tried was the culling method. The idea is that you take your object say a cube and then you duplicate it and scale it up slightly. Then you invert the culling of this duplicate. What this does is give you the effect of being able to see the duplicate behind the original object giving the illusion of an outline. The usage is the same as most, it is a basic material that I didn’t experiment too much with so there is just one optional parameter to set the duplicate objects outline color.
var mat:EdgeMaterial = new EdgeMaterial(0x000000);
mesh.setMaterialToAllSurfaces(mat);
and here is the material source code, you may notice that this material looks slightly different to the others on my blog, this is because I wrote this as more of a seperate material not so closely tied to the alternativa AGAL commands, this way I could use regular AGAL. Quite often this is how I will work, write the material in this format and then convert it into the alternativa3d’s own agal commands. I find it easier to debug and compare to examples online etc. Either way it doesn’t matter both materials work the same way.
package
{
import alternativa.engine3d.core.Camera3D;
import alternativa.engine3d.core.DrawUnit;
import alternativa.engine3d.core.Light3D;
import alternativa.engine3d.core.Object3D;
import alternativa.engine3d.core.Transform3D;
import alternativa.engine3d.materials.Material;
import alternativa.engine3d.objects.Surface;
import alternativa.engine3d.resources.Geometry;
import alternativa.engine3d.core.Renderer;
import alternativa.engine3d.core.VertexAttributes;
import alternativa.engine3d.materials.ShaderProgram;
import alternativa.engine3d.alternativa3d;
import alternativa.engine3d.materials.A3DUtils;
import flash.display.Stage3D;
import flash.display3D.Context3DTriangleFace;
import flash.utils.getQualifiedClassName;
import flash.utils.getDefinitionByName;
use namespace alternativa3d;
import flash.geom.Vector3D;
import flash.utils.Dictionary;
import flash.utils.getTimer;
import flash.display3D.Context3D;
import flash.display3D.Context3DVertexBufferFormat;
import flash.display3D.VertexBuffer3D;
import flash.display3D.Context3DProgramType;
import flash.display3D.Context3DBlendFactor;
import com.adobe.utils.AGALMiniAssembler;
import alternativa.engine3d.resources.TextureResource;
public class EdgeMaterial extends Material
{
private var vertexShaderAssembler:AGALMiniAssembler = new AGALMiniAssembler();
private var fragmentShaderAssembler:AGALMiniAssembler = new AGALMiniAssembler();
private var program:ShaderProgram;
private var colorvertexShaderAssembler:AGALMiniAssembler = new AGALMiniAssembler();
private var colorfragmentShaderAssembler:AGALMiniAssembler = new AGALMiniAssembler();
private var colorprogram:ShaderProgram;
private var color:Vector3D;
public function EdgeMaterial(color:uint = 0x000000):void
{
this.color = new Vector3D( ((color >> 16) & 0xFF)/0xFF , ((color >> 8) & 0xFF)/0xFF , (color & 0xff)/0xFF, 1 );
program = new ShaderProgram(null, null);
colorprogram = new ShaderProgram(null,null);
AGAL.init();
AGAL.mul("vt0", "va1", "vc4.x");
AGAL.add("vt0", "vt0", "va0");
AGAL.m44("op", "vt0", "vc0");
vertexShaderAssembler.assemble(Context3DProgramType.VERTEX, AGAL.code);
AGAL.init();
AGAL.mov("oc", "fc0");
fragmentShaderAssembler.assemble(Context3DProgramType.FRAGMENT, AGAL.code);
AGAL.init();
AGAL.m44("op","va0","vc0");
colorvertexShaderAssembler.assemble(Context3DProgramType.VERTEX, AGAL.code);
AGAL.init();
AGAL.mov("oc", "fc0");
colorfragmentShaderAssembler.assemble(Context3DProgramType.FRAGMENT, AGAL.code);
}
override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector., lightsLength:int, useShadow:Boolean, objectRenderPriority:int = -1):void
{
if (program.program == null)
{
program.program = camera.context3D.createProgram();
program.program.upload(vertexShaderAssembler.agalcode, fragmentShaderAssembler.agalcode);
}
if (colorprogram.program == null)
{
colorprogram.program = camera.context3D.createProgram();
colorprogram.program.upload(colorvertexShaderAssembler.agalcode, colorfragmentShaderAssembler.agalcode);
}
// link to the object from own surface
var object:Object3D = surface.object;
//Position Buffer
var positionBuffer:VertexBuffer3D = geometry.getVertexBuffer(VertexAttributes.POSITION);
//Normals Buffer
var normalsBuffer:VertexBuffer3D = geometry.getVertexBuffer(VertexAttributes.NORMAL);
var drawUnit:DrawUnit;
drawUnit = camera.renderer.createDrawUnit(object,program.program,geometry._indexBuffer,surface.indexBegin,surface.numTriangles,program);
//va0, va1
drawUnit.setVertexBufferAt(0, positionBuffer, geometry._attributesOffsets[VertexAttributes.POSITION], VertexAttributes.FORMATS[VertexAttributes.POSITION]);
drawUnit.setVertexBufferAt(1, normalsBuffer, geometry._attributesOffsets[VertexAttributes.NORMAL], VertexAttributes.FORMATS[VertexAttributes.NORMAL]);
// Constants
object.setTransformConstants(drawUnit, surface, program.vertexShader, camera);
drawUnit.setProjectionConstants(camera, 0, object.localToCameraTransform); //vc0
drawUnit.setVertexConstantsFromNumbers(4, -0.03, -0.5, 0, 0); //vc4
drawUnit.setFragmentConstantsFromNumbers(0, color.x, color.y, color.z, color.w); //fc0
drawUnit.setFragmentConstantsFromNumbers(1, 0.1, 0, 0, 0); //fc1
drawUnit.setFragmentConstantsFromNumbers(2, 255, 0, 0, 1); //fc2
//change culling!
drawUnit.culling = Context3DTriangleFace.BACK;
// Send to render
if (color.w < 1) {
drawUnit.blendSource = Context3DBlendFactor.SOURCE_ALPHA;
drawUnit.blendDestination = Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA;
camera.renderer.addDrawUnit(drawUnit, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.TRANSPARENT_SORT);
} else {
camera.renderer.addDrawUnit(drawUnit, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.OPAQUE);
}
var drawUnit2 : DrawUnit = camera.renderer.createDrawUnit(object, colorprogram.program, geometry._indexBuffer, surface.indexBegin, surface.numTriangles, colorprogram);
drawUnit2.setVertexBufferAt(0, positionBuffer, geometry._attributesOffsets[VertexAttributes.POSITION], Context3DVertexBufferFormat.FLOAT_3);
drawUnit2.setProjectionConstants(camera, 0, object.localToCameraTransform);
drawUnit2.setFragmentConstantsFromNumbers(0, 255, 0, 0, 1);
drawUnit2.blendSource = Context3DBlendFactor.SOURCE_ALPHA;
drawUnit2.blendDestination = Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA;
camera.renderer.addDrawUnit(drawUnit2, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.OPAQUE);
}
}
}
Comments
Comments are currently closed