Render motors
This commit is contained in:
parent
2ac695955e
commit
7d47de6011
@ -8,6 +8,7 @@ import net.sf.openrocket.file.wavefrontobj.export.components.BodyTubeExporter;
|
||||
import net.sf.openrocket.file.wavefrontobj.export.components.FinSetExporter;
|
||||
import net.sf.openrocket.file.wavefrontobj.export.components.LaunchLugExporter;
|
||||
import net.sf.openrocket.file.wavefrontobj.export.components.MassObjectExporter;
|
||||
import net.sf.openrocket.file.wavefrontobj.export.components.MotorExporter;
|
||||
import net.sf.openrocket.file.wavefrontobj.export.components.RailButtonExporter;
|
||||
import net.sf.openrocket.file.wavefrontobj.export.components.RocketComponentExporter;
|
||||
import net.sf.openrocket.file.wavefrontobj.export.components.RingComponentExporter;
|
||||
@ -21,6 +22,7 @@ import net.sf.openrocket.rocketcomponent.InstanceContext;
|
||||
import net.sf.openrocket.rocketcomponent.InstanceMap;
|
||||
import net.sf.openrocket.rocketcomponent.LaunchLug;
|
||||
import net.sf.openrocket.rocketcomponent.MassObject;
|
||||
import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||
import net.sf.openrocket.rocketcomponent.RailButton;
|
||||
import net.sf.openrocket.rocketcomponent.RingComponent;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
@ -135,16 +137,15 @@ public class OBJExporterFactory {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the instance transforms
|
||||
InstanceMap map = configuration.getActiveInstances();
|
||||
ArrayList<InstanceContext> contexts = map.get(component);
|
||||
contexts.get(0).transform.getXrotation();
|
||||
|
||||
|
||||
// Component exporting
|
||||
String groupName = component.getName() + "_" + idx;
|
||||
handleComponent(obj, this.configuration, this.transformer, component, groupName, this.LOD);
|
||||
|
||||
// TODO: motor rendering
|
||||
|
||||
idx++;
|
||||
}
|
||||
|
||||
@ -184,8 +185,15 @@ public class OBJExporterFactory {
|
||||
throw new IllegalArgumentException("Unsupported component type: " + component.getClass().getName());
|
||||
}
|
||||
|
||||
// Export component
|
||||
final RocketComponentExporter<T> exporter = factory.create(obj, config, transformer, component, groupName, LOD);
|
||||
exporter.addToObj();
|
||||
|
||||
// Export motor
|
||||
if (component instanceof MotorMount) {
|
||||
MotorExporter motorExporter = new MotorExporter(obj, config, transformer, component, groupName, LOD);
|
||||
motorExporter.addToObj();
|
||||
}
|
||||
}
|
||||
|
||||
interface ExporterFactory<T extends RocketComponent> {
|
||||
|
@ -0,0 +1,136 @@
|
||||
package net.sf.openrocket.file.wavefrontobj.export.components;
|
||||
|
||||
import net.sf.openrocket.file.wavefrontobj.CoordTransform;
|
||||
import net.sf.openrocket.file.wavefrontobj.DefaultObj;
|
||||
import net.sf.openrocket.file.wavefrontobj.DefaultObjFace;
|
||||
import net.sf.openrocket.file.wavefrontobj.ObjUtils;
|
||||
import net.sf.openrocket.file.wavefrontobj.export.shapes.CylinderExporter;
|
||||
import net.sf.openrocket.file.wavefrontobj.export.shapes.DiskExporter;
|
||||
import net.sf.openrocket.motor.Motor;
|
||||
import net.sf.openrocket.motor.MotorConfiguration;
|
||||
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
|
||||
import net.sf.openrocket.rocketcomponent.InstanceContext;
|
||||
import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MotorExporter {
|
||||
protected final DefaultObj obj;
|
||||
protected final FlightConfiguration config;
|
||||
protected final RocketComponent mount;
|
||||
protected final String groupName;
|
||||
protected final ObjUtils.LevelOfDetail LOD;
|
||||
protected final CoordTransform transformer;
|
||||
|
||||
/**
|
||||
* Wavefront OBJ exporter for a rocket component.
|
||||
*
|
||||
* @param obj The OBJ to export to
|
||||
* @param config The flight configuration to use for the export
|
||||
* @param transformer Coordinate system transformer to use to switch from the OpenRocket coordinate system to a custom OBJ coordinate system
|
||||
* @param mount The motor mount that holds the motor to export
|
||||
* @param groupName The name of the group to export to
|
||||
* @param LOD Level of detail to use for the export (e.g. '80')
|
||||
*/
|
||||
public MotorExporter(DefaultObj obj, FlightConfiguration config, CoordTransform transformer, RocketComponent mount,
|
||||
String groupName, ObjUtils.LevelOfDetail LOD) {
|
||||
if (!(mount instanceof MotorMount)) {
|
||||
throw new IllegalArgumentException("Motor exporter can only be used for motor mounts");
|
||||
}
|
||||
this.obj = obj;
|
||||
this.config = config;
|
||||
this.transformer = transformer;
|
||||
this.mount = mount;
|
||||
this.groupName = groupName;
|
||||
this.LOD = LOD;
|
||||
}
|
||||
|
||||
public void addToObj() {
|
||||
MotorConfiguration motoConfig = ((MotorMount) mount).getMotorConfig(config.getId());
|
||||
Motor motor = motoConfig.getMotor();
|
||||
|
||||
if (motor == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
obj.setActiveGroupNames(motor.getMotorName());
|
||||
|
||||
for (InstanceContext context : config.getActiveInstances().getInstanceContexts(mount)) {
|
||||
generateMesh(motor, context);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateMesh(Motor motor, InstanceContext context) {
|
||||
final double length = motor.getLength();
|
||||
final double radius = motor.getDiameter() / 2;
|
||||
final float coneLength = (float) (0.05 * length); // Length of the indent cone at the aft end of the motor
|
||||
final int numSides = LOD.getNrOfSides(radius);
|
||||
final int startIdx = obj.getNumVertices();
|
||||
|
||||
// Draw the cylinder
|
||||
List<Integer> foreRingVertices = new ArrayList<>();
|
||||
List<Integer> aftRingVertices = new ArrayList<>();
|
||||
CylinderExporter.addCylinderMesh(obj, transformer, null, (float) radius, (float) length, numSides, false, true,
|
||||
foreRingVertices, aftRingVertices);
|
||||
|
||||
// Close the fore end
|
||||
DiskExporter.closeDiskMesh(obj, transformer, null, foreRingVertices, false, true);
|
||||
|
||||
// Generate the aft end inner ring vertices
|
||||
List<Integer> aftInnerRingVertices = new ArrayList<>();
|
||||
final int normalsStartIdx = obj.getNumNormals();
|
||||
final float innerRadius = (float) (0.8 * radius);
|
||||
for (int i = 0; i < numSides; i++) {
|
||||
final double angle = 2.0f * Math.PI * i / numSides;
|
||||
final float x = (float) length;
|
||||
final float y = (float) (innerRadius * Math.cos(angle));
|
||||
final float z = (float) (innerRadius * Math.sin(angle));
|
||||
obj.addVertex(transformer.convertLoc(x, y, z));
|
||||
|
||||
final double slopeAngle = Math.atan(coneLength / innerRadius);
|
||||
final float nx = (float) Math.cos(slopeAngle);
|
||||
final float ny = (float) -Math.cos(angle);
|
||||
final float nz = (float) -Math.sin(angle);
|
||||
obj.addNormal(transformer.convertLocWithoutOriginOffs(nx, ny, nz));
|
||||
|
||||
aftInnerRingVertices.add(obj.getNumVertices() - 1);
|
||||
}
|
||||
|
||||
// Close outer and inner aft ring
|
||||
DiskExporter.closeDiskMesh(obj, transformer, null, aftRingVertices, aftInnerRingVertices, false, false);
|
||||
|
||||
// Add cone tip vertex
|
||||
obj.addVertex(transformer.convertLoc(length - coneLength, 0, 0));
|
||||
obj.addNormal(transformer.convertLocWithoutOriginOffs(1, 0, 0));
|
||||
|
||||
int endIdx = Math.max(obj.getNumVertices() - 1, startIdx); // Clamp in case no vertices were added
|
||||
int normalsEndIdx = Math.max(obj.getNumNormals() - 1, normalsStartIdx);
|
||||
|
||||
// Create the cone faces
|
||||
for (int i = 0; i < numSides; i++) {
|
||||
final int nextIdx = (i + 1) % numSides;
|
||||
final int[] vertexIndices = new int[] {
|
||||
endIdx,
|
||||
aftInnerRingVertices.get(nextIdx),
|
||||
aftInnerRingVertices.get(i),
|
||||
};
|
||||
final int[] normalIndices = new int[] {
|
||||
normalsEndIdx,
|
||||
normalsStartIdx + nextIdx,
|
||||
normalsStartIdx + i,
|
||||
};
|
||||
|
||||
DefaultObjFace face = new DefaultObjFace(vertexIndices, null, normalIndices);
|
||||
obj.addFace(face);
|
||||
}
|
||||
|
||||
|
||||
// Translate the mesh to the position in the rocket
|
||||
Coordinate location = context.getLocation();
|
||||
location = location.add(mount.getLength() - length, 0, 0); // Motor starts at the aft end of the mount
|
||||
ObjUtils.translateVerticesFromComponentLocation(obj, transformer, startIdx, endIdx, location);
|
||||
}
|
||||
}
|
@ -129,27 +129,27 @@ public class CylinderExporter {
|
||||
}
|
||||
|
||||
public static void addCylinderMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName,
|
||||
float radius, float height, int numSides, boolean solid,
|
||||
float radius, float length, int numSides, boolean solid,
|
||||
List<Integer> foreRingVertices, List<Integer> aftRingVertices) {
|
||||
addCylinderMesh(obj, transformer, groupName, radius, height, numSides, solid, true, foreRingVertices, aftRingVertices);
|
||||
addCylinderMesh(obj, transformer, groupName, radius, length, numSides, solid, true, foreRingVertices, aftRingVertices);
|
||||
}
|
||||
|
||||
public static void addCylinderMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName,
|
||||
float radius, float height, boolean solid, ObjUtils.LevelOfDetail LOD,
|
||||
float radius, float length, boolean solid, ObjUtils.LevelOfDetail LOD,
|
||||
List<Integer> foreRingVertices, List<Integer> aftRingVertices) {
|
||||
addCylinderMesh(obj, transformer, groupName, radius, height, LOD.getNrOfSides(radius), solid, foreRingVertices, aftRingVertices);
|
||||
addCylinderMesh(obj, transformer, groupName, radius, length, LOD.getNrOfSides(radius), solid, foreRingVertices, aftRingVertices);
|
||||
}
|
||||
|
||||
public static void addCylinderMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName,
|
||||
float radius, float height, boolean solid, boolean isOutside, int nrOfSlices,
|
||||
float radius, float length, boolean solid, boolean isOutside, int nrOfSlices,
|
||||
List<Integer> foreRingVertices, List<Integer> aftRingVertices) {
|
||||
addCylinderMesh(obj, transformer, groupName, radius, height, nrOfSlices, solid, isOutside, foreRingVertices, aftRingVertices);
|
||||
addCylinderMesh(obj, transformer, groupName, radius, length, nrOfSlices, solid, isOutside, foreRingVertices, aftRingVertices);
|
||||
}
|
||||
|
||||
public static void addCylinderMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName,
|
||||
float radius, float height, boolean solid, int nrOfSlices,
|
||||
float radius, float length, boolean solid, int nrOfSlices,
|
||||
List<Integer> foreRingVertices, List<Integer> aftRingVertices) {
|
||||
addCylinderMesh(obj, transformer, groupName, radius, height, nrOfSlices, solid, foreRingVertices, aftRingVertices);
|
||||
addCylinderMesh(obj, transformer, groupName, radius, length, nrOfSlices, solid, foreRingVertices, aftRingVertices);
|
||||
}
|
||||
|
||||
public static void generateRingVertices(DefaultObj obj, CoordTransform transformer,
|
||||
|
Loading…
x
Reference in New Issue
Block a user