package away3d.materials { import away3d.containers.*; import away3d.arcane; 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 flash.display.*; import flash.events.*; use namespace arcane; /** * Abstract class for materials that calculate lighting for the face's center * Not intended for direct use - use ShadingColorMaterial or WhiteShadingBitmapMaterial. */ public class CenterLightingMaterial extends EventDispatcher implements ITriangleMaterial { /** @private */ arcane var v0:ScreenVertex; /** @private */ arcane var v1:ScreenVertex; /** @private */ arcane var v2:ScreenVertex; /** @private */ arcane var session:AbstractRenderSession; private var point:PointLight; private var directional:DirectionalLight; private var global:AmbientLight; private var focus:Number; private var zoom:Number; private var v0z:Number; private var v0p:Number; private var v0x:Number; private var v0y:Number; private var v1z:Number; private var v1p:Number; private var v1x:Number; private var v1y:Number; private var v2z:Number; private var v2p:Number; private var v2x:Number; private var v2y: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:MatrixAway3D; private var _source:Mesh; /** * 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 CenterLightingMaterial(init:Object = null) { ini = Init.parse(init); 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); } } } /** * @inheritDoc */ public function renderTriangle(tri:DrawTriangle):void { session = tri.source.session; v0 = tri.v0; v1 = tri.v1; v2 = tri.v2; focus = tri.view.camera.focus; zoom = tri.view.camera.zoom; v0z = v0.z; v0p = (1 + v0z / focus) / zoom; v0x = v0.x * v0p; v0y = v0.y * v0p; v1z = v1.z; v1p = (1 + v1z / focus) / zoom; v1x = v1.x * v1p; v1y = v1.y * v1p; v2z = v2.z; v2p = (1 + v2z / focus) / zoom; v2x = v2.x * v2p; v2y = v2.y * v2p; 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; 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.face.normal.x; ny = tri.face.normal.y; nz = tri.face.normal.z; amb = directional.ambient * ambient_brightness; 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; rfx = _diffuseTransform.szx; rfy = _diffuseTransform.szy; rfz = _diffuseTransform.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; dfx = point.x - c0x; dfy = point.y - c0y; dfz = point.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; } renderTri(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 = point.x - c0x; dfy = point.y - c0y; dfz = point.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); } } }