/// /* Vertex animation example in Away3d using the MD2 format Demonstrates: How to use the AssetLibrary class to load an embedded internal md2 model. How to clone an asset from the AssetLibrary and apply different mateirals. How to load animations into an animation set and apply to individual meshes. Code by Rob Bateman rob@infiniteturtles.co.uk http://www.infiniteturtles.co.uk Perelith Knight, by James Green (no email given) This code is distributed under the MIT License Copyright (c) The Away Foundation http://www.theawayfoundation.org Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ module examples { export class Intermediate_PerelithKnight { private _meshInitialised : boolean = false; private _animationSetInitialised : boolean = false; private _sceneInitialised : boolean = false; //array of materials for random sampling private _pKnightTextures:Array = new Array("assets/pknight1.png", "assets/pknight2.png", "assets/pknight3.png", "assets/pknight4.png"); private _pKnightMaterials:Array = new Array(); //engine variables private _view:away.containers.View3D; private _cameraController:away.controllers.HoverController; //stats //private _stats:AwayStats; //light objects private _light:away.lights.DirectionalLight; private _lightPicker:away.materials.StaticLightPicker; //material objects private _floorMaterial:away.materials.TextureMaterial; private _shadowMapMethod:away.materials.FilteredShadowMapMethod; //scene objects private _floor:away.entities.Mesh; private _mesh:away.entities.Mesh; //navigation variables private _timer:away.utils.RequestAnimationFrame; private _time:number = 0; private _move:boolean = false; private _lastPanAngle:number; private _lastTiltAngle:number; private _lastMouseX:number; private _lastMouseY:number; private _keyUp:boolean; private _keyDown:boolean; private _keyLeft:boolean; private _keyRight:boolean; private _lookAtPosition:away.geom.Vector3D = new away.geom.Vector3D(); private _animationSet:away.animators.VertexAnimationSet; /** * Constructor */ constructor() { //setup the view this._view = new away.containers.View3D(); //setup the camera for optimal rendering this._view.camera.lens.far = 5000; //setup controller to be used on the camera this._cameraController = new away.controllers.HoverController(this._view.camera, null, 45, 20, 2000, 5); //setup the help text /* var text:TextField = new TextField(); text.defaultTextFormat = new TextFormat("Verdana", 11, 0xFFFFFF); text.embedFonts = true; text.antiAliasType = AntiAliasType.ADVANCED; text.gridFitType = GridFitType.PIXEL; text.width = 240; text.height = 100; text.selectable = false; text.mouseEnabled = false; text.text = "Click and drag - rotate\n" + "Cursor keys / WSAD / ZSQD - move\n" + "Scroll wheel - zoom"; text.filters = [new DropShadowFilter(1, 45, 0x0, 1, 0, 0)]; addChild(text); */ //setup the lights for the scene this._light = new away.lights.DirectionalLight(-0.5, -1, -1); this._light.ambient = 0.4; this._lightPicker = new away.materials.StaticLightPicker([this._light]); this._view.scene.addChild(this._light); //setup listeners on AssetLibrary away.library.AssetLibrary.addEventListener(away.events.AssetEvent.ASSET_COMPLETE, this.onAssetComplete, this); away.library.AssetLibrary.addEventListener(away.events.LoaderEvent.RESOURCE_COMPLETE, this.onResourceComplete, this); //load perilith knight textures away.library.AssetLibrary.load(new away.net.URLRequest("assets/pknight1.png")); away.library.AssetLibrary.load(new away.net.URLRequest("assets/pknight2.png")); away.library.AssetLibrary.load(new away.net.URLRequest("assets/pknight3.png")); away.library.AssetLibrary.load(new away.net.URLRequest("assets/pknight4.png")); //load floor texture away.library.AssetLibrary.load(new away.net.URLRequest("assets/floor_diffuse.jpg")); //load perelith knight data away.library.AssetLibrary.load(new away.net.URLRequest("assets/pknight.md2"), null, null, new away.loaders.MD2Parser()); //create a global shadow map method this._shadowMapMethod = new away.materials.FilteredShadowMapMethod(this._light); this._shadowMapMethod.epsilon = 0.2; //setup floor material this._floorMaterial = new away.materials.TextureMaterial(); this._floorMaterial.lightPicker = this._lightPicker; this._floorMaterial.specular = 0; this._floorMaterial.ambient = 1; this._floorMaterial.shadowMethod = this._shadowMapMethod; this._floorMaterial.repeat = true; //setup knight materials for (var i:number /*uint*/ = 0; i < this._pKnightTextures.length; i++) { var knightMaterial:away.materials.TextureMaterial = new away.materials.TextureMaterial(); //knightMaterial.normalMap = Cast.bitmapTexture(BitmapFilterEffects.normalMap(bitmapData)); //knightMaterial.specularMap = Cast.bitmapTexture(BitmapFilterEffects.outline(bitmapData)); knightMaterial.lightPicker = this._lightPicker; knightMaterial.gloss = 30; knightMaterial.specular = 1; knightMaterial.ambient = 1; knightMaterial.shadowMethod = this._shadowMapMethod; this._pKnightMaterials.push(knightMaterial); } //setup the floor this._floor = new away.entities.Mesh(new away.primitives.PlaneGeometry(5000, 5000), this._floorMaterial); this._floor.geometry.scaleUV(5, 5); //setup the scene this._view.scene.addChild(this._floor); //add stats panel //addChild(_stats = new AwayStats(_view)); //add listeners window.onresize = (event) => this.onResize(event); document.onmousedown = (event) => this.onMouseDown(event); document.onmouseup = (event) => this.onMouseUp(event); document.onmousemove = (event) => this.onMouseMove(event); document.onmousewheel = (event) => this.onMouseWheel(event); document.onkeydown = (event) => this.onKeyDown(event); document.onkeyup = (event) => this.onKeyUp(event); this.onResize(); this._timer = new away.utils.RequestAnimationFrame(this.onEnterFrame, this); this._timer.start(); } /** * Navigation and render loop */ private onEnterFrame(dt:number):void { this._time += dt; if (this._keyUp) this._lookAtPosition.x -= 10; if (this._keyDown) this._lookAtPosition.x += 10; if (this._keyLeft) this._lookAtPosition.z -= 10; if (this._keyRight) this._lookAtPosition.z += 10; this._cameraController.lookAtPosition = this._lookAtPosition; this._view.render(); } /** * Listener for asset complete event on loader */ private onAssetComplete(event:away.events.AssetEvent):void { var asset:away.library.IAsset = event.asset; switch (asset.assetType) { case away.library.AssetType.MESH : this._mesh = event.asset; //adjust the mesh this._mesh.y = 120; this._mesh.scale(5); this._meshInitialised = true; break; case away.library.AssetType.ANIMATION_SET : this._animationSet = event.asset this._animationSetInitialised = true; break; } if ( this._animationSetInitialised && this._meshInitialised && ! this._sceneInitialised) { this._sceneInitialised = true; //create 20 x 20 different clones of the knight var numWide:number = 20; var numDeep:number = 20; var k:number /*uint*/ = 0; for (var i:number /*uint*/ = 0; i < numWide; i++) { for (var j:number /*uint*/ = 0; j < numDeep; j++) { //clone mesh var clone:away.entities.Mesh = this._mesh.clone(); clone.x = (i-(numWide-1)/2)*5000/numWide; clone.z = (j-(numDeep-1)/2)*5000/numDeep; clone.castsShadows = true; clone.material = this._pKnightMaterials[Math.floor(Math.random()*this._pKnightMaterials.length)]; this._view.scene.addChild(clone); //create animator var vertexAnimator:away.animators.VertexAnimator = new away.animators.VertexAnimator(this._animationSet); //play specified state vertexAnimator.play(this._animationSet.animationNames[Math.floor(Math.random()*this._animationSet.animationNames.length)], null, Math.random()*1000); clone.animator = vertexAnimator; k++; } } } } /** * Listener function for resource complete event on asset library */ private onResourceComplete (event:away.events.LoaderEvent) { var assets:away.library.IAsset[] = event.assets; var length:number = assets.length; for ( var c : number = 0 ; c < length ; c ++ ) { var asset:away.library.IAsset = assets[c]; console.log(asset.name, event.url); switch (event.url) { //floor texture case "assets/floor_diffuse.jpg" : this._floorMaterial.texture = asset; break; //knight textures case "assets/pknight1.png" : case "assets/pknight2.png" : case "assets/pknight3.png" : case "assets/pknight4.png" : this._pKnightMaterials[this._pKnightTextures.indexOf(event.url)].texture = asset; break; //knight data case "assets/pknight.md2" : break; } } } /** * Key down listener for animation */ private onKeyDown(event):void { switch (event.keyCode) { case 38://Keyboard.UP: case 87://Keyboard.W: case 90://Keyboard.Z: //fr this._keyUp = true; break; case 40://Keyboard.DOWN: case 83://Keyboard.S: this._keyDown = true; break; case 37://Keyboard.LEFT: case 65://Keyboard.A: case 81://Keyboard.Q: //fr this._keyLeft = true; break; case 39://Keyboard.RIGHT: case 68://Keyboard.D: this._keyRight = true; break; } } /** * Key up listener */ private onKeyUp(event):void { switch (event.keyCode) { case 38://Keyboard.UP: case 87://Keyboard.W: case 90://Keyboard.Z: //fr this._keyUp = false; break; case 40://Keyboard.DOWN: case 83://Keyboard.S: this._keyDown = false; break; case 37://Keyboard.LEFT: case 65://Keyboard.A: case 81://Keyboard.Q: //fr this._keyLeft = false; break; case 39://Keyboard.RIGHT: case 68://Keyboard.D: this._keyRight = false; break; } } /** * Mouse down listener for navigation */ private onMouseDown(event):void { this._lastPanAngle = this._cameraController.panAngle; this._lastTiltAngle = this._cameraController.tiltAngle; this._lastMouseX = event.clientX; this._lastMouseY = event.clientY; this._move = true; } /** * Mouse up listener for navigation */ private onMouseUp(event):void { this._move = false; } private onMouseMove(event) { if (this._move) { this._cameraController.panAngle = 0.3*(event.clientX - this._lastMouseX) + this._lastPanAngle; this._cameraController.tiltAngle = 0.3*(event.clientY - this._lastMouseY) + this._lastTiltAngle; } } /** * Mouse wheel listener for navigation */ private onMouseWheel(event):void { this._cameraController.distance -= event.wheelDelta * 5; if (this._cameraController.distance < 100) this._cameraController.distance = 100; else if (this._cameraController.distance > 2000) this._cameraController.distance = 2000; } /** * Stage listener for resize events */ private onResize(event = null):void { this._view.y = 0; this._view.x = 0; this._view.width = window.innerWidth; this._view.height = window.innerHeight; } } } window.onload = function () { new examples.Intermediate_PerelithKnight(); }