Alternativa 8 for Dummies Part II
From AlternativaPlatform Wiki
Contents |
[edit] Lesson 2: Working with models parsers and textures
[edit] Load custom models.
At first, I will say that the engine Alternativa3D 8 supports three types of models.
A3D - created by developers Alternativa3D 8 format. Can contain only 3d objects.
DAE - (Collada) format based on language xml. May include 3d models, animations, materials.
3DS - is one of the file formats used by the Autodesk 3ds Max 3D modeling, animation and rendering software.
So. What do we need so we can see the models in the window Flash Player?
Autodesk 3ds Max 2010 - I think here is clear.
Plugin 3ds Max 2010, for export models in the format A3D.
Download the plugin, we throw in the plugins folder installed 3ds Max ==>
Start 3ds Max. Create your model or download some free downloaded from the repositories.
[edit] Load A3D
Export to the format a3d. ==>
So. Now, how to load a model into the engine Alternativa3D 8. We have two options after Embed or URLLoader.
1) Embed
To insert a model EMBED after the class declaration, we write the following line
public class Main extends Sprite { [Embed ("model.a3d", mimeType = "application/octet-stream") ] private static const Model:Class; //<------ }
We specify the name of our model, the type of downloadable content, and the name of the class on which we will refer to this model. The model is added to the file swf which greatly increases its volume.
2) URLLoader
Using URLLoader we load the model into a byte array.
var loaderA3D:URLLoader = new URLLoader(); //create a URLLoader loaderA3D.dataFormat = URLLoaderDataFormat.BINARY; //indicate that the content was loaded as a byte array, not as a text loaderA3D.load(new URLRequest("model.A3D")); //load model
We will go the second way, using URLLoader.
Download, unzip and open the project from the archive. TestParseA3D.zip
Let's look at the code ==>
package { import alternativa.engine3d.controllers.SimpleObjectController; //we need classes Alternativa3D 8 import alternativa.engine3d.core.Camera3D; import alternativa.engine3d.core.Object3D; import alternativa.engine3d.core.Resource; import alternativa.engine3d.core.View; import alternativa.engine3d.loaders.ParserA3D; import alternativa.engine3d.materials.FillMaterial; import alternativa.engine3d.objects.Mesh; import alternativa.engine3d.resources.Geometry; import flash.display.Sprite; //Flash classes import flash.display.Stage3D; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.events.Event; import flash.net.URLLoader; import flash.net.URLRequest; import flash.net.URLLoaderDataFormat; public class Main extends Sprite { private var rootContainer:Object3D = new Object3D(); //everything is clear, if it is not clear read last lesson private var camera:Camera3D; private var stage3D:Stage3D; private var car:Mesh; //container for our car /* Mesh class inherits from Object3D and may contain a 3d model with arbitrary geometry * Can also act as a container. */ private var simpleController:SimpleObjectController; public function Main(){ stage.align = StageAlign.TOP_LEFT; //align the content in the upper left corner stage.scaleMode = StageScaleMode.NO_SCALE; //do not allow scaling content camera = new Camera3D(0.1, 10000); //create a camera and position it camera.view = new View(550, 400); //create a viewport camera.rotationX = -120 * Math.PI / 180; camera.y = -100; camera.z = 50; addChild(camera.view); addChild(camera.diagram); // add diagram /* The diagram, which displays debug information. To display a diagram, it must be added to the screen. * FPS — The average number of frames per second for the gap in fpsUpdatePeriod frames. * MS — Average execution time measured using startTimer - stopTimer piece of code in milliseconds for the interval in timerUpdatePeriod frames. * MEM — Number of occupied memory in the player Mb * DRW — Amount drawing graphics in the current frame. * PLG — Amount visible polygons in the current frame. * TRI — Amount triangles are drawn in the current frame. * The camera also has methods to position diagram * * diagramAlign --> Using the class constants StageAlign indicate where a diagram would be located * Example: camera.diagramAlign = StageAlign.BOTTOM_LEFT; * * diagramHorizontalMargin --> padding from the edge of the workspace in the horizontal * Example: camera.diagramHorizontalMargin = 50; * * diagramVerticalMargin --> padding from the edge of the workspace in the vertical * Example: camera. diagramVerticalMargin = 50; */ rootContainer.addChild(camera); stage3D = stage.stage3Ds[0]; //get stage3D stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContextCreate); stage3D.requestContext3D(); //request context } private function onContextCreate(e:Event):void { stage3D.removeEventListener(Event.CONTEXT3D_CREATE, onContextCreate); var loaderA3D:URLLoader = new URLLoader(); //create a URLLoader loaderA3D.dataFormat = URLLoaderDataFormat.BINARY; //indicate that the content was loaded as a byte array, not as a text loaderA3D.load(new URLRequest("model.A3D")); loaderA3D.addEventListener(Event.COMPLETE, onA3DLoad); //end load } private function onA3DLoad(e:Event):void { var parser:ParserA3D = new ParserA3D(); //create a parser /* * ParserA3D - This class parses the format of the loaded model a3d * and scores array [objects] three-dimensional objects */ parser.parse((e.target as URLLoader).data); //parse model car = new Mesh(); //Create Mesh. rootContainer.addChild(car); //add to the main container for each (var object:Object3D in parser.objects){ //iterate through an array of [objects] if (object is Mesh){ var mesh:Mesh = Mesh(object); //transform in Mesh if (object.name == "glaslght" || object.name == "glass"){ //If the current 3D object glass or glaslght (so called lights and glass in my model) mesh.setMaterialToAllSurfaces(new FillMaterial(Math.random() * 0xFFFFFF, 0.5)); //"Paint" and make clear (as detailed in Section 1.3) } else { mesh.setMaterialToAllSurfaces(new FillMaterial(Math.random() * 0xFFFFFF)); //just "paint" } car.addChild(mesh); //add to a container for a car } } for each (var resource:Resource in rootContainer.getResources(true)){ resource.upload(stage3D.context3D); } // all resources are loaded in context3D //I do not remember I said or not but that we have anything we came all the resources necessary to download context3D and we must always remember this simpleController = new SimpleObjectController(stage, car, 1000); // assign a controller for a container car (detail in another lesson) stage.addEventListener(Event.ENTER_FRAME, onEnterFrame); } private function onEnterFrame(e:Event):void { simpleController.update(); //update the controller camera.render(stage3D); //render the scene } } }
Run and look ==>
[edit] Load DAE (Collada)
I have long suffered with parsing DaE. Standard 3D Max exporter saves with errors, plugin OpenCollada over time.
Until I found another plugin ColladaMax_FREE_3.05C. This is really a thing with it exported fine. But it does not support 3D Max over 2009
Download from here ==> Plugin ColladaMax 3.05
You can use any you want ...
Install and verify that the folder with the plugins 3D Max, he appeared
DAE export in a format. ==>
Let's see the code ==>
package { import alternativa.engine3d.controllers.SimpleObjectController; import alternativa.engine3d.core.Camera3D; import alternativa.engine3d.core.Object3D; import alternativa.engine3d.core.Resource; import alternativa.engine3d.core.View; import alternativa.engine3d.loaders.ParserCollada; //Collada parser import alternativa.engine3d.loaders.TexturesLoader; import alternativa.engine3d.loaders.ParserMaterial; //Collada material import alternativa.engine3d.materials.TextureMaterial; import alternativa.engine3d.objects.Mesh; import alternativa.engine3d.objects.Surface; import alternativa.engine3d.resources.Geometry; import alternativa.engine3d.resources.ExternalTextureResource; import alternativa.engine3d.resources.TextureResource; import flash.display.Sprite; import flash.display.Stage3D; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.events.Event; import flash.net.URLLoader; import flash.net.URLRequest; import flash.net.URLLoaderDataFormat; public class Main extends Sprite { private var rootContainer:Object3D = new Object3D(); private var camera:Camera3D; private var stage3D:Stage3D; private var mesh:Mesh; //container for the AK-47 private var simpleController:SimpleObjectController; public function Main(){ stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; camera = new Camera3D(0.1, 10000); //create a camera and position it camera.view = new View(stage.stageWidth, stage.stageHeight); //create a viewport camera.rotationX = -120 * Math.PI / 180; camera.y = -600; camera.z = 400; addChild(camera.view); addChild(camera.diagram); rootContainer.addChild(camera); stage3D = stage.stage3Ds[0]; stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContextCreate); stage3D.requestContext3D(); } private function onContextCreate(e:Event):void { stage3D.removeEventListener(Event.CONTEXT3D_CREATE, onContextCreate); var loaderCollada:URLLoader = new URLLoader(); //create a URLLoader loaderCollada.dataFormat = URLLoaderDataFormat.TEXT; //will load in text format loaderCollada.load(new URLRequest("model.DAE")); //load loaderCollada.addEventListener(Event.COMPLETE, onColladaLoad); } private function onColladaLoad(e:Event):void { var parser:ParserCollada = new ParserCollada(); // Create a parser Collada parser.parse(XML((e.target as URLLoader).data)); //parse xml from URLLoader mesh = parser.objects[1] as Mesh; //take out the mesh of [objects] // array [objects] contains a stack of 3D models downloaded from the Collada, if the model is much easier of course to add the model to the stage in the cycle, but // because I have a model, I decided to pull it directly mesh.x = 100; rootContainer.addChild(mesh); //add to a container /* Collada parser in also has an array of [materials] which includes links to all the textures used by models * Each texture has some surface mesh. To obtain this surface he has a method getSurface () which returns a Surface * Surface is a property of a material that contains TextureMaterial. To find out how much of a mesh surface is the property of numSurfaces */ var textures:Vector.<ExternalTextureResource> = new Vector.<ExternalTextureResource>(); //create a vector ExternalTextureResource for (var i:int = 0; i < mesh.numSurfaces; i++){ //cycle through all surface var surface:Surface = mesh.getSurface(i); //get the current surface var material:ParserMaterial = surface.material as ParserMaterial; //a material property, we obtain ParserMaterial (for materials in Section 1.3) if (material != null){ //if the material is there, not null var diffuse:TextureResource = material.textures["diffuse"]; //Create TextureResource-is the base class for all texture resources if (diffuse != null){ //if there is texture textures.push(diffuse); //add a vector with ExternalTextureResource surface.material = new TextureMaterial(diffuse); //and assign the surface } } } var texturesLoader:TexturesLoader = new TexturesLoader(stage3D.context3D); // Create TexturesLoader texturesLoader.loadResources(textures); //load the textures in the context simpleController = new SimpleObjectController(stage, mesh, 1000); // assign a controller for a mesh for each (var resource:Resource in rootContainer.getResources(true)){ // all resources are loaded in context3D resource.upload(stage3D.context3D); } stage.addEventListener(Event.ENTER_FRAME, onEnterFrame); } private function onEnterFrame(e:Event):void { simpleController.update(); camera.render(stage3D); } } }
Take a look:
Sources: testDaeParse.zip
[edit] Load 3DS
Alternativa3D 8 can load 3ds-files. More details about importing 3DS files and the Parser3DS class you can read in Parser3DS tutorial.
[edit] Load textures
Texture can be a picture with the sides multiples of 2 (size 32 px, 64px, 128, 256, 512, etc.). While so, then can be supported by all.
For wrapping texture object we want bitmapData.
Then we need to get this bitmapData context3D our stage3D. To do this in a class Alternativa3D 8 BitmapTextureResource. Which as argument is bitmapData, and the method of "upload", we add it to context3D. Right now all understand
What are the ways we can add texture to the engine Alternativa3D 8:
1)Embed:
[Embed(source="Citybrick 01.jpg") ]static private const MainTexture:Class; var texture:BitmapTextureResource = new BitmapTextureResource(new MainTexture().bitmapData); //BitmapTextureResource create and pass it bitmapData our texture texture.upload(stage3D.context3D); //add to context3D box.setMaterialToAllSurfaces(new TextureMaterial(texture)); //Apply a texture. Detail in Section 1.3
++: Just one line
--: The size of the swf
2)Loader:
var loader:Loader = new Loader(); //create Loader loader.contentLoaderInfo.addEventListener(Event.COMPLETE, finish); //listen to the end of the boot loader.load(new URLRequest("Citybrick01.jpg")); //load private function finish(e:Event):void { var texture:BitmapTextureResource = new BitmapTextureResource(BitmapData(e.target.content.bitmapData)); texture.upload(stage3D.context3D); box.setMaterialToAllSurfaces(new TextureMaterial(texture)); }
++: Textures are outside the swf, and can be easily edited
As we can see everything is done almost as well as via Embed
3)TexturesLoader:
Look at the code
var textureResources:Vector.<ExternalTextureResource> = new Vector.<ExternalTextureResource>(); //vector of ExternalTextureResource var metalTexture:ExternalTextureResource = new ExternalTextureResource("metal01.jpg"); //create ExternalTextureResource var electroTexture:ExternalTextureResource = new ExternalTextureResource("electro14.jpg"); // var sackTexture:ExternalTextureResource = new ExternalTextureResource("sack1.jpg"); // textureResources.push(metalTexture); //add all ExternalTextureResource in vector textureResources.push(electroTexture); textureResources.push(sackTexture); var textureLoader:TexturesLoader = new TexturesLoader(stage3D.context3D); //create TexturesLoader textureLoader.loadResources(textureResources, true, false); //and load the texture
As we can see in designer TextureLoader we pass a reference to our scene context3D
And by loadResources () load the textures. The first parameter we pass the vector of ExternalTextureResource.
ExternalTextureResource performs the same function as the BitmapTextureResource (read above). In the constructor we pass ExternalTextureResource link to our texture.
Also there is a method TextureLoader loadResource (resource: ExternalTextureResource, createTexture3D: Boolean, needBitmapData: Boolean = true): void
The difference is that in him we do not pass the vector of a single object ExternalTextureResource ExternalTextureResource
It should also tell you about TexturesLoaderEvent. Let's see the code ==>
var textureLoader:TexturesLoader = new TexturesLoader(stage3D.context3D); //create TexturesLoader textureLoader.loadResources(textureResources, true, true); //load. Here the third parameter must be necessarily true //True - means that we can get access to the loaded texture bitmapData textureLoader.addEventListener(Event.COMPLETE, onTextures); //Listen to the end of loading all the textures private function onTextures(event:Event):void { var e:TexturesLoaderEvent = TexturesLoaderEvent(event); //Event to give a TexturesLoaderEvent var bitmapDataVector:Vector.<BitmapData> = Vector.<BitmapData>(e.getBitmapDatas()); //by getBitmapDatas () class TexturesLoaderEvent obtain and record the vector bitmapData var bitmapResource:BitmapTextureResource = new BitmapTextureResource(bitmapDataVector[0]); //I need say first texture, and its load bitmapResource.upload(stage3D.context3D); //in the context of our stage box.setMaterialToAllSurfaces(new TextureMaterial(bitmapResource, 1));// and "paint the" box }
Use TextureLoaderEvent is only if you need to refer to loaded BitmapData texture. To make them any operation ...
Sources: testTexture.zip
[edit] Working with materials
Well, here we come to the fun. "Paintings" in our models
Total Alternativa3D 8 supports 6 types of materials (in the future this may change)
1) FillMaterial
We have already met him. This material fills the model in one color:
var box:Box = new Box(300, 300, 300); box.setMaterialToAllSurfaces(new FillMaterial(0x3F95F5,0.4)); //specify the color and alpha in the creation of the material rootContainer.addChild(box);
Take a look:
2) TextureMaterial
This material allows the model to fill the texture but it does not support lighting
package { import alternativa.engine3d.controllers.SimpleObjectController; import alternativa.engine3d.core.Camera3D; import alternativa.engine3d.core.Object3D; import alternativa.engine3d.core.Resource; import alternativa.engine3d.core.View; import alternativa.engine3d.materials.TextureMaterial; import alternativa.engine3d.primitives.Box; import alternativa.engine3d.resources.BitmapTextureResource; import flash.display.BitmapData; import flash.display.Sprite; import flash.display.Stage3D; import flash.events.Event; public class MaterialTwo extends Sprite { [Embed(source="Citybrick01.jpg")] static private const MainTexture:Class; //load the texture private var rootContainer:Object3D = new Object3D(); private var camera:Camera3D; private var stage3D:Stage3D; private var box:Box; private var simpleController:SimpleObjectController; public function MaterialTwo(){ camera = new Camera3D(0.1, 10000); camera.view = new View(stage.stageWidth, stage.stageHeight); camera.rotationX = -120 * Math.PI / 180; camera.z = 400 camera.y = -800; addChild(camera.view); addChild(camera.diagram); rootContainer.addChild(camera); box = new Box(300, 300, 300); //create a cube var texture:BitmapTextureResource = new BitmapTextureResource(new MainTexture().bitmapData); //create BitmapTextureResource box.setMaterialToAllSurfaces(new TextureMaterial(texture)); //"paint" texture rootContainer.addChild(box); simpleController = new SimpleObjectController(stage, box, 400); stage3D = stage.stage3Ds[0]; stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContextCreate); stage3D.requestContext3D(); } private function onContextCreate(e:Event):void { for each (var resource:Resource in rootContainer.getResources(true)){ resource.upload(stage3D.context3D); } stage.addEventListener(Event.ENTER_FRAME, onEnterFrame); } private function onEnterFrame(e:Event):void { box.rotationZ += 0.01; simpleController.update(); camera.render(stage3D); } } }
We can also use the map of transparency. Opacity map-it's black and white picture. Pure white color corresponds to the alpha 1.0, black - 0. Shades of gray, respectively, and fill a range of alpha values between 0 and 1.0. Here is an example of opacity map (left - transparency map to the right - diffuse texture):
To add it to TextureMaterial with diffuse texture we just give her a second parameter to the constructor.
Look at the constructor in full:
TextureMaterial(diffuseMap:TextureResource = null, opacityMap:TextureResource = null, alpha:Number = 1) diffuseMap:TextureResource (default = null) — texture opacityMap:TextureResource (default = null) — texture transparency alpha:Number (default = 1) - transparency
Choose to use alpha transparency, texture or set the flag useDiffuseAlphaChannel: Boolean = false. If set to false, the value from a transparency map.
Take a look:
3) LightMapMaterial.
This material allows light map.
Look at the 2 pictures
Apply material:
var texture:BitmapTextureResource = new BitmapTextureResource(new DiffTexture().bitmapData); //creating diffuse textures for BitmapTextureResource var texture2:BitmapTextureResource = new BitmapTextureResource(new LightTexture().bitmapData); //create a lightmap for texture BitmapTextureResource box.setMaterialToAllSurfaces(new LightMapMaterial(texture, texture2)); //apply to Box
Take a look:
Typically used for static objects to reduce the load on the processor It also allows you to use the opacity map.
4) StandartMaterial.
The material, which may be involved maps: normal, transparency, reflections, and the importance of gloss.
package { import alternativa.engine3d.controllers.SimpleObjectController; import alternativa.engine3d.core.Camera3D; import alternativa.engine3d.core.Object3D; import alternativa.engine3d.core.Resource; import alternativa.engine3d.core.View; import alternativa.engine3d.lights.AmbientLight; import alternativa.engine3d.loaders.ParserA3D; import alternativa.engine3d.loaders.TexturesLoader; import alternativa.engine3d.materials.StandardMaterial; import alternativa.engine3d.objects.Mesh; import alternativa.engine3d.resources.BitmapTextureResource; import alternativa.engine3d.resources.ExternalTextureResource; import flash.display.Sprite; import flash.display.Stage3D; import flash.events.Event; import flash.display.BitmapData; public class MaterialFour extends Sprite { [Embed("model.a3d",mimeType="application/octet-stream")] private static const Model:Class; private var rootContainer:Object3D = new Object3D(); private var camera:Camera3D; private var stage3D:Stage3D; private var light:AmbientLight; private var simpleController:SimpleObjectController; private var mesh:Mesh; public function MaterialFour(){ camera = new Camera3D(0.1, 100000); camera.view = new View(stage.stageWidth, stage.stageHeight, false, 0x000000); camera.rotationX = -120 * Math.PI / 180; camera.z = 80; camera.y = -70; addChild(camera.view); addChild(camera.diagram); rootContainer.addChild(camera); light = new AmbientLight(0xFFFFFF); //light. Detail in the next lesson light.z = 100; rootContainer.addChild(light); var parser:ParserA3D = new ParserA3D(); parser.parse(new Model()); mesh = parser.objects[0] as Mesh; rootContainer.addChild(mesh); simpleController = new SimpleObjectController(stage, mesh, 400); stage3D = stage.stage3Ds[0]; stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContextCreate); stage3D.requestContext3D(); } private function onContextCreate(e:Event):void { var fileTexture:Vector.<ExternalTextureResource> = new Vector.<ExternalTextureResource>(); //create vector var diffuse:ExternalTextureResource = new ExternalTextureResource("Commando.jpg"); //diffuse texture var normal:ExternalTextureResource = new ExternalTextureResource("Commando_n.jpg"); //NormalMap var specular:ExternalTextureResource = new ExternalTextureResource("Commando_spec.jpg"); //SpecularMap var opacity:ExternalTextureResource = new ExternalTextureResource("Commando_o.jpg"); //OpacityMap fileTexture.push(diffuse); //add to the vector fileTexture.push(normal); fileTexture.push(specular); fileTexture.push(opacity); var textureLoader:TexturesLoader = new TexturesLoader(stage3D.context3D); //load textureLoader.loadResources(fileTexture, true, false); mesh.setMaterialToAllSurfaces(new StandardMaterial(diffuse, normal, specular)); //apply new StandartMaterial(DiffuseTexture, NormalMap, SpecularMap, GlosnessMap, OpacityMap); for each (var resource:Resource in rootContainer.getResources(true)){ resource.upload(stage3D.context3D); } stage.addEventListener(Event.ENTER_FRAME, onEnterFrame); } private function onEnterFrame(e:Event):void { mesh.rotationZ += 0.01; simpleController.update(); camera.render(stage3D); } } }
Take a look:
5) VertexLightTextureMaterial.
Material uses dynamic lighting. If the scene is no light source you do not see the object (of light sources in the next lesson)
var texture:BitmapTextureResource = new BitmapTextureResource(new DiffTexture().bitmapData); box.setMaterialToAllSurfaces(new VertexLightTextureMaterial(texture));
Take a look:
6) ParserMaterial.
To quote the official documentation: "The material, which by default assigned to any object derived from parsing Collada or A3d. This material can be considered as debugging, as in drawing, he can only use one card / channel (only diffuse, or only specular, etc.). To display the texture, you must download them, which is convenient to use the class TexturesLoader In order for an object drawn in a complex form, you must create an instance of the material, and give him the right texture.." There nothing to add.
We have such properties ParserMaterial ==>
textures ==> List ExternalTextureResource, which can be downloaded by TexturesLoader. The keys of the object are the names of channels. Possible options: ambient, emission, diffuse, specular, shininess, reflective, transparent, bump
renderChannel==> Channel, which will be rendered. Possible options: ambient, emission, diffuse, specular, shininess, reflective, transparent, bump.
Let us change the example from above parsing Collada
var textures:Vector.<ExternalTextureResource> = new Vector.<ExternalTextureResource>(); for (var i:int = 0; i < mesh.numSurfaces; i++){ var surface:Surface = mesh.getSurface(i); var material:ParserMaterial = surface.material as ParserMaterial; material.renderChannel = "transparent"; //will render the channel "transparent" if (material != null){ var transparent:TextureResource = material.textures["transparent"]; //create a material if (transparent != null){ textures.push(transparent); surface.material = new TextureMaterial(transparent); } } }
Take a look:
We see how the materials have changed our model ....
Sources: TestMaterial.zip
Author #redefy













