Page 1 of 1

3D format conversion

Posted: Fri Aug 22, 2014 5:01 pm
by kubilus1
I wrote a tool that takes wavefront .obj files and converts them into something digestable by SGDK. ...

# python -f afile.obj > meshs.h

This works with a slightly modified cube_flat sample program from SGDK with the following patch:

Code: Select all

Index: main.c
--- main.c      (revision 194)
+++ main.c      (working copy)
@@ -2,7 +2,7 @@

 #include "meshs.h"

-#define MAX_POINTS  256
+#define MAX_POINTS 512

 Vect3D_f16 pts_3D[MAX_POINTS];
@@ -47,7 +47,7 @@


-    BMP_init(TRUE, PAL0, FALSE);
+    BMP_init(TRUE, PAL1, FALSE);

     camdist = FIX16(15);

@@ -99,9 +99,9 @@
 void updatePointsPos()
     // transform 3D point
-    M3D_transform(&transformation, cube_coord, pts_3D, 8);
+    M3D_transform(&transformation, cube_coord, pts_3D, verts);
     // project 3D point (f16) to 2D point (s16)
-    M3D_project_s16(pts_3D, pts_2D, 8);
+    M3D_project_s16(pts_3D, pts_2D, verts);

 void drawPoints(u8 col)
@@ -108,7 +108,7 @@
     if (flatDrawing)
-        Vect2D_s16 v[4];
+        Vect2D_s16 v[3];
         const Vect3D_f16 *norm;
         const u16 *poly_ind;
         u16 i;
@@ -116,7 +116,8 @@
         norm = cube_face_norm;
         poly_ind = cube_poly_ind;
-        i = 6;
+        // # of polygon faces
+        i = faces;
         while (i--)
@@ -124,9 +125,10 @@
             fix16 dp;
             u8 col = 2;

+            // Cycle through number of indices in polygon face
             *pt_dst++ = pts_2D[*poly_ind++];
             *pt_dst++ = pts_2D[*poly_ind++];
-            *pt_dst++ = pts_2D[*poly_ind++];
+            //*pt_dst++ = pts_2D[*poly_ind++];
             *pt_dst = pts_2D[*poly_ind++];

             dp = fix16Mul(transformation.lightInv.x, norm->x) +
@@ -136,8 +138,8 @@

             if (dp > 0) col += (dp >> (FIX16_FRAC_BITS - 2));

-            if (!BMP_isPolygonCulled(v, 4))
-                BMP_drawPolygon(v, 4, col);
+            if (!BMP_isPolygonCulled(v, 3))
+                BMP_drawPolygon(v, 3, col);
@@ -148,9 +150,10 @@

         l.col = col;
         line_ind = cube_line_ind;
+        // Number of lines
+        i = edges;

-        i = 12;
         while (i--)
             l.pt1 = pts_2D[*line_ind++];
Since the wavefront format (and most other 3d formats) specify polygons as a series of triangles, I had to change that.

Here's the current result: ... huttle.bin

Made quickly from

Some things I've noticed:

*Not sure if the culling is working properly. Is this due to me changing the quads to triangles?

*The script reduces duplicate points, but is still less efficient due to the increased number of lines from triangles. Is there a better 3d drawing tool/format to use?

* The Y axis appears to be reversed between the formats.

Posted: Fri Aug 22, 2014 6:17 pm
by Stef
Nice tool ! I would be even better if we could port it to C code so i could include it directly in the rescomp tool :D
I'm not really surprised about the inverted Y axis as i do revert it in SGDK (i want coordinate 0 to be at bottom as in "real life"). For the culling, well it should work (it does work on the cube example), you polygon has to be clockwise defined. As you said, using triangle is definitely not optimal as it requires to calculate more edges... but i don't know if you can specify to keep originals polygons in the OBJ format (SGDK support polygon up to 8 points).

Posted: Fri Aug 22, 2014 7:51 pm
by kubilus1
Ahh, but python works cross platform and is oh so nice to program in!

AFAICT, the format requires triangles, but I'm not an expert in it by any means.

I believe that the format defines coordinates in counter-clockwise fashion. Could that be why the polygon is kind of see-through when I make it solid?

Posted: Fri Aug 22, 2014 11:07 pm
by haroldoop
That's pretty cool. :)

Posted: Sat Aug 23, 2014 10:22 pm
by Stef
kubilus1 wrote:Ahh, but python works cross platform and is oh so nice to program in!
Yeah i know, at least on windows you need to install python.
AFAICT, the format requires triangles, but I'm not an expert in it by any means.

I believe that the format defines coordinates in counter-clockwise fashion. Could that be why the polygon is kind of see-through when I make it solid?
If they are defined in wrong clockwise order, it should display the interior of object instead, which does not appear to be the case here so i'm not sure.

Posted: Tue Sep 02, 2014 10:27 pm
by kubilus1
I've updated the tool (same link) to support more from the Wavefront format. This should now handle files created by more tools (tested with Wings3d) and support polygons with more than three points.

Currently I am not limiting the number of vertices, which I should since the engine is limited to eight.

Here's a replacement main.c file and an example bin:

I've changed the main.c from the cube_flat example enough that it is probably best just to show the entire file. This should now be able to take a converted obj file and display it.

Some issues still:

* Limit to 8 vertices per polygon - I figure I will just split them in half.
* objects that are behind objects should be hidden/not drawn.

For the second point, does anyone have any advice on this? I know the brute force way is to use the painter's algorithm, but I would still need to know the current z-order of the polygons, which could be taxing on the system.

Posted: Wed Sep 03, 2014 8:21 am
by Stef
What is used in SNES Starfox engine (and i replicated in the demo) is the BSP tree structure to store convexe 3D objects, this way you use the BSP tree to navigate in the object faces and draw them in the good order. This way you only need to sort each convexe object on mean Z instead of sorting each face.

Posted: Sat Oct 25, 2014 4:20 pm
by kubilus1
I've made some improvements to the obj2mesh conversion program and the code to run files created with this.

Obj2mesh now supports multiple polygons in the single file and calculates the center of the polygons. Polygons are now represented as a list of polygons that can be accessed for rendering, OR individually by name. ... 2Fobj2mesh

I've created an example using this: ... 3d_example

The binary: ... le/out.bin

This allows a fairly simple way of displaying all polygons by calling the 'render' function. Polygons should properly be placed in the correct order now.

I simply use the taxi-cab method for distance, and use a modification of Stef's quicksort, for order, but instead work on a list of pointers instead of objects directly.

I'm sure there's room for improvement still!

Posted: Sun Nov 16, 2014 5:11 pm
by kubilus1
Another update! Now obj2mesh supports the .mtl files! This allows for colors to be setup in Wings3d or other tools and automatically be loaded.

This uses the diffuse color property (Kd)

I've also updated the lighting so that colors are not wasted. Currently I set aside three colors, black, dark grey, light grey that are used for shading. This leaves 12 useable colors in the palette.

The example is in the same location and shows a multi-colored space ship in a star field.

(I've also renamed things in a slightly more sensible manner.)

Posted: Sat Dec 13, 2014 4:42 pm
by kubilus1
Updated obj2mech to support multiple input files. The user can now do something like:

Code: Select all

python -f obj1.obj -f obj2.obj > meshs.h
.mtl files are automatically looked for with the same path/name as the .obj file.