Sep/080
3D Engine V0.52
Made a huge leap forward the last few weeks, this version of the engine is actually quite usefull and easy for most simple 3D things. But I’m not quite ready to release source code yet there are still a few things to do, to make it more of a complete engine. Below is a demo of what it is capable of right now;
Bugfixes:
- Altered the 3D camera translation function to something that also works when looking down on an object.
Known bugs:
- The triangular polygons are now textured with only two triangles, this can still be increased…
- Focal point singularity, some 3D points that are in the focal point of the camera move to an infinite distance.
- Some polygons are incorrectly culled.
New features:
- Added a cylinder primitive
- Added a cone primitive
- Added UV mapping for all primitves; cube, sphere, cylinder and cone
- Added 3D lighting, for the moment it will support multiple light entities with only white light
- Added ambient lighting
- Added 3D surface normals
- Added colouring and texturing support for triangular polygons
Upcoming features:
- View frustum culling
- Performance increase
- Directional light and light with different colours
- Roll camera movement
- Object rotation
- Texture perspective correction
- 3D particles!
Maybe phong shading will also be possible one day with gradients but it’s not uber important. And I thought about doing shadows with the new bitmapfilter api, but that is all still very experimental. What matters the most at the moment is creating a finished version of which I will release all the source code for free. Soon I will also post about the inner workings of a 3D engine, something that I couldn’t find (as in all info being on one page) on the interwebs.
Sep/0815
Creating a PHP socket server
Socket server’s are great things for creating multiuse applications. Sockets are the most basic and thus efficient and quickest way for web applications Java, Flash, PHP, etc. to exchange data with eachother. With this you can create online multiplayer games, chat applications, mail and web servers, etc. Basically the only thing holding you back is your imagination. Most web dev’s however, don’t know how to create or use one. Well I found a way of creating a socket server with PHP. There’s not a lot of info about this on the web, but it is contrary to what many think a legal, possible and quite reliable use of PHP. It is actually even covered on the Zend Developer Zone. The code below is mainly based on that tutorial, but this one actually works in PHP5 and has been debugged a little further.
You will need three things for doing this tutorial;
- a PHP server enviroment at hand, because you will need to use your command line interface (don’t get affraid now, it’s easier than making web-apps)
- a way of creating PHP scripts; notepad, dreamweaver, etc.
- (if you want your socket server to run online) a free internet connected socket, which can pass through router, firewall, and is not beeing used by any other programs.
This is the debugged code, explanation is mainly in the comments and below;
<?php
// PHP SOCKET SERVER
error_reporting(E_ERROR);
// Configuration variables
$host = "127.0.0.1";
$port = 4041;
$max = 20;
$client = array();
// No timeouts, flush content immediatly
set_time_limit(0);
ob_implicit_flush();
// Server functions
function rLog($msg){
$msg = "[".date('Y-m-d H:i:s')."] ".$msg;
print($msg."\n");
}
// Create socket
$sock = socket_create(AF_INET,SOCK_STREAM,0) or die("[".date('Y-m-d H:i:s')."] Could not create socket\n");
// Bind to socket
socket_bind($sock,$host,$port) or die("[".date('Y-m-d H:i:s')."] Could not bind to socket\n");
// Start listening
socket_listen($sock) or die("[".date('Y-m-d H:i:s')."] Could not set up socket listener\n");
rLog("Server started at ".$host.":".$port);
// Server loop
while(true){
socket_set_block($sock);
// Setup clients listen socket for reading
$read[0] = $sock;
for($i = 0;$i<$max;$i++){
if($client[$i]['sock'] != null)
$read[$i+1] = $client[$i]['sock'];
}
// Set up a blocking call to socket_select()
$ready = socket_select($read,$write = NULL, $except = NULL, $tv_sec = NULL);
// If a new connection is being made add it to the clients array
if(in_array($sock,$read)){
for($i = 0;$i<$max;$i++){
if($client[$i]['sock']==null){
if(($client[$i]['sock'] = socket_accept($sock))<0){
rLog("socket_accept() failed: ".socket_strerror($client[$i]['sock']));
}else{
rLog("Client #".$i." connected");
}
break;
}elseif($i == $max - 1){
rLog("Too many clients");
}
}
if(--$ready <= 0)
continue;
}
for($i=0;$i<$max;$i++){
if(in_array($client[$i]['sock'],$read)){
$input = socket_read($client[$i]['sock'],1024);
if($input==null){
unset($client[$i]);
}
$n = trim($input);
$com = split(" ",$n);
if($n=="EXIT"){
if($client[$i]['sock']!=null){
// Disconnect requested
socket_close($client[$i]['sock']);
unset($client[$i]['sock']);
rLog("Disconnected(2) client #".$i);
for($p=0;$p<count($client);$p++){
socket_write($client[$p]['sock'],"DISC ".$i.chr(0));
}
if($i == $adm){
$adm = -1;
}
}
}elseif($n=="TERM"){
// Server termination requested
socket_close($sock);
rLog("Terminated server (requested by client #".$i.")");
exit();
}elseif($input){
// Strip whitespaces and write back to user
// Respond to commands
/*$output = ereg_replace("[ \t\n\r]","",$input).chr(0);
socket_write($client[$i]['sock'],$output);*/
if($n=="PING"){
socket_write($client[$i]['sock'],"PONG".chr(0));
}
if($n=="<policy-file-request/>"){
rLog("Client #".$i." requested a policy file...");
$cdmp="<?xml version=\"1.0\" encoding=\"UTF-8\"?><cross-domain-policy xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"http://www.adobe.com/xml/schemas/PolicyFileSocket.xsd\"><allow-access-from domain=\"*\" to-ports=\"*\" secure=\"false\" /><site-control permitted-cross-domain-policies=\"master-only\" /></cross-domain-policy>";
socket_write($client[$i]['sock'],$cdmp.chr(0));
socket_close($client[$i]['sock']);
unset($client[$i]);
$cdmp="";
}
}
}else{
//if($client[$i]['sock']!=null){
// Close the socket
//socket_close($client[$i]['sock']);
//unset($client[$i]);
//rLog("Disconnected(1) client #".$i);
//}
}
}
}
// Close the master sockets
socket_close($sock);
?>
Basically this is a functioning socket server (execute it via PHPs CLI) but to actually do something with it requires some minor modifications. One easy modification you can do, is create a command to send a message to all other clients;
...if($n=="PING"){
socket_write($client[$i]['sock'],"PONG".chr(0));
}
You can already use this script with Flash, but only locally. I will soon write how to properly prepare this server for Flash (e.g. make it send policy files) and how to use it with flash. And for those who cannot wait for another post please remember that you cannot test your ‘internet’ (so not local) connecting flash client on the same PC as your PHP server.
Aug/080
3D Engine V0.3
Made quite some progress lately. Got the constructSphere function up quite quickly, the UV mapping and copyPixels took a little longer but in the end really paid off:
Currently the UV mapping only works with spheres, but it will be easy to implement it into other models later. I’m quite pleased already with the performance; the demo above renders 529 polygons with a high resolution texture (1350×675 pixels). However there is still room for lots of improvement;
Bugfixes:
- Added function moveObject, wich if drawing faces should be used instead of moveGroup. (Otherwise the midPoints don’t move and thus making the z-sorting work incorrectly.)
- Reversed the y transformation in the process of making 2D points from 3D coordinates, because in the flash coordinate system the y axis is reversed
Known bugs:
- For some reason transparent bitmaps don’t work yet, I’ll have to look into the different copyPixels and beginBitmapFill functions for this one…
- For some reason looking down from above gives a distorted and unreallistic view, I’m not sure where this problem came from.
- Faces that have one, two or three points behind the camera are rendered ackwardly, but this will be fixed in the next version with view frustum culling.
- The backface culling function is not perfect yet, the top of the sphere shows about 3 faces beeing culled that shouldn’t be culled.
- The edges of UV faces are visible sometimes, this is due to the repeat parameter I use to create parts of the bitmap fill might be able to fix this with a bit of a different matrix algorithm.
New features:
- Textures from images
- The function moveObject to move objects
- A debug mode
- The sphere primitive
- UV mapping for spheres
- Backface culling
Upcoming features:
- Phong shading
- More primitives
- View frustum culling
- Lighting and shadows
- Performance improvements
- Rotate object functions
- And a few more…
The navigation is still somewhat ackward for the sake of simplicity;
- W,S let you move along the z-axis
- A,D let you move along the x-axis
- Numpad 2 and 8 let you move along the y-axis
- Left and right arrow keys let you rotate left and right
- Up and down arrow keys let you rotate up and down
Thanks to Senocular and Lifeztream for these two classes;
Senocular’s keyObject class – for detecting multiple keyboard presses at once
Lifeztream’s FPS class – for displaying the 3D engine performance
Aug/084
DIY: Build your own 3D theatre
We all dream of it; when will we have our own 3D display in our home? Allthough I’m not fond of 3D displays with glasses, this one is definitly worth a mention. Over at WIRED magazine’s website (definitly worth watching) is a nice tutorial on creating your own 3D display. It uses 2 flatpanels, a half reflective, half transparent mirror and some woodwork.
I do wonder how you’re going to be sure you got the right polarisation, but maybe it’s standard for all polarised glasses and I think the top monitors polarisation is flipped or something by the mirror. And maybe you need a more transparent mirror to get less grey shade. Apart from that it is a great and cost effective way to get a cool 3D display.
Aug/080
Queue loader items in an AS3 class
I wrote a class lately to queue loader items in AS3. I use it to load textures for my 3D engine but you can use it without modification for the loading of other files. The class is very simple, and doesn’t give any information about the loading progress apart from when it finishes loading all files. The class comes in handy when trying to load multiple files and have one event listener when all files are loaded. Below an example of the implementation:
[sourcecode language='actionscript']import qLoader; // You can change the package to for example com.input.qLoader;
var loader:qLoader = new qLoader();
// You can add relative file locations, but SWF’s online will likely
// only accept url’s on the same domain.
// You can activate debug traces by enabling the debug mode once the
// class has been created by uncommenting the following line:
// loader.mDebug = true;
loader.addLoad(”textures/stone.jpg”);
loader.addLoad(”textures/stone2.jpg”);
loader.addLoad(”textures/stone3.jpg”);
loader.addLoad(”textures/stone4.jpg”);
loader.addLoad(”textures/stone5.jpg”);
loader.addEventListener(”completeQ”,onLoaded);
// Initiate the loader
loader.initiate();
function onLoaded(evt:Event):void {
// In this example I create a bitmapData object
var bm:BitmapData = new BitmapData(loader.mFinishedItems["textures/stone.jpg"].width,loader.mFinishedItems["textures/stone.jpg"].height,false);
bm.draw(loader.mFinishedItems["textures/stone.jpg"],new Matrix());
}[/sourcecode]
The class needs to be an extension on the EventDispatcher class to work (otherwise it cannot dispatch events). I might update the class with progress info (like 100/4555Kb) or something and the loadNext() and loadItems() functions are the same but I’m too lazy for that now.
Aug/083
Bitmap skewing class
Finally, after two days of trial and error, I got my bitmap skewing class working. The class is based upon Flash and Math’s work, especially the algorithm for ‘triangulating’ (I know this is not the right word) distorted quadrilaterals. The class is quite complete there might be another function for simply rendering textures onto triangles instead of quadrilaterals. See the class in action below, adjust the “AA” level (I know it’s not really the same, but couldn’t think of a nicer term) to increase or decrease the level of precision. The higher the AA level the better it looks. Lower AA levels increase performance. The same counts for the noise reduction, which decreases the performance when turned on.
Download the skew.as class
The usage is fairly simple;
[sourcecode language='actionscript']import com.skew;
// First boolean is for noise reduction the second for debug mode
var sk:skew = new skew(false,false);
// For skews with a greater precision than 1
sk.AASkew(a,b,c,d,bitmap,sp,AAh,AAv);
// For skews with a precision of 1
sk.transformer(a,b,c,d,bitmap,sp,AAh,AAv);
// With a,b,c,d being arrays containing 2 dimensional points e.g. a = [10,10];
// And bitmap being a bitmapData object
// sp being a sprite or shape
// AAh and AAv respectively being the horizontal and vertical “AA” levels[/sourcecode]
The sk.transformer function is quite an increase in performance from the sk.AASkew function because it doesn’t require mapping the non distorted bitmap.
EDIT: Updated the skew class with a better variable name for the smoothing parameter and corrected the skew functions to smooth both halves. Thanks to Banana.
Aug/081
3D Engine V0.2
Added face rendering and a material management system to V0.1, still a lot to do though. I’d like to do more pre calculation, a few classes for the primitives, textures and a lot of performance increase by backface culling, and not calculating items behind you. Demo:
The navigation is still somewhat ackward for the sake of simplicity;
- W,S let you move along the z-axis
- A,D let you move along the x-axis
- Numpad 2 and 8 let you move along the y-axis
- Left and right arrow keys let you rotate left and right
- Up and down arrow keys let you rotate up and down
Thanks to Senocular and Lifeztream for these two classes;
Senocular’s keyObject class – for detecting multiple keyboard presses at once
Lifeztream’s FPS class – for displaying the 3D engine performance
Aug/080
3D Engine V0.1
It is still very much in development but, this version is a big improvement over the proof of concept. Currently it only renders dots. But the entire architecture has been revamped including a geometry storage system and movement. Checkout the demo below;
There is still a lot to do though, most important beeing:
- Face rendering
- Material system
- Bitmap transformations
The navigation is still somewhat ackward for the sake of simplicity;
- W,S let you move along the z-axis
- A,D let you move along the x-axis
- Numpad 2 and 8 let you move along the y-axis
- Left and right arrow keys let you rotate left and right
- Up and down arrow keys let you rotate up and down
I again used these two classes;
Senocular’s keyObject class – for detecting multiple keyboard presses at once
Lifeztream’s FPS class – for displaying the 3D engine performance
Aug/080
Proof of concept: Flexible 2D Particle System
Something very powerfull for creating reallistic and flexible effects is a particle system. This is a flexible and basic particle system I created about 2 months ago. Again this is just a proof of concept, currently the max. number of particles is about 400-500. But this can be greatly increased by removing the blur and replacing it with an image, this would however make it lose some of it’s flexibility. Below is a smoke demo, but the posibilities are endless, steam, fire, explosions to name a few…
Usage is as follows:
[sourcecode language='actionscript']import com.particles.particleSystem;
var scene:particleSystem = new particleSystem();
this.addChild(scene);
scene.pX = 40; // The x-position of the particle’s source
scene.pY = 50; // The y-position of the particle’s source
scene.vY = 0; // The speed on the y axis (can also be negative)
scene.vX = 4; // The speed on the x axis (can also be negative)
scene.deviation = 2; // The possible deviation from the standard speed
scene.transparency = 1; // The transparency of the particles (levels lower than 1 greatly deteriorate the performance
scene.color = 0×000000; // Colour of the particles
scene.lifetime = 5000; // Lifetime of the particles in milliseconds
scene.size = 10; // Size of the particles
scene.maxParticles = 300; // Maximum number of particles
scene.startBlur = 10; // The amount of blur
scene.bExplode = false; // Set this to true if you want to let the particles all explode at once
scene.start();[/sourcecode]
There is still quite some room for improvement, especially getting to know when to stop the particle system is a bit tricky.
Download the Particle System class
Aug/080
Photoshop Express
We all know photoshop is the tool for photo editing and manipulation (right?), now how about a photoshop that is web based, less processor heavy, with lots easier acces to your photos, and still from Adobe? I know what your thinking (it’ll cost a fortune..) but that’s the best part; It’s free! (for now); Try it out!
