diff --git a/README.md b/README.md index d904d08..cefda59 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ## [中文](README_ZH.md) ## Make the camera more realistic in the first-person view. -Supported versions: 1.18-1.20 Forge & Fabric. +Supported versions: 1.20-1.21 Fabric & NeoForge. Download the mod from [Releases](https://github.com/xTracr/RealCamera/releases), [Modrinth](https://modrinth.com/mod/real-camera) or [CurseForge](https://curseforge.com/minecraft/mc-mods/real-camera) Snapshots are [here](https://github.com/xTracr/RealCamera/actions/workflows/build.yml) @@ -14,26 +14,30 @@ Snapshots are [here](https://github.com/xTracr/RealCamera/actions/workflows/buil * Render player model in first-person perspective. * Use F6 to toggle the feature on or off and other hotkeys to adjust the camera. * Configure these features in the config screen (Cloth Config required). + +### Configuration (0.6+) ### + * Theoretically, most mod models are supported, but need to be configured manually: - * First, set the key binding for `Open Model View Screen`. - * Open the model view gui and left click with left Alt held to select the corresponding face of the model, scroll with left Alt held to switch between the different layers of the model. - * By clicking the `Selecting` button on the left, switch between the three to select the `Forward Vector`, `Upward Vector`, and `Target Plane`. - * Enter the `Preview` section, where you can see the relative relationship between the camera and the model and make certain adjustments (you can also adjust through key bindings). - * Enter a name and save (if needed, other settings such as priority can be changed). +* First, set the key binding for `Open Model View Screen`. + * ![model view screen](https://cdn.modrinth.com/data/fYYSAh4R/images/cc484d54238992077ab3632c274a2631efeca35f.png) +* Open the model view screen and left click with left Alt held to select the corresponding face of the model, scroll with left Alt held to switch between the different layers of the model. +* By clicking the `Selecting` button on the left, switch between the three to select the `Forward Vector`, `Upward Vector`, and `Target Plane`. +* Enter the `Preview` section, where you can see the relative relationship between the camera and the model and make certain adjustments (you can also adjust through key bindings). + * ![preview](https://cdn.modrinth.com/data/fYYSAh4R/images/22cfcf444bbf2d3c0d0280e470a29f01b9308617.png) +* Enter a name and save (if needed, other settings such as priority can be changed). -### Dependencies ### +## Dependencies ## * Fabric: - * [Fabric Loader](https://fabricmc.net/use/installer/) * [Fabric API](https://modrinth.com/mod/fabric-api) -* Forge: - * [Forge Mod Loader](https://files.minecraftforge.net/) * Both: * (Optional but recommended) [Cloth Config API](https://modrinth.com/mod/cloth-config) ## FAQ ## -* WIP +* A part of the model (e.g. hair) is always in the way, how to make it invisible? + * Increasing this value may help + ![screenshot_2024_6_2_22_42](https://github.com/xTracr/RealCamera/assets/57320980/78c246e8-34aa-4979-89de-780ee907870b) ### Compatibility ### diff --git a/README_ZH.md b/README_ZH.md index 66ab1c8..2dcf5dd 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -3,7 +3,7 @@ ## [English](README.md) ## 使第一人称视角下的摄像头更加真实。 -支持的版本: 1.18-1.20 Forge & Fabric +支持的版本: 1.20-1.21 Fabric & NeoForge 从[Releases](https://github.com/xTracr/RealCamera/releases)、[Modrinth](https://modrinth.com/mod/real-camera)或[CurseForge](https://curseforge.com/minecraft/mc-mods/real-camera)下载 快照版在[这里](https://github.com/xTracr/RealCamera/actions/workflows/build.yml) @@ -14,26 +14,30 @@ * 在第一人称视角下渲染玩家模型 * 按下F6来开关,另外一些键来调整摄像头 * 在配置界面配置以上特性(需Cloth Config) + +### 配置 ### + * 理论上支持大多数模组模型,但需要手动进行配置: - * 首先设置`打开模型视图界面`的按键绑定 - * 打开模型视图界面,左Alt+左键选择模型的对应的面,左Alt+滚轮可以在模型的不同层间切换 - * 通过点击左侧的`选择`按钮,在三者间切换,选好`向前矢量`、`向上矢量`和`目标平面` - * 进入`预览`部分,在这里可以看到摄像头与模型的相对关系并进行一定的调整(也可以通过按键绑定调整) - * 输入名称并保存(如果需要,还有其他设置如优先级可以更改) +* 首先设置`打开模型视图界面`的按键绑定 + * ![model view screen](https://cdn.modrinth.com/data/fYYSAh4R/images/cc484d54238992077ab3632c274a2631efeca35f.png) +* 打开模型视图界面,左Alt+左键选择模型的对应的面,左Alt+滚轮可以在模型的不同层间切换 +* 通过点击左侧的`选择`按钮,在三者间切换,选好`向前矢量`、`向上矢量`和`目标平面` +* 进入`预览`部分,在这里可以看到摄像头与模型的相对关系并进行一定的调整(也可以通过按键绑定调整) + * ![preview](https://cdn.modrinth.com/data/fYYSAh4R/images/22cfcf444bbf2d3c0d0280e470a29f01b9308617.png) +* 输入名称并保存(如果需要,还有其他设置如优先级可以更改) -### 依赖项目 ### +## 依赖项目 ## * Fabric: - * [Fabric Loader](https://fabricmc.net/use/installer/) * [Fabric API](https://modrinth.com/mod/fabric-api) -* Forge: - * [Forge Mod Loader](https://files.minecraftforge.net/) -* Both: +* 所有平台: * (可选但建议)[Cloth Config API](https://modrinth.com/mod/cloth-config) ## 常见问题 ## -* 施工中 +* 模型的一部分(如头发)始终挡在面前,怎样隐藏它? + * 增加这个值或许有所帮助 + ![screenshot_2024_6_2_22_42](https://github.com/xTracr/RealCamera/assets/57320980/78c246e8-34aa-4979-89de-780ee907870b) ### 兼容性 ### diff --git a/common/src/main/java/com/xtracr/realcamera/compat/CompatibilityHelper.java b/common/src/main/java/com/xtracr/realcamera/compat/CompatibilityHelper.java index 9455582..8cff172 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/CompatibilityHelper.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/CompatibilityHelper.java @@ -1,6 +1,7 @@ package com.xtracr.realcamera.compat; import com.xtracr.realcamera.RealCameraCore; +import net.minecraft.world.item.ItemStack; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -9,6 +10,7 @@ public class CompatibilityHelper { private static Class NEA_NEAnimationsLoader = null; private static Method NEA_playerTransformer_setDeltaTick = null; + protected static Method Exposure_CameraItem_isActive = null; @SuppressWarnings("unchecked") public static void initialize() { @@ -26,6 +28,11 @@ public static void initialize() { NEA_playerTransformer_setDeltaTick = NEA_PlayerTransformer.getDeclaredMethod("setDeltaTick", float.class); } catch (Exception ignored) { } + if (isClassLoaded("io.github.mortuusars.exposure.Exposure")) try { + Class Exposure_CameraItem = Class.forName("io.github.mortuusars.exposure.item.CameraItem"); + Exposure_CameraItem_isActive = Exposure_CameraItem.getDeclaredMethod("isActive", ItemStack.class); + } catch (Exception ignored) { + } } public static void NEA_setDeltaTick(float tickDelta) { diff --git a/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java b/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java index 376408b..dd8d281 100644 --- a/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java +++ b/common/src/main/java/com/xtracr/realcamera/compat/DisableHelper.java @@ -5,6 +5,7 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; import java.util.HashMap; import java.util.Map; @@ -12,12 +13,25 @@ public class DisableHelper { private static final Map> predicates = new HashMap<>(); + private static final String EXPOSURE_CAMERA = "exposure:camera"; public static void initialize() { registerOr("mainFeature", LivingEntity::isSleeping); registerOr("renderModel", entity -> entity instanceof Player player && player.isScoping()); registerOr("renderModel", entity -> ConfigFile.config().getDisableRenderItems().contains(BuiltInRegistries.ITEM.getKey(entity.getMainHandItem().getItem()).toString())); registerOr("renderModel", entity -> ConfigFile.config().getDisableRenderItems().contains(BuiltInRegistries.ITEM.getKey(entity.getOffhandItem().getItem()).toString())); + registerOr("renderModel", entity -> { + if (CompatibilityHelper.Exposure_CameraItem_isActive == null) return false; + final ItemStack itemStack; + if (EXPOSURE_CAMERA.equals(BuiltInRegistries.ITEM.getKey(entity.getMainHandItem().getItem()).toString())) itemStack = entity.getMainHandItem(); + else if (EXPOSURE_CAMERA.equals(BuiltInRegistries.ITEM.getKey(entity.getOffhandItem().getItem()).toString())) itemStack = entity.getOffhandItem(); + else return false; + try { + return (boolean) CompatibilityHelper.Exposure_CameraItem_isActive.invoke(itemStack.getItem(), itemStack); + } catch (Exception ignored) { + return false; + } + }); } public static void registerOr(String type, Predicate predicate) { diff --git a/common/src/main/java/com/xtracr/realcamera/config/BindingTarget.java b/common/src/main/java/com/xtracr/realcamera/config/BindingTarget.java index 633886e..a7d6ed8 100644 --- a/common/src/main/java/com/xtracr/realcamera/config/BindingTarget.java +++ b/common/src/main/java/com/xtracr/realcamera/config/BindingTarget.java @@ -5,10 +5,12 @@ import java.util.List; public class BindingTarget { - protected static final List defaultTargets = List.of(createDefaultTarget("minecraft_head", "minecraft:textures/entity/player/", 5, false), - createDefaultTarget("skin_head", "minecraft:skins/", 5, false), - createDefaultTarget("minecraft_head_2", "minecraft:textures/entity/player/", 0, true), - createDefaultTarget("skin_head_2", "minecraft:skins/", 0, true)); + protected static final List defaultTargets = List.of(vanillaTarget("minecraft_head", 5, false).offsetX(-0.1), + vanillaTarget("skin_head", 5, false).offsetX(-0.1), + vanillaTarget("minecraft_head_2", 1, true).offsetX(-0.1), + vanillaTarget("skin_head_2", 1, true).offsetX(-0.1), + vanillaTarget("minecraft_head_3", 0, true).offsetX(-0.06).offsetY(-0.08).disablingDepth(0.08f), + vanillaTarget("skin_head_3", 0, true).offsetX(-0.06).offsetY(-0.08).disablingDepth(0.08f)); public final String name, textureId; public int priority = 0; public float forwardU = 0, forwardV = 0, upwardU = 0, upwardV = 0, posU = 0, posV = 0, disablingDepth = 0.2f; @@ -26,13 +28,12 @@ public BindingTarget(String name, String textureId) { this.textureId = textureId; } - private static BindingTarget createDefaultTarget(String name, String textureId, int priority, boolean shouldBind) { - return new BindingTarget(name, textureId).priority(priority) + private static BindingTarget vanillaTarget(String name, int priority, boolean shouldBind) { + return new BindingTarget(name, name.contains("skin") ? "minecraft:skins/" : "minecraft:textures/entity/player/").priority(priority) .forwardU(0.1875f).forwardV(0.2f) .upwardU(0.1875f).upwardV(0.075f) .posU(0.1875f).posV(0.2f) .bindX(shouldBind).bindZ(shouldBind).bindRotation(shouldBind) - .offsetX(-0.1) .disabledTextureIds(List.of("minecraft:textures/entity/enderdragon/dragon.png")); } diff --git a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java index de4722b..61a69e8 100644 --- a/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java +++ b/common/src/main/java/com/xtracr/realcamera/gui/ModelViewScreen.java @@ -227,7 +227,7 @@ private void initRightWidgets(final int category, final int page) { @Override public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) { renderBackground(graphics);// 1.20.1 only - drawEntity(graphics, x + (xSize - ySize) / 2, y, x + (xSize + ySize) / 2, y + ySize, mouseX, mouseY, minecraft.player); + renderEntityInViewArea(graphics, x + (xSize - ySize) / 2, y, x + (xSize + ySize) / 2, y + ySize, mouseX, mouseY, minecraft.player); super.render(graphics, mouseX, mouseY, delta); } @@ -239,7 +239,7 @@ public void renderBackground(GuiGraphics graphics) { graphics.fill(x + (xSize + ySize) / 2 + 4, y, x + xSize, y + ySize, 0xFF444444); } - protected void drawEntity(GuiGraphics graphics, int x1, int y1, int x2, int y2, int mouseX, int mouseY, LivingEntity entity) { + protected void renderEntityInViewArea(GuiGraphics graphics, int x1, int y1, int x2, int y2, int mouseX, int mouseY, LivingEntity entity) { float centerX = (float) (x1 + x2) / 2.0f; float centerY = (float) (y1 + y2) / 2.0f; graphics.enableScissor(x1, y1, x2, y2); @@ -255,7 +255,7 @@ protected void drawEntity(GuiGraphics graphics, int x1, int y1, int x2, int y2, entity.yHeadRot = entity.getYRot(); entity.yHeadRotO = entity.getYRot(); Vector3f vector3f = new Vector3f((float) entityX, (float) entityY, -2.0f); - drawEntity(graphics, centerX, centerY, mouseX, mouseY, vector3f, quaternionf, entity); + renderEntityWithAnalyser(graphics, centerX, centerY, mouseX, mouseY, vector3f, quaternionf, entity); entity.yBodyRot = entityBodyYaw; entity.setYRot(entityYaw); entity.setXRot(entityPitch); @@ -264,7 +264,7 @@ protected void drawEntity(GuiGraphics graphics, int x1, int y1, int x2, int y2, graphics.disableScissor(); } - protected void drawEntity(GuiGraphics graphics, float x, float y, int mouseX, int mouseY, Vector3f offset, Quaternionf quaternionf, LivingEntity entity) { + protected void renderEntityWithAnalyser(GuiGraphics graphics, float x, float y, int mouseX, int mouseY, Vector3f offset, Quaternionf quaternionf, LivingEntity entity) { graphics.pose().pushPose(); graphics.pose().translate(x, y, 0); graphics.pose().mulPoseMatrix(new Matrix4f().scaling(entitySize, entitySize, -entitySize)); diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/GameRendererAccessor.java b/common/src/main/java/com/xtracr/realcamera/mixin/GameRendererAccessor.java new file mode 100644 index 0000000..f06020b --- /dev/null +++ b/common/src/main/java/com/xtracr/realcamera/mixin/GameRendererAccessor.java @@ -0,0 +1,14 @@ +package com.xtracr.realcamera.mixin; + +import net.minecraft.client.renderer.GameRenderer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(GameRenderer.class) +public interface GameRendererAccessor { + @Accessor + float getFov(); + + @Accessor + float getOldFov(); +} diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/MixinCamera.java b/common/src/main/java/com/xtracr/realcamera/mixin/MixinCamera.java index 6f95e8f..00d33eb 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinCamera.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinCamera.java @@ -4,6 +4,7 @@ import com.xtracr.realcamera.config.ConfigFile; import com.xtracr.realcamera.config.ModConfig; import net.minecraft.client.Camera; +import net.minecraft.client.Minecraft; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; @@ -55,14 +56,14 @@ public abstract class MixinCamera { setPosition(prevPos); setRotation(RealCameraCore.getYaw(yRot), RealCameraCore.getPitch(xRot)); } - realcamera$clipToSpace(startVec); + realcamera$clipToSpace(startVec, realcamera$getFov(tickDelta)); RealCameraCore.setCameraPos(position); } @Unique - private void realcamera$clipToSpace(Vec3 startVec) { + private void realcamera$clipToSpace(Vec3 startVec, double fov) { Vec3 offset = position.subtract(startVec); - final float depth = 0.085f; + final float depth = 0.05f + (float) (fov * (0.0001 + 0.000005 * fov)); for (int i = 0; i < 8; ++i) { float f = depth * ((i & 1) * 2 - 1); float g = depth * ((i >> 1 & 1) * 2 - 1); @@ -77,6 +78,13 @@ public abstract class MixinCamera { setPosition(startVec.add(offset)); } + @Unique + private static float realcamera$getFov(float tickDelta) { + Minecraft client = Minecraft.getInstance(); + float multiplier = Mth.lerp(tickDelta, ((GameRendererAccessor) client.gameRenderer).getOldFov(), ((GameRendererAccessor) client.gameRenderer).getFov()); + return client.options.fov().get() * multiplier; + } + @Shadow protected abstract void move(double x, double y, double z); diff --git a/common/src/main/java/com/xtracr/realcamera/mixin/MixinLevelRenderer.java b/common/src/main/java/com/xtracr/realcamera/mixin/MixinLevelRenderer.java index 8f1148d..6c8a228 100644 --- a/common/src/main/java/com/xtracr/realcamera/mixin/MixinLevelRenderer.java +++ b/common/src/main/java/com/xtracr/realcamera/mixin/MixinLevelRenderer.java @@ -4,7 +4,6 @@ import com.xtracr.realcamera.RealCameraCore; import com.xtracr.realcamera.config.ConfigFile; import net.minecraft.client.Camera; -import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.*; import net.minecraft.world.entity.Entity; import net.minecraft.world.phys.Vec3; @@ -18,8 +17,6 @@ @Mixin(LevelRenderer.class) public abstract class MixinLevelRenderer { - @Shadow - @Final private Minecraft minecraft; @Shadow @Final private RenderBuffers renderBuffers; diff --git a/common/src/main/java/com/xtracr/realcamera/util/VertexRecorder.java b/common/src/main/java/com/xtracr/realcamera/util/VertexRecorder.java index 2157f21..9f073f9 100644 --- a/common/src/main/java/com/xtracr/realcamera/util/VertexRecorder.java +++ b/common/src/main/java/com/xtracr/realcamera/util/VertexRecorder.java @@ -56,8 +56,8 @@ public void buildRecords() { public BuiltRecord getTargetPosAndRot(BindingTarget target, Matrix3f normal, Vector3f position) { return records.stream().map(record -> { if (!record.textureId().contains(target.textureId)) return null; - Vec3 forward = getPrimitive(record, target.forwardU, target.forwardV)[0].normal().normalize(); - Vec3 left = getPrimitive(record, target.upwardU, target.upwardV)[0].normal().cross(forward).normalize(); + Vec3 forward = getPrimitive(record, target.forwardU, target.forwardV)[0].normal(); + Vec3 left = getPrimitive(record, target.upwardU, target.upwardV)[0].normal().cross(forward); Vertex[] face = getPrimitive(record, target.posU, target.posV); if (face[0].normal().equals(Vec3.ZERO) && forward.equals(Vec3.ZERO) && left.equals(Vec3.ZERO)) return null; normal.set(left.toVector3f(), forward.cross(left).toVector3f(), forward.toVector3f()); @@ -194,7 +194,7 @@ public Vec3 pos() { } public Vec3 normal() { - return new Vec3(normalX, normalY, normalZ); + return new Vec3(normalX, normalY, normalZ).normalize(); } public Vertex transform(Matrix4f positionMatrix, Matrix3f normalMatrix) { diff --git a/common/src/main/resources/realcamera-common.mixins.json b/common/src/main/resources/realcamera-common.mixins.json index f0c8eb8..6493449 100644 --- a/common/src/main/resources/realcamera-common.mixins.json +++ b/common/src/main/resources/realcamera-common.mixins.json @@ -7,6 +7,7 @@ ], "client": [ "CameraAccessor", + "GameRendererAccessor", "MixinCamera", "MixinGameRenderer", "MixinGui", diff --git a/gradle.properties b/gradle.properties index 094e41c..685bb75 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ forge_version=1.20.1-47.3.1 fabric_loader_version=0.15.10 #yarn_mappings=1.20.1+build.10 # Mod Properties -mod_version=0.6.1-beta +mod_version=0.6.2-beta.1 maven_group=com.xtracr.realcamera archives_base_name=realcamera # Dependencies