Tesiting 3d obj rendering

This commit is contained in:
2026-03-02 15:01:18 +01:00
parent 2b0f1dcb48
commit 178fb1a484
3 changed files with 91 additions and 42 deletions
+3
View File
@@ -87,6 +87,9 @@ dependencies {
modApi "dev.felnull:special-model-loader:1.4.0+pre.1"
include "dev.felnull:special-model-loader:1.4.0+pre.1"
implementation "de.javagl:obj:0.4.0"
include "de.javagl:obj:0.4.0"
// SVG Rendering Library
include implementation("com.formdev:svgSalamander:1.1.4")
@@ -1,62 +1,34 @@
package org.saturnclient.cosmetics.hat;
import org.saturnclient.saturnclient.client.player.SaturnPlayer;
import org.saturnclient.saturnclient.SaturnClient;
import net.minecraft.client.render.OverlayTexture;
import java.io.IOException;
import org.saturnclient.cosmetics.obj.ObjRenderer;
import de.javagl.obj.Obj;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.entity.feature.FeatureRenderer;
import net.minecraft.client.render.entity.feature.FeatureRendererContext;
import net.minecraft.client.render.entity.model.PlayerEntityModel;
import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.EquippableComponent;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.item.ModelTransformationMode;
import net.minecraft.util.Identifier;
public class HatFeatureRenderer extends FeatureRenderer<PlayerEntityRenderState, PlayerEntityModel> {
static Identifier HAT = Identifier.of("saturnclient", "models/item/horns/horns.obj");
Obj obj;
public HatFeatureRenderer(FeatureRendererContext<PlayerEntityRenderState, PlayerEntityModel> context) {
super(context);
try {
this.obj = ObjRenderer.loadObj(HAT);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void render(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light,
PlayerEntityRenderState state, float limbAngle, float limbDistance) {
ItemStack headItem = state.equippedHeadStack;
SaturnPlayer player = SaturnPlayer.get(state.name);
if (!headItem.isEmpty() || state.invisible || player == null || player.hat.isEmpty()) {
return;
}
matrices.push();
this.getContextModel().head.rotate(matrices);
matrices.multiply(net.minecraft.util.math.RotationAxis.POSITIVE_X.rotationDegrees(180.0f));
matrices.multiply(net.minecraft.util.math.RotationAxis.POSITIVE_Y.rotationDegrees(180.0f));
ItemStack customHat = new ItemStack(Items.STICK);
customHat.set(DataComponentTypes.ITEM_MODEL,
Identifier.of("saturnclient:hat_" + player.hat));
customHat.set(DataComponentTypes.EQUIPPABLE,
EquippableComponent.builder(EquipmentSlot.HEAD).build());
ItemRenderer itemRenderer = SaturnClient.client.getItemRenderer();
itemRenderer.renderItem(
customHat,
ModelTransformationMode.THIRD_PERSON_RIGHT_HAND,
light,
OverlayTexture.DEFAULT_UV,
matrices,
vertexConsumers,
null,
0);
matrices.pop();
ObjRenderer.renderObj(this.obj, matrices, vertexConsumers, light, 0);
}
}
@@ -0,0 +1,74 @@
package org.saturnclient.cosmetics.obj;
import java.io.IOException;
import java.io.InputStream;
import de.javagl.obj.FloatTuple;
import de.javagl.obj.Obj;
import de.javagl.obj.ObjFace;
import de.javagl.obj.ObjReader;
import de.javagl.obj.ObjUtils;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider;
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()) {
return ObjUtils.convertToRenderable(ObjReader.read(is));
}
}
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")));
MatrixStack.Entry entry = matrices.peek();
int faces = obj.getNumFaces();
for (int f = 0; f < faces; f++) {
ObjFace face = obj.getFace(f);
for (int i = 0; i < 3; i++) {
writeVertex(obj, face, i, consumer, entry, light, overlay);
}
}
}
/** 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) {
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
int normalIndex = face.getNormalIndex(index);
if (normalIndex >= 0) {
FloatTuple n = obj.getNormal(normalIndex);
nx = n.getX();
ny = n.getY();
nz = n.getZ();
}
consumer.vertex(matrix, x, y, z)
.color(255, 255, 255, 255)
.texture(0f, 0f)
.overlay(overlay)
.light(light)
.normal(matrix, nx, ny, nz);
}
}