Add texturing for motors

This commit is contained in:
SiboVG 2023-08-21 02:42:51 +02:00
parent 4fc3901f00
commit d63e2e9084
3 changed files with 137 additions and 17 deletions

View File

@ -74,10 +74,10 @@ public class MotorExporter {
List<Integer> foreRingVertices = new ArrayList<>();
List<Integer> aftRingVertices = new ArrayList<>();
CylinderExporter.addCylinderMesh(obj, transformer, null, (float) radius, (float) length, numSides, false, true,
foreRingVertices, aftRingVertices);
0, 1, 0.125f, 0.875f, foreRingVertices, aftRingVertices);
// Close the fore end
DiskExporter.closeDiskMesh(obj, transformer, null, foreRingVertices, false, true);
DiskExporter.closeDiskMesh(obj, transformer, null, foreRingVertices, false, true, 0, 1, 0.875f, 1);
// Generate the aft end inner ring vertices
List<Integer> aftInnerRingVertices = new ArrayList<>();
@ -100,12 +100,26 @@ public class MotorExporter {
}
// Close outer and inner aft ring
DiskExporter.closeDiskMesh(obj, transformer, null, aftRingVertices, aftInnerRingVertices, false, false);
DiskExporter.closeDiskMesh(obj, transformer, null, aftRingVertices, aftInnerRingVertices, false, false, 0, 1, 0.125f, 0.1f);
// Add cone tip vertex
obj.addVertex(transformer.convertLoc(length - coneLength, 0, 0));
obj.addNormal(transformer.convertLocWithoutOriginOffs(1, 0, 0));
// Add texture coordinates
final int texCoordsStartIdx = obj.getNumTexCoords();
//// Inner aft ring
for (int i = 0; i <= numSides; i++) {
final float u = ((float) i) / numSides;
obj.addTexCoord(u, 0.1f);
}
//// Cone tip
for (int i = 0; i <= numSides; i++) {
final float u = ((float) i) / numSides;
obj.addTexCoord(u, 0f);
}
int endIdx = Math.max(obj.getNumVertices() - 1, startIdx); // Clamp in case no vertices were added
int normalsEndIdx = Math.max(obj.getNumNormals() - 1, normalsStartIdx);
@ -122,8 +136,14 @@ public class MotorExporter {
normalsStartIdx + nextIdx,
normalsStartIdx + i,
};
final int[] texCoordIndices = new int[] {
numSides+1 + i,
i+1,
i,
};
ObjUtils.offsetIndex(texCoordIndices, texCoordsStartIdx);
DefaultObjFace face = new DefaultObjFace(vertexIndices, null, normalIndices);
DefaultObjFace face = new DefaultObjFace(vertexIndices, texCoordIndices, normalIndices);
obj.addFace(face);
}

View File

@ -5,6 +5,7 @@ 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.util.MathUtil;
import java.util.List;
@ -22,6 +23,10 @@ public class CylinderExporter {
* NOTE: Culling is not really thought of for the hollow cylinder; this mode is really meant to be
* combined with other objects
* @param isOutside Whether the cylinder is an outside face (true) or inside face (false)
* @param uMin The minimum u texture coordinate
* @param uMax The maximum u texture coordinate
* @param vMin The minimum v texture coordinate
* @param vMax The maximum v texture coordinate
* @param foreRingVertices A list to add the fore (top) ring vertex indices to
* @param aftRingVertices A list to add the aft (bottom) ring vertex indices to
* @param foreRingNormals A list to add the fore (top) ring normal indices to
@ -29,6 +34,7 @@ public class CylinderExporter {
*/
public static void addCylinderMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName,
float foreRadius, float aftRadius, float length, int numSides, boolean solid, boolean isOutside,
float uMin, float uMax, float vMin, float vMax,
List<Integer> foreRingVertices, List<Integer> aftRingVertices,
List<Integer> foreRingNormals, List<Integer> aftRingNormals) {
// Set the new group
@ -52,10 +58,12 @@ public class CylinderExporter {
}
// Generate side top vertices
generateRingVertices(obj, transformer, numSides, 0, length, length, foreRadius, aftRadius, isOutside, foreRingVertices, foreRingNormals);
generateRingVertices(obj, transformer, numSides, 0, length, length, foreRadius, aftRadius, isOutside,
uMin, uMax, vMin, vMax, foreRingVertices, foreRingNormals);
// Generate side bottom vertices
generateRingVertices(obj, transformer, numSides, length, 0, length, aftRadius, foreRadius, isOutside, aftRingVertices, aftRingNormals);
generateRingVertices(obj, transformer, numSides, length, 0, length, aftRadius, foreRadius, isOutside,
uMin, uMax, vMin, vMax, aftRingVertices, aftRingNormals);
// Create faces for the bottom and top
if (solid) {
@ -138,6 +146,21 @@ public class CylinderExporter {
obj.addFace(face);
}
}
public static void addCylinderMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName,
float foreRadius, float aftRadius, float length, int numSides, boolean solid, boolean isOutside,
List<Integer> foreRingVertices, List<Integer> aftRingVertices,
List<Integer> foreRingNormals, List<Integer> aftRingNormals) {
addCylinderMesh(obj, transformer, groupName, foreRadius, aftRadius, length, numSides, solid, isOutside,
0, 1, 0, 1, foreRingVertices, aftRingVertices, foreRingNormals, aftRingNormals);
}
public static void addCylinderMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName,
float foreRadius, float aftRadius, float length, int numSides, boolean solid, boolean isOutside,
float uMin, float uMax, float vMin, float vMax,
List<Integer> foreRingVertices, List<Integer> aftRingVertices) {
addCylinderMesh(obj, transformer, groupName, foreRadius, aftRadius, length, numSides, solid, isOutside,
uMin, uMax, vMin, vMax, foreRingVertices, aftRingVertices, null, null);
}
public static void addCylinderMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName,
float foreRadius, float aftRadius, float length, int numSides, boolean solid, boolean isOutside,
@ -146,6 +169,14 @@ public class CylinderExporter {
foreRingVertices, aftRingVertices, null, null);
}
public static void addCylinderMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName,
float radius, float length, int numSides, boolean solid, boolean isOutside,
float uMin, float uMax, float vMin, float vMax,
List<Integer> foreRingVertices, List<Integer> aftRingVertices) {
addCylinderMesh(obj, transformer, groupName, radius, radius, length, numSides, solid, isOutside,
uMin, uMax, vMin, vMax, foreRingVertices, aftRingVertices);
}
public static void addCylinderMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName,
float radius, float length, int numSides, boolean solid, boolean isOutside,
List<Integer> foreRingVertices, List<Integer> aftRingVertices) {
@ -172,7 +203,8 @@ public class CylinderExporter {
public static void generateRingVertices(DefaultObj obj, CoordTransform transformer,
int numSides, float x, float nextX, float xMax, float radius, float nextRadius,
boolean isOutside, List<Integer> vertexList, List<Integer> normalList) {
boolean isOutside, float uMin, float uMax, float vMin, float vMax,
List<Integer> vertexList, List<Integer> normalList) {
int startIdx = obj.getNumVertices();
int normalsStartIdx = obj.getNumNormals();
@ -181,10 +213,11 @@ public class CylinderExporter {
final float y = radius * (float) Math.cos(angle);
final float z = radius * (float) Math.sin(angle);
// Side top vertices
// Vertex
obj.addVertex(transformer.convertLoc(x, y, z));
// We need special nx normal when the radius changes
// Normal
//// We need special nx normal when the radius changes
float nx;
if (Float.compare(radius, nextRadius) != 0) {
final double slopeAngle = Math.atan(Math.abs(nextX - x) / (nextRadius - radius));
@ -209,13 +242,17 @@ public class CylinderExporter {
}
// Texture coordinates
final float u = (float) i / numSides;
final float v = isOutside ? (xMax - x) / xMax : x / xMax; // For some reason, the texture is vertically flipped in OR for inside cylinders. Don't really like it, but it is what it is
float u = ((float) i) / numSides;
u = (float) MathUtil.map(u, 0, 1, uMin, uMax);
float v = isOutside ? (xMax - x) / xMax : x / xMax; // For some reason, the texture is vertically flipped in OR for inside cylinders. Don't really like it, but it is what it is
v = (float) MathUtil.map(v, 0, 1, vMin, vMax);
obj.addTexCoord(u, v);
}
// Need to add a last texture coordinate for the end of the texture
final float v = isOutside ? (xMax - x) / xMax : x / xMax;
obj.addTexCoord(1f, v);
float v = isOutside ? (xMax - x) / xMax : x / xMax;
v = (float) MathUtil.map(v, 0, 1, vMin, vMax);
obj.addTexCoord(uMax, v);
}
}

View File

@ -19,10 +19,15 @@ public class DiskExporter {
* @param innerVertices The indices of the inner vertices, or null if the disk is solid
* @param isClockwise Whether the vertices are in clockwise order (true) or counter-clockwise order (false)
* @param isTopFace Whether the disk is a top face (true) or bottom face (false)
* @param uMin The minimum u texture coordinate
* @param uMax The maximum u texture coordinate
* @param vMin The minimum v texture coordinate
* @param vMax The maximum v texture coordinate
*/
public static void closeDiskMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName,
@NotNull List<Integer> outerVertices, List<Integer> innerVertices,
boolean isClockwise, boolean isTopFace) {
boolean isClockwise, boolean isTopFace,
float uMin, float uMax, float vMin, float vMax) {
if (outerVertices.isEmpty()) {
throw new IllegalArgumentException("Outer vertices cannot be empty");
}
@ -45,6 +50,21 @@ public class DiskExporter {
obj.addNormal(transformer.convertLocWithoutOriginOffs(isTopFace ? -1 : 1, 0, 0)); // TODO: hm, what if the object is rotated? If the disk is not drawn in the y direction?
final int normalIndex = obj.getNumNormals() - 1;
final int texCoordsStartIdx = obj.getNumTexCoords();
final int numSides = outerVertices.size();
// Create the texture coordinates
//// Outer vertices
for (int i = 0; i <= numSides; i++) {
final float u = uMin + ((float) i) / numSides * (uMax - uMin);
obj.addTexCoord(u, vMin);
}
//// Inner vertices
for (int i = 0; i <= numSides; i++) {
final float u = uMin + ((float) i) / numSides * (uMax - uMin);
obj.addTexCoord(u, vMax);
}
if (isSolid) {
// Add the center vertex
final int centerVertexIdx;
@ -59,6 +79,8 @@ public class DiskExporter {
// Add the triangle faces
for (int i = 0; i < outerVertices.size(); i++) {
int nextIdx = (i + 1) % outerVertices.size();
// Vertices
int[] vertexIndices = new int[] {
centerVertexIdx,
outerVertices.get(nextIdx),
@ -66,14 +88,27 @@ public class DiskExporter {
};
vertexIndices = ObjUtils.reverseIndexWinding(vertexIndices, isTopFace != isClockwise);
// Normals
int[] normalIndices = new int[] { normalIndex, normalIndex, normalIndex };
DefaultObjFace face = new DefaultObjFace(vertexIndices, null, normalIndices);
// Texture coordinates
int[] texCoordsIndices = new int[] {
numSides+1 + i,
i+1,
i,
};
texCoordsIndices = ObjUtils.reverseIndexWinding(texCoordsIndices, isTopFace != isClockwise);
ObjUtils.offsetIndex(texCoordsIndices, texCoordsStartIdx);
DefaultObjFace face = new DefaultObjFace(vertexIndices, texCoordsIndices, normalIndices);
obj.addFace(face);
}
} else {
// Add the quad faces
for (int i = 0; i < outerVertices.size(); i++) {
int nextIdx = (i + 1) % outerVertices.size();
// Vertices
int[] vertexIndices = new int[] {
outerVertices.get(i), // Bottom-left of quad
innerVertices.get(i), // Top-left of quad
@ -82,13 +117,40 @@ public class DiskExporter {
};
vertexIndices = ObjUtils.reverseIndexWinding(vertexIndices, isTopFace != isClockwise);
// Normals
int[] normalIndices = new int[] { normalIndex, normalIndex, normalIndex, normalIndex };
DefaultObjFace face = new DefaultObjFace(vertexIndices, null, normalIndices);
// Texture coordinates
int[] texCoordsIndices = new int[] {
i,
numSides+1 + i,
numSides+1 + i+1,
i+1,
};
texCoordsIndices = ObjUtils.reverseIndexWinding(texCoordsIndices, isTopFace != isClockwise);
ObjUtils.offsetIndex(texCoordsIndices, texCoordsStartIdx);
DefaultObjFace face = new DefaultObjFace(vertexIndices, texCoordsIndices, normalIndices);
obj.addFace(face);
}
}
}
public static void closeDiskMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName,
@NotNull List<Integer> outerVertices, List<Integer> innerVertices,
boolean isClockwise, boolean isTopFace) {
// By default, OpenRocket doesn't really render textures on disks (often edges of tubes), so we don't either
closeDiskMesh(obj, transformer, groupName, outerVertices, innerVertices, isClockwise, isTopFace, 0, 0, 0, 0);
}
public static void closeDiskMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName,
@NotNull List<Integer> outerVertices, boolean isClockwise, boolean isTopFace,
float uMin, float uMax, float vMin, float vMax) {
closeDiskMesh(obj, transformer, groupName, outerVertices, null, isClockwise, isTopFace, uMin, uMax, vMin, vMax);
}
/**
* Adds a (closed) disk mesh to the obj by using existing outer and inner vertices
* @param obj The obj to add the mesh to
@ -100,7 +162,8 @@ public class DiskExporter {
*/
public static void closeDiskMesh(@NotNull DefaultObj obj, @NotNull CoordTransform transformer, String groupName,
@NotNull List<Integer> outerVertices, boolean isClockwise, boolean isTopFace) {
closeDiskMesh(obj, transformer, groupName, outerVertices, null, isClockwise, isTopFace);
// By default, OpenRocket doesn't really render textures on disks (often edges of tubes), so we don't either
closeDiskMesh(obj, transformer, groupName, outerVertices, isClockwise, isTopFace, 0, 0, 0, 0);
}
}