Augmented Reality and the base of the original ARToolkit has taken the flash world by storm with the FLARToolkit and really the speed updates of the AVM2 in Flash9 and Flash10 to be able to pull off the OpenCV calculations needed on the bitmap data from each frame of a camera. It has been around quite some time but now web based engines such as Flash and now Processing can take advantage of this awesome technology.
Den Ivanov did some cool experiments with this kit but adding the capability to do multiple markers. In his videos the processing runtime seems to process the render pretty quickly. It seems that most Flash AR is around like 5-10 frames per second for the detection.
Here is a video with more information on Silverlight 3 Beta features that are matches of the latest Flash killer features in pixel shaders, 3d planes (ability to create pseudo-3d engines like papervision3d), local saving, pixel operations/bitmap handling, local messaging (silverlight to silverlight – like localconnection), out of browser desktop running ability of SL3, SEO and search indexing capabilities / deep linking navigation and more.
Video of the features of SL3 Beta, Demos, at a Slow Pace from #mix09
A few points after the video and taking a tour of the features.
The pixel shaders are written in HLSL (shader 2), however they are compiled to byte code and do not currently use the gpu for rendering. While the pixel shaders are very cool and the language to write them is standard pretty much for shaders in HLSL shader model 2 DirectX-based (the other is GLSL OpenGL based) they have not allowed this byte code to run on the GPU… yet. Here Flash and Pixel Bender actually are ahead there.
Although there are 3d planes which is very exciting, no good pseudo 3d engine exists yet matching the 3 in flash (papervision3d, away3d, sandy). When SL3 comes out I am sure we will see a few emerge or build them ourselves because this iteration of SL3 looks pretty fun.
Pixel based operations will be a huge advancement much like it was in earlier flash versions as it adds some demo scene type abilities and experiments with pixels that are fun. This also lends to doing cool things like shaders, effects, AR, face recognition, motion detection etc.
Effects like Blur and Drop shadow are good and the ability to add custom ones, great. However currently they are pretty performance intensive. They are also in Flash but there needs to be some refinement in SL3 effects before launch.
Desktop runnable apps in out of browser will be nice and this is a direct compete with Adobe AIR which was a surprise.
Local Communication supports desktop to browser communication.
Isolated storage (similar to shared objects) supports 1MB in browser, 25MB out of browser defaults.
This version of silverlight is really a 1.0 version as typical with most software. Version 2 or version 3 is usually what the initial design goals pan out. Much like the latest unity3d version (2.5) that has windows support and the iPhone SDK 3.0 that both came out this week, even actionscript 3 compared to earlier versions, these toolkits are finally iterated enough that they are really solid platforms for building cool stuff on and become platforms. The next version of all these could be very, very dangerous.
Huge missing features:
Although there are some great features in SL3 beta, it is still not done and it is still missing some key components that Flash has which make it very attractive in the interactive space.
Camera and Microphone support - Macromedia hired one of the smartest dudes around in Jeremy Allaire back in flash 6 days to help add support for Flash Communication Server (Flash Media Server now) Camer and Microphone support. One of the best R&D periods at Macromedia. SL needs this soon.
Printing support – what was long a problem in Flash is so in SL, there is no good printing support
No GPU usage for Pixel Effects/Shaders – (neither flash nor silverlight support hardware accelerated shaders in PixelEffects/Pixelbender – Pixel Effects/Shaders need GPU support (see Kevin Goldsmith’s article on GPU mixed with CPU and how this may or may not be good. However processors are speeding up and multi-core helps software rendering, the quality of GPU is well beyond what software rendering can deliver for a few years to come at least while architecture advances, probably more like 5-10 years.
No UDP plans yet - Adobe has RTMFP, SL sockets has no public plans for adding UDP that I have seen
No Alpha Channel in Video - You can do this with a shader though but not supported by default.
Silverlight 3 Video
Flash has the upperhand in video and probably will still even though SL3 has H.264. Flash added this at the same time and though they still have FLV which revolutionized web video they are now much broader in support in video than SL3. Silverlight has H.264 and VC1 support (their own FLV like codec). Still pretty cool a couple years ago there was no HD on the web now everyone has it in H.264 video support.
Currently nothing innovative, mainly catchup still, but here are some options
Silverlight 3 beta and the video below the features and highlights will look very similar to flash and flash community advancements over the last couple years. There is no innovation just yet.
But where that could happen is in socket support with UDP. Flash has moved on this in RTMFP and the beginning of larger scale networking support with UDP with samples like stratus. This is a huge differentiating feature for what I think will be game changer on the web (it already is on desktop mmos) in real-time or closer to real-time support for larger sets of users in online games like MMOs or virtual communities, even tools to make request based real-time sites like micro-blogging faster and able to handle more users (right now it is very linear if users get many followers, UDP will allow a better distributed framework for messaging).
Local Storage
Silverlight and Unity3D all need this, Flash could use better support for this. Local saving of a files for cache beyond the internet cache and greater than the 1MB/25MB limits of SL3 IsolatedStorage. This is an issue when you are making large scale games in that you need to save lots of assets to a client but to make it economical you want ot save more than the default internet cache amount. Flash Shared Object (Local) allow you to do this somewhat but it would be great to have a way to just download files for cache (upon user agreement) to store assets in bulk of allowable types (images, video, models, bundles) to the file system.
Hardware rendering for 3d support and UDP support will put Flash and SL3 on par with the killer Unity3D kit for making online web games and other activex/plugins like instantaction that allow you to do these things already.
The one thing SL has over Flash
Flash and Flex are great. But there is this massive division in the community and marketing of Flash. Silverlight is entirely unified and this has much to do with starting clean at a time that interactive development is heading more into a technology and developers control. Flash and Flex need to bring it together. AS3 has been out long enough that the people with skills have hopped on and taken it to a new level, mainly from programmers. If Adobe created a version of Flash that was a new IDE and consolidated Flex and Flash into just Flash, made the IDE as powerful as FDT or FlashDevelop3 there could be hope to bring the platform together. I understand they had to work it in slowly because it was a designers platform really (even though coders still pushed the limits in games and apps built on it) so they had to tip toe carefully on this to not alienate people. But now I think the division is a serious problem with the platform and must be addressed, noone expected Silverlight to be this quick on at least SL3 features. And even though the initial approach might have been bad as SL1 was a huge letdown, Microsoft does not give up and you can see in the XBOX360 and DirectX that they are very pursuant. DirectX really didn’t become huge until version 7 so these guys won’t relent.
I am not a huge fan of using the proprietary tools. Even in Flash I use as much open source as I can even though the player is locked, but Moonlight is something that trails Silverlight development and is a very unique thing in both open source and cross platform/multiplatform development. It is a clear relationship and aims to make Silverlight run on multiplatform mono including Linux. This could win out in the end who knows.
I have been really busy this week just delving into all them and hope to start making more cool and useful projects in them. The best part is right now is great to be an interactive or game developer as all major software companies and markets are focused on retaining good developers. I don’t’ recall a time other than the beginning the the web virtual land rush that has so many options and markets that skilled developers and designers can choose from. Good times.
Recently two compact tweening engines have been released. Grant Skinner’s GTweeny and laborat’s ByteTween. This adds to the two that focus on micro-tween kit sizes in TweenLite and TweensyZero
Basically these engines look to be micro and provide pretty nice features while being so small. Micro tweening engines like GTweeny (3k), ByteTween (1.7k), TweenLite (2.7k), TweensyZero (2.9k) and Tweener (9k) have varying levels of support of features (Tweener being the most loaded with color and filter support without other kits just init, also TweenLite with a nice configurator to include only what you need). Micro kits have benefits when used for banners, animated assets (where you have many assets and the per asset savings is worthwhile) and other places you just want really small output.
SPEED – I’m not aware of any popular tweening engine with a similar feature set that’s as fast as TweenLite. See the speed comparisons yourself.
Feature set – In addition to tweening ANY numeric property of ANY object, TweenLite can tween filters, hex colors, volume, tint, saturation, contrast, frames, and even do bezier tweening, plus LOTS more. TweenMax extends TweenLite and adds even more capabilities like pause/resume, rounding, event listeners, timeScale, and more. Overwrite management is an important consideration for a tweening engine as well which is another area where the GreenSock tweening platform shines. You have options for AUTO overwriting or you can manually define how each tween will handle overlapping tweens of the same object.
Expandability – With its new plugin architecture, you can activate as many (or as few) features as your project requires. Or write your own plugin if you need a feature that’s unavailable. Minimize bloat, and maximize performance.
Management features – TweenGroup makes it surprisingly simple to create complex sequences and groups of TweenLite/Max tweens that you can pause(), resume(), restart(), or reverse(). You can even tween a TweenGroup’s “progress” property to fastforward or rewind the entire group/sequence.
Ease of use – Designers and Developers alike rave about how intuitive the GreenSock tweening platform is.
Updates – Frequent updates and feature additions make the GreenSock tweening platform reliable and robust.
AS2 and AS3 – Most other engines are only developed for AS2 or AS3 but not both.
gTweeny is gTween’s lightweight younger sibling. It strips a lot of the secondary features of GTween (proxy, timing modes, etc) in favour of smaller file size. It is currently under 3kb…
The decision on which to use can be affected be features you want, how it feels (many use the same object syntax so it is dynamic), what performance do they have (all are orders of magnitude faster than the built in tween (flash) or transitions (mx/flex)), which size is ok, author/community support needed (some are more active than others adding features or simplifying and tweaking performance methodically), and many other factors. There are definitely plenty to choose from.
Nicolas Cannasse is at it again. This time with a PBJ (Pixel Bender File) binary file reader and writer in haXe and Pixel Bender Assembler tools. What this can do is create and decompile PBJ files with haXe, the possibilities are limitless to how this is used including dynamic pbj file creation.
The latest haXefile format library contains complete support to read and write PBJ file, enabling you to write Pixel Bender assembler directly in haXe, then compile it on-the-fly into PBJ bytes, which can then be saved on disk or loaded directly in Flash.
Augmented reality is a very cool technology. It is the star wars holograms that we always want, it is playing a game that maps out the physical world mixed with virtual assets, it is straight up cool.
The FLARToolKit is doing some of this cool in Flash. This little toolkit is pretty sweet mapping points and sets of points to patterns, colors or other visual queues that technology can latch onto. Combine this with a webcam and you have some pretty cool AR.
Be sure to check out the shadow demo that this is based on:
After posting my shadow experiment, Patrick Matte posed a question wondering if I would be able to do real-time reflections in a similar manner. The next day I had it done, along with some nice iterations along the way: orthographic and perspective projection (I can release those later if anyone really wants them). I’ve been sitting on it every since and finally decided I would take the time to write a little description into how its done and give the code to those who are interested (and I fixed up some code for backface culling in the reflection this morning).
The SWFZ engine is one Flash 3D engine that took a different approach. It is a bit early in its technique used but the author at custom:media Jono has decided to float the source code out there in ghost mode (no active development but not dead). It is just ready to branch and others to run with it. He is floating the source but I think in 1-2 years this will be the preferred method if processors and multicore parallel usage is optimized. We shall see.
The implementation method and difference with SWFZ engine in Flash for 3d is that is is a pixel based renderer or scanline. It is based on a really fun game engine called Irrlicht which has been pretty active for the last few years but is a C++ DirectX and OpenGL engine. Since SWFZ has to run in Flash and it is a pixel renderer/scanline it has some limitations currently in Flash. Games and renders have to be fast to pull this off and Flash is limited by the software renderer but as computers get multiple processors and flash player gets better at this then this will be a viable option (it is the same thing that limits Canvas based renderers right now). One main problem with this is you can’t go too full screen the biggest sizes that perform well are smaller windows 320×240 etc. But if the processors can handle it it is actually more efficient when it removes overlap, extra triangle drawing and painters algorithm like problems dont’ pop up (triangle overlap when on same plane). This method draws pixel by pixel but fast enough flash engines like Papervision, Sandy3D and Away3D draw overlaps due to the drawing technique, back to front.
But SWFZ still manages to pull off some amazing feats such as these demos
Jono has put some great classes into SWFZ engine such as bsp parsers, quake md2 parsers, animated mesh, and lots of great examples in porting C++ Irrlicht to AS3. This was a very early example of how AS3 was fun for programmers to port stuff from C or C++ into Flash. AS3 is just fun. Also be sure to check the site for more samples like an FPS game, some basic ai etc.
SWFZ engine is the result of four years of me messing with 3D in Flash.
I was a complete newbie to 3D, so a lot of learning has happened to get to here.
If you’re interested in 3D engines check out the resource links at the bottom of the page:
The Demo:
Model
.md2 format from ID’s Quake2.
Uses frame based animation
Textured with jpeg
No lighting, No Gouraud Shading, just plain texture
Skybox
Textures are just jpegs.
Boxes
Rendering – Textured Gouraud , Textured Gouraud with Alpha, Textured Gouraud with Quick Alpha, Gouraud Shaded, and the large box is just Textured.
Star Texture – Targa (.tga) file format.
AS3 classes
171 classes and interfaces
Scene
No lighting
No collision detection
SWFZ engine technology:
The demo only shows a small part of the capabilities of the engine. In the coming weeks I will get www.custommedia.co.nz up and running and start to post more info then.
Currently implement stuff:
New file formats supported
.tga – Targa Image
.bmp – Bitmap Image
.3ds – 3D Studio Max
.bsp – Quake3 levels
.md2 – Quake2 models
.obj – Wavefront 3d object (static)
.zip – Read from a zip archive (all in Flash, no server side scripts)
3D Rendering
mipmaps
perspective correct texturing + affine texturing
Flat shading
Gouraud
Textured Gouraud
Textured Flat
Textured Two Layers
Gouraud Alpha
Textured Flat Alpha
Textured Gouraud Alpha
3D Scene
Billboards
Parent, Child scene nodes
OctTree
Skybox
Static Meshes
Animated Meshes
Basic collision detection
Scene node animators
If any code is useful to you maybe drop him a donation or what would be nice if this was all setup at google code and used to be integrated into other engines. Irrlicht ports are fun and there is a future in this method when processors catch up I think.
I have been one upped by mr. doob! I did a little nascar like RC pro am like prototype in march ‘07 when the pv3d kit showed up on my screen and I was hooked like most suceptible flashers who have longed for 3d in flash! Only my version is like Nintendo64 and his is like xbox360 with updated effects and physics kits and some doob magic. All these are based off of, of course the original race car driver in Papervision and its creator Carlos Ulloa (Adobe should be paying this man).
Now I don’t’ particularly like Nascar all that much but who doesn’t like to peel out to some fiddlin’? I mainly do Nascar stuff because it is highly marketable and like the only answer most ad agencies have for getting the southern us markets it seems, that and c-o-u-n-t-r-y mu-si-c (must be said at a slower rate).
But I digress, this is a perfect mix of advertisment, game play, fun and experience. It is fast, simple, and playable. Exactly the simplicity and smoothness needed of gameplay and playback. Great ad work but it also gives something fun to do and best of all it is built in AS3 flash with a plethora of libraries from the flash as3 community.
The game platform is emerging fantastically in the AS3 market. mrdoob used these kits to build this:
It would be cool to see a post on how he did the replays with tweener – I imagine just a series of points collected with car state (current position state) and then just play them back with a call back or time delay. You’d have to capture alot for smooth playback without laggy movements. I am working on multiplayer games with this same issue for a current project.
Game on! The question is when will this be SOTD or SOTM at thefwa.com?
Real-time pixel manipulation in flash is getting faster, but is still probably going to have to be faked in AS3, maybe AS4 will provide us per pixel speeds that Andre Michelle has been harping on since flash 8.5. Native operations can be much faster in that area. AIF might look to change some of that but that is Flash 10.
Here is the code for the as3 raytracer. Read more at laserpirate.
package{import flash.display.Sprite;import flash.display.Bitmap;import flash.display.BitmapData;import flash.events.Event;import flash.utils.getTimer;import flash.events.MouseEvent;import flash.text.TextField;import flash.text.TextFormat;publicclass RayTracer extends Sprite
{privatevar t:Number;privatevar dt:Number = .01;privatevar frameTimeTxt:TextField;public static const BUFFER_WIDTH:int =160;public static const BUFFER_HEIGHT:int =120;public static const BUFFER_SCALEDDOWN:int = 320 / BUFFER_WIDTH;public static const HALF_BUFFER_WIDTH:int = BUFFER_WIDTH /2;public static const HALF_BUFFER_HEIGHT:int = BUFFER_HEIGHT /2;privatevar outputBitmapData:BitmapData;privatevar outputBitmap:Bitmap;publicvar FOV:Number =20;publicvar sphereCenterX:Array =[0, 0, 0, 0];publicvar sphereCenterY:Array =[0,-.2, .4, 100.5];publicvar sphereCenterZ:Array =[4, 4, 4, 10];publicvar sphereRadius:Array =[.35, .35, .25, 100];publicvar sphereR:Array =[255, 0, 0, 20];publicvar sphereG:Array =[0, 150, 0, 20];publicvar sphereB:Array =[0, 0, 255, 20];publicvar sphereReflects:Array =[false,false,false,true];publicvar sphereReflectiveness:Array =[0,0,0,.3];publicvar sphere2dX:Array =new Array(sphereCenterX.length);publicvar sphere2dY:Array =new Array(sphereCenterX.length);publicvar sphere2dR:Array =new Array(sphereCenterX.length);publicvar numSpheres = sphereCenterX.length;var skyR:int =20;var skyG:int =20;var skyB:int =20;var skyColor:int =(skyR<<16)+(skyG<<8)+ skyB;var ambientIllumination:Number = .1;var canvas:BlankClip;var theta:Number =0;var mouseIsDown:Boolean =false;var mouseDownTheta:Number =0;var mouseDownX:Number =0;publicfunction RayTracer(){
outputBitmapData =new BitmapData(BUFFER_WIDTH, BUFFER_HEIGHT,false);
outputBitmap =new Bitmap(outputBitmapData);
addChild(outputBitmap);//outputBitmap.smoothing = true;
outputBitmap.width=320;
outputBitmap.height=240;
canvas =new BlankClip;
addChild(canvas);
canvas.buttonMode=true;
canvas.useHandCursor=true;
frameTimeTxt =new TextField();
frameTimeTxt.defaultTextFormat=new TextFormat("Arial");
frameTimeTxt.x=8;
frameTimeTxt.y=8;
frameTimeTxt.width=640;
frameTimeTxt.textColor= 0xFFFFFF;
frameTimeTxt.selectable=false;
addChild(frameTimeTxt);
t =0;
addEventListener(Event.ENTER_FRAME, update,false, 0,true);
canvas.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
canvas.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);}publicfunction mouseDownHandler(e:*):void{
mouseIsDown =true;
mouseDownX = stage.mouseX;
mouseDownTheta = theta;}publicfunction mouseUpHandler(e:*):void{
mouseIsDown =false;}publicfunction update(e:*){// start frame timer and update global timevar timer:Number = getTimer();
t += dt;// handle mouse rotationif( mouseIsDown ) theta = mouseDownTheta - .0015 *(stage.mouseX- mouseDownX);
theta += dt;// do some funky animation
sphereCenterX[0]= .5*Math.sin(theta*5);
sphereCenterZ[0]=1 + .5*Math.cos(theta*5);
sphereCenterX[1]= .5*Math.sin(theta*5 + 2 * Math.PI/ 3);
sphereCenterZ[1]= 1 + .5*Math.cos(theta*5 + 2 * Math.PI/ 3);
sphereCenterX[2]= .5*Math.sin(theta*5 + 4 * Math.PI/ 3);
sphereCenterZ[2]= 1 + .5*Math.cos(theta*5 + 4 * Math.PI/ 3);// reused variablesvar x:int;var y:int;var i:int;var j:int;var r:int;var g:int;var b:int;var dx:Number;var dy:Number;var rayDirX:Number;var rayDirY:Number;var rayDirZ:Number;var rayDirMag:Number;var reflectRayDirX:Number;var reflectRayDirY:Number;var reflectRayDirZ:Number;var intersectionX:Number;var intersectionY:Number;var intersectionZ:Number;var reflectIntersectionX:Number;var reflectIntersectionY:Number;var reflectIntersectionZ:Number;var rayToSphereCenterX:Number;var rayToSphereCenterY:Number;var rayToSphereCenterZ:Number;var lengthRTSC2:Number;var closestApproach:Number;var halfCord2:Number;var dist:Number;var normalX:Number;var normalY:Number;var normalZ:Number;var normalMag:Number;var illumination:Number;var reflectIllumination:Number;var reflectR:Number;var reflectG:Number;var reflectB:Number;// setup light dirvar lightDirX:Number = .3;var lightDirY:Number =-1;var lightDirZ:Number =-.5;var lightDirMag:Number = 1/Math.sqrt(lightDirX*lightDirX +lightDirY*lightDirY +lightDirZ*lightDirZ);
lightDirX *= lightDirMag;
lightDirY *= lightDirMag;
lightDirZ *= lightDirMag;// vars used to in intersection testsvar closestIntersectionDist:Number;var closestSphereIndex:int;var reflectClosestSphereIndex:int;// compute screen space bounding circles//canvas.graphics.clear();//canvas.graphics.lineStyle(1, 0xFF0000, .25);for(i =0; i < numSpheres;++i){
sphere2dX[i]=(BUFFER_WIDTH / 2 + FOV * sphereCenterX[i] / sphereCenterZ[i]);
sphere2dY[i]=(BUFFER_HEIGHT /2 + FOV * sphereCenterY[i] / sphereCenterZ[i]);
sphere2dR[i]=(3 * FOV * sphereRadius[i]/ sphereCenterZ[i]);//canvas.graphics.drawCircle(sphere2dX[i]*BUFFER_SCALEDDOWN, sphere2dY[i]*BUFFER_SCALEDDOWN, sphere2dR[i]*BUFFER_SCALEDDOWN);
sphere2dR[i]*= sphere2dR[i];// store the squared value}// write to each pixel
outputBitmapData.lock();for(y =0; y < BUFFER_HEIGHT;++y){for(x =0; x < BUFFER_WIDTH;++x){// compute ray direction
rayDirX = x - HALF_BUFFER_WIDTH;
rayDirY = y - HALF_BUFFER_HEIGHT;
rayDirZ = FOV;
rayDirMag = 1/Math.sqrt(rayDirX * rayDirX + rayDirY * rayDirY +rayDirZ * rayDirZ);
rayDirX *= rayDirMag;
rayDirY *= rayDirMag;
rayDirZ *= rayDirMag;/// trace the primary ray ///
closestIntersectionDist = Number.POSITIVE_INFINITY;
closestSphereIndex =-1
for(i =0; i < numSpheres;++i){// check against screen space bounding circle
dx = x - sphere2dX[i];
dy = y - sphere2dY[i];if( dx * dx + dy * dy > sphere2dR[i])continue;// begin actual ray tracing if its inside the bounding circle
lengthRTSC2 = sphereCenterX[i]* sphereCenterX[i]+
sphereCenterY[i]* sphereCenterY[i]+
sphereCenterZ[i]* sphereCenterZ[i];
closestApproach = sphereCenterX[i]* rayDirX +
sphereCenterY[i]* rayDirY +
sphereCenterZ[i]* rayDirZ;if( closestApproach <0)// intersection behind the origincontinue;
halfCord2 = sphereRadius[i]* sphereRadius[i]- lengthRTSC2 +(closestApproach * closestApproach);if( halfCord2 <0)// ray misses the spherecontinue;// ray hits the sphere
dist = closestApproach - Math.sqrt(halfCord2);if( dist < closestIntersectionDist ){
closestIntersectionDist = dist;
closestSphereIndex=i;}}/// end of trace primary ray ///// primary ray doesn't hit anythingif( closestSphereIndex ==- 1){
outputBitmapData.setPixel(x, y, skyColor);}else// primary ray hits a sphere.. calculate shading, shadow and reflection{// location of ray-sphere intersection
intersectionX = rayDirX * closestIntersectionDist;
intersectionY = rayDirY * closestIntersectionDist;
intersectionZ = rayDirZ * closestIntersectionDist;// sphere normal at intersection point
normalX = intersectionX - sphereCenterX[closestSphereIndex];
normalY = intersectionY - sphereCenterY[closestSphereIndex];
normalZ = intersectionZ - sphereCenterZ[closestSphereIndex];
normalX /= sphereRadius[closestSphereIndex];// could be multiply by precacluated 1/rad
normalY /= sphereRadius[closestSphereIndex];
normalZ /= sphereRadius[closestSphereIndex];// diffuse illumination coef
illumination = normalX * lightDirX +
normalY * lightDirY +
normalZ * lightDirZ;if( illumination < ambientIllumination )
illumination = ambientIllumination;/// trace a shadow ray ///var isInShadow:Boolean =false;for(j =0; j < numSpheres;++j){if( j == closestSphereIndex )continue;
rayToSphereCenterX = sphereCenterX[j]- intersectionX;
rayToSphereCenterY = sphereCenterY[j]- intersectionY;
rayToSphereCenterZ = sphereCenterZ[j]- intersectionZ;
lengthRTSC2 = rayToSphereCenterX * rayToSphereCenterX +
rayToSphereCenterY * rayToSphereCenterY +
rayToSphereCenterZ * rayToSphereCenterZ;
closestApproach = rayToSphereCenterX * lightDirX +
rayToSphereCenterY * lightDirY +
rayToSphereCenterZ * lightDirZ;if( closestApproach <0)// intersection behind the origincontinue;
halfCord2 = sphereRadius[j]* sphereRadius[j]- lengthRTSC2 +(closestApproach * closestApproach);if( halfCord2 <0)// ray misses the spherecontinue;
isInShadow =true;break;}/// end of shadow ray ///if( isInShadow ) illumination *= .5;/// trace reflected ray ///if( sphereReflects[closestSphereIndex]){// calculate reflected ray directionvar reflectCoef:Number = 2 *(rayDirX * normalX + rayDirY * normalY + rayDirZ * normalZ);
reflectRayDirX = rayDirX - normalX * reflectCoef;
reflectRayDirY = rayDirY - normalY * reflectCoef;
reflectRayDirZ = rayDirZ - normalZ * reflectCoef;
closestIntersectionDist = Number.POSITIVE_INFINITY;
reflectClosestSphereIndex =-1
for(j =0; j < numSpheres;++j){if( j == closestSphereIndex )continue;
rayToSphereCenterX = sphereCenterX[j]- intersectionX;
rayToSphereCenterY = sphereCenterY[j]- intersectionY;
rayToSphereCenterZ = sphereCenterZ[j]- intersectionZ;
lengthRTSC2 = rayToSphereCenterX * rayToSphereCenterX +
rayToSphereCenterY * rayToSphereCenterY +
rayToSphereCenterZ * rayToSphereCenterZ;
closestApproach = rayToSphereCenterX * reflectRayDirX +
rayToSphereCenterY * reflectRayDirY +
rayToSphereCenterZ * reflectRayDirZ;if( closestApproach <0)// intersection behind the origincontinue;
halfCord2 = sphereRadius[j]* sphereRadius[j]- lengthRTSC2 +(closestApproach * closestApproach);if( halfCord2 <0)// ray misses the spherecontinue;// ray hits the sphere
dist = closestApproach - Math.sqrt(halfCord2);if( dist < closestIntersectionDist ){
closestIntersectionDist = dist;
reflectClosestSphereIndex=j;}}// end loop through spheres for reflect rayif( reflectClosestSphereIndex ==-1)// reflected ray misses{
r = sphereR[closestSphereIndex]* illumination;
g = sphereG[closestSphereIndex]* illumination;
b = sphereB[closestSphereIndex]* illumination;}else{//trace("ref hit");// location of ray-sphere intersection
reflectIntersectionX = reflectRayDirX * closestIntersectionDist + intersectionX;
reflectIntersectionY = reflectRayDirY * closestIntersectionDist + intersectionY;
reflectIntersectionZ = reflectRayDirZ * closestIntersectionDist + intersectionZ;// sphere normal at intersection point
normalX = reflectIntersectionX - sphereCenterX[reflectClosestSphereIndex];
normalY = reflectIntersectionY - sphereCenterY[reflectClosestSphereIndex];
normalZ = reflectIntersectionZ - sphereCenterZ[reflectClosestSphereIndex];
normalX /= sphereRadius[reflectClosestSphereIndex];// could be multiply by precacluated 1/rad
normalY /= sphereRadius[reflectClosestSphereIndex];
normalZ /= sphereRadius[reflectClosestSphereIndex];// diffuse illumination coef
reflectIllumination = normalX * lightDirX +
normalY * lightDirY +
normalZ * lightDirZ;if( reflectIllumination < ambientIllumination )
reflectIllumination = ambientIllumination;
r = sphereR[closestSphereIndex]* illumination + .5 * sphereR[reflectClosestSphereIndex]* reflectIllumination;
g = sphereG[closestSphereIndex]* illumination + .5 * sphereG[reflectClosestSphereIndex]* reflectIllumination;
b = sphereB[closestSphereIndex]* illumination + .5 * sphereB[reflectClosestSphereIndex]* reflectIllumination;if( r > 255 ) r =255;if( g > 255 ) g =255;if( b > 255 ) b =255;}// end if reflected ray hits}/// end if reflectselse// primary ray doesn't reflect{
r = sphereR[closestSphereIndex]* illumination;
g = sphereG[closestSphereIndex]* illumination;
b = sphereB[closestSphereIndex]* illumination;}
outputBitmapData.setPixel(x, y,(r<<16)+(g<<8)+ b);}// end if primary ray hit}// end x loop}// end y loop
outputBitmapData.unlock();// compute FPSvar fps:Number = 1.0/((getTimer()- timer)/ 1000.0);
frameTimeTxt.text="Drag to rotate. FPS: "+ int(fps);}}}