Outline material alternativa3d

Posted by davidejones

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

You can download the example files here

Trackback URL for this post: http://davidejones.com/blog/1618-outline-material-alternativa3d/trackback/

Being Sociable...

  • If you like this article then please share it on your favourite social network and follow me on twitter for the latest updates

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>