Add basic material exporting :)
This commit is contained in:
parent
ee51a7ec49
commit
6e981a39a0
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,8 @@ package net.sf.openrocket.file.wavefrontobj.export;
|
|||||||
|
|
||||||
import de.javagl.obj.ObjWriter;
|
import de.javagl.obj.ObjWriter;
|
||||||
import net.sf.openrocket.file.wavefrontobj.CoordTransform;
|
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.DefaultObj;
|
||||||
import net.sf.openrocket.file.wavefrontobj.ObjUtils;
|
import net.sf.openrocket.file.wavefrontobj.ObjUtils;
|
||||||
import net.sf.openrocket.file.wavefrontobj.export.components.BodyTubeExporter;
|
import net.sf.openrocket.file.wavefrontobj.export.components.BodyTubeExporter;
|
||||||
@ -94,6 +96,8 @@ public class OBJExporterFactory {
|
|||||||
public void doExport() {
|
public void doExport() {
|
||||||
DefaultObj obj = new DefaultObj();
|
DefaultObj obj = new DefaultObj();
|
||||||
Map<String, DefaultObj> objFileMap;
|
Map<String, DefaultObj> objFileMap;
|
||||||
|
Map<DefaultObj, List<DefaultMtl>> materials = new HashMap<>();
|
||||||
|
materials.put(obj, new ArrayList<>());
|
||||||
boolean exportAsSeparateFiles = this.options.isExportAsSeparateFiles();
|
boolean exportAsSeparateFiles = this.options.isExportAsSeparateFiles();
|
||||||
|
|
||||||
if (exportAsSeparateFiles) {
|
if (exportAsSeparateFiles) {
|
||||||
@ -129,11 +133,13 @@ public class OBJExporterFactory {
|
|||||||
// If separate export, create a new OBJ for each component
|
// If separate export, create a new OBJ for each component
|
||||||
if (exportAsSeparateFiles) {
|
if (exportAsSeparateFiles) {
|
||||||
obj = new DefaultObj();
|
obj = new DefaultObj();
|
||||||
|
materials.put(obj, new ArrayList<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Component exporting
|
// Component exporting
|
||||||
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,
|
||||||
|
materials.get(obj), this.options.getLOD(), options);
|
||||||
|
|
||||||
// If separate export, add this object to the map of objects to export
|
// If separate export, add this object to the map of objects to export
|
||||||
if (exportAsSeparateFiles) {
|
if (exportAsSeparateFiles) {
|
||||||
@ -169,6 +175,18 @@ public class OBJExporterFactory {
|
|||||||
ObjUtils.scaleVertices(obj, options.getScaling());
|
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
|
// Write the OBJ file
|
||||||
writeObj(obj, filePath);
|
writeObj(obj, filePath);
|
||||||
}
|
}
|
||||||
@ -184,7 +202,8 @@ public class OBJExporterFactory {
|
|||||||
|
|
||||||
@SuppressWarnings("unchecked") // This is safe because of the structure we set up.
|
@SuppressWarnings("unchecked") // This is safe because of the structure we set up.
|
||||||
private <T extends RocketComponent> void handleComponent(DefaultObj obj, FlightConfiguration config, CoordTransform transformer,
|
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;
|
ExporterFactory<T> factory = null;
|
||||||
Class<?> currentClass = component.getClass();
|
Class<?> currentClass = component.getClass();
|
||||||
|
|
||||||
@ -198,6 +217,12 @@ public class OBJExporterFactory {
|
|||||||
throw new IllegalArgumentException("Unsupported component type: " + component.getClass().getName());
|
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
|
// 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();
|
||||||
|
@ -19,6 +19,8 @@ public class RingComponentExporter extends RocketComponentExporter<RingComponent
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addToObj() {
|
public void addToObj() {
|
||||||
|
obj.setActiveGroupNames(groupName);
|
||||||
|
|
||||||
final float outerRadius = (float) component.getOuterRadius();
|
final float outerRadius = (float) component.getOuterRadius();
|
||||||
final float innerRadius = (float) component.getInnerRadius();
|
final float innerRadius = (float) component.getInnerRadius();
|
||||||
final float length = (float) component.getLength();
|
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) {
|
private void generateMesh(float outerRadius, float innerRadius, float length, InstanceContext context) {
|
||||||
// Generate the mesh
|
// Generate the mesh
|
||||||
int startIdx = obj.getNumVertices();
|
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
|
int endIdx = Math.max(obj.getNumVertices() - 1, startIdx); // Clamp in case no vertices were added
|
||||||
|
|
||||||
// Translate the mesh to the position in the rocket
|
// Translate the mesh to the position in the rocket
|
||||||
|
Loading…
x
Reference in New Issue
Block a user