package org.codemonkey.papervision3d.object { import flash.display.Sprite; import org.codemonkey.papervision3d.util.PV3DUtil; import org.codemonkey.papervision3d.util.RealtimeDisplayObject3D; import org.papervision3d.cameras.Camera3D; import org.papervision3d.core.proto.MaterialObject3D; import org.papervision3d.lights.PointLight3D; import org.papervision3d.materials.MovieMaterial; import org.papervision3d.objects.primitives.Plane; import org.papervision3d.objects.primitives.Sphere; import org.papervision3d.view.layer.util.ViewportLayerSortMode; import org.papervision3d.view.layer.ViewportLayer; import org.papervision3d.view.Viewport3D; /** * Defines two spheres for geological- and clouds texture. Also defines a fresnel glow as Plane. * Furthermore defines two Plane masks to mask perfect spheres and to make sure the glow Plane * Is as big as the planet sphere. * * Keeps a reference to an optional pointlight reference (sun), which can be used in the planet textures. * * @author Benny Bottema */ public class Planet extends RealtimeDisplayObject3D { public static const QUALITY_MINIMUM:Number = 4; public static const QUALITY_LOW:Number = 12; public static const QUALITY_MEDIUM:Number = 16; public static const QUALITY_HIGH:Number = 24; protected var sunLight:PointLight3D; private var planetRotationSpeed:Number; private var cloudsRotationSpeed:Number; private var _planet:Sphere; private var clouds:Sphere; private var planetMask:Plane; private var cloudMask:Plane; private var glow:Plane; /** * Creates planet/clouds spheres, glow plane, and mask planes for planet/clouds spheres. */ public function Planet(viewport:Viewport3D, diameter:Number, sunLight:PointLight3D = null, quality:Number = QUALITY_MEDIUM, planetRotationSpeed:Number = .3, cloudsRotationSpeed:Number = .15, updateFrequency:Number = 125, phasePerSecond:Number = 1) { super(updateFrequency, phasePerSecond); this.sunLight = sunLight; this.planetRotationSpeed = planetRotationSpeed; this.cloudsRotationSpeed = cloudsRotationSpeed; // for some reason I can't get the planes for circle masks and fresnell // glow to get the exact same diameter as the spheres const GLOWSIZE:Number = diameter * 1.06; const GRADIENT_QUALITY:Number = 500; addChild(_planet = new Sphere(createPlanetMaterial(), diameter / 2, quality, quality)); addChild(clouds = new Sphere(createCloudMaterial(), diameter / 2, QUALITY_LOW, QUALITY_LOW)); addChild(planetMask = new Plane(createPlanetMaskMaterial(GRADIENT_QUALITY), GLOWSIZE, GLOWSIZE)); addChild(cloudMask = new Plane(createPlanetMaskMaterial(GRADIENT_QUALITY), GLOWSIZE, GLOWSIZE)); addChild(glow = new Plane(createGlowMaterial(GRADIENT_QUALITY, [0, .1, .3, 0], [0xBB, 0xE9, 0xFA, 0xFF]), GLOWSIZE, GLOWSIZE)); // apparently planes always need to be flipped over (or have doublesided materials) glow.geometry.flipFaces(); planetMask.geometry.flipFaces(); cloudMask.geometry.flipFaces(); // structure layers so that the glow is always on top of the planet var containerLayer:ViewportLayer = PV3DUtil.createLayer(viewport, null, viewport.containerSprite); var planetLayer:ViewportLayer = PV3DUtil.createLayer(viewport, planet, containerLayer, 0); var cloudLayer:ViewportLayer = PV3DUtil.createLayer(viewport, clouds, containerLayer, 1); var planetMaskLayer:ViewportLayer = PV3DUtil.createLayer(viewport, planetMask, containerLayer, 2); var cloudMaskLayer:ViewportLayer = PV3DUtil.createLayer(viewport, cloudMask, containerLayer, 3); var glowLayer:ViewportLayer = PV3DUtil.createLayer(viewport, glow, containerLayer, 4); containerLayer.sortMode = ViewportLayerSortMode.INDEX_SORT; // apply planet mask, so that the planet is garuanteed coveren by the glow planetLayer.cacheAsBitmap = planetMaskLayer.cacheAsBitmap = true; cloudLayer.cacheAsBitmap = cloudMaskLayer.cacheAsBitmap = true; planetLayer.mask = planetMaskLayer; cloudLayer.mask = cloudMaskLayer; } /** * Defines a masking disc the same size as the fresnel glow 'around' Earth. */ private function createPlanetMaskMaterial(size:Number):MaterialObject3D { var planetMaskTexture:Sprite = PV3DUtil.createGradientSprite(size, [0, 0], [1, 0], [0xFA, 0xFF]); return new MovieMaterial(planetMaskTexture, true); } protected function createPlanetMaterial():MaterialObject3D { return null; // abstract, should be implemented by subclasses } protected function createCloudMaterial():MaterialObject3D { return null; // abstract, should be implemented by subclasses } protected function createGlowMaterial(size:Number, alphas:Array, ratios:Array):MaterialObject3D { return null; // abstract, should be implemented by subclasses } /** * Rotates Earth and clouds separately. Makes sure the glow- and mask planes are pointed towards the camera */ public override function update(camera:Camera3D):void { planet.yaw(planetRotationSpeed); clouds.yaw(cloudsRotationSpeed); glow.lookAt(camera); planetMask.copyTransform(glow); cloudMask.copyTransform(glow); super.update(camera); } /** * Defined so that the planet can be used outside this class (to rotate for example). */ public function get planet():Sphere { return _planet; } } }