OBB再次大失败(?)

This commit is contained in:
Atsuishio 2025-06-13 16:49:30 +08:00 committed by Light_Quanta
parent d14710743c
commit 9b7773350f
No known key found for this signature in database
GPG key ID: 11A39A1B8C890959
7 changed files with 246 additions and 3 deletions

View file

@ -0,0 +1,40 @@
package com.atsuishio.superbwarfare.client.renderer.special;
import com.atsuishio.superbwarfare.tools.OBB;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.Vec3;
import org.joml.Quaternionf;
import org.joml.Vector3f;
/**
* Codes based on @AnECanSaiTin's <a href="https://github.com/AnECanSaiTin/HitboxAPI">HitboxAPI</a>
**/
public class OBBRenderer {
public static final OBBRenderer INSTANCE = new OBBRenderer();
public void render(Entity entity, OBB obb, PoseStack poseStack, VertexConsumer buffer, float red, float green, float blue, float alpha) {
Vec3 position = entity.position();
Vector3f center = obb.center();
Vector3f halfExtents = obb.extents();
Quaternionf rotation = obb.rotation();
renderOBB(
poseStack, buffer,
(float) (center.x() - position.x()), (float) (center.y() - position.y()), (float) (center.z() - position.z()),
rotation,
halfExtents.x(), halfExtents.y(), halfExtents.z(),
red, green, blue, alpha
);
}
public static void renderOBB(PoseStack poseStack, VertexConsumer buffer, float centerX, float centerY, float centerZ, Quaternionf rotation, float halfX, float halfY, float halfZ, float red, float green, float blue, float alpha) {
poseStack.pushPose();
poseStack.translate(centerX, centerY, centerZ);
poseStack.mulPose(rotation);
LevelRenderer.renderLineBox(poseStack, buffer, -halfX, -halfY, -halfZ, halfX, halfY, halfZ, red, green, blue, alpha);
poseStack.popPose();
}
}

View file

@ -0,0 +1,10 @@
package com.atsuishio.superbwarfare.entity;
import com.atsuishio.superbwarfare.tools.OBB;
public interface OBBEntity {
OBB getOBB();
void updateOBB();
}

View file

@ -3,6 +3,7 @@ package com.atsuishio.superbwarfare.entity.vehicle;
import com.atsuishio.superbwarfare.Mod;
import com.atsuishio.superbwarfare.config.server.ExplosionConfig;
import com.atsuishio.superbwarfare.config.server.VehicleConfig;
import com.atsuishio.superbwarfare.entity.OBBEntity;
import com.atsuishio.superbwarfare.entity.projectile.SwarmDroneEntity;
import com.atsuishio.superbwarfare.entity.vehicle.base.ContainerMobileVehicleEntity;
import com.atsuishio.superbwarfare.entity.vehicle.base.LandArmorEntity;
@ -62,8 +63,7 @@ import net.neoforged.neoforge.network.PacketDistributor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.joml.Math;
import org.joml.Matrix4f;
import org.joml.Vector4f;
import org.joml.*;
import software.bernie.geckolib.animatable.GeoEntity;
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
import software.bernie.geckolib.animation.*;
@ -77,7 +77,7 @@ import java.util.List;
import static com.atsuishio.superbwarfare.client.RenderHelper.preciseBlit;
import static com.atsuishio.superbwarfare.tools.ParticleTool.sendParticle;
public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEntity, LandArmorEntity, WeaponVehicleEntity {
public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEntity, LandArmorEntity, WeaponVehicleEntity, OBBEntity {
public static final EntityDataAccessor<Integer> MG_AMMO = SynchedEntityData.defineId(Yx100Entity.class, EntityDataSerializers.INT);
public static final EntityDataAccessor<Integer> LOADED_AP = SynchedEntityData.defineId(Yx100Entity.class, EntityDataSerializers.INT);
@ -88,8 +88,11 @@ public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEnti
private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this);
public int droneReloadCoolDown;
public OBB obb;
public Yx100Entity(EntityType<Yx100Entity> type, Level world) {
super(type, world);
this.obb = new OBB(this.position().toVector3f(), new Vector3f(3.5f, 3.0f, 5.0f), new Quaternionf());
}
@Override
@ -227,6 +230,8 @@ public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEnti
public void baseTick() {
super.baseTick();
this.updateOBB();
if (getLeftTrack() < 0) {
setLeftTrack(80);
}
@ -1286,4 +1291,17 @@ public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEnti
public @Nullable ResourceLocation getVehicleItemIcon() {
return Mod.loc("textures/gui/vehicle/type/land.png");
}
@Override
public OBB getOBB() {
return this.obb;
}
// TODO 实现正确的旋转设置
@Override
public void updateOBB() {
Quaternionf rotation = eulerToQuaternion(-getRoll(), -getYRot(), getXRot());
this.obb.setRotation(rotation);
this.obb.center().set(this.position().toVector3f());
}
}

View file

@ -816,6 +816,23 @@ public abstract class VehicleEntity extends Entity {
return transform.transform(new Vector4f(x, y, z, 1));
}
public static Quaternionf eulerToQuaternion(float yaw, float pitch, float roll) {
double cy = Math.cos(yaw * 0.5 * Mth.DEG_TO_RAD);
double sy = Math.sin(yaw * 0.5 * Mth.DEG_TO_RAD);
double cp = Math.cos(pitch * 0.5 * Mth.DEG_TO_RAD);
double sp = Math.sin(pitch * 0.5 * Mth.DEG_TO_RAD);
double cr = Math.cos(roll * 0.5 * Mth.DEG_TO_RAD);
double sr = Math.sin(roll * 0.5 * Mth.DEG_TO_RAD);
Quaternionf q = new Quaternionf();
q.w = (float) (cy * cp * cr + sy * sp * sr);
q.x = (float) (cy * cp * sr - sy * sp * cr);
q.y = (float) (sy * cp * sr + cy * sp * cr);
q.z = (float) (sy * cp * cr - cy * sp * sr);
return q;
}
public void handleClientSync() {
if (isControlledByLocalInstance()) {
interpolationSteps = 0;

View file

@ -0,0 +1,24 @@
package com.atsuishio.superbwarfare.mixins;
import com.atsuishio.superbwarfare.client.renderer.special.OBBRenderer;
import com.atsuishio.superbwarfare.entity.OBBEntity;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
import net.minecraft.world.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(EntityRenderDispatcher.class)
public class EntityRenderDispatcherMixin {
@Inject(method = "renderHitbox",
at = @At("RETURN"))
private static void renderHitbox(PoseStack poseStack, VertexConsumer buffer, Entity entity, float red, float green, float blue, float alpha, CallbackInfo ci) {
if (entity instanceof OBBEntity obbEntity) {
OBBRenderer.INSTANCE.render(entity, obbEntity.getOBB(), poseStack, buffer, 1, 1, 1, 1);
}
}
}

View file

@ -0,0 +1,133 @@
package com.atsuishio.superbwarfare.tools;
import net.minecraft.world.phys.AABB;
import org.joml.Intersectionf;
import org.joml.Math;
import org.joml.Quaternionf;
import org.joml.Vector3f;
/**
* Codes based on @AnECanSaiTin's <a href="https://github.com/AnECanSaiTin/HitboxAPI">HitboxAPI</a>
*
* @param center 旋转中心
* @param extents 三个轴向上的半长
* @param rotation 旋转
*/
public record OBB(Vector3f center, Vector3f extents, Quaternionf rotation) {
public void setCenter(Vector3f center) {
this.center.set(center);
}
public void setExtents(Vector3f extents) {
this.extents.set(extents);
}
public void setRotation(Quaternionf rotation) {
this.rotation.set(rotation);
}
/**
* 获取OBB的8个顶点坐标
*
* @return 顶点坐标
*/
public Vector3f[] getVertices() {
Vector3f[] vertices = new Vector3f[8];
Vector3f[] localVertices = new Vector3f[]{
new Vector3f(-extents.x, -extents.y, -extents.z),
new Vector3f(extents.x, -extents.y, -extents.z),
new Vector3f(extents.x, extents.y, -extents.z),
new Vector3f(-extents.x, extents.y, -extents.z),
new Vector3f(-extents.x, -extents.y, extents.z),
new Vector3f(extents.x, -extents.y, extents.z),
new Vector3f(extents.x, extents.y, extents.z),
new Vector3f(-extents.x, extents.y, extents.z)
};
for (int i = 0; i < 8; i++) {
Vector3f vertex = localVertices[i];
vertex.rotate(rotation);
vertex.add(center);
vertices[i] = vertex;
}
return vertices;
}
/**
* 获取OBB的三个正交轴
*
* @return 正交轴
*/
public Vector3f[] getAxes() {
Vector3f[] axes = new Vector3f[]{
new Vector3f(1, 0, 0),
new Vector3f(0, 1, 0),
new Vector3f(0, 0, 1)};
rotation.transform(axes[0]);
rotation.transform(axes[1]);
rotation.transform(axes[2]);
return axes;
}
/**
* 判断两个OBB是否相撞
*/
public static boolean isColliding(OBB obb, OBB other) {
Vector3f[] axes1 = obb.getAxes();
Vector3f[] axes2 = other.getAxes();
return Intersectionf.testObOb(obb.center(), axes1[0], axes1[1], axes1[2], obb.extents(),
other.center(), axes2[0], axes2[1], axes2[2], other.extents());
}
/**
* 判断OBB和AABB是否相撞
*/
public static boolean isColliding(OBB obb, AABB aabb) {
Vector3f obbCenter = obb.center();
Vector3f[] obbAxes = obb.getAxes();
Vector3f obbHalfExtents = obb.extents();
Vector3f aabbCenter = aabb.getCenter().toVector3f();
Vector3f aabbHalfExtents = new Vector3f((float) (aabb.getXsize() / 2f), (float) (aabb.getYsize() / 2f), (float) (aabb.getZsize() / 2f));
return Intersectionf.testObOb(
obbCenter.x, obbCenter.y, obbCenter.z,
obbAxes[0].x, obbAxes[0].y, obbAxes[0].z,
obbAxes[1].x, obbAxes[1].y, obbAxes[1].z,
obbAxes[2].x, obbAxes[2].y, obbAxes[2].z,
obbHalfExtents.x, obbHalfExtents.y, obbHalfExtents.z,
aabbCenter.x, aabbCenter.y, aabbCenter.z,
1, 0, 0,
0, 1, 0,
0, 0, 1,
aabbHalfExtents.x, aabbHalfExtents.y, aabbHalfExtents.z
);
}
/**
* 计算OBB上离待判定点最近的点
*
* @param point 待判定点
* @param obb OBB盒
* @return 在OBB上离待判定点最近的点
*/
public static Vector3f getClosestPointOBB(Vector3f point, OBB obb) {
Vector3f nearP = new Vector3f(obb.center());
Vector3f dist = point.sub(nearP, new Vector3f());
float[] extents = new float[]{obb.extents().x, obb.extents().y, obb.extents().z};
Vector3f[] axes = obb.getAxes();
for (int i = 0; i < 3; i++) {
float distance = dist.dot(axes[i]);
distance = Math.clamp(distance, -extents[i], extents[i]);
nearP.x += distance * axes[i].x;
nearP.y += distance * axes[i].y;
nearP.z += distance * axes[i].z;
}
return nearP;
}
}

View file

@ -16,6 +16,7 @@
"CameraMixin",
"ClientPacketListenerMixin",
"ClientPlayerEntityMixin",
"EntityRenderDispatcherMixin",
"GameRendererMixin",
"ItemInHandLayerMixin",
"KeyboardInputMixin",