Add vertex scaling
This commit is contained in:
parent
15d3bce807
commit
bff72d3532
@ -203,6 +203,63 @@ public class ObjUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scale the vertices of an object around a certain origin.
|
||||||
|
* <b>NOTE: this uses the Wavefront OBJ coordinate system</b>
|
||||||
|
* @param obj The object to scale the vertices of
|
||||||
|
* @param startIdx The starting vertex index to scale
|
||||||
|
* @param endIdx The ending vertex index to scale (inclusive)
|
||||||
|
* @param scaleX The scaling factor in the x direction
|
||||||
|
* @param scaleY The scaling factor in the y direction
|
||||||
|
* @param scaleZ The scaling factor in the z direction
|
||||||
|
* @param origX The x coordinate of the origin of the scaling
|
||||||
|
* @param origY The y coordinate of the origin of the scaling
|
||||||
|
* @param origZ The z coordinate of the origin of the scaling
|
||||||
|
*/
|
||||||
|
public static void scaleVertices(DefaultObj obj, int startIdx, int endIdx,
|
||||||
|
float scaleX, float scaleY, float scaleZ,
|
||||||
|
float origX, float origY, float origZ) {
|
||||||
|
verifyIndexRange(obj, startIdx, endIdx);
|
||||||
|
|
||||||
|
if (Float.compare(scaleX, 1) == 0 && Float.compare(scaleY, 1) == 0 && Float.compare(scaleZ, 1) == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = startIdx; i <= endIdx; i++) {
|
||||||
|
FloatTuple vertex = obj.getVertex(i);
|
||||||
|
|
||||||
|
// Translate vertex to origin
|
||||||
|
final float x = vertex.getX() - origX;
|
||||||
|
final float y = vertex.getY() - origY;
|
||||||
|
final float z = vertex.getZ() - origZ;
|
||||||
|
|
||||||
|
// Apply scaling
|
||||||
|
float scaledX = x * scaleX;
|
||||||
|
float scaledY = y * scaleY;
|
||||||
|
float scaledZ = z * scaleZ;
|
||||||
|
|
||||||
|
// Translate vertex back to its original position
|
||||||
|
scaledX += origX;
|
||||||
|
scaledY += origY;
|
||||||
|
scaledZ += origZ;
|
||||||
|
|
||||||
|
FloatTuple scaledVertex = new DefaultFloatTuple(scaledX, scaledY, scaledZ);
|
||||||
|
obj.setVertex(i, scaledVertex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scale the vertices of an object around the origin
|
||||||
|
* <b>NOTE: this uses the Wavefront OBJ coordinate system</b>
|
||||||
|
* @param obj The object to scale the vertices of
|
||||||
|
* @param scaling The uniform scaling factor
|
||||||
|
*/
|
||||||
|
public static void scaleVertices(DefaultObj obj, float scaling) {
|
||||||
|
scaleVertices(obj, 0, obj.getNumVertices() - 1,
|
||||||
|
scaling, scaling, scaling,
|
||||||
|
0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
private static void verifyIndexRange(DefaultObj obj, int startIdx, int endIdx) {
|
private static void verifyIndexRange(DefaultObj obj, int startIdx, int endIdx) {
|
||||||
if (startIdx < 0 || startIdx >= obj.getNumVertices()) {
|
if (startIdx < 0 || startIdx >= obj.getNumVertices()) {
|
||||||
throw new IllegalArgumentException("startIdx must be between 0 and the number of vertices");
|
throw new IllegalArgumentException("startIdx must be between 0 and the number of vertices");
|
||||||
|
@ -36,6 +36,10 @@ public class OBJExportOptions {
|
|||||||
* This is used to convert the coordinates from the rocket's coordinate system to the OBJ coordinate system (which is arbitrary).
|
* This is used to convert the coordinates from the rocket's coordinate system to the OBJ coordinate system (which is arbitrary).
|
||||||
*/
|
*/
|
||||||
private CoordTransform transformer;
|
private CoordTransform transformer;
|
||||||
|
/**
|
||||||
|
* The scaling factor to use for the export (1 = no scaling).
|
||||||
|
*/
|
||||||
|
private float scaling;
|
||||||
|
|
||||||
// TODO: scaling (to mm = x1000, or SI units)
|
// TODO: scaling (to mm = x1000, or SI units)
|
||||||
|
|
||||||
@ -47,6 +51,7 @@ public class OBJExportOptions {
|
|||||||
this.triangulate = false;
|
this.triangulate = false;
|
||||||
this.LOD = ObjUtils.LevelOfDetail.NORMAL;
|
this.LOD = ObjUtils.LevelOfDetail.NORMAL;
|
||||||
this.transformer = new DefaultCoordTransform(rocket.getLength());
|
this.transformer = new DefaultCoordTransform(rocket.getLength());
|
||||||
|
this.scaling = 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isExportChildren() {
|
public boolean isExportChildren() {
|
||||||
@ -104,4 +109,12 @@ public class OBJExportOptions {
|
|||||||
public void setExportAsSeparateFiles(boolean exportAsSeparateFiles) {
|
public void setExportAsSeparateFiles(boolean exportAsSeparateFiles) {
|
||||||
this.exportAsSeparateFiles = exportAsSeparateFiles;
|
this.exportAsSeparateFiles = exportAsSeparateFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float getScaling() {
|
||||||
|
return scaling;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScaling(float scaling) {
|
||||||
|
this.scaling = scaling;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ import java.io.FileOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -92,8 +93,15 @@ public class OBJExporterFactory {
|
|||||||
*/
|
*/
|
||||||
public void doExport() {
|
public void doExport() {
|
||||||
DefaultObj obj = new DefaultObj();
|
DefaultObj obj = new DefaultObj();
|
||||||
|
Map<String, DefaultObj> objFileMap;
|
||||||
boolean exportAsSeparateFiles = this.options.isExportAsSeparateFiles();
|
boolean exportAsSeparateFiles = this.options.isExportAsSeparateFiles();
|
||||||
|
|
||||||
|
if (exportAsSeparateFiles) {
|
||||||
|
objFileMap = new HashMap<>();
|
||||||
|
} else {
|
||||||
|
objFileMap = Map.of(this.filePath, obj);
|
||||||
|
}
|
||||||
|
|
||||||
// Get all the components to export
|
// Get all the components to export
|
||||||
Set<RocketComponent> componentsToExport = new HashSet<>(this.components);
|
Set<RocketComponent> componentsToExport = new HashSet<>(this.components);
|
||||||
if (this.options.isExportChildren()) {
|
if (this.options.isExportChildren()) {
|
||||||
@ -127,30 +135,42 @@ public class OBJExporterFactory {
|
|||||||
String groupName = idx + "_" + component.getName();
|
String groupName = idx + "_" + component.getName();
|
||||||
handleComponent(obj, this.configuration, this.options.getTransformer(), component, groupName, this.options.getLOD());
|
handleComponent(obj, this.configuration, this.options.getTransformer(), component, groupName, this.options.getLOD());
|
||||||
|
|
||||||
// If separate export, already need to write the OBJ here
|
// If separate export, add this object to the map of objects to export
|
||||||
if (exportAsSeparateFiles) {
|
if (exportAsSeparateFiles) {
|
||||||
String path = FileUtils.removeExtension(this.filePath) + "_" + groupName + ".obj";
|
String path = FileUtils.removeExtension(this.filePath) + "_" + groupName + ".obj";
|
||||||
writeObj(obj, path);
|
objFileMap.put(path, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.options.isTriangulate()) {
|
// Apply export options and write the OBJ files
|
||||||
obj = de.javagl.obj.ObjUtils.triangulate(obj, new DefaultObj());
|
for (Map.Entry<String, DefaultObj> entry : objFileMap.entrySet()) {
|
||||||
}
|
String filePath = entry.getKey();
|
||||||
|
obj = entry.getValue();
|
||||||
|
|
||||||
if (this.options.isRemoveOffset()) {
|
// Triangulate mesh
|
||||||
// Because of some rotation and translation operations when creating the meshes, the bounds can be inaccurate.
|
if (this.options.isTriangulate()) {
|
||||||
// Therefore, we will recalculate them to be sure.
|
obj = de.javagl.obj.ObjUtils.triangulate(obj, new DefaultObj());
|
||||||
// Is a bit computationally expensive, but it's the only way to be sure...
|
}
|
||||||
obj.recalculateAllVertexBounds();
|
|
||||||
|
|
||||||
ObjUtils.removeVertexOffset(obj, this.options.getTransformer());
|
// Remove position offset
|
||||||
}
|
if (this.options.isRemoveOffset()) {
|
||||||
|
// Because of some rotation and translation operations when creating the meshes, the bounds can be inaccurate.
|
||||||
|
// Therefore, we will recalculate them to be sure.
|
||||||
|
// Is a bit computationally expensive, but it's the only way to be sure...
|
||||||
|
obj.recalculateAllVertexBounds();
|
||||||
|
|
||||||
if (!exportAsSeparateFiles) {
|
ObjUtils.removeVertexOffset(obj, this.options.getTransformer());
|
||||||
writeObj(obj, this.filePath);
|
}
|
||||||
|
|
||||||
|
// Perform scaling
|
||||||
|
if (Float.compare(options.getScaling(), 1) != 0) {
|
||||||
|
ObjUtils.scaleVertices(obj, options.getScaling());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the OBJ file
|
||||||
|
writeObj(obj, filePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user