Ejemplo: Proscenium – Añadir textura con transparencia Año: 2012 V.: AS3
[e]
Proscenium – As3 – Add texture or png image with transparency to a plane.
Aquí vengo con mi primer experimento con la Api Proscenium de adobe, durante el desarrollo del experimento me encontré que al añadir una imagen con trasparencias a un plano, las partes trasparentes se rellenaban con un color gris opaco. Me imagino que para realizar este proceso existen varios métodos como por ejemplo hacer un mapeado de las sombras, el tema es saber cómo y el problema la falta de referencias o soporte ya que como sabéis Proscenium carece prácticamente de información, básicamente te tienes que buscar la vida, así que finalmente termine encontrando una solución en una recóndita pagina china (Que haríamos sin los chinos…).
Al final de la entrada encontrareis la descarga del ejemplo completo
Aquí tenéis el código sencillo
Importamos la imagen
1 |
[Embed( source="source/content/circuit.png" )]protected static const CIRCUIT:Class; |
//Creamos el plano y aplicamos el material
1 2 3 4 5 6 7 8 9 |
var bmdC:BitmapData = ( new CIRCUIT() as Bitmap ).bitmapData; var materialC:MaterialStandard = new MaterialStandard(); materialC.specularColor.set( 0.8, 0.8, 0.8 ); materialC.ambientColor.set( 0.2, 0.2, 0.2 ); materialC.diffuseMap = new TextureMap(bmdC); //createOpacityMap se encarga de crear las trasparencias materialC.opacityMap = new TextureMap(createOpacityMap(bmdC)); _circuit = MeshUtils.createPlane( bmdC.width,bmdC.height, 1, 1, materialC, "Circuit" ); instance.scene.addChild(_circuit ); |
//Funcion encargada de devolver el mapeado trasparente
1 2 3 4 5 6 7 8 9 |
private function createOpacityMap( bmd:BitmapData ):BitmapData { var sourceRect:Rectangle = new Rectangle(0,0,bmd.width,bmd.height); var destPoint:Point = new Point(0,0); var alphaBMD:BitmapData = new BitmapData(bmd.width,bmd.height,false,0xff000000); alphaBMD.copyChannel( bmd, sourceRect, destPoint, BitmapDataChannel.ALPHA, BitmapDataChannel.RED ); alphaBMD.copyChannel( bmd, sourceRect, destPoint, BitmapDataChannel.ALPHA, BitmapDataChannel.GREEN ); alphaBMD.copyChannel( bmd, sourceRect, destPoint, BitmapDataChannel.ALPHA, BitmapDataChannel.BLUE ); return alphaBMD; } |
Aqui os dejo un ejemplo junto con el codigo completo del experimento, en el podeis apreciar que se carga una imagen de un circuito donde se puede ver por sus zonas trasparentes otra textura de fondo de otro plano inferior.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 |
package{ import com.adobe.utils.*; import com.adobe.display.*; import com.adobe.scenegraph.*; import flash.display3D.textures.*; import flash.display.*; import flash.display3D.*; import flash.events.*; import flash.geom.*; import flash.utils.*; [ SWF( width="632", height="626", backgroundColor="0x000000", frameRate="125" ) ] public class MainBase3 extends Sprite{ private var instance:Instance3D; private var _camera:SceneCamera; private var _light:SceneLight; private var _light2:SceneLight; private var _world:SceneMesh; private var _background:SceneMesh; private var _car:SceneMesh; private var _circuit:SceneMesh; private var persp:int = 1; //Propiedades de rotacion del mapa y control de movimiento private var sR:Number = 2;//speedRotationKeyBoard private var xyVel:Number = 5; private var consPi:Number = Math.PI / 180; private var rad:Number =-90*consPi; private var cos:Number = xyVel * Math.cos(rad); private var sen:Number = xyVel * Math.sin(rad); private var ka:Array = new Array(); private var key:int; private var pres:int = 3; private var worldRotation:Number = 0;//Initial World Rotation [Embed( source="source/content/background632.jpg" )]protected static const BACKGROUND:Class; [Embed( source="source/content/circuit.png" )]protected static const CIRCUIT:Class; [Embed( source="source/content/coche.png" )]protected static const CAR:Class; public function MainBase3(){ //Esperamos a que el stage este disponible addEventListener( Event.ADDED_TO_STAGE, InitStage); } protected function InitStage( event:Event ):void{ persp1_btn.addEventListener(MouseEvent.CLICK,onPersp1); persp2_btn.addEventListener(MouseEvent.CLICK,onPersp2); stage.scaleMode = StageScaleMode.NO_SCALE; stage.align = StageAlign.TOP_LEFT; //Recuperamos la referencia del escenario 3d if( stage.stage3Ds.length > 0 ){//Comprobamos que existen los escenarios 3D var stage3D:Stage3D = stage.stage3Ds[ 0 ] as Stage3D; //Le añadimos un listener al stage3D para esuchar cuando se ha creado el contexto despues de solicitarlo //Nota: En caso de perdida de contexto este evento volvera a ser llamado stage3D.addEventListener( Event.CONTEXT3D_CREATE, onContext3DInit); //Solicitamos cargar/crear el contexto3D al stage3D y le indicamos el modo de renderizado como automatico stage3D.requestContext3D(Context3DRenderMode.AUTO); } } protected function onContext3DInit( event:Event ):void{ //Una vez cargado el contexto dentro del stage3D volvemos a recuperar su referencia var stage3D:Stage3D = event.target as Stage3D; if ( !stage3D ){return;} //Creamos una instancia3D de acceso global del contexto recien creado dentro del stage //Este tipo de envoltorio sirve para trabajar directametne con el contexto instance = new Instance3D( stage3D.context3D ); //Configuramos el tipo de NIEBLA /*Con FOG_EXP el Incremento del valor de la niebla de un punto a otro no es constante sino que cada vez es mayor (exponencial). la transición es algo más brusca.*/ //instance.primarySettings.fogMode = RenderSettings.FOG_EXP; //instance.primarySettings.fogDensity = 120; /*FOG_LINEAR: Es un tipo de niebla con una transición bastante suave. El valor de la niebla se va incrementando de forma lineal en función de la distancia a la cámara y de la densidad de la misma. */ //instance.primarySettings.fogMode = RenderSettings.FOG_LINEAR; //Configuramos el color de la niebla var color:Color = new Color(); color.setFromUInt(0x000000); instance.primarySettings.backgroundColor = color; /*Configuramos el comienzo con fogStart: sólo tiene sentido en la niebla lineal. Desde la cámara a la distancia de comienzo la niebla no entra en acción. */ //instance.primarySettings.fogStart = 0; /*Configuramos el final con fogEnd: sólo tiene sentido en la niebla lineal. A partir de esta distancia la niebla alcanzará una densidad 1 (completa, no se verá nada). Esto quiere decir que el gradiente de niebla abarca el intervalo que va desde la distancia de comienzo a la distancia de finalizado.*/ //instance.primarySettings.fogEnd = 0.1; //Efecto HDR para toda la escena //instance.primarySettings.useHDRMapping = true; //instance.primarySettings.kHDRMapping = 2; /* Inicializamos la camara Nota:Para no tener que crear una nueva camara aprovechamos que en la escena ya existe una por defecto y la referenciamos */ _camera = instance.scene.activeCamera; //_camera.fov = 0; //_camera.identity(); //No se para que sirve. No he encontrado referencias para identity por parte de Adobe //Levantamos o mejor dicho alejamos la camara del plano o posicion 0 mediante el eje Z _camera.translate(0,0,445); //_camera.position = new Vector3D( 0, 0, 760 ); //Hace lo mismo que translate, pero position no aparece en ninguna referencia /* Rotamos la camara sobre si misma mediante el eje X para que apunte al plano Nota: Es posible pasar un tercer parametro (vector) que permite cambiar el punto de pivote de la camara por ejemplo new _camera.appendRotation( -90, Vector3D.X_AXIS, new Vector3D(0,0,0)); Por defecto el punto de pivote de la camara es su propio centro. */ _camera.appendRotation( -90, Vector3D.X_AXIS ); //Inicializamos las Luces //LUZ (Luz spot para el coche) _light = new SceneLight(); _light.color.setFromUInt(0xFFFFFF); //_light.color.set( .5, .6, .7 ); //_light.appendTranslation( -20, 130, 20 ); _light.kind = "spot"; _light.intensity = 3; _light.transform.prependRotation( -180, Vector3D.Y_AXIS); _light.transform.prependRotation(-5, Vector3D.X_AXIS ); _light.shadowMapEnabled = true; _light.setShadowMapSize( 632,626 ); _light.transform.appendTranslation(0,0,0); //LUZ 2 (General para la escena) //_light2 = new SceneLight(); //_light2.color.setFromUInt(0x000000); //_light.color.set( .5, .6, .7 ); //_light.appendTranslation( -20, 130, 20 ); //_light2.kind = "distant"; //_light2.intensity = 0; //_light2.transform.prependRotation(-90, Vector3D.X_AXIS ); //_light2.shadowMapEnabled = true; //_light2.setShadowMapSize( 632,626 ); //instance.scene.addChild(_light2); //Configuracion de los modelos //SCENE MESH 1 background var material:MaterialStandard = new MaterialStandard(); material.specularColor.set( 0.8, 0.8, 0.8 ); material.ambientColor.set( 0.2, 0.2, 0.2 ); var textureMap:TextureMap = new TextureMap( new BACKGROUND().bitmapData ); material.diffuseMap = textureMap; _background = MeshUtils.createPlane(632,626,1,1,material,"background"); _background.transform.appendTranslation(0, 0, 0 ); instance.scene.addChild(_background); //SCENE MESH 2 WORLD CONTAINER _world = new SceneMesh(); _world.transform.appendTranslation( 0, 5, 0 ); instance.scene.addChild( _world ); //SCENE MESH 2 CIRCUIT PNG alpha var materialC:MaterialStandard = new MaterialStandard(); //Creamos un BitmapData para añadirlo como textura y para sustraer el canal alpha de los .PNG y añadirlo var bmdC:BitmapData = ( new CIRCUIT() as Bitmap ).bitmapData; materialC.diffuseMap = new TextureMap(bmdC); materialC.opacityMap = new TextureMap(createOpacityMap(bmdC)); _circuit = MeshUtils.createPlane( bmdC.width,bmdC.height, 1, 1, materialC, "Circuit" ); _circuit.transform.appendTranslation( 0, 0, 0 ); _world.addChild(_circuit ); //SCENE MESH 3 CAR var material2:MaterialStandard = new MaterialStandard(); material2.specularColor.set( 0.8, 0.8, 0.8 ); material2.ambientColor.set( 0.2, 0.2, 0.2 ); var bmdCAR:BitmapData = ( new CAR() as Bitmap ).bitmapData; material2.diffuseMap = new TextureMap(bmdCAR); material2.opacityMap = new TextureMap(createOpacityMap(bmdCAR)); _car = MeshUtils.createPlane(bmdCAR.width,bmdCAR.height, 1, 1, material2, "car" ); _car.transform.appendTranslation( 0, 10, 0 ); _car.eulerRotate(0,-180,0); _world.addChild( _car ); _car.addChild( _light ); /* Nota: Tambien podemos crear un terreno abructo con createFractalTerrain _background = MeshUtils.createFractalTerrain(100,100,bmd.width,bmd.height,15,1,1,1,material,"terrain" ); */ var mtrl2:MaterialStandard = new MaterialStandard; mtrl2.diffuseColor.set( 0.8, 0.2, 0.3 ); var sphere:SceneMesh = MeshUtils.createSphere( 20, 32, 32, mtrl2, "sphere" ); sphere.appendTranslation( 100, 10, 0 ); _circuit.addChild( sphere ); _light.addToShadowMap(sphere); Resize(); stage.addEventListener(KeyboardEvent.KEY_DOWN,onKey); stage.addEventListener(KeyboardEvent.KEY_UP,onKey); stage.addEventListener( Event.ENTER_FRAME, RENDER_FRAME ); stage.addEventListener( Event.RESIZE, Resize); } public function Resize(e:Event=null):void{ if ( !instance.scene )return; instance.configureBackBuffer( stage.stageWidth, stage.stageHeight, 2, true ); instance.scene.activeCamera.aspect = stage.stageWidth / stage.stageHeight; instance.render(); } protected function RENDER_FRAME( event:Event ):void{ if (int(ka[0])) { rad =((worldRotation +=sR)-90)*consPi; _world.eulerRotate(0,sR,0); _car.eulerRotate(0,-sR,0); cos = xyVel * Math.cos(rad); sen = xyVel * Math.sin(rad); } else if (int(ka[1])) { rad =((worldRotation -=sR)-90)*consPi; _world.eulerRotate(0,-sR,0); _car.eulerRotate(0,sR,0); cos = xyVel * Math.cos(rad); sen = xyVel * Math.sin(rad); } if (int(ka[2])) { _circuit.move(-cos,0,-sen); } else if (int(ka[3])) { _circuit.move(+cos,0,+sen); } instance.render( 0, false ); instance.present(); } protected function onKey( event:KeyboardEvent ):void{ var k:int = event.keyCode; event.type == "keyUp" ? [pres = 0,key == k ? key = 0:[]]:[key != k ? [pres = 1,key = k]:[]]; if (pres == 0 || pres == 1) { if ( k == 37 || k == 38 || k == 39 || k == 40) { if (k == 39) { ka[0] = pres;//rotate rigth } if (k == 37) { ka[1] = pres;//rotate left } if (k == 38) {//Move Up ka[2] = pres; } if (k == 40) {//Move Down ka[3] = pres; } }//End if check number Keys if (k == 32 || k == 65 || k == 68 etc.. pres = 3; }//End if (pres == 0 || pres == 1) { }//End onKey private function createOpacityMap( bmd:BitmapData ):BitmapData { var sourceRect:Rectangle = new Rectangle(0,0,bmd.width,bmd.height); var destPoint:Point = new Point(0,0); var alphaBMD:BitmapData = new BitmapData(bmd.width,bmd.height,false,0xff000000); alphaBMD.copyChannel( bmd, sourceRect, destPoint, BitmapDataChannel.ALPHA, BitmapDataChannel.RED ); alphaBMD.copyChannel( bmd, sourceRect, destPoint, BitmapDataChannel.ALPHA, BitmapDataChannel.GREEN ); alphaBMD.copyChannel( bmd, sourceRect, destPoint, BitmapDataChannel.ALPHA, BitmapDataChannel.BLUE ); return alphaBMD; } private function onPersp1(e:Event):void{ if(persp !=1){ persp = 1; _camera.translate(0,-30,445); _camera.appendRotation( -90, Vector3D.X_AXIS ); } } private function onPersp2(e:Event):void{ if(persp !=2){ persp = 2; _camera.appendRotation( 90, Vector3D.X_AXIS ); _camera.translate(0,30,-445); } } } } |
Para probar el ejemplo de la descarga ejecutad el html y recordad que el parametro wmode debe se igual a «direct»
[download id=»38″ format=»2″]