/**
* Copyright nannabelle93 ( http://wonderfl.net/user/nannabelle93 )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/xmw9
*/
// forked from lizhi's 3d fire
package
{
import flash.display.*;
import flash.events.Event;
import flash.filters.BlurFilter;
import flash.filters.DisplacementMapFilter;
import flash.filters.GlowFilter;
import flash.text.TextField;
import net.hires.debug.Stats;
import flash.geom.*;
/**
* ...
* @author lizhi http://game-develop.net/
*/
[SWF(frameRate=60)]
public class Test3D6 extends Sprite
{
private var root3d:Obj3D = new Obj3D;
private var obj:Obj3D = new Obj3D;
private var light:Vector3D = new Vector3D(0, -1, -.1);
private var lightHelp:Matrix3D = new Matrix3D;
private var camera:Camera = new Camera;
private var view:Shape = new Shape;
private var bview:BitmapData = new BitmapData(400, 400, false, 0);
private var map:BitmapData = bview.clone();
private var gd:Vector.<IGraphicsData> = new Vector.<IGraphicsData>;
private var pps:Vector.<Polygon> = new Vector.<Polygon>;
public static var tcount:int = 0;
private var debug:TextField = new TextField;
public function Test3D6()
{
light.normalize();
var texture:BitmapData = new BitmapData(30, 30, false,0xff0000);
texture.perlinNoise(40, 40, 2, 1, true, true);
var r:Number = 0;
for (var i:int = 0; i < 5; i++)
{
var obj3d:Obj3D = /*Math.random() < .5?createCube():*/createSphere(4,4,7,true);
obj3d.rotation.x = Math.PI * Math.random();
obj3d.rotation.y = Math.PI * Math.random();
obj3d.rotation.z = Math.PI * Math.random();
obj3d.scale.x = obj3d.scale.y = obj3d.scale.z = 30;
obj3d.position.x = (Math.random() - .5) * 500;
obj3d.position.y = (Math.random() - .5) * 500;
obj3d.position.z = (Math.random() - .5) * 500;
//var r:Number = Math.random();
if (r < .2) {
obj3d.material = new LineMaterial(obj3d,0xffffff*Math.random());
}else if (r < .4) {
obj3d.faceLight = true;
obj3d.material = new FlatColorMaterial(obj3d,0xffffff*Math.random());
}else if (r<.6) {
obj3d.faceLight = true;
obj3d.material = new FlatBmdFillMaterial(obj3d,texture);
}else if(r<.8){
obj3d.vectorlight = true;
obj3d.material = new GouraudColorMaterial(obj3d, 0xffffff * Math.random());
}else {
obj3d.vectorlight = true;
obj3d.material = new GouraudBmdMaterial(obj3d, texture);
}
r += .2;
obj.add(obj3d);
}
root3d.add(obj);
camera.position.z = -1000;
addEventListener(Event.ENTER_FRAME, enterFrame);
//addChild(view);
view.x = view.y = 200;
addChild(new Bitmap(bview));
map.perlinNoise(10, 10, 2, 1, true, true);
addChild(new Stats);
debug.autoSize = "left";
debug.textColor = 0xff0000;
addChild(debug);
debug.x = 80;
}
private function enterFrame(e:Event):void
{
debug.text = "triangle : "+tcount;
view.graphics.clear();
camera.rotation.z += .01;
camera.matrix.recompose(camera.comps);
camera.invert.copyFrom(camera.matrix);
camera.invert.invert();
pps.length = 0;
for each (var obj3d:Obj3D in root3d.children)
{
do3d(obj3d);
}
pps.sort(psort);
gd.length = 0;
for each (var p:Polygon in pps)
{
p.materialBase.doMaterial(gd);
}
view.graphics.drawGraphicsData(gd);
//post effect
//return;
bview.scroll(0, -2);
bview.colorTransform(bview.rect, new ColorTransform(.99, .8, .5, .999));
bview.applyFilter(bview, bview.rect, new Point, new BlurFilter);
bview.applyFilter(bview, bview.rect, new Point, new DisplacementMapFilter(map, new Point,1,2,10,10));
bview.draw(view, view.transform.matrix);
}
private function psort(p1:Polygon, p2:Polygon):Number
{
return p2.vz - p1.vz;
}
private final function do3d(obj3d:Obj3D):void
{
obj3d.rotation.x += .01;
obj3d.rotation.y += .02;
obj3d.rotation.z += .03;
obj3d.matrix.recompose(obj3d.comps);
obj3d.worldMatrix.copyFrom(obj3d.matrix);
obj3d.worldMatrix.append(obj3d.parent.worldMatrix);
obj3d.viewMatrix.copyFrom(obj3d.worldMatrix);
obj3d.viewMatrix.append(camera.invert);
obj3d.viewMatrix.transformVectors(obj3d.vin, obj3d.vout);
Utils3D.projectVectors(camera.perspectiveProjection, obj3d.vout, obj3d.projectedVerts, obj3d.uvt);
if(obj3d.vectorlight||obj3d.faceLight){
var comp:Vector.<Vector3D> = obj3d.worldMatrix.decompose();
comp[0].x = comp[0].y = comp[0].z = 0;
comp[2].x = comp[2].y = comp[2].z = 1;
lightHelp.recompose(comp);
}
if (obj3d.vectorlight) {
lightHelp.transformVectors(obj3d.normVin, obj3d.normVout);
var normVout:Vector.<Number> = obj3d.normVout;
var normUv:Vector.<Number> = obj3d.normUv;
var uvt:Vector.<Number> = obj3d.uvt;
for (var i:int = 0, len:int = obj3d.normVin.length / 3; i < len; i ++ ) {
var i3:int = i * 3;
var ai0:Number = i3;
var ai1:Number = i3 + 1;
var ai2:Number = i3 + 2;
var al:Number = light.x * normVout[ai0] + light.y * normVout[ai1] + light.z * normVout[ai2];
if (al < .03) al = .03;
normUv[i*2] = al;
}
}
var vout:Vector.<Number> = obj3d.vout;
for each (var polygon:Polygon in obj3d.polygons)
{
polygon.vz = 0;
var indices:Vector.<int> = polygon.indices;
for (i = 0, len = indices.length; i < len; i ++)
{
polygon.vz += vout[indices[i]*3+2];
}
polygon.vz /= indices.length;
if(obj3d.faceLight){
var norm:Vector3D = lightHelp.transformVector(polygon.norm);
polygon.lightWeight = /*norm.x * light.x + norm.y * light.y + norm.z * light.z;*/ norm.dotProduct(light);
if (polygon.lightWeight < .03) polygon.lightWeight = .03;
}
pps.push(polygon);
}
for each (var c3d:Obj3D in obj3d.children)
{
do3d(c3d);
}
}
private function createCube():Obj3D
{
var color:uint = 0;
var obj3d:Obj3D = new Obj3D;
obj3d.vin = Vector.<Number>([ -1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1,
-1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1,
-1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1,
1, -1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1,
-1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1,
-1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1]);
obj3d.uvt = Vector.<Number>([0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0,0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0,0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0,0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0,0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0,0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0]);
obj3d.projectedVerts = new Vector.<Number>(obj3d.vin.length*2/3);
obj3d.vout = new Vector.<Number>(obj3d.vin.length);
obj3d.polygons.push(createPolygon(obj3d, Vector.<int>([0, 2, 1, 1, 2, 3]), new Vector3D(0, 0, 1)));
obj3d.polygons.push(createPolygon(obj3d,Vector.<int>([4, 5, 6, 5, 7, 6]), new Vector3D(0, 0, -1)));
obj3d.polygons.push(createPolygon(obj3d, Vector.<int>([8, 10, 9, 9, 10, 11]), new Vector3D(-1, 0, 0)));
obj3d.polygons.push(createPolygon(obj3d, Vector.<int>([12, 13, 14, 13, 15, 14]), new Vector3D(1, 0, 0)));
obj3d.polygons.push(createPolygon(obj3d,Vector.<int>([16, 17, 18, 17, 19, 18]), new Vector3D(0, -1, 0)));
obj3d.polygons.push(createPolygon(obj3d,Vector.<int>([20, 22, 21, 21, 22, 23]), new Vector3D(0, 1, 0)));
return obj3d;
}
public function createSphere(r:Number,nv:int = 4, nh:int = 7,vnorm:Boolean=false):Obj3D {
var obj3d:Obj3D = new Obj3D;
obj3d.vin.push(0, -r,0);
obj3d.uvt.push(.5,0,0);
for (var i:int = 1; i <= nv;i++ ) {
var az:Number = (i / (nv + 1) - .5) * Math.PI;
var uvv:Number = i / (nv + 1);
for (var j:int = 0; j < nh; j++ ) {
obj3d.uvt.push(j/nh,uvv,0);
var v:Vector3D = new Vector3D(r);
var ay:Number = j / nh * 2 * Math.PI;
var x:Number = v.x * Math.cos(az);
v.y = v.x * Math.sin(az);
v.x = x * Math.cos(ay);
v.z = x * Math.sin(ay);
obj3d.vin.push(v.x,v.y,v.z);
var a:int = (i - 1) * nh + j + 1;
var b:int = j == (nh - 1)?a - nh + 1:a + 1;
var c:int = i == nv?nv * nh + 1:a + nh;
var d:int = j == (nh - 1)?c - nh + 1:c + 1;
if (i != nv) obj3d.polygons.push(createPolygon(obj3d, Vector.<int>([a, b, c, b, d, c]), new Vector3D));
else obj3d.polygons.push(createPolygon(obj3d, Vector.<int>([a, b, c]), new Vector3D));
}
}
obj3d.vin.push(0, r,0);
obj3d.uvt.push(.5,1,0);
for (j = 0; j < nh; j++ ) {
obj3d.polygons.push(createPolygon(obj3d, Vector.<int>([0, j == (nh - 1)?1:j + 2, j + 1]), new Vector3D));
}
obj3d.projectedVerts = new Vector.<Number>(obj3d.vin.length*2/3);
obj3d.vout = new Vector.<Number>(obj3d.vin.length);
if(vnorm){
obj3d.normVin = new Vector.<Number>(obj3d.vin.length);
obj3d.normVout = new Vector.<Number>(obj3d.vin.length);
obj3d.normUv = new Vector.<Number>(obj3d.vin.length*2/3);
}
computeNorm(obj3d);
return obj3d;
}
private function computeNorm(obj3d:Obj3D):void {
for each(var p:Polygon in obj3d.polygons) {
p.norm.scaleBy(0);
for each(var i:int in p.indices) {
p.norm.x += obj3d.vin[i*3];
p.norm.y += obj3d.vin[i*3+1];
p.norm.z += obj3d.vin[i*3+2];
}
p.norm.normalize();
}
if (obj3d.normVin) {
var v:Vector3D = new Vector3D;
var len:int = obj3d.vin.length;
for(i = 0; i < len;i+=3 ) {
v.x = obj3d.vin[i];
v.y = obj3d.vin[i+1];
v.z = obj3d.vin[i+2];
v.normalize();
obj3d.normVin[i] = v.x;
obj3d.normVin[i+1] = v.y;
obj3d.normVin[i + 2] = v.z;
}
}
}
private function createPolygon(obj3d:Obj3D,indices:Vector.<int>, norm:Vector3D):Polygon
{
var polygon:Polygon = new Polygon;
polygon.obj3d = obj3d;
polygon.indices = indices;
polygon.norm = norm;
return polygon;
}
}
}
import flash.display.*;
import flash.geom.*;
import flash.utils.ByteArray;
import flash.utils.Dictionary;
class Obj3D
{
public var parent:Obj3D;
public var children:Vector.<Obj3D> = new Vector.<Obj3D>;
public var matrix:Matrix3D = new Matrix3D;
public var comps:Vector.<Vector3D> = matrix.decompose();
public var position:Vector3D = comps[0];
public var rotation:Vector3D = comps[1];
public var scale:Vector3D = comps[2];
public var worldMatrix:Matrix3D = new Matrix3D;
public var viewMatrix:Matrix3D = new Matrix3D;
public var polygons:Vector.<Polygon> = new Vector.<Polygon>;
public var vin:Vector.<Number> = new Vector.<Number>;
public var vout:Vector.<Number> = new Vector.<Number>;
public var uvt:Vector.<Number> = new Vector.<Number>;
public var projectedVerts:Vector.<Number> = new Vector.<Number>;
public var faceLight:Boolean = false;//是否计算facelight
public var vectorlight:Boolean = false;//是否计算顶点光
public var normVin:Vector.<Number>;
public var normVout:Vector.<Number>;
public var normUv:Vector.<Number>;
public var material:Material;
public function add(obj3d:Obj3D):Obj3D
{
children.push(obj3d);
obj3d.parent = this;
for each(var p:Polygon in obj3d.polygons) {
Test3D6.tcount += p.indices.length / 3;
}
return obj3d;
}
}
class Polygon
{
public var obj3d:Obj3D;
public var indices:Vector.<int> = new Vector.<int>;
public var lines:Vector.<Point> = new Vector.<Point>; //直线
public var clines:Vector.<Vector3D> = new Vector.<Vector3D>; //曲线
public var vz:Number;
public var lightWeight:Number = 1;
public var norm:Vector3D;
public var materialBase:MaterialBase;
}
class Camera extends Obj3D
{
public var invert:Matrix3D = new Matrix3D;
public var perspectiveProjection:Matrix3D = (new PerspectiveProjection()).toMatrix3D();
}
class Material
{
private var obj:Obj3D;
private var c:Class;
public function Material(obj:Obj3D,c:Class)
{
this.c = c;
this.obj = obj;
foreach();
}
public function foreach():void {
for each (var p:Polygon in obj.polygons)
{
var mb:MaterialBase = new c as MaterialBase;
p.materialBase = mb;
mb.p = p;
mb.m = this;
func(mb, p);
}
}
public function func(mb:MaterialBase, p:Polygon):void {
}
}
class MaterialBase
{
public var p:Polygon;
public var m:Material;
public function doMaterial(gd:Vector.<IGraphicsData>):void {
}
}
class LineMaterial extends Material{
private var color:uint;
public function LineMaterial(obj:Obj3D,color:uint) {
this.color = color;
super(obj,LineMaterialBase);
}
override public function func(mb:MaterialBase, p:Polygon):void {
var lm:LineMaterialBase = mb as LineMaterialBase;
lm.tg.vertices = p.obj3d.projectedVerts;
lm.tg.indices = p.indices;
lm.stroke.fill = new GraphicsSolidFill(color);
}
}
class LineMaterialBase extends MaterialBase {
public var stroke:GraphicsStroke = new GraphicsStroke(1);
public var tg:GraphicsTrianglePath = new GraphicsTrianglePath(null, null, null, TriangleCulling.NEGATIVE);
public var strokeNull:GraphicsStroke = new GraphicsStroke;
[Inline]
override final public function doMaterial(gd:Vector.<IGraphicsData>):void {
gd.push(stroke, tg, strokeNull);
}
}
class FlatColorMaterial extends Material{
public var color:uint;
public var r:int;
public var g:int;
public var b:int;
public function FlatColorMaterial(obj:Obj3D,color:uint) {
this.color = color;
r = (color & 0xff0000) >> 16;
g = (color & 0xff00) >> 8;
b = (color & 0xff) ;
super(obj,FlatColorMaterialBase);
}
override public function func(mb:MaterialBase, p:Polygon):void {
var lm:FlatColorMaterialBase = mb as FlatColorMaterialBase;
lm.tg.vertices = p.obj3d.projectedVerts;
lm.tg.indices = p.indices;
lm.fill.color = color;
}
}
class FlatColorMaterialBase extends MaterialBase {
public var fill:GraphicsSolidFill = new GraphicsSolidFill();
public var tg:GraphicsTrianglePath = new GraphicsTrianglePath(null, null, null, TriangleCulling.NEGATIVE);
public var endFill:GraphicsEndFill = new GraphicsEndFill;
[Inline]
override final public function doMaterial(gd:Vector.<IGraphicsData>):void {
var cm:FlatColorMaterial = m as FlatColorMaterial;
fill.color = ((p.lightWeight * cm.r) << 16) | ((p.lightWeight * cm.g) << 8) | ((p.lightWeight * cm.b) );
gd.push(fill, tg, endFill);
}
}
class BmdFillMaterial extends Material{
private var texture:BitmapData;
public function BmdFillMaterial(obj:Obj3D,texture:BitmapData) {
this.texture = texture;
super(obj,BmdFillMaterialBase);
}
override public function func(mb:MaterialBase, p:Polygon):void {
var lm:BmdFillMaterialBase = mb as BmdFillMaterialBase;
lm.tg.vertices = p.obj3d.projectedVerts;
lm.tg.indices = p.indices;
lm.tg.uvtData = p.obj3d.uvt;
lm.fill.bitmapData = texture;
}
}
class BmdFillMaterialBase extends MaterialBase{
public var fill:GraphicsBitmapFill = new GraphicsBitmapFill();
public var tg:GraphicsTrianglePath = new GraphicsTrianglePath(null, null, null, TriangleCulling.NEGATIVE);
public var endFill:GraphicsEndFill = new GraphicsEndFill;
[Inline]
override final public function doMaterial(gd:Vector.<IGraphicsData>):void {
gd.push(fill, tg, endFill);
}
}
class FlatBmdFillMaterial extends Material{
private var texture:BitmapData;
public function FlatBmdFillMaterial(obj:Obj3D,texture:BitmapData) {
this.texture = texture;
super(obj,FlatBmdFillMaterialBase);
}
override public function func(mb:MaterialBase, p:Polygon):void {
var lm:FlatBmdFillMaterialBase = mb as FlatBmdFillMaterialBase;
lm.btg.vertices = p.obj3d.projectedVerts;
lm.btg.indices = p.indices;
lm.btg.uvtData = p.obj3d.uvt;
lm.bfill.bitmapData = texture;
lm.ctg.vertices = p.obj3d.projectedVerts;
lm.ctg.indices = p.indices;
}
}
class FlatBmdFillMaterialBase extends MaterialBase{
public var bfill:GraphicsBitmapFill = new GraphicsBitmapFill();
public var btg:GraphicsTrianglePath = new GraphicsTrianglePath(null, null, null, TriangleCulling.NEGATIVE);
public var cfill:GraphicsSolidFill = new GraphicsSolidFill();
public var ctg:GraphicsTrianglePath = new GraphicsTrianglePath(null, null, null, TriangleCulling.NEGATIVE);
public var endFill:GraphicsEndFill = new GraphicsEndFill;
[Inline]
override final public function doMaterial(gd:Vector.<IGraphicsData>):void {
cfill.alpha = 1-p.lightWeight;
gd.push(bfill, btg,cfill,ctg ,endFill);
}
}
class GouraudColorMaterial extends Material{
public var color:uint;
public var texture:BitmapData;
public function GouraudColorMaterial(obj:Obj3D,color:uint) {
this.color = color;
var w:int = 0xff;
texture = new BitmapData(w, 1, false);
var matr:Matrix = new Matrix
matr.createGradientBox(w ,1);
var pen:Shape = new Shape;
pen.graphics.beginGradientFill(GradientType.LINEAR, [0, color], [1, 1], [1,0xff],matr);
pen.graphics.drawRect(0, 0, w, 1);
pen.graphics.endFill();
texture.draw(pen);
super(obj,GouraudColorMaterialBase);
}
override public function func(mb:MaterialBase, p:Polygon):void {
var lm:GouraudColorMaterialBase = mb as GouraudColorMaterialBase;
lm.tg.vertices = p.obj3d.projectedVerts;
lm.tg.indices = p.indices;
lm.tg.uvtData = p.obj3d.normUv;
lm.fill.bitmapData = texture;
}
}
class GouraudColorMaterialBase extends MaterialBase {
public var fill:GraphicsBitmapFill = new GraphicsBitmapFill();
public var tg:GraphicsTrianglePath = new GraphicsTrianglePath(null, null, null, TriangleCulling.NEGATIVE);
public var endFill:GraphicsEndFill = new GraphicsEndFill;
[Inline]
override final public function doMaterial(gd:Vector.<IGraphicsData>):void {
gd.push(fill, tg, endFill);
}
}
class GouraudBmdMaterial extends Material{
private var btexture:BitmapData;
public var ctexture:BitmapData;
public function GouraudBmdMaterial(obj:Obj3D,btexture:BitmapData) {
this.btexture = btexture;
var w:int = 0xff;
ctexture = new BitmapData(w, 1, true,0);
var matr:Matrix = new Matrix
matr.createGradientBox(w ,1);
var pen:Shape = new Shape;
pen.graphics.beginGradientFill(GradientType.LINEAR, [0, 0], [1, 0], [1,0xff],matr);
pen.graphics.drawRect(0, 0, w, 1);
pen.graphics.endFill();
ctexture.draw(pen);
super(obj,GouraudBmdMaterialBase);
}
override public function func(mb:MaterialBase, p:Polygon):void {
var lm:GouraudBmdMaterialBase = mb as GouraudBmdMaterialBase;
lm.ctg.vertices = p.obj3d.projectedVerts;
lm.ctg.indices = p.indices;
lm.ctg.uvtData = p.obj3d.normUv;
lm.cfill.bitmapData = ctexture;
lm.btg.vertices = p.obj3d.projectedVerts;
lm.btg.indices = p.indices;
lm.btg.uvtData = p.obj3d.uvt;
lm.bfill.bitmapData = btexture;
}
}
class GouraudBmdMaterialBase extends MaterialBase {
public var bfill:GraphicsBitmapFill = new GraphicsBitmapFill();
public var btg:GraphicsTrianglePath = new GraphicsTrianglePath(null, null, null, TriangleCulling.NEGATIVE);
public var cfill:GraphicsBitmapFill = new GraphicsBitmapFill();
public var ctg:GraphicsTrianglePath = new GraphicsTrianglePath(null, null, null, TriangleCulling.NEGATIVE);
public var endFill:GraphicsEndFill = new GraphicsEndFill;
[Inline]
override final public function doMaterial(gd:Vector.<IGraphicsData>):void {
gd.push(bfill, btg,cfill,ctg ,endFill);
}
}