3D graphics authoring for embedded systems designers: Part 2- Deploying 3D objects - Embedded.com

3D graphics authoring for embedded systems designers: Part 2- Deploying 3D objects

This part of the article is about the basic framework of 3D objects, how they are organized, and fundamentals you will need to understand regardless of the method used to deploy them. 3D objects can be exported from a 3D authoring tool in an array of different formats. Here we will focus on the common Wavefront Technologies OBJ format. The OBJ format is a standard 3D object format supported by virtually every 3D authoring tool. (See note on 3D graphics deployment tools at end of article.)

OBJ files are ASCII text files that contain geometry information for a 3D object. This includes vertex positions, texture coordinates, and polygon faces. A variety of other information can be included in an OBJ file; however, here we will only focus on these three attributes of a 3D object/model. Listing 1 shows the OBJ file that we will be referencing, a simple cube. This could just as easily be an extremely complex several thousand triangle model, but that would take up far too much space to list – so, a cube it is. This model was developed in Autodesk 3ds Max and exported using the OBJ export option. The settings used during export were faces as triangles, texture coordinates and optimize vertex and texture coordinates.

# object Cube01
# vertices begin
v -10.0000 0.0000 10.0000
v -10.0000 0.0000 -10.0000
v 10.0000 0.0000 -10.0000
v 10.0000 0.0000 10.0000
v -10.0000 20.0000 10.0000
v 10.0000 20.0000 10.0000
v 10.0000 20.0000 -10.0000
v -10.0000 20.0000 -10.0000
# vertices end, 8 vertices

# texture coords begin
vt 0.9988 0.3344 0.0000
vt 0.9988 0.6648 0.0000
vt 0.6681 0.6648 0.0000
vt 0.6681 0.3344 0.0000
vt 0.3359 0.6668 0.0000
vt 0.6663 0.6668 0.0000
vt 0.6663 0.9992 0.0000
vt 0.3359 0.9992 0.0000
vt 0.0007 0.6666 0.0000
vt 0.3347 0.6666 0.0000
vt 0.3347 0.9992 0.0000
vt 0.0007 0.9992 0.0000
vt -0.0000 0.3340 0.0000
vt 0.3344 0.3340 0.0000
vt 0.3344 0.6658 0.0000
vt -0.0000 0.6658 0.0000
vt 0.3370 0.3347 0.0000
vt 0.6652 0.3347 0.0000
vt 0.6652 0.6662 0.0000
vt 0.3370 0.6662 0.0000
vt 0.6681 0.6679 0.0000
vt 0.9996 0.6679 0.0000
vt 0.9996 0.9980 0.0000
vt 0.6681 0.9980 0.0000
# texture cords end, 24 texture coords

g Cube01
# faces begin
f 1/1 2/2 3/3
f 3/3 4/4 1/1
f 5/5 6/6 7/7
f 7/7 8/8 5/5
f 1/9 4/10 6/11
f 6/11 5/12 1/9
f 4/13 3/14 7/15
f 7/15 6/16 4/13
f 3/17 2/18 8/19
f 8/19 7/20 3/17
f 2/21 1/22 5/23
f 5/23 8/24 2/21
# faces end, 12 triangles

Listing 1 – Cube01 OBJ file

The entries in the Cube01 OBJ file in Listing 1 labeled with ‘v’ are the vertices that make up the 3D object’s geometric mesh of triangles. Those labeled with ‘vt’ are the texture coordinates, as explained in the previous article. The entries labeled with ‘f’ are the “faces” that make up the 3D object. The entries labeled with ‘#’ are comments and have no bearing on the 3D object.

In this case, our 3D object is made up of 12 faces or triangles that form a “cube” (Figure 1 ). Each face entry is an index into the vertices (‘v’) and texture coordinate (‘vt’) lists. As you know, a triangle consists of three vertices. So for every triangle, we need three vertex coordinates and three texture coordinates. The first face/triangle entry is 1/1 2/2 3/3. 1/1 indicates the first entry in the vertex list and the first entry in the texture coordinate list. 2/2 indicates the second entry in the vertex list and the second entry in the texture coordinate list. 3/3 indicates the third entry in the vertex list and the third entry in the texture coordinate list.

For the first triangle, the vertex and texture coordinate entries are:

// face 1/1 2/2 3/3
vertex(-10.000000, 0.000000, 10.000000, 0.9988, 0.3344); // 1/1
vertex(-10.000000, 0.000000, -10.000000, 0.9988, 0.6648); // 2/2
vertex( 10.000000, 0.000000, -10.000000, 0.6681, 0.6648); // 3/3

Subsequent faces are assembled accordingly.

Figure 1: Cube01 Mesh

There is a simple way to visualize 3D objects while becoming familiar with the OBJ file format. A free open source programming environment called “Processing” can be downloaded and installed in a PC, Mac, or Linux environment with ease – see http://processing.org. Processing was developed at the MIT Media Lab and is an excellent tool for programming with a focus on visual context. It is ideal for learning embedded 3D programming fundamentals. To save you the time and trouble of typing the source code for our project, all the files you need for the process described in this article can be found at http://ricktewell.wordpress.com.

Launch the Processing environment. You will be taken to a “sketch” notepad. Here you will either cut and paste or type the source code in Listing 2 that will graphically demonstrate how the above Cube01 OBJ file can be expressed in code that actually displays a 3D object on screen.

PImage img;
void setup() {
size(640, 480, P3D);
img = loadImage(“cube.png”);
noStroke();
}

void draw() {
background(0);
noFill();
translate(width / 2, height / 2, 360);
rotateX(map(mouseY, 0, height, -PI, PI));
rotateY(map(mouseX, 0, width, -PI, PI));
textureMode(NORMALIZED);
beginShape(TRIANGLES);
texture(img);
DrawVertices();
endShape();
}

void DrawVertices() {
// Face 1 – f 1/1 2/2 3/3
vertex(-10.000000, 0.000000, 10.000000, 0.9988, 0.3344); // 1/1
vertex(-10.000000, 0.000000, -10.000000, 0.9988, 0.6648); // 2/2
vertex( 10.000000, 0.000000, -10.000000, 0.6681, 0.6648); // 3/3
// Face 2 – f 3/3 4/4 1/1
vertex(10.000000, 0.000000, -10.000000, 0.6681, 0.6648); // 3/3
vertex(10.000000, 0.000000, 10.000000, 0.6681, 0.3344); // 4/4
vertex(-10.000000, 0.000000, 10.000000, 0.9988, 0.3344); // 1/1
// Face 3 – f 5/5 6/6 7/7
vertex(-10.000000, 20.000000, 10.000000, 0.3359, 0.6668); // 5/5
vertex(10.000000, 20.000000, 10.000000, 0.6663, 0.6668); // 6/6
vertex(10.000000, 20.000000, -10.000000, 0.6663, 0.9992); // 7/7
// Face 4 – f 7/7 8/8 5/5
vertex(10.000000, 20.000000, -10.000000, 0.6663, 0.9992); // 7/7
vertex(-10.000000, 20.000000, -10.000000, 0.3359, 0.9992); // 8/8
vertex(-10.000000, 20.000000, 10.000000, 0.3359, 0.6668); // 5/5
// Face 5 – f 1/9 4/10 6/11
vertex(-10.000000, 0.000000, 10.000000, 0.0007, 0.6666); // 1/9
vertex(10.000000, 0.000000, 10.000000, 0.3347, 0.6666); // 4/10
vertex(10.000000, 20.000000, 10.000000, 0.3347, 0.9992); // 6/11
// Face 6 – f 6/11 5/12 1/9
vertex(10.000000, 20.000000, 10.000000, 0.3347, 0.9992); // 6/11
vertex(-10.000000, 20.000000, 10.000000, 0.0007, 0.9992); // 5/12
vertex(-10.000000, 0.000000, 10.000000, 0.0007, 0.6666); // 1/9
// Face 7 – f 4/13 3/14 7/15
vertex(10.000000, 0.000000, 10.000000, -0.0000, 0.3340); // 4/13
vertex(10.000000, 0.000000, -10.000000, 0.3344, 0.3340); // 3/14
vertex(10.000000, 20.000000, -10.000000, 0.3344, 0.6658); // 7/15
// Face 8 – f 7/15 6/16 4/13
vertex(10.000000, 20.000000, -10.000000, 0.3344, 0.6658); // 7/15
vertex(10.000000, 20.000000, 10.000000, -0.0000, 0.6658); // 6/16
vertex(10.000000, 0.000000, 10.000000, -0.0000, 0.3340); // 4/13
// Face 9 – f 3/17 2/18 8/19
vertex(10.000000, 0.000000, -10.000000, 0.3370, 0.3347); // 3/17
vertex(-10.000000, 0.000000, -10.000000, 0.6652, 0.3347); // 2/18
vertex(-10.000000, 20.000000, -10.000000, 0.6652, 0.6662); // 8/19
// Face 10 – f 8/19 7/20 3/17
vertex(-10.000000, 20.000000, -10.000000, 0.6652, 0.6662); // 8/19
vertex(10.000000, 20.000000, -10.000000, 0.3370, 0.6662); // 7/20
vertex(10.000000, 0.000000, -10.000000, 0.3370, 0.3347); // 3/17
// Face 11 – f 2/21 1/22 5/23
vertex(-10.000000, 0.000000, -10.000000, 0.6681, 0.6679); // 2/21
vertex(-10.000000, 0.000000, 10.000000, 0.9996, 0.6679); // 1/22
vertex(-10.000000, 20.000000, 10.000000, 0.9996, 0.9980); // 5/23
// Face 12 – f 5/23 8/24 2/21
vertex(-10.000000, 20.000000, 10.000000, 0.9996, 0.9980); // 5/23
vertex(-10.000000, 20.000000, -10.000000, 0.6681, 0.9980); // 8/24
vertex(-10.000000, 0.000000, -10.000000, 0.6681, 0.6679); // 2/21
}

Listing 2 – Cube01 Processing Source Code

The texture map for the cube is shown in Figure 2 . As you can see, everyside of the cube is represented in the texture map. The texturecoordinates that were generated by 3ds Max when the OBJ was exported arewhat map each section of the texture maps to each face on the cube. Asyou can see from Figure 1, the cube is made up of 12 triangles and eachtriangle is represented in the OBJ and Processing code as a face.

Figure 2: Cube01 Texture Map

Face9 is represented in the OBJ file as “f 3/17 2/18 8/19”. The first threenumbers in the vertex() function represent the vertex’s x, y and zcoordinates in 3D model space. Remember that each face or triangle hasthree vertices so there must be three vertex() functions called forevery triangle that makes up the 3D object. Numbers on the left side ofthe ‘/’ symbol are vertex table index numbers. Numbers on the right sideof the ‘/’ symbol are texture coordinate table index numbers. The firstvertex is indexed with a “3” so in the table at the third entry and youwill find a 10.000000, 0.000000 and a -10.000000. These three numbersare our x, y and z coordinates in 3D model space for the first vertex ofour triangle. The first texture coordinate entry is a ‘17’, so at theseventeenth entry in our texture coordinate table in the OBJ file andyou will find 0.3370, 0.3347, and 0.0000. Texture coordinates aretypically made up of two numbers, a U and a V, as explained in theprevious article. The third number (called a ‘W’ – which was the 0.0000)is not necessary for our purposes and is ignored. Now we have all thedata required for our first vertex entry:

vertex(10.000000, 0.000000, -10.000000, 0.3370, 0.3347); // 3/17

This is repeated two more times to create the triangle.

// Face 9 – f 3/17 2/18 8/19
vertex(-10.000000, 0.000000, -10.000000, 0.6652, 0.3347); // 2/18
vertex(-10.000000, 20.000000, -10.000000, 0.6652, 0.6662); // 8/19

Pleasenote that you must start with the first face entry in the .OBJ file andprocess sequentially or your 3D object will not display correctly. Iused Face 9 above as a “spot” example. Obviously a converter utilitycould be written that would convert an OBJ file to a list of vertex()function calls, and I might write one of those and put it and theresulting source code up at http://ricktewell.wordpress.com.

Nowthat you understand the code, you can run it. Be sure to copy thetexture map “cube.png” to your Processing sketch’s project directory. Tocreate this directory, save your Processing sketch using File->SaveAs. Simply copy “cube.png” into this sketch directory. Under Windows,this will be found under MyDocumentsProcessingSketch_Name. Now pressthe “Run” button and you should see your 3D cube. By moving the mouseyou can rotate the cube on multiples axes (Figure 3 ).

Figure 3: Cube01

Atthis point, you might be thinking “Great! I can show a 3D object on aPC or Mac…what does this have to do with embedded systems?” The answeris that if you understand the processes outlined above, you know mosteverything you need to know in order to display a 3D object on anyembedded system. Yes, the code will be different, but the process is thesame. Let’s review the steps:

1. Create the 3D object using a 3D authoring tool
2. Export the 3D object using the OBJ format
3. Convert the data in the OBJ format into something that can be understood by the 3D environment you are using
4. The 3D system will need the vertices and the texture coordinate map and the texture bitmap in order to show the object

Byway of a simple example for OpenGL ES, instead of the vertex() functionwe used in the processing environment, you might use glVertex3fv() andglTexCoord2f() – I say “might” because there are other ways toaccomplish the same thing using other mechanisms in OpenGL ES that canbe more efficient. The basic purposes, however, are identical. You arepassing the geometry and the texture coordinates to the 3D rendereralong with the texture bitmap.

3D graphics can be complex and inmany ways daunting. I strongly encourage you, if you are a beginner, tospend some time using the Processing environment to learn thefundamentals of 3D graphics. There is so much there to learn without theadded burden of fighting the development tools – compilers, debuggers,RTOS environment, licensing, etc. Spend time just learning the basics of3D programming. The Processing environment fully supports OpenGL aswell, so you can move on to lighting, fogging, and even the wild andwacky world of shaders. 3D is becoming such an essential part ofgraphics programming including GUI development. It is my hope that thisarticle sparks an interest in you to add your mark to 3D graphics onembedded devices.

3D graphics deployment tools
There are avariety of methods used to deploy 3D objects on embedded device screens,including low-level 3D APIs (OpenGL ES, Direct3D Mobile), native devicelow-level 3D APIs (Fujitsu V03), high-level 3D APIs (JSR 184, JSR 297),a wide variety of 3D “engines” (SIO2, Unreal, Bork 3D), and varioushigher level graphics user interface (GUI) design tools (Unity, CGIStudio). Any one of these methods could be the subject of a longarticle, and a discussion of all of them is beyond the scope of thepresent article. I will mention only that a common method of deploying3D objects is to write some code using OpenGL ES (ES refers to “embeddedsystems”). The two primary versions of OpenGL ES are are 1.1 and2.0. There is a vast difference between the two versions, and they arenot compatible, with OpenGL ES 1.1 being a subset of the full OpenGL 1.5specification and OpenGL ES 2.0 being a subset of the full Open GL 2.0specification. OpenGL ES introduces you to a complex world of thingslike lighting, fogging, matrices, display lists, mipmaps, vertex bufferobjects and, with OpenGL ES 2.0, the complicated world of “shaders.” Tolearn more about OpenGL ES programming, visit http://nehe.gamedev.net/,operated by GameDev.net

Rick Tewell is the Director ofEngineering for Fujitsu Semiconductor. He has a long history in embeddedelectronics and is an embedded graphics specialist with more than twodecades of experience. He also served in a variety of posts with LigosCorp., Sequoia Advanced Technologies and Columbia Data Products prior tojoining Fujitsu Semiconductor.

Leave a Reply

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