Skip to content

Commit 5b209fc

Browse files
committed
Update README
1 parent 24f66a0 commit 5b209fc

File tree

1 file changed

+73
-56
lines changed

1 file changed

+73
-56
lines changed

README.md

Lines changed: 73 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ java-data-front
55

66
A Java library for reading Wavefront 3D model resources (OBJ, MTL).
77

8-
**Note:** Though planned in the future, it is not possible to serialize OBJ or MTL resources at the moment.
9-
108
The OBJ and MTL file formats are one of the most popular 3D model formats used at the moment. This is mainly due to their simplicity.
119

1210
OBJ files are used to describe the coordinates, connections and shapes that make up a 3D model.
@@ -34,52 +32,37 @@ d 0.7
3432
map_Kd vehicle.png
3533
```
3634

37-
I am not sure what is the exact history of these file formats, but I believe they were first introduced by the Wavefront Technologies company for their 3D software. Now they are available in practically all 3D modeling softwares.
35+
The `obj` and `mtl` file formats were originally developed by the Wavefront Technologies company for their 3D visualizer software. Currently, they are available in practically all 3D modeling solutions.
3836

39-
## Parsing OBJs
37+
## Loading OBJ resources
4038

4139
Using this library is meant to be easy and straightforward. All you need to do is instantiate an `OBJParser` and pass it an `InputStream` to your OBJ resource.
4240

4341
**Example:**
4442

4543
```java
4644
// Open a stream to your OBJ resource
47-
final InputStream in = new FileInputStream("example.obj");
48-
49-
// Create an OBJParser and parse the resource
50-
final IOBJParser parser = new OBJParser();
51-
final OBJModel model = parser.parse(in);
52-
53-
// Use the model representation to get some basic info
54-
System.out.println(MessageFormat.format(
55-
"OBJ model has {0} vertices, {1} normals, {2} texture coordinates, and {3} objects.",
56-
model.getVertices().size(),
57-
model.getNormals().size(),
58-
model.getTexCoords().size(),
59-
model.getObjects().size()));
60-
```
61-
62-
Let's look at the API in a bit more detail.
63-
64-
So parsing is straightforward. You saw that in the previous code snippet. What's important to keep in mind is that you can have any InputStream. This means that you could open your model from a Java resource or a remote HTTP resource.
65-
66-
**Example:**
67-
68-
```java
69-
final URL url = new URL("http://www.example.org/models/example.obj");
70-
final InputStream in = url.openStream();
71-
final IOBJParser parser = new OBJParser();
72-
final OBJModel model = parser.parse(in);
73-
// You know what to do next...
45+
try (InputStream in = new FileInputStream("example.obj")) {
46+
// Create an OBJParser and parse the resource
47+
final IOBJParser parser = new OBJParser();
48+
final OBJModel model = parser.parse(in);
49+
50+
// Use the model representation to get some basic info
51+
System.out.println(MessageFormat.format(
52+
"OBJ model has {0} vertices, {1} normals, {2} texture coordinates, and {3} objects.",
53+
model.getVertices().size(),
54+
model.getNormals().size(),
55+
model.getTexCoords().size(),
56+
model.getObjects().size()));
57+
}
7458
```
7559

76-
No matter where you load the OBJ resource from, you always get the same `OBJModel` model representation.
60+
When you parse an OBJ resource, you get a `OBJModel` representation.
61+
We use the `getVertices`, `getNormals`, and `getTexCoords` methods to get access to all of the vertices, normals and texture coordinates respectively that are defined in the OBJ resource. Since these can be shared between multiple objects, their getter methods are defined on the root `OBJModel` element.
7762

78-
As you've seen above, we used the `getVertices()`, `getNormals()`, and `getTexCoords()` methods. These give you access to all of the vertices, normals and texture coordinates respectively that were defined in the OBJ resource. Since these are shared between objects, that's why they are defined on the root `OBJModel` element.
63+
Additionally, you have the `getMaterialLibraries` method. It provides a list of all the material dependencies that were declared in the OBJ resource. The method returns a list of strings, representing resources that can be parsed via a `MTLParser` parser. It is up to your implementation to locate those resources and process them, as the `OBJParser` has no way of knowing from where the OBJ resource originates.
7964

80-
Additionally, you have the `getMaterialLibraries()` method. This one provides you a list of all the material dependencies that were declared in the OBJ resource. The method returns a list of strings. You will need to use the `MTLParser` to load these resources. It is up to you to locate those resources, though. Since the parser has no idea from where the original OBJ resource is being parsed, it cannot know how to resolve relative dependencies (could be file, could be URL, etc.).
81-
82-
The most interesting of methods is the `getObjects()` method which lists all of the objects that are defined in the OBJ resource. These are the entities you would usually iterate through to get the mesh data.
65+
The `getObjects` method lists all of the objects that are defined in the OBJ resource. These are the entities you would usually iterate through to get the mesh data.
8366

8467
**Example:**
8568

@@ -98,14 +81,14 @@ One thing that does not exactly match the OBJ specification is the `OBJMesh` con
9881
**Example:**
9982

10083
```java
101-
final OBJMesh mesh = ...; // You already know how to get this.
84+
final OBJMesh mesh = ...;
10285
final String materialName = mesh.getMaterialName();
10386
final List<OBJFace> faces = mesh.getFaces();
10487
```
10588

106-
You would use the `materialName` to select the proper material to use for rendering the list of `OBJFace` instances. You will need to locate the material in one of the `OBJMaterial` resources that you have previously loaded as instructed by `getMaterialLibraries()`.
89+
One would use the `materialName` value to select the proper material to use for rendering the list of `OBJFace` instances. The actual material would need to have been parsed in advance (as explained above) and probably stored in a map structure for easy access.
10790

108-
Now that you know how to get to the distinct faces and which material to use, what's left is to get their mesh data.
91+
Knowing how to get to all faces and related materials, one needs a way to get the mesh data of each individual face.
10992

11093
**Example:**
11194

@@ -128,35 +111,37 @@ for (OBJDataReference reference : face.getReferences()) {
128111
}
129112
```
130113

131-
A face can be defined by arbitrary number of vertices, as long as they are more than three. This is why each has the `getReferences()` method that returns a list of `OBJDataReference` objects. This object represents a single vertex and allows you to locate the positional, normal and texture coordinate information for that vertex. This happens through the usage for indices that point at the master data (i.e. `getVertices()`, `getNormals()`, `getTexCoords()`). There are helper methods like `hasNormalIndex()` that help you determine if the vertex has a normal declared and `getNormal` that automatically locates the `OBJNormal` instance for you.
114+
A face can be defined by arbitrary number of vertices, as long as they are more than three. This is why each face has the `getReferences` method that returns a list of `OBJDataReference` objects. This object represents a single vertex and allows you to locate the positional, normal and texture coordinate information for that vertex. This happens through the usage for indices that point at the master data (the one available through `getVertices`, `getNormals`, `getTexCoords`). There are helper methods like `hasNormalIndex` that help you determine if the vertex has a normal declared and `getNormal` that automatically locates the `OBJNormal` instance for you.
115+
132116

117+
## Loading MTL resources
133118

134-
## Parsing MTLs
135-
Parsing material libraries is performed in the same way as objects. All you need to do is instantiate an `MTLParser` and pass it an `InputStream` to your MTL resource.
119+
Parsing material libraries is performed in the same way as objects. All one needs to do is instantiate an `MTLParser` and pass it an `InputStream` to the MTL resource.
136120

137121
**Example:**
138122

139123
```java
140-
final InputStream in = new FileInputStream("example.mtl");
141-
final IMTLParser parser = new MTLParser();
142-
final MTLLibrary library = parser.parse(in);
143-
for (MTLMaterial material : library.getMaterials()) {
144-
System.out.println(MessageFormat.format("Material with name ``{0}``.", material.getName()));
124+
try (InputStream in = new FileInputStream("example.mtl")) {
125+
final IMTLParser parser = new MTLParser();
126+
final MTLLibrary library = parser.parse(in);
127+
for (MTLMaterial material : library.getMaterials()) {
128+
System.out.println(MessageFormat.format("Material with name `{0}`.", material.getName()));
129+
}
145130
}
146131
```
147132

148-
The `MTLMaterial` object represents a material that is defined in the MTL resource. You can have many of these defined in a single resource. Each of these has a name and some generic material data like diffuse color, ambient color, specular color, etc.
133+
The `MTLMaterial` object represents a material that is defined in the MTL resource. There can be a number of these defined in a single MTL resource. Each of these has a name and some generic material data like diffuse color, ambient color, specular color, etc.
149134

150135
**Example:**
151136

152137
```java
153-
final MTLMaterial material = ...; // You already know how to get this.
138+
final MTLMaterial material = ...;
154139
final MTLColor diffuseColor = material.getDiffuseColor();
155140
final MTLColor ambientColor = material.getAmbientColor();
156141
final MTLColor specularColor = material.getSpecularColor();
157142
```
158143

159-
As you can see, parsing MTL resources is not that different from parsing OBJ resources. You wouldn't usually parse MTL resources on their own, though. Most often you would use the information from the OBJ resource to locate the MTL resources and load them.
144+
One would rarely parse MTL files separately. Often, this would be as part of the parsing of an OBJ file.
160145

161146
**Example:**
162147

@@ -167,19 +152,51 @@ final IMTLParser mtlParser = new MTLParser();
167152
final InputStream objStream = ...; // Depends on your use case.
168153
final OBJModel model = objParser.parse(objStream);
169154
for (String libraryReference : model.getMaterialLibraries()) {
170-
final InputStream mtlStream = ...; // You will need to resolve this based on `libraryReference`
155+
final InputStream mtlStream = ...; // You will need to resolve this based on `libraryReference` and the storage used
171156
final MTLLibrary library = mtlParser.parse(mtlStream);
172-
// Do something with the library. Maybe store it for later usage.
157+
// Do something with the library. Maybe store it in a map for later usage.
173158
}
174159
```
175160

176-
## Notes
161+
## Setting Up
162+
163+
Even though this project relies on Maven for packaging, it has not been published to the central Maven repository. Following are a number of approaches to get the library imported in your project.
164+
165+
### JitPack
166+
167+
An amazing web page that allows one to import Maven projects directly from GitHub. It is ideal for publishing new and small projects like this one.
168+
One only needs to add the following configuration in their `pom.xml` file to get the library included.
169+
170+
```xml
171+
<repositories>
172+
<repository>
173+
<id>jitpack.io</id>
174+
<url>https://jitpack.io</url>
175+
</repository>
176+
</repositories>
177+
178+
<dependencies>
179+
<dependency>
180+
<groupId>com.github.mokiat</groupId>
181+
<artifactId>java-data-front</artifactId>
182+
<version>v2.0.0</version>
183+
</dependency>
184+
</dependencies>
185+
```
186+
187+
JitPack works with other packaging frameworks as well. Check the [official webpage](https://jitpack.io/) for more information.
188+
189+
### Packaging
190+
191+
If `JitPack` is not an option for your use case, then you could package the `jar` files into your project. They are available for download from the [Releases](https://github.com/mokiat/java-data-front/releases) section of the repository.
192+
177193

178-
This library was implemented to support other projects of mine. As such, it supports only a subset of the OBJ and MTL specifications (which are large). The features that are provided should be sufficient for most use cases.
194+
### Local Maven repository
179195

180-
Though not shown in the code snippets above, it is important that you always close any `InputStream` objects as that is not done by the API. I have omitted that on purpose to keep the snippets simple to read.
196+
You can use a set of commands to import the `jar` files into your local Maven repository. Following are two available approaches. (I find the first one to do the job)
181197

182-
If you want to see an application that already uses this library, take a look at **[ModelViewer3D](https://play.google.com/store/apps/details?id=com.momchil_atanasov.android.modelviewer)**.
198+
* [http://maven.apache.org/plugins/maven-install-plugin/examples/custom-pom-installation.html](http://maven.apache.org/plugins/maven-install-plugin/examples/custom-pom-installation.html)
199+
* [http://maven.apache.org/guides/mini/guide-3rd-party-jars-local.html](http://maven.apache.org/guides/mini/guide-3rd-party-jars-local.html)
183200

184201
## License
185202

0 commit comments

Comments
 (0)