这是它的要点,你可以看到旋转角度从0到236然后跳到119 - 0,很奇怪。
我想得到一个模型的角度,以度数(0-360)为单位。但是到目前为止使用libgdx我无法使用:
获得预期的结果angle = modelInstance.transform.getRotation(new Quaternion()).getAxisAngle(Vector3.Zero)
假设我只围绕y轴旋转,这是从libgdx中的变换矩阵获得旋转角度的正确方法吗?
我已经包含了一个完整的示例类,以证明我通过这种方式获得旋转所获得的角度不是预期的,而不是0到360的完整旋转我得到类似0 - 117然后跳转到243。
public class RotateExperiment extends InputAdapter implements ApplicationListener {
private Environment environment;
private ModelBatch modelBatch;
private Camera camera;
private ModelInstance player;
@Override
public void create() {
this.player = new ModelInstance(new ModelBuilder().createCone(10, 10,10, 10, new Material(ColorAttribute.createDiffuse(Color.GRAY)), VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal));
int w = Gdx.graphics.getWidth();
int h = Gdx.graphics.getHeight();
modelBatch = new ModelBatch();
camera = new PerspectiveCamera(67, w, h);
camera.position.set(10f, 10f, 10f);
camera.lookAt(0,0,0);
camera.near = 0.1f;
camera.far = 300f;
camera.update();
environment = new Environment();
environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));
environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));
}
@Override
public void dispose() {}
private void updateModel(){
Vector3 directionVector = new Vector3(0,0,0);
if(Gdx.input.isKeyPressed(Input.Keys.S)){
directionVector.z = -1;
}
if(Gdx.input.isKeyPressed(Input.Keys.W)){
directionVector.z = 1;
}
if(Gdx.input.isKeyPressed(Input.Keys.A)){
if(Gdx.input.isButtonPressed(Input.Buttons.RIGHT)){
directionVector.y = 1;
} else {
player.transform.rotate(Vector3.Y, 90 * Gdx.graphics.getDeltaTime());
}
}
if(Gdx.input.isKeyPressed(Input.Keys.D)){
if(Gdx.input.isButtonPressed(Input.Buttons.RIGHT)){
directionVector.y = -1;
} else {
player.transform.rotate(Vector3.Y, -90 * Gdx.graphics.getDeltaTime());
}
}
if(directionVector.z != 0 || directionVector.y != 0){
player.transform.translate(directionVector.nor().scl(20 * Gdx.graphics.getDeltaTime()));
}
}
public void update() {
if(player != null){
updateModel();
//update angle text -> actual test code
outputText.setText(String.valueOf(player.transform.getRotation(new Quaternion()).getAxisAngle(Vector3.Zero)));
}
}
@Override
public void render() {
update();
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
modelBatch.begin(camera);
modelBatch.render(player, environment);
modelBatch.end();
}
@Override
public void resize(int width, int height) {
Gdx.gl.glViewport(0, 0, width, height);
}
@Override
public void pause() {}
@Override
public void resume() {}
private final static JLabel outputText = new JLabel("test");
public static void main(String[] args) {
LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
cfg.title = "TestRotation";
cfg.useGL20 = true;
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
cfg.width = screenSize.width;
cfg.height = screenSize.height;
new LwjglApplication(new RotateExperiment(), cfg);
JFrame outputWindow = new JFrame();
JPanel outputPanel = new JPanel();
outputPanel.add(outputText);
outputWindow.add(outputPanel);
outputWindow.setAlwaysOnTop(true);
outputWindow.setVisible(true);
outputWindow.pack();
outputWindow.toFront();
}
}
如果您正在运行该示例,请在加载后单击libgdx渲染窗口,并且可以使用“A”和“D”控制模型旋转。使用上述方法生成的旋转也在单独的JFrame中输出。
修改 我相信可疑代码可能采用libgdx方法将4x4转换矩阵转换为四元数: Quaternion.setFromAxes 。当你调用transform.getRotation()时,这会调用setFromAxes并传入矩阵轴。我已经看到了open issue,但正如你在他的示例中看到的那样,我的立方体模型没有缩放,所以这不可能是正在发生的事情。 setFromAxes代码如下:
// the trace is the sum of the diagonal elements; see
// http://mathworld.wolfram.com/MatrixTrace.html
final float m00 = xx, m01 = xy, m02 = xz;
final float m10 = yx, m11 = yy, m12 = yz;
final float m20 = zx, m21 = zy, m22 = zz;
final float t = m00 + m11 + m22;
// we protect the division by s by ensuring that s>=1
double x, y, z, w;
if (t >= 0) { // |w| >= .5
double s = Math.sqrt(t + 1); // |s|>=1 ...
w = 0.5 * s;
s = 0.5 / s; // so this division isn't bad
x = (m21 - m12) * s;
y = (m02 - m20) * s;
z = (m10 - m01) * s;
} else if ((m00 > m11) && (m00 > m22)) {
double s = Math.sqrt(1.0 + m00 - m11 - m22); // |s|>=1
x = s * 0.5; // |x| >= .5
s = 0.5 / s;
y = (m10 + m01) * s;
z = (m02 + m20) * s;
w = (m21 - m12) * s;
} else if (m11 > m22) {
double s = Math.sqrt(1.0 + m11 - m00 - m22); // |s|>=1
y = s * 0.5; // |y| >= .5
s = 0.5 / s;
x = (m10 + m01) * s;
z = (m21 + m12) * s;
w = (m02 - m20) * s;
} else {
double s = Math.sqrt(1.0 + m22 - m00 - m11); // |s|>=1
z = s * 0.5; // |z| >= .5
s = 0.5 / s;
x = (m02 + m20) * s;
y = (m21 + m12) * s;
w = (m10 - m01) * s;
}
return set((float)x, (float)y, (float)z, (float)w);
答案 0 :(得分:3)
因此,假设您有一个非缩放模型,并且只围绕y轴执行了旋转,则以下代码将仅从模型中的变换矩阵中获取角度0 -360:
Vector3 axisVec = new Vector3();
int angle = (int) (player.transform.getRotation(new Quaternion()).getAxisAngle(axisVec) * axisVec.nor().y);
angle = angle < 0 ? angle + 360 : angle; //convert <0 values
如果你有一个缩放模型,那么根据open issue的当前解决方案是规范化setFromAxes代码中的轴,我已经用以下内容替换了我的setFromAxes,直到它被更新:
private Quaternion setFromAxes(float xx, float xy, float xz, float yx, float yy, float yz, float zx, float zy, float zz){
//normalise axis
Vector3 xAxis = new Vector3(xx, xy, xz).nor();
Vector3 yAxis = new Vector3(yx, yy, yz).nor();
Vector3 zAxis = new Vector3(zx, zy, zz).nor();
xx = xAxis.x;
xy = xAxis.y;
xz = xAxis.z;
yx = yAxis.x;
yy = yAxis.y;
yz = yAxis.z;
zx = zAxis.x;
zy = zAxis.y;
zz = zAxis.z;
// the trace is the sum of the diagonal elements; see
// http://mathworld.wolfram.com/MatrixTrace.html
final float m00 = xx, m01 = xy, m02 = xz;
final float m10 = yx, m11 = yy, m12 = yz;
final float m20 = zx, m21 = zy, m22 = zz;
final float t = m00 + m11 + m22;
// we protect the division by s by ensuring that s>=1
double x, y, z, w;
if (t >= 0) { // |w| >= .5
double s = Math.sqrt(t + 1); // |s|>=1 ...
w = 0.5 * s;
s = 0.5 / s; // so this division isn't bad
x = (m21 - m12) * s;
y = (m02 - m20) * s;
z = (m10 - m01) * s;
} else if ((m00 > m11) && (m00 > m22)) {
double s = Math.sqrt(1.0 + m00 - m11 - m22); // |s|>=1
x = s * 0.5; // |x| >= .5
s = 0.5 / s;
y = (m10 + m01) * s;
z = (m02 + m20) * s;
w = (m21 - m12) * s;
} else if (m11 > m22) {
double s = Math.sqrt(1.0 + m11 - m00 - m22); // |s|>=1
y = s * 0.5; // |y| >= .5
s = 0.5 / s;
x = (m10 + m01) * s;
z = (m21 + m12) * s;
w = (m02 - m20) * s;
} else {
double s = Math.sqrt(1.0 + m22 - m00 - m11); // |s|>=1
z = s * 0.5; // |z| >= .5
s = 0.5 / s;
x = (m02 + m20) * s;
y = (m21 + m12) * s;
w = (m10 - m01) * s;
}
return new Quaternion((float)x, (float)y, (float)z, (float)w);
}