Hi,
well quite not far from success (optimistic...)
here is the process:
>>>we create a CenterLightingMaterialCache instance that implement IUVMaterial:
var backer:CenterLightingMaterialCache = new
CenterLightingMaterialCache
(sourceObj:Mesh,bitmap:BitmapData,view:View3D,directional:DirectionalLight3D,init:Object=null)
Mesh: the object we'll work with (only use it's geometry);
bitmap:the bitmapdata that will be used to render the shader, can be
any bitmapdata
the view: the view ...
directionnalLight: a light (here directionnal)
>>>then we call:
backer.renderBacker();
for each of the faces of the mesh, we create a new DrawTriangle and
calculate some values according to the light/geometry and pass it to
the drawTriangle
and call a "renderTri" like method :
renderTriBacked
(tri:DrawTriangle,session:AbstractRenderSession,kar:Number,kag:Number,kab:Number,kdr:Number,kdg:Number,kdb:Number,ksr:Number,ksg:Number,ksb:Number,smooth:Boolean
= true,repeat:Boolean = false);
that will draw each drawtriangle in a sprite depending on uv.
>>>then we can use this sprite to draw a new bitmapdata and apply as prebacked
>>>material.
var btm:BitmapData = new BitmapData
(backer._mapCache.width,backer._mapCache.height) ;
btm.draw(backer._mapCache.height);
that's all !
but I'm really having some trouble, here they are:
line 193 -196 : I need to had a light in the lightArray of the
sourceMesh in order to calculate the line 307 loop.
line 503 -548 : they must be a prettier way to draw that with face or
draw primitive coords.
thay are also a lot of ugly things but it's a work in process.
Fabrice, do you think I'm right and would you help me correct and
achieve ???
the class:
package away3d.materials{
import away3d.arcane;
import away3d.containers.*;
import away3d.core.base.*;
import away3d.core.draw.*;
import away3d.core.light.*;
import away3d.core.math.*;
import away3d.core.render.*;
import away3d.core.utils.*;
import away3d.events.*;
import away3d.lights.*;
import flash.display.*;
import flash.filters.*;
import flash.events.*;
import flash.utils.*;
import flash.geom.*;
use namespace arcane;
/**
* Abstract class for materials that calculate lighting for the
face's center
* Not intended for direct use - use <code>ShadingColorMaterial</
code> or <code>WhiteShadingBitmapMaterial</code>.
*/
public class CenterLightingMaterialCache extends EventDispatcher
implements IUVMaterial {
/** @private */
arcane var v0:ScreenVertex;
/** @private */
arcane var v1:ScreenVertex;
/** @private */
arcane var v2:ScreenVertex;
/** @private */
arcane var session:AbstractRenderSession;
/** @private */
arcane function notifyMaterialUpdate():void {
_materialDirty=false;
if (! hasEventListener(MaterialEvent.MATERIAL_UPDATED))
{
return;
}
if (_materialupdated==null) {
_materialupdated=new MaterialEvent
(MaterialEvent.MATERIAL_UPDATED,this);
}
dispatchEvent(_materialupdated);
}
private var point:PointLight;
private var directional:DirectionalLight;
private var global:AmbientLight;
private var focus:Number;
private var zoom:Number;
private var v0x:Number;
private var v0y:Number;
private var v0z:Number;
private var v1x:Number;
private var v1y:Number;
private var v1z:Number;
private var v2x:Number;
private var v2y:Number;
private var v2z:Number;
private var d1x:Number;
private var d1y:Number;
private var d1z:Number;
private var d2x:Number;
private var d2y:Number;
private var d2z:Number;
private var pa:Number;
private var pb:Number;
private var pc:Number;
private var pdd:Number;
private var c0x:Number;
private var c0y:Number;
private var c0z:Number;
private var kar:Number;
private var kag:Number;
private var kab:Number;
private var kdr:Number;
private var kdg:Number;
private var kdb:Number;
private var ksr:Number;
private var ksg:Number;
private var ksb:Number;
private var red:Number;
private var green:Number;
private var blue:Number;
private var dfx:Number;
private var dfy:Number;
private var dfz:Number;
private var df:Number;
private var nx:Number;
private var ny:Number;
private var nz:Number;
private var fade:Number;
private var amb:Number;
private var nf:Number;
private var diff:Number;
private var rfx:Number;
private var rfy:Number;
private var rfz:Number;
private var spec:Number;
private var rf:Number;
private var graphics:Graphics;
private var cz:Number;
private var cx:Number;
private var cy:Number;
private var ncz:Number;
private var ncx:Number;
private var ncy:Number;
private var sum:Number;
private var ffz:Number;
private var ffx:Number;
private var ffy:Number;
private var fz:Number;
private var fx:Number;
private var fy:Number;
private var rz:Number;
private var rx:Number;
private var ry:Number;
private var draw_normal:Boolean=false;
private var draw_fall:Boolean=false;
private var draw_fall_k:Number=1;
private var draw_reflect:Boolean=false;
private var draw_reflect_k:Number=1;
private var _diffuseTransform:Matrix3D;
private var _specularTransform:Matrix3D;
private var _viewPosition:Number3D;
private var _source:Mesh;
private var _view:View3D;
private var _materialDirty:Boolean;
private var _materialupdated:MaterialEvent;
private var render:Boolean=true;
//
public var _mapCache:Sprite;
private var _bitmap:BitmapData;
private var colorTransform:ColorMatrixFilter = new
ColorMatrixFilter
();
private var cache:Dictionary=new Dictionary(true);
private var step:int=1;
private var mapping:Matrix;
private var br:Number;
private var _texturemapping:Matrix;
private var _faceMaterialVO:FaceMaterialVO;
private var _faceDictionary:Dictionary=new Dictionary(true);
private var blackrender:Boolean;
private var whiterender:Boolean;
private var whitek:Number=0.2;
private var bitmapPoint:Point=new Point(0,0);
private var _light:DirectionalLight3D;
private var session:AbstractRenderSession;
private var i:int;
/**
* Instance of the Init object used to hold and parse
default
property values
* specified by the initialiser object in the 3d object
constructor.
*/
protected var ini:Init;
/** @private */
protected function renderTri
(tri:DrawTriangle,session:AbstractRenderSession,kar:Number,kag:Number,kab:Number,kdr:Number,kdg:Number,kdb:Number,ksr:Number,ksg:Number,ksb:Number):void
{
throw new Error("Not implemented");
}
/**
* Coefficient for ambient light level
*/
public var ambient_brightness:Number=1;
/**
* Coefficient for diffuse light level
*/
public var diffuse_brightness:Number=1;
/**
* Coefficient for specular light level
*/
public var specular_brightness:Number=1;
/**
* Coefficient for shininess level
*/
public var shininess:Number=20;
/**
* @private
*/
public function CenterLightingMaterialCache
(sourceObj:Mesh,bitmap:BitmapData,view:View3D,directional:DirectionalLight3D,init:Object=null)
{
ini=Init.parse(init);
_bitmap=bitmap;
_light=directional;
_source=sourceObj;
var directionalLight:DirectionalLight = new
DirectionalLight();
directionalLight.light=_light;
_source.lightarray.directionals=new Array[_light
];///read only
trace(_source.lightarray.directionals);
//_source.lightarray.directionalLight(directionalLight)
//_source.lightarray.directionals[0].light = _light;
_view=view;
_mapCache = new Sprite();
shininess=ini.getColor("shininess",20);
}
/**
* @inheritDoc
*/
public function
updateMaterial(source:Object3D,view:View3D):void {
for each (directional in
source.lightarray.directionals) {
if (! directional.diffuseTransform[source]||
view.scene.updatedObjects[source]) {
directional.setDiffuseTransform(source);
_materialDirty=true;
}
if (! directional.specularTransform[source]) {
directional.specularTransform[source]=new Dictionary(true);
}
if (!
directional.specularTransform[source][view]||
view.scene.updatedObjects[source]||view.updated) {
directional.setSpecularTransform(source,view);
_materialDirty=true;
}
}
for each (point in source.lightarray.points) {
if (!
point.viewPositions[view]||view.scene.updatedObjects
[source]||view.updated) {
point.setViewPosition(view);
_materialDirty=true;
}
}
if (_materialDirty) {
clearFaces(source,view);
}
}
public function clearFaces
(source:Object3D=null,view:View3D=null):void {
notifyMaterialUpdate();
}
/**
* @inheritDoc
*/
public function renderBacker():void {//replace the
tri:DrawTriangle
loop
trace(_source.faces.length);
for(i= 0;i<_source.faces.length;i++);
{
var faceDrawed:FaceVO=_source.faces[i].faceVO
as FaceVO;
var tri:DrawTriangle=new DrawTriangle();
DrawPrimitive(tri).source=_source;
tri.faceVO=faceDrawed;
tri.uv0=faceDrawed.uv0;
tri.uv1=faceDrawed.uv1;
tri.uv2=faceDrawed.uv2;
tri.v0 = new ScreenVertex(faceDrawed.v0.x,
faceDrawed.v0.y,
faceDrawed.v0.z);
tri.v1 = new ScreenVertex(faceDrawed.v1.x,
faceDrawed.v1.y,
faceDrawed.v1.z);
tri.v2 = new ScreenVertex(faceDrawed.v2.x,
faceDrawed.v2.y,
faceDrawed.v2.z);
session=tri.source.session;
v0=tri.v0;
v1=tri.v1;
v2=tri.v2;
focus=_view.camera.focus;
zoom=_view.camera.zoom;
v0x=v0.vx;
v0y=v0.vy;
v0z=v0.z;
v1x=v1.vx;
v1y=v1.vy;
v1z=v1.z;
v2x=v2.vx;
v2y=v2.vy;
v2z=v2.z;
d1x=v1x-v0x;
d1y=v1y-v0y;
d1z=v1z-v0z;
d2x=v2x-v0x;
d2y=v2y-v0y;
d2z=v2z-v0z;
pa=d1y*d2z-d1z*d2y;
pb=d1z*d2x-d1x*d2z;
pc=d1x*d2y-d1y*d2x;
pdd=Math.sqrt(pa*pa+pb*pb+pc*pc);
pa/=pdd;
pb/=pdd;
pc/=pdd;
c0x=v0x+v1x+v2x/3;
c0y=v0y+v1y+v2y/3;
c0z=v0z+v1z+v2z/3;
kar=kag=kab=kdr=kdg=kdb=ksr=ksg=ksb=0;
//_source=tri.source as Mesh;
//_view=tri.view;
for each (directional in
tri.source.lightarray.directionals) {
_diffuseTransform=directional.diffuseTransform[_source];
red=directional.red;
green=directional.green;
blue=directional.blue;
dfx=_diffuseTransform.szx;
dfy=_diffuseTransform.szy;
dfz=_diffuseTransform.szz;
nx=tri.faceVO.face.normal.x;
ny=tri.faceVO.face.normal.y;
nz=tri.faceVO.face.normal.z;
amb=directional.ambient*ambient_brightness;
trace(amb);
kar+=red*amb;
kag+=green*amb;
kab+=blue*amb;
nf=dfx*nx+dfy*ny+dfz*nz;
if (nf<0) {
continue;
}
diff=directional.diffuse*nf*diffuse_brightness;
kdr+=red*diff;
kdg+=green*diff;
kdb+=blue*diff;
_specularTransform=directional.specularTransform[_source][_view];
rfx=_specularTransform.szx;
rfy=_specularTransform.szy;
rfz=_specularTransform.szz;
rf=rfx*nx+rfy*ny+rfz*nz;
spec=directional.specular*Math.pow(rf,shininess)
*specular_brightness;
ksr+=red*spec;
ksg+=green*spec;
ksb+=blue*spec;
}
for each (point in
tri.source.lightarray.points) {
red=point.red;
green=point.green;
blue=point.blue;
_viewPosition=point.viewPositions[tri.view];
dfx=_viewPosition.x-c0x;
dfy=_viewPosition.y-c0y;
dfz=_viewPosition.z-c0z;
df=Math.sqrt(dfx*dfx+dfy*dfy+dfz*dfz);
dfx/=df;
dfy/=df;
dfz/=df;
fade=1/df/df;
amb=point.ambient*fade*ambient_brightness;
kar+=red*amb;
kag+=green*amb;
kab+=blue*amb;
nf=dfx*pa+dfy*pb+dfz*pc;
if (nf<0) {
continue;
}
diff=point.diffuse*fade*nf*diffuse_brightness;
kdr+=red*diff;
kdg+=green*diff;
kdb+=blue*diff;
rfz=dfz-2*nf*pc;
if (rfz<0) {
continue;
}
rfx=dfx-2*nf*pa;
rfy=dfy-2*nf*pb;
spec=point.specular*fade*Math.pow(rfz,shininess)
*specular_brightness;
ksr+=red*spec;
ksg+=green*spec;
ksb+=blue*spec;
//render = false;
}
renderTriBacked(tri,session,kar,kag,kab,kdr,kdg,kdb,ksr,ksg,ksb);
if (draw_fall||draw_reflect||draw_normal) {
graphics=session.graphics,cz=c0z,cx=c0x*zoom/1+cz/
focus,cy=c0y*zoom/1+cz/focus;
if (draw_normal) {
ncz=c0z+30*pc,ncx=c0x+30*pa*zoom*focus/focus+ncz,ncy=c0y
+30*pb*zoom*focus/focus+ncz;
graphics.lineStyle(1,0x000000,1);
graphics.moveTo(cx,cy);
graphics.lineTo(ncx,ncy);
graphics.moveTo(cx,cy);
graphics.drawCircle(cx,cy,2);
}
if (draw_fall||draw_reflect) {
for each (point in
tri.source.lightarray.points) {
red=point.red;
green=point.green;
blue=point.blue;
sum=red+green+blue/0xFF;
red/=sum;
green/=sum;
blue/=sum;
dfx=_viewPosition.x-c0x;
dfy=_viewPosition.y-c0y;
dfz=_viewPosition.z-c0z;
df=Math.sqrt(dfx*dfx+dfy*dfy+dfz*dfz);
dfx/=df;
dfy/=df;
dfz/=df;
nf=dfx*pa+dfy*pb+dfz*pc;
if (nf<0) {
continue;
}
if (draw_fall) {
ffz=c0z+30*dfz*1-draw_fall_k,ffx=c0x+30*dfx*1-
draw_fall_k*zoom*focus/focus+ffz,ffy=c0y+30*dfy*1-
draw_fall_k*zoom*focus/focus+ffz,fz=c0z+30*dfz,fx=c0x
+30*dfx*zoom*focus/focus+fz,fy=c0y+30*dfy*zoom*focus/focus+fz;
graphics.lineStyle(1,int(red)*0x10000+int(green)*0x100+int
(blue),1);
graphics.moveTo(ffx,ffy);
graphics.lineTo(fx,fy);
graphics.moveTo(ffx,ffy);
}
if (draw_reflect) {
rfx=dfx-2*nf*pa;
rfy=dfy-2*nf*pb;
rfz=dfz-2*nf*pc;
rz=c0z-30*rfz*draw_reflect_k,rx=c0x-30*rfx*draw_reflect_k*zoom*focus/
focus+rz,ry=c0y-30*rfy*draw_reflect_k*zoom*focus/focus+rz;
graphics.lineStyle(1,int(red*0.5)*0x10000+int(green*0.5)
*0x100+int(blue*0.5),1);
graphics.moveTo(cx,cy);
graphics.lineTo(rx,ry);
graphics.moveTo(cx,cy);
}
}
}
}
}
}
/**
* @private
*/
public function get visible():Boolean {
throw new Error("Not implemented");
}
/**
* @inheritDoc
*/
public function addOnMaterialUpdate(listener:Function):void {
//addEventListener(MaterialEvent.MATERIAL_UPDATED,
listener, false,
0, true);
}
/**
* @inheritDoc
*/
public function removeOnMaterialUpdate(listener:Function):void {
removeEventListener(MaterialEvent.MATERIAL_UPDATED,listener,false);
}
protected function renderTriBacked
(tri:DrawTriangle,session:AbstractRenderSession,kar:Number,kag:Number,kab:Number,kdr:Number,kdg:Number,kdb:Number,ksr:Number,ksg:Number,ksb:Number,smooth:Boolean
= true,repeat:Boolean = false):void {
br=kar+kag+kab+kdr+kdg+kdb+ksr+ksg+ksb/3;
//br=Math.random()*1;
trace(br);
//trace("renderTriBacked");
mapping=getMapping(tri);
var unfoldedX:Number=tri.faceVO.uv0.u*_bitmap.width;
var unfoldedY:Number=tri.faceVO.uv0.v*_bitmap.height;
v0=tri.v0;
v1=tri.v1;
v2=tri.v2;
trace(_mapCache);
/*
if (br<1&&blackrender||step<16&&! _bitmap.transparent) {
//session.renderTriangleBitmap
(_bitmap,mapping,v0,v1,v2,smooth,repeat);
//session.renderTriangleColor(0x000000,1-br,v0,v1,v2);
} else if (br>1&&whiterender) {
//session.renderTriangleBitmap
(_bitmap,mapping,v0,v1,v2,smooth,repeat);
//session.renderTriangleColor(0xFFFFFF,br-1*whitek,v0,v1,v2);
} else {
*/
if (step<64) {
if (Math.random()<0.01) {
doubleStepTo(64);
}
}
var brightness:Number=ladder(br);
var bitmap:BitmapData=cache[brightness];
if (bitmap==null) {
bitmap=new
BitmapData(_bitmap.width,_bitmap.height,true,
0x00000000);
colorTransform.matrix=[brightness,0,0,0,0,0,brightness,
0,0,0,0,0,brightness,0,0,0,0,0,1,0];
bitmap.applyFilter
(_bitmap,bitmap.rect,bitmapPoint,colorTransform);
cache[brightness]=bitmap;
}
if (step%2==0) {
_mapCache.graphics.lineStyle();
_mapCache.graphics.beginBitmapFill(bitmap);
//_mapCache.graphics.beginFill(0xFFFFFF*brightness);
_mapCache.graphics.moveTo(unfoldedX,unfoldedY);
_mapCache.graphics.lineTo(unfoldedX+66,unfoldedY);
_mapCache.graphics.lineTo(unfoldedX,unfoldedY+66);
_mapCache.graphics.endFill();
} else {
_mapCache.graphics.lineStyle();
_mapCache.graphics.beginBitmapFill(bitmap);
//_mapCache.graphics.beginFill(0xFFFFFF*brightness);
_mapCache.graphics.moveTo(unfoldedX+66,unfoldedY);
_mapCache.graphics.lineTo(unfoldedX+66,unfoldedY+66);
_mapCache.graphics.lineTo(unfoldedX,unfoldedY+66);
_mapCache.graphics.endFill();
}
//}
}
public function getMapping(tri:DrawTriangle):Matrix {
if (tri.generated) {
_texturemapping=tri.transformUV(this).clone();
_texturemapping.invert();
return _texturemapping;
}
_faceMaterialVO=getFaceMaterialVO(tri.faceVO,tri.source,tri.view);
if (! _faceMaterialVO.invalidated) {
return _faceMaterialVO.texturemapping;
}
_texturemapping=tri.transformUV(this).clone();
_texturemapping.invert();
return _faceMaterialVO.texturemapping = _texturemapping;
}
public function getFaceMaterialVO(faceVO:FaceVO,
source:Object3D =
null, view:View3D = null):FaceMaterialVO {
if ((_faceMaterialVO = _faceDictionary[faceVO])) {
return _faceMaterialVO;
}
return _faceDictionary[faceVO] = new FaceMaterialVO();
}
private function ladder(v:Number):Number {
if (v<1/0xFF) {
return 0;
}
if (v>0xFF) {
v=0xFF;
}
return Math.exp(Math.round(Math.log(v)*step)/step);
}
public function doubleStepTo(limit:int):void {
if (step<limit) {
step*=2;
}
}
public function get width():Number {
return _bitmap.width;
}
/**
* @inheritDoc
*/
public function get height():Number {
return _bitmap.height;
}
/**
* @inheritDoc
*/
public function get bitmap():BitmapData {
return _bitmap;
}
/**
* @inheritDoc
*/
public function getPixel32(u:Number, v:Number):uint {
return _bitmap.getPixel32(u*_bitmap.width, (1 -
v)*_bitmap.height);
}
public function invalidateFaces(source:Object3D = null,
view:View3D
= null):void {
for each (_faceMaterialVO in _faceDictionary) {
_faceMaterialVO.invalidated=true;
}
}
}
}