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.FinSetExporter;
|
||||||
import net.sf.openrocket.file.wavefrontobj.export.components.LaunchLugExporter;
|
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.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.RailButtonExporter;
|
||||||
import net.sf.openrocket.file.wavefrontobj.export.components.RocketComponentExporter;
|
import net.sf.openrocket.file.wavefrontobj.export.components.RocketComponentExporter;
|
||||||
import net.sf.openrocket.file.wavefrontobj.export.components.RingComponentExporter;
|
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.InstanceMap;
|
||||||
import net.sf.openrocket.rocketcomponent.LaunchLug;
|
import net.sf.openrocket.rocketcomponent.LaunchLug;
|
||||||
import net.sf.openrocket.rocketcomponent.MassObject;
|
import net.sf.openrocket.rocketcomponent.MassObject;
|
||||||
|
import net.sf.openrocket.rocketcomponent.MotorMount;
|
||||||
import net.sf.openrocket.rocketcomponent.RailButton;
|
import net.sf.openrocket.rocketcomponent.RailButton;
|
||||||
import net.sf.openrocket.rocketcomponent.RingComponent;
|
import net.sf.openrocket.rocketcomponent.RingComponent;
|
||||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||||
@ -135,16 +137,15 @@ public class OBJExporterFactory {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the instance transforms
|
||||||
InstanceMap map = configuration.getActiveInstances();
|
InstanceMap map = configuration.getActiveInstances();
|
||||||
ArrayList<InstanceContext> contexts = map.get(component);
|
ArrayList<InstanceContext> contexts = map.get(component);
|
||||||
contexts.get(0).transform.getXrotation();
|
contexts.get(0).transform.getXrotation();
|
||||||
|
|
||||||
|
// Component exporting
|
||||||
String groupName = component.getName() + "_" + idx;
|
String groupName = component.getName() + "_" + idx;
|
||||||
handleComponent(obj, this.configuration, this.transformer, component, groupName, this.LOD);
|
handleComponent(obj, this.configuration, this.transformer, component, groupName, this.LOD);
|
||||||
|
|
||||||
// TODO: motor rendering
|
|
||||||
|
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,8 +185,15 @@ public class OBJExporterFactory {
|
|||||||
throw new IllegalArgumentException("Unsupported component type: " + component.getClass().getName());
|
throw new IllegalArgumentException("Unsupported component type: " + component.getClass().getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Export component
|
||||||
final RocketComponentExporter<T> exporter = factory.create(obj, config, transformer, component, groupName, LOD);
|
final RocketComponentExporter<T> exporter = factory.create(obj, config, transformer, component, groupName, LOD);
|
||||||
exporter.addToObj();
|
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> {
|
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,
|
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) {
|
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,
|
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) {
|
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,
|
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) {
|
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,
|
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) {
|
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,
|
public static void generateRingVertices(DefaultObj obj, CoordTransform transformer,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user