Home Page
Projects > 3D Engines
Search:
3D Engines Thumbnail
3D Engines v1.0
Completed
Basic software 3D polygonal rendering engines for a single mesh in: Flash, C++, Java, and then in D3D w/ C++.
Rating: 7 (Was just a little speed testing experiment)
Project Time: 8/7/2005-8/9/2005: 6
Languages: C++, Java, Flash, Direct3D
Requirements: Example-specific dependencies
Downloads: Binary Source (See any updates below for prior versions)
Sections: Information, Content, Concepts, Notes, Updates, Comments
Information
This was an experiment to get some solid performance numbers from computationally expensive processes written in different languages.
Content
General Information:

The speed results were pretty much what I expected, with Java and Flash being what they are (interpreted languages). The basic code was ported to each language then rewritten for optimized speed in that language. Whenever I talk about computer languages in this project, I am generally only referring to C/C++, Java, and Flash.


All of the engines (except the DirectX (Direct3D [D3D]) version) are done through software and have no polygon sorting, so those graphical glitches are intentional. All of the engines except the Flash version have options you can toggle through keyboard shortcuts that are displayed in the title along with the FPS. The possible shortcut keys are as follows:

  • w: Wireframe - Toggle wireframe display
  • p: Polygon - Toggle filled polygons
  • b: Backface Culling - Toggle backface culling (backwards facing polygons are not displayed), not available in C++ DirectX version as it is inherent. Turning on backface culling should always increase the FPS.
  • s: Software mode - Toggle software mode (Non software [hardware] mode runs through the graphics card and should be, for obvious reasons, the fastest), only available in C++ DirectX version.
Other information in the title section (non toggle options)
  • #: The number of polygons (faces) being drawn
  • FPS: Frames per second (a metric for graphical rendering speed). Metrics on this project page are taken from a laptop with a Intel Duo Core T2500 2.0GHZ CPU and 2GB of RAM with graphics windows at 640x480 in size with only wireframe on and no back culling, unless noted otherwise.

Different Version Information:
  • Wireframe and polygon drawing are done in separate passes, so having only one turned on increases FPS.
  • This is the only version with proper polygon ordering support.
  • It can toggle between DirectX software mode [16-21 fps], which is very slow because it tries to emulate all processes of a graphics card, and hardware mode [660-720 fps] [860-910 fps in poly only mode] which is the fastest by far, as it’s what normal 3D engines are done through.
3D Engines: C++, D3D
C++, Software Rendering:
  • Wireframe and polygon drawing are done in the same pass, so having only one turned on does not increase FPS.
  • This version is the fastest software based version [290-300 fps] [500-630 fps with backface culling], as C++ is a very fast low level language.
  • This version utilizes Pointer Transversing.
3D Engines: C++, Software
Java, Software Rendering:
  • Wireframe and polygon drawing are done in separate passes, so having only one turned on increases FPS.
  • The FPS wasn’t nearly as bad as I expected for Java [200-210 fps] until I turned on filled polygons [74 fps]. In this case the wireframe is a better judge of language speed ability, as it’s the Java libraries slowing things down during polygon filling, and libraries do not denote a languages abilities (though they often denote their worth in many peoples opinions).
  • This version utilizes Local variables, Precalculating index lookups, and Loop unrolling.
  • There might be a bug in the backface culling in this one... but it’s hard to tell... meh
  • Please note you have to click the applet to access the keyboard shortcut toggle options.
  • Many extra options for the applet are passed through the HTML interface. The model (InputFile) needs to be a HTTP URL where the model can be loaded from (currently set to my domain). This is needed due to certain Java security permissions... and it still may not load the mesh file anyways because of security stuff... darn Java
See live version here
3D Engines: Java, Software
Flash, Software Rendering:
  • Wireframe and polygon drawing are done in the same pass, but with different function calls, so having only one turned on increases FPS.
  • Flash is not meant to be a computing language, so it is SLOW [6 fps].
  • This version utilizes Local variables, Precalculating index lookups, and Loop unrolling.
  • The options for this one, including line thickness, are all available through clicking the buttons at the top. There is no option for backface culling though.
  • I did a further optimization in this one and instead of using an indexed face list pointing to a vertex list, I just stored all the verticies directly into the face list. Poor slow Flash...
See live version here
Wireframe
3D Engines: Flash, Wireframe

Polygons and Wireframe
3D Engines: Flash, Polygons and Wireframe

Single Polygon (120 fps is Flash’s maximum)
3D Engines: Flash, Single Polygon, Polygons and Wireframe

  • Local variable assignment:
    • Copying often looked up variables into a local variable in a high processing intensive function for quicker lookups, usually onto the stack. This can be utilized in any language, but is especially important for Flash, and a little bit less so in Java.
  • Precalculating index lookups:
    • This is most useful in Flash, as other languages try to find and remember indexes for loops, and compiled ones like C++ are especially adept at it since index lookups are now built into CPUs.
    • For example:
      for(a=5;a<10;a++)
      	b[a*3]=6;
      
      could be written as
      for(a=15;a<30;a+=3)
      	b[a]=6;
      
  • Pointer transversing/addition:
    • This is only really possible in C++ as it is one of the now rare languages with pointers. This basically means ignoring index lookups by directly remembering pointers. These days, this is only useful in very specific circumstances, as index lookups are now built into CPUs.
    • For example:
      int *foo=new int[10];
      for(int i=0;i<10;i++)
      	foo[i]=0;
      
      could be written as
      int *foo=new int[10], *tempfoo=foo, *endfoo=foo+10;
      for(;tempfoo<endfoo;tempfoo++)
      	*tempfoo=0;
      
  • Loop unrolling:
    • This means taking out static count for-loops in favor of having the line written out for each loop iteration. This method used to be important for compiled computer languages like C, but modern compilers are pretty good at doing this automatically when they detect it can be used and would be beneficial. This is still very important for interpreted languages however.
    • For example, a matrix multiplying routine written in C++ could look like:
      Matrix* MatrixMultiply(Matrix *MatrixOut, Matrix *Matrix1, Matrix *Matrix2) //Assumes MatrixOut is already zeroed out
      {
      	for(int i=0;i<4;i++)
      		for(int p=0;p<4;p++)
      			for(int s=0;s<4;s++)
      				MatrixOut->m[i][p]+=Matrix1->m[i][s]*Matrix2->m[s][p];
      	return MatrixOut;
      }
      
      While it would look like the following for optimization in Flash:
      function MatrixMatrixMultiply(A, B) {
      	var C = [[], [], [],[]];
      	C[0][0] = A[0][0]*B[0][0]+A[0][1]*B[1][0]+A[0][2]*B[2][0]+A[0][3]*B[3][0];
      	C[0][1] = A[0][0]*B[0][1]+A[0][1]*B[1][1]+A[0][2]*B[2][1]+A[0][3]*B[3][1];
      	C[0][2] = A[0][0]*B[0][2]+A[0][1]*B[1][2]+A[0][2]*B[2][2]+A[0][3]*B[3][2];
      	C[0][3] = A[0][0]*B[0][3]+A[0][1]*B[1][3]+A[0][2]*B[2][3]+A[0][3]*B[3][3];
      	C[1][0] = A[1][0]*B[0][0]+A[1][1]*B[1][0]+A[1][2]*B[2][0]+A[1][3]*B[3][0];
      	C[1][1] = A[1][0]*B[0][1]+A[1][1]*B[1][1]+A[1][2]*B[2][1]+A[1][3]*B[3][1];
      	C[1][2] = A[1][0]*B[0][2]+A[1][1]*B[1][2]+A[1][2]*B[2][2]+A[1][3]*B[3][2];
      	C[1][3] = A[1][0]*B[0][3]+A[1][1]*B[1][3]+A[1][2]*B[2][3]+A[1][3]*B[3][3];
      	C[2][0] = A[2][0]*B[0][0]+A[2][1]*B[1][0]+A[2][2]*B[2][0]+A[2][3]*B[3][0];
      	C[2][1] = A[2][0]*B[0][1]+A[2][1]*B[1][1]+A[2][2]*B[2][1]+A[2][3]*B[3][1];
      	C[2][2] = A[2][0]*B[0][2]+A[2][1]*B[1][2]+A[2][2]*B[2][2]+A[2][3]*B[3][2];
      	C[2][3] = A[2][0]*B[0][3]+A[2][1]*B[1][3]+A[2][2]*B[2][3]+A[2][3]*B[3][3];
      	C[3][0] = A[3][0]*B[0][0]+A[3][1]*B[1][0]+A[3][2]*B[2][0]+A[3][3]*B[3][0];
      	C[3][1] = A[3][0]*B[0][1]+A[3][1]*B[1][1]+A[3][2]*B[2][1]+A[3][3]*B[3][1];
      	C[3][2] = A[3][0]*B[0][2]+A[3][1]*B[1][2]+A[3][2]*B[2][2]+A[3][3]*B[3][2];
      	C[3][3] = A[3][0]*B[0][3]+A[3][1]*B[1][3]+A[3][2]*B[2][3]+A[3][3]*B[3][3];
      	return C;
      }
      

Other Information:
.x files should in the following text format:
  • Number of Verticies[line break]
  • List of verticies
    • XPositionFloat;YPositionFloat;ZPositionFloat[line break]
  • Number of polygons[line break]
  • List of polygons
    • CornerVertexIndex1,CornerVertexIndex2,CornerVertexIndex3[line break]

.b3d files are binary representations of the above x files in the following format:
  • Number of verticies: 2 bytes (WORD)
  • Vertex information: 12 bytes*Number of verticies - Each vertex consists of 3 floats defining x, y, and z position
  • Number of polygons: 2 bytes (WORD)
  • Polygon information: 6 bytes*Number of polygons - Each polygon consists of 3 WORD indexes which point to their corner’s vertex
The .b3d files are created using the Compiled3DToBinary.exe with .x files in a normal DirectX .x mesh format, which is the same as the above .x format except polygon lists are preceded by a “3;”.
The Compiled3DToBinary is a very quick and simplistic hack and not meant to handle files that aren’t in the proper format that it expects. When opened, you type in the (relative) path to a .x file without the “.x” at the end. It then converts the file and saves the new file at the same path, but instead ending in “.b3d”.

The following directories are found in the source code release, each containing a different version of the 3D engine: “CPP_DirectX”, “CPP_Software”, “Flash”, “Java
The “Compiled3DToBinary” directory is used to compile .x files into the .b3d format for the C++ and Java engines. See the above paragraphs for more information.
The “include” directory contains files used in both C++ projects (an FPS counter and the Hyrulean Productions icon).
The “Models” directory contains 3 models: Square.x and Triangle.x, which were both created by myself, and plane.x/plane.b3d. I am unsure where the plane.x file (which the plane.b3d file is created from) comes from, but I did not create it. I think it was part of the DirectX SDK or something.
Concepts
3D Geometry, graphics, cross-language development
Notes
With a little 3D knowledge involving vectors and matrices, true 3D engines can be written in any language. Speeding up these engines however is a little tougher.
Updates
Dakusan License v2.0 @ 2009-11-04 16:06:57 - Download

I have updated the licensing information across the board for my website and all its projects to the Dakusan License v2.0, a slightly modified version of the Original BSD License.

The Copyright page and all project downloads have been updated accordingly.

Added Readme files to all project downloads @ 2009-09-19 05:35:19

Binary and source zip downloads for all Projects now have readme files in them, except as mentioned below.

This only applies to the Draw Image Project in Web Scripts, and not the Directory Manager project (The only project zip file now without a readme).

3D Engines v1.0 @ 2008-08-14 23:22:58 - Download

Version 1.0 of the 3D Engines project has been uploaded, along with source code.

The content section has been written up (it was basically empty before...) and I redid all the screenshots to reflect the updated versions.

Live copies of the Java and Flash versions have also been put online.

Comments
To add comments, please go to the forum page for this project (guest comments are allowed for the Projects, Posts, and Updates Forums).
Comments are owned by the user who posted them. We accept no responsibility for the contents of these comments.

No comments for this Project