Add basic material exporting :)

This commit is contained in:
SiboVG 2023-08-17 00:55:49 +02:00
parent ee51a7ec49
commit 6e981a39a0
3 changed files with 98 additions and 3 deletions

View File

@ -0,0 +1,68 @@
package net.sf.openrocket.file.wavefrontobj.export;
import net.sf.openrocket.appearance.Appearance;
import net.sf.openrocket.appearance.defaults.DefaultAppearance;
import net.sf.openrocket.file.wavefrontobj.DefaultMtl;
import net.sf.openrocket.file.wavefrontobj.DefaultObj;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.util.Color;
import java.util.List;
/**
* Helper class for exporting a rocket component's appearance to an MTL file.
*
* @author Sibo Van Gool <sibo.vangool@hotmail.com>
*/
public class MtlExpoter {
private final DefaultObj obj;
private final RocketComponent component;
private final String materialName;
private List<DefaultMtl> materials;
/**
* Export the appearance of a rocket component
* <b>NOTE: </b> you still have to call {@link #doExport()} to actually export the appearance.
* @param obj The obj file that will use the material
* @param component The component to export the appearance of
* @param materialName The name of the material to generate
* @param materials The list of materials to add the new material(s) to
*/
public MtlExpoter(DefaultObj obj, RocketComponent component, String materialName, List<DefaultMtl> materials) {
this.obj = obj;
this.component = component;
this.materialName = materialName;
this.materials = materials;
}
/**
* Export the appearance of the component to the MTL file. Also sets the active material group in the OBJ file.
*/
public void doExport() {
// Set the active material group
obj.setActiveMaterialGroupName(materialName);
DefaultMtl material = new DefaultMtl(materialName);
// Get the component appearance
Appearance appearance = component.getAppearance();
if (appearance == null) {
appearance = DefaultAppearance.getDefaultAppearance(component);
}
// Apply coloring
Color color = appearance.getPaint();
final float r = color.getRed()/255f;
final float g = color.getGreen()/255f;
final float b = color.getBlue()/255f;
material.setKd(r, g, b); // Diffuse color
material.setKa(0f, 0f, 0f); // No emission
material.setKs(1f, 1f, 1f); // Use white specular highlights
material.setD(color.getAlpha()/255f); // Opacity
material.setNs((float) appearance.getShine() * 750); // Shine (max is 1000, but this too strong compared to OpenRocket's max)
material.setIllum(2); // Use Phong reflection (specular highlights etc.)
// TODO: Apply texture
materials.add(material);
}
}

View File

@ -2,6 +2,8 @@ package net.sf.openrocket.file.wavefrontobj.export;
import de.javagl.obj.ObjWriter;
import net.sf.openrocket.file.wavefrontobj.CoordTransform;
import net.sf.openrocket.file.wavefrontobj.DefaultMtl;
import net.sf.openrocket.file.wavefrontobj.DefaultMtlWriter;
import net.sf.openrocket.file.wavefrontobj.DefaultObj;
import net.sf.openrocket.file.wavefrontobj.ObjUtils;
import net.sf.openrocket.file.wavefrontobj.export.components.BodyTubeExporter;
@ -94,6 +96,8 @@ public class OBJExporterFactory {
public void doExport() {
DefaultObj obj = new DefaultObj();
Map<String, DefaultObj> objFileMap;
Map<DefaultObj, List<DefaultMtl>> materials = new HashMap<>();
materials.put(obj, new ArrayList<>());
boolean exportAsSeparateFiles = this.options.isExportAsSeparateFiles();
if (exportAsSeparateFiles) {
@ -129,11 +133,13 @@ public class OBJExporterFactory {
// If separate export, create a new OBJ for each component
if (exportAsSeparateFiles) {
obj = new DefaultObj();
materials.put(obj, new ArrayList<>());
}
// Component exporting
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,
materials.get(obj), this.options.getLOD(), options);
// If separate export, add this object to the map of objects to export
if (exportAsSeparateFiles) {
@ -169,6 +175,18 @@ public class OBJExporterFactory {
ObjUtils.scaleVertices(obj, options.getScaling());
}
// Export materials
if (options.isExportAppearance()) {
String mtlFilePath = FileUtils.removeExtension(filePath) + ".mtl";
List<DefaultMtl> mtls = materials.get(obj);
try (OutputStream mtlOutputStream = new FileOutputStream(mtlFilePath)) {
DefaultMtlWriter.write(mtls, mtlOutputStream);
} catch (IOException e) {
throw new RuntimeException(e);
}
obj.setMtlFileNames(List.of(mtlFilePath));
}
// Write the OBJ file
writeObj(obj, filePath);
}
@ -184,7 +202,8 @@ public class OBJExporterFactory {
@SuppressWarnings("unchecked") // This is safe because of the structure we set up.
private <T extends RocketComponent> void handleComponent(DefaultObj obj, FlightConfiguration config, CoordTransform transformer,
T component, String groupName, ObjUtils.LevelOfDetail LOD) {
T component, String groupName, List<DefaultMtl> materials,
ObjUtils.LevelOfDetail LOD, OBJExportOptions options) {
ExporterFactory<T> factory = null;
Class<?> currentClass = component.getClass();
@ -198,6 +217,12 @@ public class OBJExporterFactory {
throw new IllegalArgumentException("Unsupported component type: " + component.getClass().getName());
}
// Export material
if (options.isExportAppearance()) {
MtlExpoter mtlExpoter = new MtlExpoter(obj, component, "mat_" + groupName, materials);
mtlExpoter.doExport();
}
// Export component
final RocketComponentExporter<T> exporter = factory.create(obj, config, transformer, component, groupName, LOD);
exporter.addToObj();

View File

@ -19,6 +19,8 @@ public class RingComponentExporter extends RocketComponentExporter<RingComponent
@Override
public void addToObj() {
obj.setActiveGroupNames(groupName);
final float outerRadius = (float) component.getOuterRadius();
final float innerRadius = (float) component.getInnerRadius();
final float length = (float) component.getLength();
@ -32,7 +34,7 @@ public class RingComponentExporter extends RocketComponentExporter<RingComponent
private void generateMesh(float outerRadius, float innerRadius, float length, InstanceContext context) {
// Generate the mesh
int startIdx = obj.getNumVertices();
TubeExporter.addTubeMesh(obj, transformer, groupName, outerRadius, innerRadius, length, LOD);
TubeExporter.addTubeMesh(obj, transformer, null, outerRadius, innerRadius, length, LOD);
int endIdx = Math.max(obj.getNumVertices() - 1, startIdx); // Clamp in case no vertices were added
// Translate the mesh to the position in the rocket