LogoLogo
  • Home
  • Projects
  • About
  • Contact

Getting Started with Proscenium

Devon O. · October 09, 2011 · Actionscript · 13 comments
5

So I had a chance this weekend to sit down and play around with Adobe’s new 3D framework for Stage3D, Proscenium, and thought I’d share a few of the results (a word of caution, there are no preloaders for any of the examples and may load a bit slowly).

The first shows some reflections and shadows. Move your mouse around to raise and lower the camera.

In the second, I thought I’d play around with some physics. Use the keyboard arrow keys to roll the red ball around and knock over some crates. Note: there seems to be something buggy with the Proscenium keyboardEventHandler() method and you may have to refresh the page to get control of the ball.

In the third, I thought I’d play around with a video texture. If you have a webcam attached, you can see yourself in a sphere with a mirror orbiting around (look hard enough and you may see the back of your head).

My first impressions of Proscenium are generally pretty favorable. There are a few things I’d like to see worked out, such as the keyboard event handler mentioned above. Also, there doesn’t seem to be an easy way to apply a texture to a cube. If you want the same thing on every side, such as my crates in the physics example, that’s easy enough, but if you want a different texture per side (e.g. a die), there’s no obvious way of getting it done simply. Finally, while Proscenium supports particles, there’s no easy or high level way to get them working. Prepare yourself for writing some AGAL. It would be nice if the folks working on the project took a cue from those working on the Starling framework and created a method of creating particles based on a config / xml file.

Proscenium is still in early stages though and is coming along very nicely. I’ll be really interested in seeing how it develops. As I mentioned in a tweet earlier this week, it may just give Away3D a run for it’s money. It still has a good ways to go though.

For anyone interested, the commented source code for all three examples is posted below:

Example 1 (shadows and reflections):

C#
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
/**
*    Copyright (c) 2011 Devon O. Wolfgang
*
*    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.
*/
package
{
    import com.adobe.scenegraph.BasicScene;
    import com.adobe.scenegraph.MaterialStandard;
    import com.adobe.scenegraph.MeshUtils;
    import com.adobe.scenegraph.RenderSettings;
    import com.adobe.scenegraph.RenderTextureCube;
    import com.adobe.scenegraph.SceneCamera;
    import com.adobe.scenegraph.SceneLight;
    import com.adobe.scenegraph.SceneMesh;
    import com.adobe.scenegraph.SceneSkyBox;
    import com.adobe.scenegraph.TextureMap;
    import flash.display.BitmapData;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.display3D.Context3DRenderMode;
    import flash.events.Event;
    import flash.geom.ColorTransform;
    import flash.geom.Vector3D;
    
    /**
     * Proscenium example with multiple lights, shadows, reflections, and custom texture.
     * @author Devon O.
     */
    
    [SWF(width='800', height='600', backgroundColor='#000000', frameRate='60')]
    public class Main extends BasicScene
    {
        [Embed(source="../res/sky/back.jpg")]
        private const SKY0:Class;
        
        [Embed(source="../res/sky/up.jpg")]
        private const SKY1:Class;
        
        [Embed(source="../res/sky/front.jpg")]
        private const SKY2:Class;
        
        [Embed(source="../res/sky/down.jpg")]
        private const SKY3:Class;
        
        [Embed(source="../res/sky/right.jpg")]
        private const SKY4:Class;
        
        [Embed(source="../res/sky/left.jpg")]
        private const SKY5:Class;
 
        private var mCamera:SceneCamera;
        private var mLight1:SceneLight;
        private var mLight2:SceneLight;
        private var mShadowMapSize:int = 128;
        private var mCameraHeight:Number = 15.0;
        
        private var mLargePlanet:SceneMesh;
        private var mSmallPlanet:SceneMesh;
        
        public function Main(renderMode:String = Context3DRenderMode.AUTO):void
        {
            super(renderMode);
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private function init(event:Event = null):void
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;
        }
        
        override protected function initLights():void
        {
            super.initLights();
            
            // set up some exponential fog
            instance.primarySettings.fogMode = RenderSettings.FOG_EXP;
            instance.primarySettings.fogDensity = 300;
            
            // add a point and distant light, set their colors, and prepare them for casting shadows
            mLight1 = new SceneLight(SceneLight.KIND_POINT);
            mLight1.color.setFromUInt(0x837749);
            mLight1.appendTranslation(0, 50, 20);
            mLight1.shadowMapEnabled = true;
            mLight1.setShadowMapSize(mShadowMapSize, mShadowMapSize);
            scene.addChild(mLight1);
            
            mLight2 = new SceneLight(SceneLight.KIND_DISTANT);
            mLight2.color.setFromUInt(0x837749);
            mLight2.appendTranslation(5, 60, -20);
            mLight2.shadowMapEnabled = true;
            mLight2.setShadowMapSize(mShadowMapSize, mShadowMapSize);
            scene.addChild(mLight2);
        }
        
        override protected function initModels():void
        {
            super.initModels();
            
            // create a skybox from embedded bitmaps
            var skyboxData:Vector.<BitmapData> = new Vector.<BitmapData>( 6, true );
            skyboxData[0] = new SKY0().bitmapData;
            skyboxData[1] = new SKY2().bitmapData;
            skyboxData[2] = new SKY1().bitmapData;
            skyboxData[3] = new SKY3().bitmapData;
            skyboxData[4] = new SKY4().bitmapData;
            skyboxData[5] = new SKY5().bitmapData;
            var sky:SceneSkyBox = new SceneSkyBox( skyboxData, false );
            scene.addChild(sky);
            
            // create a nice looking terrain with fractal hills and lower it a little
            var ground:SceneMesh = MeshUtils.createFractalTerrain(100, 100, 500, 500, 65);
            ground.setPosition(0, -50, 0);
            scene.addChild(ground);
            
            // this will be used to reflect the entire scene
            var cubeMap:RenderTextureCube = new RenderTextureCube(256);
            cubeMap.addSceneNode(scene);
            
            // create a material which will use the cube map above as an environment map
            var material:MaterialStandard = new MaterialStandard();
            material.environmentMap = cubeMap;
            material.ambientColor.setFromUInt(0x000000);
            material.diffuseColor.setFromUInt(0x000000);
            material.environmentMapStrength = .98;
            
            // apply that material to a sphere and add the sphere to the scene
            mLargePlanet = MeshUtils.createSphere(8, 32, 32, material);
            mLargePlanet.appendTranslation(0, 10, 0);
            cubeMap.attachedNode = mLargePlanet;    // attach the cube map to the sphere (!)
            scene.addChild(mLargePlanet);
            
            // create a bitmapdata for a texture, make it a bit interesting with perlin noise and color it to fit in
            var texture:BitmapData = new BitmapData(256, 256, false);
            texture.perlinNoise(16, 16, 8, 93, true, true, 7, true);
            texture.colorTransform(texture.rect, new ColorTransform(0x29 / 0xFF, 0x1A / 0xFF, 0x0E / 0xFF));
            
            // create an actual texture that uses the above bitmap data
            var map:TextureMap = new TextureMap(texture);
            
            // create a material that uses that bitmap data texture as an emissive map
            material = new MaterialStandard();
            material.emissiveMap = map;
            material.ambientColor.setFromUInt(0x000000);
            material.diffuseColor.setFromUInt(0x000000);
            
            // apply that material to a smaller sphere
            mSmallPlanet = MeshUtils.createSphere(3, 32, 32, material);
            mSmallPlanet.appendTranslation(20, 12, 0);
            scene.addChild(mSmallPlanet);
            
            // and why not apply that same material to the ground created earlier
            ground.applyMaterial(material);
            
            // make the smaller sphere cast shadows from both lights in the scene
            mLight1.addToShadowMap(mSmallPlanet);
            mLight2.addToShadowMap(mSmallPlanet);
        }
        
        override protected function resetCamera():void
        {
            // just initializes the camera. Its position is constantly set during the onAnimate call
            mCamera = scene.activeCamera;
            mCamera.identity();
        }
        
        override protected function onAnimate(t:Number, dt:Number):void
        {
            super.onAnimate(t, dt);
            
            
            // raise and lower the camera with a bit of easing but keeping it circling around and looking at the larger sphere
            var r:Number = ((stage.mouseY / stage.stageHeight) - .5) * 2;
            var th:Number = -15 * r;
            mCameraHeight += ((th + 5) - mCameraHeight) / 10;
            
            mCamera.setPosition(Math.sin(t * .5) * 55, mCameraHeight, Math.cos(t * .5) *55);
            mCamera.lookat(mCamera.position, mLargePlanet.position, Vector3D.Y_AXIS);
            
            // orbit the smaller planet around the larger
            mSmallPlanet.appendRotation(1.25, Vector3D.Y_AXIS);
        }
        
    }
}

Example 2 (physics):

C#
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
/**
*    Copyright (c) 2011 Devon O. Wolfgang
*
*    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.
*/
package  
{
    import com.adobe.scenegraph.BasicScene;
    import com.adobe.scenegraph.MaterialStandard;
    import com.adobe.scenegraph.PelletManager;
    import com.adobe.scenegraph.RenderSettings;
    import com.adobe.scenegraph.SceneCamera;
    import com.adobe.scenegraph.SceneLight;
    import com.adobe.scenegraph.SceneMesh;
    import com.adobe.scenegraph.SceneNode;
    import com.adobe.scenegraph.SceneSkyBox;
    import com.adobe.scenegraph.TextureMap;
    import flash.display.BitmapData;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.display3D.Context3DRenderMode;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.geom.ColorTransform;
    import flash.geom.Vector3D;
    import flash.ui.Keyboard;
    
    /**
     * Proscenium example with basic physics
     * @author Devon O.
     */
    
    [SWF(width='800', height='600', backgroundColor='#000000', frameRate='60')]
    public class Main extends BasicScene
    {
        [Embed(source="../res/sky/Sky0000.jpg")]
        private const SKY0:Class;
        
        [Embed(source="../res/sky/Sky0001.jpg")]
        private const SKY1:Class;
        
        [Embed(source="../res/sky/Sky0002.jpg")]
        private const SKY2:Class;
        
        [Embed(source="../res/sky/Sky0003.jpg")]
        private const SKY3:Class;
        
        [Embed(source="../res/sky/Sky0004.jpg")]
        private const SKY4:Class;
        
        [Embed(source="../res/sky/Sky0005.jpg")]
        private const SKY5:Class;
        
        [Embed(source = "../res/crate1.jpg")]
        private const CRATE_MAT:Class;
        
        private const NUM_CRATES:int = 5;
        
        private var mPellet:PelletManager;
        
        private var mLight1:SceneLight;
        private var mLight2:SceneLight;
        private var mShadowMapSize:int = 1024;
        
        private var mCamera:SceneCamera;
        private var mBall:SceneMesh;
        private var mSceneObjs:Vector.<SceneMesh> = new Vector.<SceneMesh>();
        
        public function Main(renderMode:String = Context3DRenderMode.AUTO)
        {
            super(renderMode);
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private function init(event:Event = null):void
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;
        }
        
        override protected function initLights():void
        {
            super.initLights();
            
            // some linear fog with a start and end
            instance.primarySettings.fogMode = RenderSettings.FOG_LINEAR;
            instance.primarySettings.fogStart = 0;
            instance.primarySettings.fogEnd = .01;
            
            
            // two scene lights point and distant, prepped for casting shadows
            mLight1 = new SceneLight(SceneLight.KIND_POINT);
            mLight1.color.setFromUInt(0x8C98A7);
            mLight1.appendTranslation(50, 150, 20);
            mLight1.shadowMapEnabled = true;
            mLight1.setShadowMapSize(mShadowMapSize, mShadowMapSize);
            scene.addChild(mLight1);
            
            mLight2 = new SceneLight(SceneLight.KIND_DISTANT);
            mLight2.color.setFromUInt(0xE2E2E2);
            mLight2.appendTranslation(5, 60, -20);
            mLight2.shadowMapEnabled = true;
            mLight2.setShadowMapSize(mShadowMapSize, mShadowMapSize);
            scene.addChild(mLight2);
        }
        
        override protected function initModels():void
        {
            super.initModels();
            
            // skybox created from embedded bitmaps
            var skyboxData:Vector.<BitmapData> = new Vector.<BitmapData>( 6, true );
            skyboxData[0] = new SKY0().bitmapData;
            skyboxData[1] = new SKY2().bitmapData;
            skyboxData[2] = new SKY1().bitmapData;
            skyboxData[3] = new SKY3().bitmapData;
            skyboxData[4] = new SKY4().bitmapData;
            skyboxData[5] = new SKY5().bitmapData;
            var sky:SceneSkyBox = new SceneSkyBox( skyboxData, false );
            scene.addChild(sky);
            
            // used to control the physics and create scene meshes
            mPellet = new PelletManager();
            
            // everything added to this scene node will cast shadows
            var caster:SceneNode = new SceneNode();
            scene.addChild(caster);
            
            // ground texture created from bitmapdata and mapped to a box mesh
            var texture:BitmapData = new BitmapData(128, 128, false, 0x002200);
            texture.noise(23, 0, 0xFF, 7, true);
            texture.colorTransform(texture.rect, new ColorTransform(0, .10, 0));
            var map1:TextureMap = new TextureMap(texture);
            var mat1:MaterialStandard = new MaterialStandard();
            mat1.emissiveMap = map1;
            mat1.specularIntensity = 0;
            mat1.specularColor.setFromUInt(0x000000);
            mat1.ambientColor.setFromUInt(0x000000);
 
            var ground:SceneMesh = mPellet.createBox(500, 1, 500, mat1);
            // set the ground's mass to 0 so that it won't be affected by the physics
            ground.physicsObject.mass = 0;
            scene.addChild(ground);
            
            // create a new texture from an embedded bitmap of a crate image
            texture = new CRATE_MAT().bitmapData;
            var map2:TextureMap = new TextureMap(texture);
            var mat2:MaterialStandard = new MaterialStandard();
            mat2.diffuseColor.setFromUInt(0x000000);
            mat2.ambientColor.setFromUInt(0x000000);
            mat2.emissiveMap = map2;
            
            // create 5 'crates', add them to the caster node and push them into a sceneObj collection
            for (var i:int = 0; i < NUM_CRATES; i++)
            {
                var crate:SceneMesh = mPellet.createBox(8, 8, 8, mat2);
                crate.setPosition(0, 20 + i * 5, 0);
                crate.prependRotation(Math.random() * 360, Vector3D.Y_AXIS);
                mSceneObjs.push(crate);
                caster.addChild(crate);
            }
            
            // create a ball texture from bitmapdata and give it a slightly red color
            texture = new BitmapData(256, 256, false);
            texture.perlinNoise(16, 16, 8, 93, true, true, 7, true);
            texture.colorTransform(texture.rect, new ColorTransform(.4, .2, .2));
            var map3:TextureMap = new TextureMap(texture);
            var mat3:MaterialStandard = new MaterialStandard();
            mat3.emissiveMap = map3;
            mBall = mPellet.createSphere(4, 32, 32, mat3);
            mBall.setPosition(0, 10, 20);
            
            // add the ball to our collection of scene objects and caster
            mSceneObjs.push(mBall);
            caster.addChild(mBall);
            
            // make it so our caster node casts shadows
            mLight1.addToShadowMap(caster);
            mLight2.addToShadowMap(caster);
        }
        
        override protected function resetCamera():void
        {
            // just initialize the camera
            mCamera = scene.activeCamera;
            mCamera.identity();
        }
        
        override protected function onAnimate(t:Number, dt:Number):void
        {
            super.onAnimate(t, dt);
            
            // step through the physics
            mPellet.stepWithSubsteps(dt, 2);
            
            // position the camera to watch the ball
            mCamera.setPosition( mBall.position.x - 100, 25, mBall.position.z );
            mCamera.lookat(mCamera.position, mBall.position, Vector3D.Y_AXIS);
            
            // loop through our collection of scene objects
            // if any have fallen off the edge of the ground clear their forces and set them back over the ground
            var i:int = mSceneObjs.length;
            while (i--)
            {
                var obj:SceneMesh = mSceneObjs[i];
                if (obj.position.y < -5)
                {
                    obj.physicsObject.setLinearVelocity();
                    obj.physicsObject.setLinearVelocity();
                    obj.setPosition(0, 50, 0);
                }
            }
        }
        
        override protected function keyboardEventHandler(event:KeyboardEvent):void
        {
            super.keyboardEventHandler(event);
            
            // use the arrow keys to apply an impulse to the ball object
            // this seems a bit buggy and stops working 1 / 10 times or so
            switch(event.type)
            {
                case KeyboardEvent.KEY_DOWN :
 
                    switch(event.keyCode)
                    {
                        case Keyboard.UP :
                            mBall.physicsObject.applyImpulseToCenter(3, 0, 0);
                            break;
                            
                        case Keyboard.DOWN :
                            mBall.physicsObject.applyImpulseToCenter(-3, 0, 0);
                            break;
                            
                        case Keyboard.RIGHT :
                            mBall.physicsObject.applyImpulseToCenter(0, 0, 3);
                            break;
                            
                        case Keyboard.LEFT :
                            mBall.physicsObject.applyImpulseToCenter(0, 0, -3);
                            break;
                    }
            }
        }
    }
}

Example 3 (video texture):

C#
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
/**
*    Copyright (c) <year> Devon O. Wolfgang
*
*    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.
*/
 
package  
{
    import com.adobe.scenegraph.BasicScene;
    import com.adobe.scenegraph.MaterialStandard;
    import com.adobe.scenegraph.MeshUtils;
    import com.adobe.scenegraph.RenderSettings;
    import com.adobe.scenegraph.RenderTextureReflection;
    import com.adobe.scenegraph.SceneCamera;
    import com.adobe.scenegraph.SceneLight;
    import com.adobe.scenegraph.SceneMesh;
    import com.adobe.scenegraph.SceneNode;
    import com.adobe.scenegraph.SceneSkyBox;
    import com.adobe.scenegraph.TextureMap;
    import flash.display.BitmapData;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.display3D.Context3DRenderMode;
    import flash.events.Event;
    import flash.geom.Matrix;
    import flash.geom.Vector3D;
    import flash.media.Camera;
    import flash.media.Video;
    
    /**
     * Proscenium example with video texture and mirror (plane) reflection
     * @author Devon O.
     */
    
    [SWF(width='800', height='600', backgroundColor='#000000', frameRate='40')]
    public class Main extends BasicScene
    {
        
        [Embed(source="../res/sky/Sky0000.jpg")]
        private const SKY0:Class;
        
        [Embed(source="../res/sky/Sky0001.jpg")]
        private const SKY1:Class;
        
        [Embed(source="../res/sky/Sky0002.jpg")]
        private const SKY2:Class;
        
        [Embed(source="../res/sky/Sky0003.jpg")]
        private const SKY3:Class;
        
        [Embed(source="../res/sky/Sky0004.jpg")]
        private const SKY4:Class;
        
        [Embed(source="../res/sky/Sky0005.jpg")]
        private const SKY5:Class;
        
        private var mLight1:SceneLight;
        private var mLight2:SceneLight;
        private var mShadowMapSize:int = 256;
        
        private var mCamera:SceneCamera;
        private var mBall:SceneMesh;
        
        // video
        private var mVideo:Video;
        private var mVideoData:BitmapData;
        private var mVideoTexture:TextureMap;
        private var mIsVideo:Boolean = false;
        private var mScreen:SceneMesh;
        private var mMat:Matrix = new Matrix();
        
        public function Main(renderMode:String = Context3DRenderMode.AUTO)
        {
            super(renderMode);
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private function init(event:Event = null):void
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;
            initVideo();
        }
        
        private function initVideo():void
        {
            // create a bitmapdata and texture that uses that uses that data
            mVideoData = new BitmapData(128, 128, false, 0x000000);
            mVideoTexture = new TextureMap(mVideoData);
            
            // get the webcam
            var camIndex:int = 0;
            for ( var i:int = 0 ; i < Camera.names.length ; i++ ) {
                if ( Camera.names[ i ] == "USB Video Class Video" ) {
                    camIndex = i;
                    break;
                }
            }
            var cam:Camera = Camera.getCamera(String(camIndex));
            
            // if a webcam exists, create a video object
            if (cam)
            {
                mVideo = new Video();
                mVideo.attachCamera(cam);
                mVideo.smoothing = true;
                mMat.scale(mVideoData.width / mVideo.width, mVideoData.height / mVideo.height);
                mIsVideo = true;
            }
        }
        
        override protected function initLights():void
        {
            super.initLights();
            
            // some fog
            instance.primarySettings.fogMode = RenderSettings.FOG_EXP2;
            instance.primarySettings.fogDensity = 200;
            
            // some lights
            mLight1 = new SceneLight(SceneLight.KIND_POINT);
            mLight1.color.setFromUInt(0x837749);
            mLight1.appendTranslation( 0, 50, 20 );
            mLight1.shadowMapEnabled = true;
            mLight1.setShadowMapSize(mShadowMapSize, mShadowMapSize);
            scene.addChild(mLight1);
            
            mLight2 = new SceneLight(SceneLight.KIND_DISTANT);
            mLight2.color.setFromUInt(0x837749);
            mLight2.appendTranslation( 5, 60, -20 );
            mLight2.shadowMapEnabled = true;
            mLight2.setShadowMapSize(mShadowMapSize, mShadowMapSize);
            scene.addChild(mLight2);
        }
        
        override protected function initModels():void
        {
            super.initModels();
            
            // skybox
            var bitmapDatas:Vector.<BitmapData> = new Vector.<BitmapData>( 6, true );
            bitmapDatas[0] = new SKY0().bitmapData;
            bitmapDatas[1] = new SKY2().bitmapData;
            bitmapDatas[2] = new SKY1().bitmapData;
            bitmapDatas[3] = new SKY3().bitmapData;
            bitmapDatas[4] = new SKY4().bitmapData;
            bitmapDatas[5] = new SKY5().bitmapData;
            var sky:SceneSkyBox = new SceneSkyBox( bitmapDatas, false );
            scene.addChild(sky);
            
            // fractal ground set low
            var ground:SceneMesh = MeshUtils.createFractalTerrain(100, 100, 1000, 1000, 85);
            ground.setPosition(0, -150, 0);
            scene.addChild(ground);
            
            // create a material that uses our video texture and apply it to a sphere
            var mat:MaterialStandard = new MaterialStandard();
            mat.emissiveMap = mVideoTexture;
            mat.specularExponent = 30;
            mat.diffuseColor.setFromUInt(0x000000);
            mat.ambientColor.setFromUInt(0x000000);
            mat.environmentMapStrength = .99;
            mBall = MeshUtils.createSphere(32, 32, 32, mat);
            scene.addChild(mBall);
            
            // used to apply reflective material to a plane
            var ref:RenderTextureReflection = new RenderTextureReflection(256, 256);
            
            // create a material that uses the reflective texture
            var mat2:MaterialStandard = new MaterialStandard();
            mat2.emissiveMap = ref;
            
            // create a plane with the above material
            mScreen = MeshUtils.createPlane(40, 40, 2, 2, mat2);
            mScreen.setPosition(50, 20, 0);
            scene.addChild(mScreen);
            
            // specify the reflective texture's geometry and that it should reflect the entire scene
            ref.reflectionGeometry = mScreen;
            ref.addSceneNode(scene);
            
            // allow the ball to cast shadows
            mLight1.addToShadowMap(mBall);
            mLight2.addToShadowMap(mBall);
        }
        
        override protected function resetCamera():void
        {
            // initialize the camera
            mCamera = scene.activeCamera;
            mCamera.identity();
        }
        
        override protected function onAnimate(t:Number, dt:Number):void
        {
            super.onAnimate(t, dt);
            
            // rotate the 'mirror' around the ball while keeping it rotated in a way that it always reflects the ball
            mScreen.lookat(mScreen.position, mBall.position, Vector3D.Y_AXIS);
            mScreen.appendRotation(2, Vector3D.Y_AXIS);
            mScreen.prependRotation(-90, Vector3D.X_AXIS);
            
            // if a webcam is running, draw the video into the video bitmap data and update the texture with that bitmapdata
            if (mIsVideo)
            {
                mVideoData.draw(mVideo, mMat);
                mVideoTexture.update(mVideoData);
            }
            
            // orbit the camera around the ball
            mCamera.setPosition(Math.sin(t * .5) * 200, 10, Math.cos(t * .5) * 200);
            mCamera.lookat(mCamera.position, mBall.position, Vector3D.Y_AXIS);
        }
        
    }
}
  Facebook   Pinterest   Twitter   Google+
  • 3D Scanner (Kinda Sorta)
    October 07, 2009 · 4 comments
    2223
    6
    Read more
  • Rockin and Rollin with the JiglibFlash Terrain
    March 16, 2010 · 8 comments
    2471
    6
    Read more
  • DirectionalBlurFilter && .swc Library and Stuff
    November 02, 2008 · 9 comments
    2315
    2
    Read more
13 Comments:
  1. Cool, but seems a little bit slow, doesn’t it?

    Fábio Azevedo · October 09, 2011
  2. Hey Fabio,

    For aesthetic purposes I took out the stats display, but it didn’t seem to be so bad on my windows machine. The first ran at a steady 60 FPS, the physics example wavered around 40 FPS (though the physics itself does seem a little sluggish. I tried upping the substeps and adjusting the gravity, but couldn’t find anything that helped much). The last one only seems to run around 30 FPS, but that doesn’t surprise me with the bitmap drawing. I’m sure it could be optimized a bit.

    Devon O. · October 09, 2011
  3. so..cool..

    Red_camel · October 09, 2011
  4. How to animate vertices changing the sources

    amiko · October 13, 2011
  5. Good question Amiko. Not really sure. I’ll have to look into it more.

    Devon O. · October 13, 2011
  6. http://winxalex.blogspot.com/2011/10/md2-model-loader-proscenium-3d.html

    its beta
    still try to discover better way and decipher AnimationController, AnimationTrack and Sampler and vertex source change when you have scene mesh.
    I hope we can chat.
    Regards
    Alex

    winxalex · October 14, 2011
  7. Hi Davon
    I hoped we could share some toughs about Proscenium but seem you are busy.
    When you have time take a look
    http://winxalex.blogspot.com/2011/10/import-bvh-biovision-motion-proscenium.html

    winxalex · October 24, 2011
  8. Hi,

    Thanks for the article, I’m currently testing Proscenium myself and I was confused by the keyboard event handling as well.. This is how I did to change it:

    override protected function initHandlers():void
    {
    super.initHandlers();
    stage.addEventListener( KeyboardEvent.KEY_DOWN, keyDownHandler );
    stage.addEventListener( KeyboardEvent.KEY_UP, keyUpHandler );
    }

    override protected function keyboardEventHandler(event:KeyboardEvent):void
    {
    trace(“default KeyboardEventHandler”);
    }

    Not the best solution, but works.

    Stef · October 25, 2011
  9. @winxalex – sorry for the delay. I really only have free time on the weekends. And then only if I’m lucky. That model you made looks great. Have you figured out how to get to individual vertices?

    @Stef thank you for the keyboard tip.

    Devon O. · October 30, 2011
  10. Davon I saw you were busy on 2D :)
    Actually I didn’t build the models I made loader for Quake MD2 inside Flash11 and other I attache Biovision motion files to model :)
    Vertices are encapsulated. But I’ll try some hack so I can manipulate them later. I was working on something else
    Please check and let me know your toughs.
    http://winxalex.blogspot.com/2011/10/collada-dae-to-proscenium-actionscript.html
    Regards

    winxalex · October 30, 2011
  11. Hi Davon
    Here how you can manipulate vertices :))
    http://winxalex.blogspot.com/2011/11/how-to-morph-manipulate-vertices.html

    winxalex · November 05, 2011
  12. That’s fantastic!

    Devon O. · November 06, 2011
  13. Hi Davon,

    Have you some informations about Proscenium RoadMap ?
    I try to communicate with Adobe Team, but nobody give me informations !

    Proscenium looks great, but community are so small and there’s no tutorials, no videos, no informations !

    I’m disapointed !

    Thanks

    kopacabana · March 10, 2012

Leave a Comment! Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Devon O. Wolfgang

AIR | Unity3D | AR/VR

Unity Certified Developer

Technical Reviewer of “The Essential Guide to Flash CS4 AIR Development” and “Starling Game Development Essentials”

Reviewer of “The Starling Handbook”

Unity Engineer at Touch Press.

Categories
  • Actionscript (95)
  • AIR (16)
  • Flash (99)
  • Games (7)
  • Liberty (13)
  • Life (53)
  • Shaders (20)
  • Unity3D (21)
Recent Comments
  • Devon O. on Unity Ripple or Shock Wave Effect
  • Feral_Pug on Unity Ripple or Shock Wave Effect
  • bavvireal on Unity3D Endless Runner Part I – Curved Worlds
  • Danielius Vargonas on Custom Post Processing with the LWRP
  • Luca G on Unity Ripple or Shock Wave Effect
Archives
  • December 2020 (1)
  • December 2019 (1)
  • September 2019 (1)
  • February 2019 (2)
  • December 2018 (1)
  • July 2018 (1)
  • June 2018 (1)
  • May 2018 (2)
  • January 2018 (1)
  • December 2017 (2)
  • October 2017 (1)
  • September 2017 (2)
  • January 2017 (1)
  • July 2016 (1)
  • December 2015 (2)
  • March 2015 (1)
  • September 2014 (1)
  • January 2014 (1)
  • August 2013 (1)
  • July 2013 (1)
  • May 2013 (1)
  • March 2013 (2)
  • December 2012 (1)
  • November 2012 (1)
  • September 2012 (3)
  • June 2012 (2)
  • May 2012 (1)
  • April 2012 (1)
  • December 2011 (2)
  • October 2011 (3)
  • September 2011 (1)
  • August 2011 (1)
  • July 2011 (1)
  • May 2011 (2)
  • April 2011 (2)
  • March 2011 (1)
  • February 2011 (1)
  • January 2011 (2)
  • December 2010 (3)
  • October 2010 (5)
  • September 2010 (1)
  • July 2010 (2)
  • May 2010 (5)
  • April 2010 (2)
  • March 2010 (7)
  • February 2010 (5)
  • January 2010 (5)
  • December 2009 (3)
  • November 2009 (1)
  • October 2009 (5)
  • September 2009 (5)
  • August 2009 (1)
  • July 2009 (1)
  • June 2009 (2)
  • May 2009 (6)
  • April 2009 (4)
  • March 2009 (2)
  • February 2009 (4)
  • January 2009 (1)
  • December 2008 (5)
  • November 2008 (2)
  • September 2008 (1)
  • August 2008 (6)
  • July 2008 (6)
  • June 2008 (9)
  • May 2008 (4)
  • April 2008 (3)
  • March 2008 (4)
  • February 2008 (9)
  • January 2008 (7)
  • December 2007 (6)
Copyright © 2017 Devon O. Wolfgang