Translation notice
This page was translated with machine translation and may contain inaccuracies. If you can help improve it, please open an issue or submit a pull request.
A feasible method to convert OBJ model to json model
keywords OBJ model, json model, Minecraft, geometry structure conversion, voxelization, lightweight model, tangent space
Overview and background
This article aims to study a feasible high-precision, nearly lossless and lightweight method of converting OBJ (Wavefront) to JSON model (Minecraft style) to help artists quickly import the project into the Minecraft scene after completing the design in a general modeling software.
There are significant differences between the two models we considered. The OBJ model defines the geometric structure of the object by vertices and surfaces, with triangular surface meshes as the core (some software also supports polygonal surfaces), and can represent complex geometric structures (such as curved surfaces) with high precision and low polygon count. Minecraft's json model is defined by voxels that have been translated, rotated, and scaled, and usually cannot represent complex surfaces well, or even triangles. Without considering textures and maps, we will next discuss a feasible method to convert OBJ models to json models with acceptable visual effects errors.
Traditional implementation of model voxelization
Method introduction
The traditional way to convert an OBJ model to a voxelized model similar to a json model is to approximate the geometry of the OBJ model with axis-aligned cubes (voxels). The basic idea of this method is:
Place the OBJ model into a 3D mesh
Determine the minimum subdivision mesh
For each grid cell, check if it intersects the OBJ model, and if so, fill a voxel
Optimize the generated voxel model to reduce the number of voxels
Get the final voxel model
Shortcomings of the method
The implementation of this traditional method is simple, but it has shortcomings that cannot be ignored:
The visual error produced by this method is too large (we have not yet defined the error), especially for curved and sloped surfaces, and voxelized models tend to appear very rough.
Achieving high visual accuracy requires the use of very fine meshes, resulting in a massive increase in voxel count and making the model very large and difficult to use in Minecraft.
Even if optimization is performed, such as merging some voxels, or using different levels of detail (LOD) at different locations, the generated voxel model may still contain a large number of redundant voxels, which affects performance and is not conducive to modification by artists.
Improvement method
Define error
In order to better measure the difference between the converted json model and the original OBJ model, and for us to implement the optimization algorithm, we need to define the error values before and after conversion.
Volume error
For the error caused by volume fitting (such as traditional methods), we can use the distortion volume to measure it. The distortion volume is defined as the difference between the union volume of the two models and their intersection volume. Since we will eventually observe the model at various angles, we need to calculate the distortion volume projection area under different viewing angles and take the average value as the final error indicator.
Research points out that convex polyhedron in three-dimensional space is
Right now,
in
surface error
Errors caused by surface fitting
Similarly, we do not consider the influence of occlusion and directly use the sum of the distortion surface area of each subdivision surface as the error metric. The specific calculation formula is related to the fitting method, which we will introduce next, but the idea is similar to the volume error.
Optimization direction
Model complexity can be measured by the number of voxels. We hope that the error and complexity are as small as possible, but the two are often contradictory. Define a cost index that is proportional to the error and complexity (weighted sum measurement is used here), that is
in
A review of improved voxelization methods
Since Minecraft's json model is defined based on rotatable voxels, we can take advantage of this to better fit the geometry of the OBJ model by allowing the voxels to rotate, thereby reducing errors.
For the original OBJ model, we define connected, parallel triangles as a surface. Triangles in the surface satisfy the following conditions:
Adjacent triangles in the surface have at least two shared vertices
The normal directions of all triangles in the surface are the same (i.e. parallel), and the angle error must be small enough to be considered in actual implementation.
Triangles that meet the above two conditions also belong to the surface if they are adjacent to triangles in the same surface.
For each surface, we calculate its tangent space (tangent space), that is, define a local coordinate system so that the normal direction of the surface is aligned with an axis of the local coordinate system. We then voxelize in this tangent space, using axis-aligned voxels to approximate the geometry of the surface.
Specific implementation steps
Read OBJ model
This step is relatively simple. The OBJ file format is a text format. You can use existing libraries (such as TinyOBJLoader) to parse OBJ files. You only need to extract vertex, normal and face index information. In the file, respectivelyv n fThe first lines represent vertex, normal, and face indices.
Sometimes the normal information may not exist or be unreliable, we can calculate the normal from the vertex and face information. For each triangular face, we can calculate the normal using the cross product:
Sometimes polygonal faces appear in the OBJ model (such as the model exported by Blender). We can triangulate the polygonal faces and convert them into multiple triangular faces for processing.
Construct surface connected components
We traverse all the triangular faces we read, create connected components according to the above definition, and obtain multiple surfaces, each of which is an undirected graph.
Compute tangent space
In each surface, we take the normal of that surface as the normal of the tangent space
Three vectors form an orthogonal local coordinate system, and we construct a transformation matrix
Since this matrix is orthogonal, its inverse exists and is equal to its transpose:
coordinate all vertices of the surface
Find the optimal rectangle in tangent space
In the tangent space, we need to find an optimal rectangle to initially fill the interior of the surface, so that after deleting the area of this rectangle, the number of remaining triangles is minimal. At the same time, since the error in this step can be avoided, we cannot accept any error, that is, to satisfy the rectangle, the conditions must be met:
- Rectangles that satisfy the condition are contained inside the surface.
- Due to artistic requirements, the side length of the rectangle needs to be the smallest element.
an integer multiple of
Intuitively, the larger the rectangular area that meets such conditions, the better, but it is smaller than the maximum rectangular area that can be placed in the boundary of the surface. At the same time, there may be certain restrictions on angles and positions to minimize the remaining triangular surfaces.
We can find the optimal rectangle through enumeration. The specific steps are as follows (it can be replaced by a more efficient method to improve performance):
- Extract the boundary vertices of a surface in tangent space
- Align each edge with the coordinate axis respectively, and then use
For LOD, mesh the area within the boundary (only meshes completely contained within the boundary are retained) - For each grid cell, try making it the lower left corner of a rectangle, then enumerate the possible widths and heights (both
an integer multiple of ), check whether the rectangle is completely contained within the bounds - For a rectangle that meets the conditions, calculate the number of remaining triangles after deleting the rectangle, and record the rectangle with the smallest number of remaining triangles as the current optimal solution.
Note that after deleting the rectangle, the remaining areas may have non-triangular faces. We need to re-triangulate these areas to ensure that all remaining areas are composed of triangular faces. And for the remaining triangles, we need to recalculate their connected components, and the final measure is the total number of remaining triangle faces.
After determining the rectangle, we multiply it by left
Process remaining triangles
For triangular surfaces, since there is a minimum element
For small triangles, we try two fitting methods:
Fit the triangle using two bounding rectangles. For the vertex corresponding to the largest angle, place two rectangles parallel to the adjacent sides of the vertex inside the triangle so that the inner sides of the two rectangles intersect at a point on the opposite side of the vertex. By taking different intersection points, different fits can be obtained, and the method with the smallest error can be selected. The dimensions of the bounding rectangle need not be
An integer multiple of , but if the solution can be obtained is an integer multiple of , then select can minimize the error in integer multiples solution. Calculate the center of gravity of the triangle, and then use the center of gravity as the center directly using a
The rectangle fits the triangle, one side coincides with the side of the triangle, and the error is calculated 。
error here
$$e_S = \frac{1}{4} \sum_{S \in S_{voxel}, S \notin S_{triangle}} Area(S)$$
Choose the one with the smaller error among the two methods as the fitting method for the small triangle.
For medium triangles, we only consider the method of using two surrounding rectangles. The process is similar to that of small triangles.
For large triangles, we first fit the triangle with three bounding rectangles. Place a rectangle from three vertices along the adjacent sides, with thicknesses of
. This creates an inner region that we voxelize (pixel) traditionally, but requires each rectangle to be of size An integer multiple of , and merge adjacent rectangles after processing. At this time Let the internal region have a solution and The smallest value, similarly, if the solution can be obtained is an integer multiple of , then select can minimize the error in integer multiples solution.
To find all rectangles, we multiply them by left
Below we discuss the coverage methods mentioned above in detail:
Double hemming method:

The double wrapping method can fit small triangles well under normal circumstances.


In special cases, it can be found that when the vertices of the rectangle are fixed on the three corners of the triangle, it will be impossible to fit, and the rectangle needs to be extended.
Note: Although this situation can always be avoided by adjusting the position of point D, we are not sure yet whether limiting the position of D is better than allowing the rectangle to be extended, so we choose to allow the rectangle to be extended.
Therefore, the logic of the double wrapping method suitable for general situations is:
Select the maximum angle, recorded as
, the adjacent angle is recorded as and , the opposite sides of the three angles are written as 。 exist
Take a little bit , Pass do perpendicular to , respectively from the ray intersection point 。 by
For example, if exist above, then the rectangle An edge of , the length of the adjacent side perpendicular to it is Its value is equal to and distance; if exist along On the extension line of the direction, the rectangle An edge of , the length of its perpendicular adjacent side is also 。
To simplify calculations, we assume
So,
In general calculations, the angle
In the special case where the rectangle needs to be extended, the distortion area is:
And the critical condition is
So we can use amax()function to uniformly represent the distortion area:
The sum of the areas on both sides does not overlap, so the total distortion area is:
The error is the distortion area
And the constraints are
Using the Lagrange multiplier method, we construct the Lagrange function:
right
Notice,
It is easy to prove that only one side needs to extend the rectangle, that is, there are only three situations:
In a given condition that satisfies the constraints
like
like
Substituting the three situations into the above system of equations respectively, find candidate solutions, then calculate the error, and select the solution with the smallest error as the final solution. At this time it will
wraparound
The logic of the wrap-around method suitable for large triangles is:
We use different LOD to determine the internal area, that is, discretize the internal area as
grid, Pick ,in is the side length of the largest inscribed rectangle of a triangle and The integer part of the ratio. For the "large triangle" in our definition, 。 Under different LODs, pixelate the internal area (inscribed fitting), that is, within the divided grid, select the grid completely contained within the triangle as the pixel block.
Select three vertices of the triangle
, place three rectangles along the adjacent sides. , whose thicknesses are respectively . Choose the smallest Cover the area that cannot be covered by inscribed fitting, and calculate the distortion area caused by wrapping 。
For this step, we need to first select the direction, that is, select one side as the bottom edge. At this time, the determined pixels will generate the left, right, and top borders. For the hypotenuse on the left, we calculate the distance between each grid point of the left boundary and the upper boundary from the hypotenuse, and take the minimum value as
Calculate different sides as bases separately
Next we discuss the distortion area

Consider the general wraparound method, assuming

When considering that the vertex angle is an obtuse angle, it is obvious that there is no error area near the obtuse angle. Taking the right side as an example, the area of the red triangle can be calculated as
This is just the opposite of the distortion area term we originally calculated here for the rectangle on the right. If we apply the original formula, this term is just the negative value of the area of the red triangle, so we need to remove it.
passmaxrestrict
- Calculate the error value at each LOD
and number of voxels , choose such that the cost index The smallest solution is taken as the final solution.
In this algorithm, the optimal solution is uniquely determined by LOD because
Description of voxel blocks
Now for all the rectangles that have been determined, we need to convert them into the format required by the Minecraft json model. The voxel definition in the Minecraft json model is slightly different on different platforms, but it mainly consists of the following information (we do not consider textures):
Voxel position: Defines the position of the voxel in three-dimensional space. in Bedrock Edition voxel definition
originArrays and Java EditionfromThe array is at this location.Voxel size: Define the length, width, and height of the voxel. in Bedrock Edition voxel definition
sizeThe array is of this size. For Java Edition,toAn array is the sum of position and size.Rotation of the voxel: Defines the rotation angle of the voxel relative to its local coordinate system, which is described by the rotation Euler angles of the three axes. in Bedrock Edition voxel definition
rotationArrays and Java Editionrotation.x,rotation.y,rotation.zThe key is this rotation information.Rotation center: Defines the reference point for voxel rotation. in Bedrock Edition voxel definition
pivotArrays and Java Editionrotation.originThe object is this center of rotation.
In order to confirm these four pieces of information, we need to confirm the transformation matrix from the unit cube to the target rectangle.
The order of voxel transformation is: first scale, then translate, and finally rotate around the rotation center by 3 Euler angles. Therefore, the transformation matrix can be expressed as:
in
For the rectangular vertices we get, we first calculate the minimum point
You can get the position and size of the voxel:
because
Calculate axis of rotation
,in It is based on the global coordinate system axis. Calculate rotation angle
。 Construct a rotation matrix using Rodrigues' rotation formula
:
in
Finally, we can decompose the rotation matrix by
Remember
Euler angles can be extracted from the matrix:
remember
Since gimbal deadlock may occur, we need to
Define a smaller threshold$$\varepsilon = 10^{-6}$$
when
when
In fact, since the rotation center and rotation axis are arbitrary, there are multiple possible solutions to achieve the same visual effect. In our calculation, the rotation center is the smallest point of the voxel.
Therefore, the four pieces of information we need are as follows:
Bedrock Edition voxel definition:
{
"origin": [v_min.x, v_min.y, v_min.z],
"size": [|d_x|, |d_y|, 0],
"rotation": [rx_in_degrees, ry_in_degrees, rz_in_degrees],
"pivot": [v_min.x, v_min.y, v_min.z]
}Java version voxel definition:
{
"from": [v_min.x, v_min.y, v_min.z],
"to": [v_min.x + |d_x|, v_min.y + |d_y|, v_min.z],
"rotation": {
"origin": [v_min.x, v_min.y, v_min.z],
"x": rx,
"y": ry,
"z": rz
}
}Just write it directly in json format.
remaining questions
Although we proposed a feasible method to convert OBJ models to json models, there are still some remaining issues that need further research and resolution:
The algorithm for finding the optimal rectangle described in the article is relatively complex, especially when dealing with complex surfaces. A more efficient algorithm may be needed to speed up the process.
We regard triangular surfaces as independent from other triangular surfaces. Artists usually hide large chunks of errors in invisible areas (such as closed interiors), thereby reducing the number of cubes and achieving relatively small errors. We have not considered this yet.
The current method mainly takes error as the optimization goal, and in most cases cannot optimize the voxel number (cube number) to the same low level as manual production. Compared with models manually made by artists, automatically converted models usually have higher errors and block numbers.
For very complex geometries, current methods may still fail to achieve ideal visual effects, and the combination of other techniques, such as subdivision surfaces or multi-resolution representations, can be considered in the future to further improve the conversion quality.
But all in all, this tangent space-based voxelization method provides a promising solution for high-precision, lightweight OBJ to json model conversion. According to the ideas in the article, a practical conversion tool can be written to help artists apply design results to Minecraft scenes more efficiently.