Working mtl obj rendering

This commit is contained in:
2026-03-03 02:51:06 +01:00
parent e3ad918755
commit 80684f7e07
4 changed files with 84 additions and 30 deletions
@@ -1,9 +1,11 @@
package org.saturnclient.cosmetics.hat;
import java.io.IOException;
import java.util.Map;
import org.saturnclient.cosmetics.obj.ObjRenderer;
import de.javagl.obj.Mtl;
import de.javagl.obj.Obj;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.entity.feature.FeatureRenderer;
@@ -15,12 +17,15 @@ import net.minecraft.util.Identifier;
public class HatFeatureRenderer extends FeatureRenderer<PlayerEntityRenderState, PlayerEntityModel> {
static Identifier HAT = Identifier.of("saturnclient", "models/item/horns/horns.obj");
static Identifier BLACK_MTL = Identifier.of("saturnclient", "models/item/black.mtl");
Obj obj;
Map<String, Mtl> mtl;
public HatFeatureRenderer(FeatureRendererContext<PlayerEntityRenderState, PlayerEntityModel> context) {
super(context);
try {
this.obj = ObjRenderer.loadObj(HAT);
this.mtl = ObjRenderer.loadMtl(BLACK_MTL);
} catch (IOException e) {
e.printStackTrace();
}
@@ -29,6 +34,6 @@ public class HatFeatureRenderer extends FeatureRenderer<PlayerEntityRenderState,
@Override
public void render(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light,
PlayerEntityRenderState state, float limbAngle, float limbDistance) {
ObjRenderer.renderObj(this.obj, matrices, vertexConsumers, light, 0);
ObjRenderer.renderObj(this.obj, this.mtl, matrices, vertexConsumers, light, 0);
}
}
@@ -2,11 +2,10 @@ package org.saturnclient.cosmetics.obj;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import de.javagl.obj.FloatTuple;
import de.javagl.obj.Obj;
import de.javagl.obj.ObjFace;
import de.javagl.obj.ObjReader;
import de.javagl.obj.*;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.RenderLayer;
@@ -16,6 +15,7 @@ import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.Identifier;
public class ObjRenderer {
public static Obj loadObj(Identifier objId) throws IOException {
try (InputStream is = MinecraftClient.getInstance().getResourceManager()
.getResource(objId).get().getInputStream()) {
@@ -23,42 +23,83 @@ public class ObjRenderer {
}
}
public static void renderObj(Obj obj, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light,
int overlay) {
VertexConsumer consumer = vertexConsumers.getBuffer(
RenderLayer.getEntityAlpha(Identifier.of("textures/misc/white.png")));
public static Map<String, Mtl> loadMtl(Identifier mtlId) throws IOException {
try (InputStream is = MinecraftClient.getInstance().getResourceManager()
.getResource(mtlId).get().getInputStream()) {
List<Mtl> mtlList = MtlReader.read(is);
Map<String, Mtl> mtlMap = new java.util.LinkedHashMap<>();
for (Mtl mtl : mtlList) {
mtlMap.put(mtl.getName(), mtl);
}
return mtlMap;
}
}
public static void renderObj(Obj obj, Map<String, Mtl> mtlMap, MatrixStack matrices,
VertexConsumerProvider vertexConsumers, int light, int overlay) {
MatrixStack.Entry entry = matrices.peek();
int faces = obj.getNumFaces();
Map<String, Obj> materialGroups = ObjSplitting.splitByMaterialGroups(obj);
System.out.println("Faces " + faces + ", vertices " + obj.getNumVertices());
for (Map.Entry<String, Obj> group : materialGroups.entrySet()) {
String materialName = group.getKey();
Obj groupObj = group.getValue();
for (int f = 0; f < faces; f++) {
ObjFace face = obj.getFace(f);
int vertices = face.getNumVertices();
Mtl mtl = mtlMap != null ? mtlMap.get(materialName) : null;
// Reverse winding order: OBJ is CCW, Minecraft expects CW
for (int i = vertices - 1; i >= 0; i--) {
writeVertex(obj, face, i, consumer, entry, light, overlay);
// Resolve texture identifier using same logic as ObjUnbakedModelModel
Identifier texture = Identifier.of("minecraft:textures/misc/white.png");
if (mtl != null) {
String mapKd = mtl.getMapKd();
if (mapKd != null) {
// "#key" references are not resolvable at runtime without a texture map,
// so we only support direct resource location strings here
if (!mapKd.startsWith("#")) {
texture = Identifier.of(mapKd);
}
}
}
// Diffuse color (Kd)
float r = 1f, g = 1f, b = 1f;
if (mtl != null) {
FloatTuple kd = mtl.getKd();
if (kd != null) {
r = kd.getX();
g = kd.getY();
b = kd.getZ();
}
}
VertexConsumer consumer = vertexConsumers.getBuffer(RenderLayer.getEntityAlpha(texture));
int faces = groupObj.getNumFaces();
final float fr = r, fg = g, fb = b;
for (int f = 0; f < faces; f++) {
ObjFace face = groupObj.getFace(f);
int verts = face.getNumVertices();
// Your original winding order logic, untouched
for (int i = verts - 1; i >= 0; i--) {
writeVertex(groupObj, face, i, consumer, entry, light, overlay, fr, fg, fb);
}
}
}
}
/** Write a single vertex to the VertexConsumer using the OBJ FloatTuple */
private static void writeVertex(Obj obj, ObjFace face, int index, VertexConsumer consumer, MatrixStack.Entry matrix,
int light, int overlay) {
private static void writeVertex(Obj obj, ObjFace face, int index, VertexConsumer consumer,
MatrixStack.Entry matrix, int light, int overlay,
float r, float g, float b) {
FloatTuple pos = obj.getVertex(face.getVertexIndex(index));
float x = pos.getX();
float y = pos.getY();
float z = pos.getZ();
// Default normal
float nx = 0f;
float ny = 1f;
float nz = 0f;
// Use OBJ normal if available
float nx = 0f, ny = 1f, nz = 0f;
int normalIndex = face.getNormalIndex(index);
if (normalIndex >= 0) {
FloatTuple n = obj.getNormal(normalIndex);
@@ -67,9 +108,17 @@ public class ObjRenderer {
nz = n.getZ();
}
float u = 0f, v = 0f;
int texIndex = face.getTexCoordIndex(index);
if (texIndex >= 0) {
FloatTuple tc = obj.getTexCoord(texIndex);
u = tc.getX();
v = 1f - tc.getY(); // Flip V: OBJ bottom-left origin -> Minecraft top-left
}
consumer.vertex(matrix, x, y, z)
.color(255, 255, 255, 255)
.texture(0f, 0f)
.color(r, g, b, 1f)
.texture(u, v)
.overlay(overlay)
.light(light)
.normal(matrix, nx, ny, nz);
@@ -10,4 +10,4 @@ Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2
map_Kd saturnclient:item/halo_black
map_Kd saturnclient:textures/item/halo_black.png
@@ -10,4 +10,4 @@ Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2
map_Kd saturnclient:item/halo
map_Kd saturnclient:textures/item/halo.png