How to load a 3d object in Android?
I have the .obj f开发者_运维问答ile and .mtl file but don't know how to import it. I have tried the tutorials, they aren't working.
One way to load an Object from an .obj file is to first get the inputstream from the file, then you go through each line, since one line consists of one vertex. The part where you then use youre data from the .obj file to acctually draw it is something that you easily can find a bunch of tutorials on online, one example: http://www.droidnova.com/android-3d-game-tutorial-part-i,312.html . If you want to get deeper into Opengl and acctually learn alot you can use Nehe the allmightys online tutorial that covers very much and goes quite deep into OpenGL programming: http://nehe.gamedev.net/ .
Anyway, the .obj file loading could start of by something like this:
while ((line = reader.readLine()) != null)
{
if (line.startsWith("f"))
{
faces++;
processFLine(line);
} else if (line.startsWith("vn"))
{
normals++;
processVNLine(line);
} else if (line.startsWith("vt"))
{
UVCoords++;
processVTLine(line);
} else if (line.startsWith("v"))
{
vertices++;
processVLine(line);
}
}
For everything except when line starts with 'f' it's quite straight forward, you just store thoose two or three values in something, I preferred a Vector:
private void processVNLine(String line)
{
String[] tokens = line.split("[ ]+");
int c = tokens.length;
for (int i = 1; i < c; i++)
{ // add the normals to the normal vector
_vn.add(Float.valueOf(tokens[i]));
}
}
For the faces part (where line starts with 'f', you would preferably first check how many '/' each vertex consists of:
private void processFLine(String line)
{
String[] tokens = line.split("[ ]+");
int c = tokens.length;
if (tokens[1].matches("[0-9]+"))
{
caseFEqOne(tokens, c);
}
if (tokens[1].matches("[0-9]+/[0-9]+"))
{
caseFEqTwo(tokens, c);
}
if (tokens[1].matches("[0-9]+//[0-9]+"))
{
caseFEqOneAndThree(tokens, c);
}
if (tokens[1].matches("[0-9]+/[0-9]+/[0-9]+"))
{
caseFEqThree(tokens, c);
}
}
Each face is built up by three vertex, where each vertex indexes is v/vt/vn.
This is what could happen if you have v/vt. It stores the indices in seperate vectors.
private void caseFEqTwo(String[] tokens, int c)
{
for (int i = 1; i < c; i++)
{
Short s = Short.valueOf(tokens[i].split("/")[0]);
s--;
_vPointer.add(s);
s = Short.valueOf(tokens[i].split("/")[1]);
s--;
_vtPointer.add(s);
}
}
Now you have handled this by adding the indices into sperarate Vectors or arrays.
Now you should have Vectors that consists of coordinates and vector that consists of indices for each type(v, vt or vn). You should as well have the number of faces. By knowing the number of faces you can now start a loop that goes from 0 to number of faces.
If you now create new vectors that consists of the final result, you can in this loop move the coordinates at the index from the loop index to the loop index in the results vectors.
This may need some explenation maybe so here is a simple example:
private void reArrange()
{
Iterator<Short> i;
short s;
i = _vPointer.iterator();
while (i.hasNext())
{
s = (short) (i.next() * 3);
for (int k = 0; k < 3; k++)
{
_vResult.add(_v.get(s + k));
}
}
i = _vnPointer.iterator();
while (i.hasNext())
{
s = (short) (i.next() * 3);
for (int k = 0; k < 3; k++)
{
_vnResult.add(_vn.get(s + k));
}
}
i = _vtPointer.iterator();
while (i.hasNext())
{
s = (short) (i.next() * 2);
for (int k = 0; k < 2; k++)
{
_vtResult.add(1f - _vt.get(s + k));
}
}
_indices = new short[faces * 3];
for (short k = 0; k < faces * 3; k++)
{
_indices[k] = k;
}
}
Now your'e acctually done and have the information you need from the .obj file. So by converting thoose vectors to FloatBuffers and by creating a ShortBuffer that is as simple as 0,1,2,3,4,5 ... and so on you can use thoose with OpenGL-ES to draw your'e object.
(This is not completly written by me, I used a basic concept i found somewhere online, can't find now tho, and then made it fit nicely to what i wanted and adjusted it abit to get easier to understand)
What this doesn't cover is the part where you also load a .mtl file that you oftenly will get as well while exporting an Object from a program. If you want to implement that as well you could have a look at this: http://people.sc.fsu.edu/~jburkardt/data/mtl/mtl.html
This is something that can be good to have if your'e building an Object in a program and want a more exact replica where this will give you values for how light should be handled to materials as well.
If you have any questions, feel free to ask them.
(I know that this might not be the optimal way of loading a .obj file since we use up to 9 different vectors but if you use serialization as well this might acctually get quite fast.)
OpenGL is not a scene graph library. It provides you a set of sophisticated drawing tools, but nothing more. Loading 3D models, scene management, etc. are all left for you to implement, or use a library for.
it's far late now ...but still helpful solution : min3D engine help to load 3d model in android
Following are syeps:
1) Download Rajawali lib.
2) Create an RenderActivity
private Object3dContainer faceObject3D; private Object3dContainer objModel;
@Override
public void initScene() {
scene.lights().add(new Light());
scene.lights().add(new Light());
Light myLight = new Light();
myLight.position.setZ(150);
scene.lights().add(myLight);
IParser parser = Parser.createParser(Parser.Type.OBJ,
getResources(), "com.azoi.opengltutor:raw/monster_high", true);
parser.parse();
objModel = parser.getParsedObject();
objModel.scale().x = objModel.scale().y = objModel.scale().z = .7f;
scene.addChild(objModel);
}
add ur 3d model obj file in res/raw directory...here it's monster_high
That's it...register activity in Manifest and run :) .
if you want to move 3d model override updateScene(..):
public void updateScene() {
super.updateScene();
objModel.rotation().x++;
objModel.rotation().y--;
objModel.rotation().z++;
}
more on here http://code.google.com/p/min3d/wiki/HowToLoadObjFile Enjoy :)
精彩评论