Kampfsystem, hier: Positionierung des Schwertes, weitere Features für die Griffe ergänzt
This commit is contained in:
@@ -11,6 +11,7 @@ import com.jme3.scene.Spatial;
|
||||
import com.jme3.scene.control.AbstractControl;
|
||||
import de.blight.common.model.Item;
|
||||
import de.blight.common.model.ItemGrip;
|
||||
import de.blight.common.model.ItemSubCategory;
|
||||
import de.blight.game.animation.RetargetingSystem;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -28,11 +29,13 @@ public class NpcWeaponAttachmentControl extends AbstractControl {
|
||||
private static final String BONE_HAND = "mixamorig:RightHand";
|
||||
private static final String BONE_PALM = "mixamorig:RightHandMiddle1";
|
||||
private static final String BONE_LEFT_FOREARM = "mixamorig:LeftHand";
|
||||
|
||||
private static final float DEG_TO_RAD = (float) Math.PI / 180f;
|
||||
private static final float HALF_PI = (float) Math.PI * 0.5f;
|
||||
|
||||
private static final Vector3f BACK_GRIP_OFFSET = new Vector3f(0.0f, 0.40f, -0.13f);
|
||||
private static final Vector3f HAND_GRIP_OFFSET = new Vector3f(0.1f, 0.00f, 0.05f);
|
||||
private static final Vector3f HAND_GRIP_OFFSET = new Vector3f(
|
||||
ItemGrip.HAND_GRIP_OFFSET_X, ItemGrip.HAND_GRIP_OFFSET_Y, ItemGrip.HAND_GRIP_OFFSET_Z);
|
||||
private static final Vector3f SHIELD_BACK_OFFSET = new Vector3f(0.12f, -0.10f, -0.10f);
|
||||
|
||||
private static final float SHIELD_ARM_ROT_X = -HALF_PI;
|
||||
@@ -97,7 +100,6 @@ public class NpcWeaponAttachmentControl extends AbstractControl {
|
||||
} catch (Exception e) { log.warn("[NpcWeaponAttach] Bone '{}' nicht gefunden: {}", BONE_PALM, e.getMessage()); }
|
||||
try { leftForeArmNode = skinCtrl.getAttachmentsNode(BONE_LEFT_FOREARM); }
|
||||
catch (Exception e) { log.warn("[NpcWeaponAttach] Bone '{}' nicht gefunden: {}", BONE_LEFT_FOREARM, e.getMessage()); }
|
||||
|
||||
handBindRotInChar = extractJointBindRot(skinCtrl, BONE_HAND);
|
||||
leftForeArmBindRotInChar = extractJointBindRot(skinCtrl, BONE_LEFT_FOREARM);
|
||||
|
||||
@@ -126,7 +128,6 @@ public class NpcWeaponAttachmentControl extends AbstractControl {
|
||||
palmOffsetLocal = computePalmOffset(handNode, palmNodeRef);
|
||||
}
|
||||
}
|
||||
|
||||
Quaternion charWorldRotInv = spatial.getWorldRotation().inverse();
|
||||
Vector3f charWorldPos = spatial.getWorldTranslation();
|
||||
|
||||
@@ -137,11 +138,23 @@ public class NpcWeaponAttachmentControl extends AbstractControl {
|
||||
Vector3f boneInChar = charWorldRotInv.mult(boneNode.getWorldTranslation().subtract(charWorldPos));
|
||||
Quaternion boneRotInChar = charWorldRotInv.mult(boneNode.getWorldRotation());
|
||||
if (drawn) {
|
||||
ItemGrip wGrip = weaponItem != null ? weaponItem.getGrip() : null;
|
||||
boolean isTwoHand = weaponItem != null && weaponItem.getSubCategory() == ItemSubCategory.TWO_HANDED_SWORD;
|
||||
Vector3f attachInChar = (palmOffsetLocal != null)
|
||||
? boneInChar.add(boneRotInChar.mult(palmOffsetLocal.mult(0.5f)))
|
||||
: boneInChar;
|
||||
applyHandTransform(weaponSpatial, attachInChar, boneRotInChar,
|
||||
weaponItem != null ? weaponItem.getGrip() : null);
|
||||
boolean usesTwoHand = isTwoHand && leftForeArmNode != null
|
||||
&& wGrip != null
|
||||
&& (wGrip.getGrip2PosX() != 0f || wGrip.getGrip2PosY() != 0f || wGrip.getGrip2PosZ() != 0f);
|
||||
if (usesTwoHand) {
|
||||
Vector3f handballen = (palmOffsetLocal != null)
|
||||
? boneInChar.subtract(boneRotInChar.mult(palmOffsetLocal.mult(0.5f)))
|
||||
: boneInChar;
|
||||
applyTwoHandTransform(weaponSpatial, handballen, boneRotInChar,
|
||||
wGrip, charWorldRotInv, charWorldPos);
|
||||
} else {
|
||||
applyHandTransform(weaponSpatial, attachInChar, boneRotInChar, wGrip);
|
||||
}
|
||||
} else {
|
||||
applyBackTransform(weaponSpatial, boneInChar, boneRotInChar,
|
||||
weaponItem != null ? weaponItem.getGrip() : null);
|
||||
@@ -195,22 +208,92 @@ public class NpcWeaponAttachmentControl extends AbstractControl {
|
||||
Quaternion animDelta = (handBindRotInChar != null)
|
||||
? boneRotInChar.mult(handBindRotInChar.inverse())
|
||||
: boneRotInChar;
|
||||
Quaternion weaponRot = animDelta.mult(gripRot.inverse());
|
||||
boolean bladeAtMinusZ = grip != null && grip.getGrip2PosZ() != 0f && grip.getGrip2PosZ() > grip.getPosZ();
|
||||
Quaternion bladeFlip = bladeAtMinusZ
|
||||
? new Quaternion().fromAngles(com.jme3.math.FastMath.PI, 0f, 0f)
|
||||
: new Quaternion();
|
||||
Quaternion weaponRot = animDelta.mult(bladeFlip).mult(gripRot.inverse());
|
||||
Vector3f handOff = bladeAtMinusZ
|
||||
? new Vector3f(HAND_GRIP_OFFSET.x, HAND_GRIP_OFFSET.y, -HAND_GRIP_OFFSET.z)
|
||||
: HAND_GRIP_OFFSET;
|
||||
Vector3f weaponPos = bonePosInChar.subtract(weaponRot.mult(gripPos));
|
||||
weaponPos = weaponPos.add(weaponRot.mult(HAND_GRIP_OFFSET));
|
||||
weaponPos = weaponPos.add(weaponRot.mult(handOff));
|
||||
s.setLocalRotation(weaponRot);
|
||||
s.setLocalTranslation(weaponPos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zweihänder: Schwert dreht sich frei um Griff1 (rechte Handteller-Innenfläche) als Pivot;
|
||||
* die Richtung wird so gewählt, dass Griff2 so nah wie möglich am linken Handteller liegt.
|
||||
*/
|
||||
private void applyTwoHandTransform(Spatial s, Vector3f bonePosInChar, Quaternion boneRotInChar,
|
||||
ItemGrip grip, Quaternion charWorldRotInv, Vector3f charWorldPos) {
|
||||
Quaternion gripRot = new Quaternion().fromAngles(
|
||||
DEG_TO_RAD * grip.getRotX(), DEG_TO_RAD * grip.getRotY(), DEG_TO_RAD * grip.getRotZ());
|
||||
Quaternion animDelta = (handBindRotInChar != null)
|
||||
? boneRotInChar.mult(handBindRotInChar.inverse()) : boneRotInChar;
|
||||
boolean bladeAtMinusZ3 = grip.getGrip2PosZ() > grip.getPosZ();
|
||||
Quaternion bladeFlip3 = bladeAtMinusZ3
|
||||
? new Quaternion().fromAngles(com.jme3.math.FastMath.PI, 0f, 0f)
|
||||
: new Quaternion();
|
||||
Quaternion weaponRot = animDelta.mult(bladeFlip3).mult(gripRot.inverse());
|
||||
|
||||
// Griff-Achse im Modell-Space: Griff1 → Griff2
|
||||
Vector3f g1 = new Vector3f(grip.getPosX(), grip.getPosY(), grip.getPosZ());
|
||||
Vector3f g2 = new Vector3f(grip.getGrip2PosX(), grip.getGrip2PosY(), grip.getGrip2PosZ());
|
||||
Vector3f modelGripAxis = g2.subtract(g1).normalizeLocal();
|
||||
Vector3f currentGripAxis = weaponRot.mult(modelGripAxis);
|
||||
|
||||
// Zielachse: rechtes Handgelenk → linkes Handgelenk im Char-Space
|
||||
Vector3f rightWristInChar = charWorldRotInv.mult(handNode.getWorldTranslation().subtract(charWorldPos));
|
||||
Vector3f leftWristInChar = charWorldRotInv.mult(leftForeArmNode.getWorldTranslation().subtract(charWorldPos));
|
||||
Vector3f targetGripAxis = leftWristInChar.subtract(rightWristInChar).normalizeLocal();
|
||||
|
||||
Quaternion swingCorr = swingFromTo(currentGripAxis, targetGripAxis);
|
||||
weaponRot = swingCorr.mult(weaponRot);
|
||||
|
||||
// Grip1 direkt am Handteller platzieren (bonePosInChar enthält palmOffset bereits).
|
||||
// Kein zusätzlicher HAND_GRIP_OFFSET – wir haben die exakten Greifpositionen.
|
||||
Vector3f weaponPos = bonePosInChar.subtract(weaponRot.mult(g1));
|
||||
s.setLocalRotation(weaponRot);
|
||||
s.setLocalTranslation(weaponPos);
|
||||
}
|
||||
|
||||
private static Quaternion swingFromTo(Vector3f from, Vector3f to) {
|
||||
float dot = com.jme3.math.FastMath.clamp(from.dot(to), -1f, 1f);
|
||||
Vector3f axis = from.cross(to);
|
||||
float axisLen = axis.length();
|
||||
if (axisLen < 0.001f) {
|
||||
if (dot > 0f) return new Quaternion();
|
||||
Vector3f perp = Math.abs(from.x) <= Math.abs(from.y)
|
||||
? from.cross(Vector3f.UNIT_X).normalizeLocal()
|
||||
: from.cross(Vector3f.UNIT_Y).normalizeLocal();
|
||||
return new Quaternion().fromAngleNormalAxis(com.jme3.math.FastMath.PI, perp);
|
||||
}
|
||||
return new Quaternion().fromAngleNormalAxis(com.jme3.math.FastMath.acos(dot), axis.divideLocal(axisLen));
|
||||
}
|
||||
|
||||
private static final Quaternion BACK_ROT_NORM = new Quaternion(0f, -(float) Math.sqrt(0.5), (float) Math.sqrt(0.5), 0f);
|
||||
|
||||
private void applyBackTransform(Spatial s, Vector3f boneInChar,
|
||||
Quaternion boneRotInChar, ItemGrip grip) {
|
||||
Quaternion backRot = new Quaternion().fromAngles(0f, 0f, HALF_PI);
|
||||
Quaternion weaponRot = boneRotInChar.mult(backRot);
|
||||
Quaternion gripRot = (grip != null)
|
||||
? new Quaternion().fromAngles(DEG_TO_RAD * grip.getRotX(),
|
||||
DEG_TO_RAD * grip.getRotY(),
|
||||
DEG_TO_RAD * grip.getRotZ())
|
||||
: new Quaternion();
|
||||
boolean bladeAtMinusZ2 = grip != null && grip.getGrip2PosZ() != 0f && grip.getGrip2PosZ() > grip.getPosZ();
|
||||
Quaternion bladeFlip2 = bladeAtMinusZ2
|
||||
? new Quaternion().fromAngles(com.jme3.math.FastMath.PI, 0f, 0f)
|
||||
: new Quaternion();
|
||||
Quaternion weaponRot = boneRotInChar.mult(BACK_ROT_NORM).mult(bladeFlip2).mult(gripRot.inverse());
|
||||
Vector3f target = boneInChar.add(boneRotInChar.mult(BACK_GRIP_OFFSET));
|
||||
Vector3f gripPos = grip != null
|
||||
? new Vector3f(grip.getPosX(), grip.getPosY(), grip.getPosZ()) : Vector3f.ZERO;
|
||||
Vector3f backPos = target.subtract(weaponRot.mult(gripPos));
|
||||
if (bladeAtMinusZ2) backPos = backPos.add(0.1f, 0f, 0f);
|
||||
s.setLocalRotation(weaponRot);
|
||||
s.setLocalTranslation(target.subtract(weaponRot.mult(gripPos)));
|
||||
s.setLocalTranslation(backPos);
|
||||
}
|
||||
|
||||
// ── Schild-Transforms (1:1 von WeaponAttachmentControl) ──────────────────────
|
||||
|
||||
@@ -11,6 +11,7 @@ import com.jme3.scene.Spatial;
|
||||
import com.jme3.scene.control.AbstractControl;
|
||||
import de.blight.common.model.Item;
|
||||
import de.blight.common.model.ItemGrip;
|
||||
import de.blight.common.model.ItemSubCategory;
|
||||
import de.blight.common.model.MainCharacter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -31,12 +32,13 @@ public class WeaponAttachmentControl extends AbstractControl {
|
||||
private static final String BONE_HAND = "mixamorig:RightHand";
|
||||
private static final String BONE_PALM = "mixamorig:RightHandMiddle1";
|
||||
private static final String BONE_LEFT_FOREARM = "mixamorig:LeftHand";
|
||||
|
||||
private static final float DEG_TO_RAD = (float) Math.PI / 180f;
|
||||
private static final float HALF_PI = (float) Math.PI * 0.5f;
|
||||
|
||||
private static final Vector3f BACK_GRIP_OFFSET = new Vector3f(0.0f, 0.40f, -0.13f);
|
||||
/** Zusatz-Versatz beim gezückten Schwert in lokalem Waffen-Space (X=entlang Klinge, Y=entlang Griff, Z=senkrecht zur Schneide). */
|
||||
private static final Vector3f HAND_GRIP_OFFSET = new Vector3f(0.1f, 0.0f, 0.05f);
|
||||
private static final Vector3f HAND_GRIP_OFFSET = new Vector3f(
|
||||
ItemGrip.HAND_GRIP_OFFSET_X, ItemGrip.HAND_GRIP_OFFSET_Y, ItemGrip.HAND_GRIP_OFFSET_Z);
|
||||
|
||||
/** Schild am Rücken: Griff unterhalb der Schultern, parallel zum Boden, Schild über dem Schwert. */
|
||||
private static final Vector3f SHIELD_BACK_OFFSET = new Vector3f(0.12f, -0.10f, -0.10f);
|
||||
@@ -126,7 +128,6 @@ public class WeaponAttachmentControl extends AbstractControl {
|
||||
log.info("[WeaponAttach] palmOffsetLocal (from nodes)={}", palmOffsetLocal);
|
||||
}
|
||||
}
|
||||
|
||||
Item current = mc.getEquippedMeleeWeapon();
|
||||
Item shield = mc.getEquippedShield();
|
||||
boolean drawn = playerInput.isWeaponDrawn();
|
||||
@@ -139,7 +140,7 @@ public class WeaponAttachmentControl extends AbstractControl {
|
||||
|
||||
if (weaponSpatial != null) {
|
||||
lastDrawnState = drawn;
|
||||
updateWeaponTransform(drawn, current != null ? current.getGrip() : null);
|
||||
updateWeaponTransform(drawn, current);
|
||||
}
|
||||
|
||||
if (shield != lastEquippedShield) {
|
||||
@@ -173,7 +174,8 @@ public class WeaponAttachmentControl extends AbstractControl {
|
||||
|
||||
// ── Transform-Update (jedes Frame) ────────────────────────────────────────
|
||||
|
||||
private void updateWeaponTransform(boolean drawn, ItemGrip grip) {
|
||||
private void updateWeaponTransform(boolean drawn, Item item) {
|
||||
ItemGrip grip = item != null ? item.getGrip() : null;
|
||||
Node boneNode = drawn ? handNode : backNode;
|
||||
if (boneNode == null) return;
|
||||
|
||||
@@ -185,10 +187,22 @@ public class WeaponAttachmentControl extends AbstractControl {
|
||||
Quaternion boneRotInChar = charWorldRotInv.mult(boneNode.getWorldRotation());
|
||||
|
||||
if (drawn) {
|
||||
boolean isTwoHand = item != null && item.getSubCategory() == ItemSubCategory.TWO_HANDED_SWORD;
|
||||
Vector3f attachInChar = (palmOffsetLocal != null)
|
||||
? boneInChar.add(boneRotInChar.mult(palmOffsetLocal.mult(0.5f)))
|
||||
: boneInChar;
|
||||
applyHandTransform(attachInChar, boneRotInChar, grip);
|
||||
boolean usesTwoHand = isTwoHand && leftForeArmNode != null
|
||||
&& grip != null
|
||||
&& (grip.getGrip2PosX() != 0f || grip.getGrip2PosY() != 0f || grip.getGrip2PosZ() != 0f);
|
||||
if (usesTwoHand) {
|
||||
// Handballen: entgegengesetzte Richtung von palmOffset (der Richtung Finger zeigt)
|
||||
Vector3f handballen = (palmOffsetLocal != null)
|
||||
? boneInChar.subtract(boneRotInChar.mult(palmOffsetLocal.mult(0.5f)))
|
||||
: boneInChar;
|
||||
applyTwoHandTransform(handballen, boneRotInChar, grip, charWorldRotInv, charWorldPos);
|
||||
} else {
|
||||
applyHandTransform(attachInChar, boneRotInChar, grip);
|
||||
}
|
||||
} else {
|
||||
applyBackTransform(boneInChar, boneRotInChar, grip);
|
||||
}
|
||||
@@ -205,7 +219,11 @@ public class WeaponAttachmentControl extends AbstractControl {
|
||||
Quaternion animDelta = (handBindRotInChar != null)
|
||||
? boneRotInChar.mult(handBindRotInChar.inverse())
|
||||
: boneRotInChar;
|
||||
Quaternion weaponRot = animDelta.mult(gripRot.inverse());
|
||||
boolean bladeAtMinusZ2 = grip != null && grip.getGrip2PosZ() != 0f && grip.getGrip2PosZ() > grip.getPosZ();
|
||||
Quaternion bladeFlip2 = bladeAtMinusZ2
|
||||
? new Quaternion().fromAngles(com.jme3.math.FastMath.PI, 0f, 0f)
|
||||
: new Quaternion();
|
||||
Quaternion weaponRot = animDelta.mult(bladeFlip2).mult(gripRot.inverse());
|
||||
|
||||
if (!gripDiagLogged && weaponSpatial != null) {
|
||||
gripDiagLogged = true;
|
||||
@@ -240,12 +258,74 @@ public class WeaponAttachmentControl extends AbstractControl {
|
||||
}
|
||||
}
|
||||
|
||||
Vector3f handOff2 = bladeAtMinusZ2
|
||||
? new Vector3f(HAND_GRIP_OFFSET.x, HAND_GRIP_OFFSET.y, -HAND_GRIP_OFFSET.z)
|
||||
: HAND_GRIP_OFFSET;
|
||||
Vector3f weaponPos = bonePosInChar.subtract(weaponRot.mult(gripPos));
|
||||
weaponPos = weaponPos.add(weaponRot.mult(HAND_GRIP_OFFSET));
|
||||
weaponPos = weaponPos.add(weaponRot.mult(handOff2));
|
||||
if (grip != null && (grip.getHandOffsetX() != 0f || grip.getHandOffsetY() != 0f || grip.getHandOffsetZ() != 0f)) {
|
||||
weaponPos = weaponPos.add(grip.getHandOffsetX(), grip.getHandOffsetY(), grip.getHandOffsetZ());
|
||||
}
|
||||
weaponSpatial.setLocalRotation(weaponRot);
|
||||
weaponSpatial.setLocalTranslation(weaponPos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zweihänder-Constraint: orientiert die Waffe so, dass die Linie grip1→grip2 (Modell-Space)
|
||||
* auf die Linie RightHand→LeftHand (Char-Space) zeigt. Roll bleibt aus gripRot erhalten.
|
||||
*/
|
||||
private void applyTwoHandTransform(Vector3f bonePosInChar, Quaternion boneRotInChar,
|
||||
ItemGrip grip,
|
||||
Quaternion charWorldRotInv, Vector3f charWorldPos) {
|
||||
// Erst Standard-Einhand-Rotation berechnen (gibt Roll-Basis aus gripRot)
|
||||
Quaternion gripRot = new Quaternion().fromAngles(
|
||||
DEG_TO_RAD * grip.getRotX(), DEG_TO_RAD * grip.getRotY(), DEG_TO_RAD * grip.getRotZ());
|
||||
Quaternion animDelta = (handBindRotInChar != null)
|
||||
? boneRotInChar.mult(handBindRotInChar.inverse()) : boneRotInChar;
|
||||
boolean bladeAtMinusZ3 = grip.getGrip2PosZ() > grip.getPosZ();
|
||||
Quaternion bladeFlip3 = bladeAtMinusZ3
|
||||
? new Quaternion().fromAngles(com.jme3.math.FastMath.PI, 0f, 0f)
|
||||
: new Quaternion();
|
||||
Quaternion weaponRot = animDelta.mult(bladeFlip3).mult(gripRot.inverse());
|
||||
|
||||
// Griff-Achse im Modell-Space: grip1 → grip2
|
||||
Vector3f g1 = new Vector3f(grip.getPosX(), grip.getPosY(), grip.getPosZ());
|
||||
Vector3f g2 = new Vector3f(grip.getGrip2PosX(), grip.getGrip2PosY(), grip.getGrip2PosZ());
|
||||
Vector3f modelGripAxis = g2.subtract(g1).normalizeLocal();
|
||||
|
||||
// Aktuelle Griff-Achse im Char-Space (nach Einhand-Rotation)
|
||||
Vector3f currentGripAxis = weaponRot.mult(modelGripAxis);
|
||||
|
||||
// Ziel-Achse: rechtes Handgelenk → linkes Handgelenk im Char-Space
|
||||
Vector3f rightWristInChar = charWorldRotInv.mult(handNode.getWorldTranslation().subtract(charWorldPos));
|
||||
Vector3f leftWristInChar = charWorldRotInv.mult(leftForeArmNode.getWorldTranslation().subtract(charWorldPos));
|
||||
Vector3f targetGripAxis = leftWristInChar.subtract(rightWristInChar).normalizeLocal();
|
||||
|
||||
// Minimale Swing-Rotation: dreht currentGripAxis → targetGripAxis, kein Roll-Einfluss
|
||||
Quaternion swingCorr = swingFromTo(currentGripAxis, targetGripAxis);
|
||||
weaponRot = swingCorr.mult(weaponRot);
|
||||
|
||||
// Grip1 direkt am Handteller platzieren (bonePosInChar enthält palmOffset bereits).
|
||||
// Kein zusätzlicher HAND_GRIP_OFFSET – wir haben die exakten Greifpositionen.
|
||||
Vector3f weaponPos = bonePosInChar.subtract(weaponRot.mult(g1));
|
||||
weaponSpatial.setLocalRotation(weaponRot);
|
||||
weaponSpatial.setLocalTranslation(weaponPos);
|
||||
}
|
||||
|
||||
private static Quaternion swingFromTo(Vector3f from, Vector3f to) {
|
||||
float dot = com.jme3.math.FastMath.clamp(from.dot(to), -1f, 1f);
|
||||
Vector3f axis = from.cross(to);
|
||||
float axisLen = axis.length();
|
||||
if (axisLen < 0.001f) {
|
||||
if (dot > 0f) return new Quaternion();
|
||||
Vector3f perp = Math.abs(from.x) <= Math.abs(from.y)
|
||||
? from.cross(Vector3f.UNIT_X).normalizeLocal()
|
||||
: from.cross(Vector3f.UNIT_Y).normalizeLocal();
|
||||
return new Quaternion().fromAngleNormalAxis(com.jme3.math.FastMath.PI, perp);
|
||||
}
|
||||
return new Quaternion().fromAngleNormalAxis(com.jme3.math.FastMath.acos(dot), axis.divideLocal(axisLen));
|
||||
}
|
||||
|
||||
private static float round1(float v) { return Math.round(v * 10f) / 10f; }
|
||||
|
||||
/**
|
||||
@@ -273,15 +353,32 @@ public class WeaponAttachmentControl extends AbstractControl {
|
||||
return bindMat.toRotationQuat().normalizeLocal();
|
||||
}
|
||||
|
||||
// backRot normalisiert: fromAngles(0,0,PI/2) * kurzschwert_gripRot
|
||||
// → Waffe wird zuerst per gripRot^-1 normalisiert, dann per backRot am Rücken ausgerichtet.
|
||||
// Ergebnis für Kurzschwert (gripRot=fromAngles(0,-90°,90°)) identisch zur alten Formel.
|
||||
private static final Quaternion BACK_ROT_NORM = new Quaternion(0f, -(float) Math.sqrt(0.5), (float) Math.sqrt(0.5), 0f);
|
||||
|
||||
private void applyBackTransform(Vector3f bonePosInChar, Quaternion boneRotInChar, ItemGrip grip) {
|
||||
Quaternion backRot = new Quaternion().fromAngles(0f, 0f, HALF_PI);
|
||||
Quaternion weaponRot = boneRotInChar.mult(backRot);
|
||||
Quaternion gripRot = (grip != null)
|
||||
? new Quaternion().fromAngles(DEG_TO_RAD * grip.getRotX(),
|
||||
DEG_TO_RAD * grip.getRotY(),
|
||||
DEG_TO_RAD * grip.getRotZ())
|
||||
: new Quaternion();
|
||||
// Klinge bei -Z erkannt (grip2PosZ > posZ) → 180° um X vorschalten, damit BACK_ROT_NORM
|
||||
// dieselbe Wirkung hat wie bei korrekt ausgerichtetem Modell (Klinge bei +Z).
|
||||
boolean bladeAtMinusZ = grip != null && grip.getGrip2PosZ() != 0f && grip.getGrip2PosZ() > grip.getPosZ();
|
||||
Quaternion bladeFlip = bladeAtMinusZ
|
||||
? new Quaternion().fromAngles(com.jme3.math.FastMath.PI, 0f, 0f)
|
||||
: new Quaternion();
|
||||
Quaternion weaponRot = boneRotInChar.mult(BACK_ROT_NORM).mult(bladeFlip).mult(gripRot.inverse());
|
||||
Vector3f gripTarget = bonePosInChar.add(boneRotInChar.mult(BACK_GRIP_OFFSET));
|
||||
Vector3f gripPos = (grip != null)
|
||||
Vector3f gripPos = (grip != null)
|
||||
? new Vector3f(grip.getPosX(), grip.getPosY(), grip.getPosZ())
|
||||
: Vector3f.ZERO;
|
||||
Vector3f backPos = gripTarget.subtract(weaponRot.mult(gripPos));
|
||||
if (bladeAtMinusZ) backPos = backPos.add(0.1f, 0f, 0f);
|
||||
weaponSpatial.setLocalRotation(weaponRot);
|
||||
weaponSpatial.setLocalTranslation(gripTarget.subtract(weaponRot.mult(gripPos)));
|
||||
weaponSpatial.setLocalTranslation(backPos);
|
||||
}
|
||||
|
||||
// ── Schild ────────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user