Compare commits

...
Author SHA1 Message Date
apion 7b3fd8206e Got rotations working for locator bound riders (kinda) 2025-02-08 20:15:21 -05:00
4 changed files with 124 additions and 52 deletions
@@ -15,7 +15,11 @@ import org.joml.Vector3f;
import java.util.function.Function;
public interface Rollable {
//The directions specified by all of the vectors in this class are from the perspective
//of an observer looking at the front of the player model
//These vectors aren't actually accurate, since "forward" can be any of +x -x +z -z depending on the rotation about
//the world-Y axis of the player
Vector3f FORWARDS = new Vector3f(0, 0, 1);
Vector3f LEFT = new Vector3f(1, 0, 0);
Vector3f UP = new Vector3f(0, 1, 0);
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.api.riding.Rideable;
import com.cobblemon.mod.common.api.riding.Seat;
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate;
import com.cobblemon.mod.common.client.render.ClientPlayerIcon;
import com.cobblemon.mod.common.client.render.player.PlayerRendererHook;
import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.cobblemon.mod.common.client.render.MatrixWrapper;
@@ -22,6 +23,7 @@ import com.mojang.blaze3d.vertex.PoseStack;
import net.fabricmc.loader.impl.lib.sat4j.core.Vec;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
import net.minecraft.util.Mth;
@@ -40,53 +42,10 @@ public class PlayerRendererMixin {
@WrapMethod(method = "render")
public void applyRotation(AbstractClientPlayer player, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource multiBufferSource, int i, Operation<Integer> original) {
if(player instanceof Rollable && !disableRollableRenderDebug) {
Rollable rollable = (Rollable) player;
if(rollable.shouldRoll()){
poseStack.pushPose();
Matrix4f transformationMatrix = new Matrix4f();
Vector3f center = new Vector3f(0, player.getBbHeight()/2, 0);
transformationMatrix.translate(center);
//transformationMatrix.rotate(180f.toRadians() - (rollable.getYaw()).toRadians(), rollable.getUpVector(), transformationMatrix);
transformationMatrix.rotate((float) Math.toRadians(-rollable.getPitch()), rollable.getLeftVector(), transformationMatrix);
transformationMatrix.rotate((float) Math.toRadians(-rollable.getRoll()), rollable.getForwardVector(), transformationMatrix);
transformationMatrix.translate(center.negate(new Vector3f()));
poseStack.mulPose(transformationMatrix);
}
}
if (player.getVehicle() instanceof Rideable) {
Rideable vehicle = (Rideable) player.getVehicle();
PokemonEntity entity = vehicle.getRiding().getEntity();
int seatIndex = entity.getPassengers().indexOf(player);
Seat seat = entity.getSeats().get(seatIndex);
PokemonClientDelegate delegate = (PokemonClientDelegate) entity.getDelegate();
MatrixWrapper locator = delegate.getLocatorStates().get(seat.getLocator());
if (locator != null) {
Matrix4f pose = poseStack.last().pose();
Vector3f locatorTranslation = locator.getOrigin().toVector3f();
Vector3f cameraPosition = Minecraft.getInstance().gameRenderer.getMainCamera().getPosition().toVector3f();
Vector3f locatorOffset = new Vector3f(locatorTranslation).sub(entity.position().toVector3f());
Vector3f oldEntityPos = new Vector3d(entity.xOld, entity.yOld, entity.zOld).get(new Vector3f());
Vector3f oldLocatorPos = oldEntityPos.add(locatorOffset);
pose.setTranslation(
Mth.lerp(partialTicks, oldLocatorPos.x, locatorTranslation.x) - cameraPosition.x,
Mth.lerp(partialTicks, oldLocatorPos.y, locatorTranslation.y) - cameraPosition.y,
Mth.lerp(partialTicks, oldLocatorPos.z, locatorTranslation.z) - cameraPosition.z
);
//Move down half a block to compensate for the sitting player pose
pose.translate(0F, -0.5F, 0F);
}
}
PlayerRendererHook.INSTANCE.before(player, entityYaw, partialTicks, poseStack, multiBufferSource, i);
original.call(player, entityYaw, partialTicks, poseStack, multiBufferSource, i);
ClientPlayerIcon.Companion.onRenderPlayer(player);
if(player instanceof Rollable && !disableRollableRenderDebug && ((Rollable) player).shouldRoll()){
poseStack.popPose();
}
}
}
@@ -0,0 +1,117 @@
package com.cobblemon.mod.common.client.render.player
import com.cobblemon.mod.common.Rollable
import com.cobblemon.mod.common.api.riding.Rideable
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
import com.cobblemon.mod.common.client.render.ClientPlayerIcon.Companion.onRenderPlayer
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.mixin.PlayerRendererMixin
import com.cobblemon.mod.common.util.math.geometry.toRadians
import com.cobblemon.mod.common.util.math.geometry.transformPosition
import com.cobblemon.mod.common.util.toVec3d
import com.llamalad7.mixinextras.injector.wrapoperation.Operation
import com.mojang.blaze3d.vertex.PoseStack
import net.minecraft.client.Minecraft
import net.minecraft.client.player.AbstractClientPlayer
import net.minecraft.client.renderer.LevelRenderer
import net.minecraft.client.renderer.MultiBufferSource
import net.minecraft.client.renderer.RenderType
import net.minecraft.util.Mth
import net.minecraft.world.phys.Vec3
import org.joml.AxisAngle4f
import org.joml.Matrix3f
import org.joml.Matrix4f
import org.joml.Quaternionf
import org.joml.Vector3d
import org.joml.Vector3f
import org.joml.Vector4f
object PlayerRendererHook {
var maxPartialTicks = 0F
const val disableRollableRenderDebug: Boolean = false
fun before(
player: AbstractClientPlayer,
entityYaw: Float,
partialTicks: Float,
poseStack: PoseStack,
multiBufferSource: MultiBufferSource,
i: Int
) {
val shouldRoll = player is Rollable && player.shouldRoll()
if (player.vehicle is Rideable) {
//We want to ignore where vanilla is placing the player, so get rid of any transformations that have occured so far
poseStack.setIdentity()
//The actual rendering of the player model expects to be able to use coordinates relative to the camera's position
//So all of our coordinates need to be offset by the camera position
val cameraPos = Minecraft.getInstance().gameRenderer.mainCamera.position
val vehicle = player.vehicle as Rideable
val entity = player.vehicle!!
//Get the seat
val seatIndex = vehicle.riding.entity.passengers.indexOf(player)
val seat = vehicle.riding.entity.seats[seatIndex]
var playerPosition = seat.offset
//If we are riding a posable entity, use the locator position over the seat offset
if (entity is PosableEntity) {
val posableState = entity.delegate as PosableState
val locator = posableState.locatorStates[seat.locator]!!
val locatorOffset = locator.getOrigin().subtract(entity.position())
val oldLocatorPos = locatorOffset.add(Vec3(entity.xOld, entity.yOld, entity.zOld))
val curLocatorPos = oldLocatorPos.lerp(locator.getOrigin(), partialTicks.toDouble()).subtract(cameraPos)
playerPosition = curLocatorPos
}
if (shouldRoll) {
//Here, basically what we are doing is figuring out the coords of the rotated locator.
//We have to do the same rotations that are done in the pokemon renderer
val rollable = player as Rollable
val pokemonCenter = Vec3(entity.xOld, entity.yOld, entity.zOld).lerp(entity.position(), partialTicks.toDouble()).add(0.0, entity.bbHeight / 2.0, 0.0).subtract(cameraPos)
val transformationMatrix = Matrix4f()
transformationMatrix.translate(pokemonCenter.toVector3f())
transformationMatrix.rotate(180f.toRadians() - (rollable.yaw).toRadians(), rollable.upVector, transformationMatrix)
transformationMatrix.rotate((-rollable.pitch).toRadians(), rollable.leftVector, transformationMatrix)
transformationMatrix.rotate((-rollable.roll).toRadians(), rollable.forwardVector, transformationMatrix)
transformationMatrix.translate(pokemonCenter.toVector3f().negate())
playerPosition = transformationMatrix.transformPosition(playerPosition)
//We need to move "down" half a block to account for the player crouching pose.
playerPosition = playerPosition.subtract(Vector3f(rollable.upVector).mul(0.5F).toVec3d())
}
else {
playerPosition = playerPosition.subtract(0.0, 0.5, 0.0)
}
poseStack.translate(playerPosition.x, playerPosition.y, playerPosition.z)
if (shouldRoll) {
val orientation = Matrix4f((player as Rollable).orientation ?: Matrix3f())
val rotation = orientation.getRotation(AxisAngle4f())
poseStack.mulPose(Quaternionf(rotation))
}
}
}
fun renderAxisLines(
player: AbstractClientPlayer,
entityYaw: Float,
partialTicks: Float,
poseStack: PoseStack,
multiBufferSource: MultiBufferSource,
i: Int
) {
if (player is Rollable) {
val pose = poseStack.last().pose()
val buffer = multiBufferSource.getBuffer(RenderType.lines())
//"Forward" is red
val forwardVector = player.forwardVector.mul(2F)
buffer.addVertex(pose, 0F, 0F, 0F).setColor(1F, 0F, 0F, 1F).setNormal(1F, 1F, 1F)
buffer.addVertex(pose, forwardVector.x, forwardVector.y, forwardVector.z).setColor(1F, 0F, 0F, 1F).setNormal(1F, 1F, 1F)
//"Left" is blue
val leftVector = player.leftVector.mul(2F)
buffer.addVertex(pose, 0F, 0F, 0F).setColor(0F, 0F, 1F, 1F).setNormal(1F, 1F, 1F)
buffer.addVertex(pose, leftVector.x, leftVector.y, leftVector.z).setColor(0F, 0F, 1F, 1F).setNormal(1F, 1F, 1F)
//"Up" is green
val upVector = player.upVector.mul(2F)
buffer.addVertex(pose, 0F, 0F, 0F).setColor(0F, 1F, 0F, 1F).setNormal(1F, 1F, 1F)
buffer.addVertex(pose, upVector.x, upVector.y, upVector.z).setColor(0F, 1F, 0F, 1F).setNormal(1F, 1F, 1F)
}
}
}
@@ -167,14 +167,6 @@ class PokemonRenderer(
val driver = entity.firstPassenger ?: return
val rollable = driver as? Rollable ?: return
//val camera = Minecraft.getInstance().gameRenderer.mainCamera
//val isThirdPerson = camera.isDetached
//val vehicleOrigin = entity.position()
//val driverOrigin = if (isThirdPerson) driver.position() else driver.eyePosition
//val offset = driverOrigin.subtract(vehicleOrigin)
poseMatrix.pushPose()
if(!DISABLE_ROLLING_DEBUG && rollable.shouldRoll()){