使用 java3D 和 rotpospathInterpolator 制作正确的动画
Making a correct animation with java3D and rotpospathInterpolator
我试图让一个物体在我的场景中飞过一个正方形(它做对了)但我希望它也面向它要去的地方...
问题是当前物体在飞行,并且在飞行时旋转(这是不自然的)。我想让它飞到一个点,然后停下来旋转,然后飞到下一个点,然后再旋转等等。
我正在尝试使用 Java3D 函数实现此目的:
RotPosPathInterpolator
这就是我正在做的事情:
Alpha alphaNave = new Alpha( -1, Alpha.INCREASING_ENABLE, 0,0,6000,0,0,0,0,0 );
TransformGroup target = new TransformGroup();
Transform3D axisOfRotPos = new Transform3D();
float[] alphas = {0.0f, 0.25f, 0.50f, 0.75f, 1.0f};
Quat4f[] quats = new Quat4f[5];
Point3f[] positions = new Point3f[5];
target.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
quats[0] = new Quat4f(0.0f, 1.0f, 0.0f, (float) Math.toRadians(0));
quats[1] = new Quat4f(0.0f, 1.0f, 0.0f, (float) Math.toRadians(90));
quats[2] = new Quat4f(0.0f, 1.0f, 0.0f, (float) Math.toRadians(180));
quats[3] = new Quat4f(0.0f, 1.0f, 0.0f, (float) Math.toRadians(270));
quats[4] = quats[0];
positions[0]= new Point3f( -20.0f, 0.0f, 20.0f);
positions[1]= new Point3f( -20.0f, 0.0f, -20.0f);
positions[2]= new Point3f( 20.0f, 0.0f, -20.0f);
positions[3]= new Point3f( 20.0f, 0.0f, 20.0f);
positions[4]= positions[0];
RotPosPathInterpolator rotPosPath = new RotPosPathInterpolator(
alphaNave, target, axisOfRotPos, alphas, quats, positions);
首先是一个简短的旁注:创建四元数时,最后一个分量是而不是只是角度。为了创建描述绕某个轴旋转的四元数,大约某个角度,最简单的方法是遍历 AxisAngle4f
class.
AxisAngle4f a = new AxisAngle4f(0.0f, 1.0f, 0.0f, angleInRadians);
Quat4f q = new Quat4f();
q.set(a);
(不幸的是,没有方便的构造函数。我建议将这 3 行包装在实用方法中,returns 适当的四元数)。
关于实际问题:如果我理解正确,则期望的行为是这样的:
(这是根据我在下面添加的 MCVE 创建的)。
如果你只想有一个运动(没有旋转),那么你必须在插值路径中插入两个点,只有位置发生变化,但旋转保持不变。同样,当您只需要旋转时,您必须创建两个点,其中只有旋转发生变化,但位置保持不变。当然,您始终必须相应地调整 alpha
值。
对于这个例子,您的路径将包含 9 个点。手动添加这些点并计算所需的 alpha
值很麻烦。我建议为此创建一个小实用程序 class。以下 MCVE 允许将点(每个点由一个位置和一个角度组成)添加到 InterpolatorData
class,然后为插值器提供数据。
import java.awt.GraphicsConfiguration;
import java.util.ArrayList;
import java.util.List;
import javax.media.j3d.Alpha;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.RotPosPathInterpolator;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.vecmath.AxisAngle4f;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
import javax.vecmath.Quat4f;
import javax.vecmath.Vector3d;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.SimpleUniverse;
public class RotPosPathInterpolatorTest
{
public static void main(String[] args)
{
System.setProperty("sun.awt.noerasebackground", "true");
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);;
GraphicsConfiguration config =
SimpleUniverse.getPreferredConfiguration();
Canvas3D canvas = new Canvas3D(config);
frame.getContentPane().add(canvas);
SimpleUniverse simpleUniverse = new SimpleUniverse(canvas);
BranchGroup rootBranchGroup = new BranchGroup();
createContents(rootBranchGroup);
simpleUniverse.addBranchGraph(rootBranchGroup);
Transform3D t0 = new Transform3D();
t0.rotX(Math.toRadians(-45));
Transform3D t1 = new Transform3D();
t1.setTranslation(new Vector3d(0,0,10));
t0.mul(t1);
simpleUniverse.
getViewingPlatform().
getViewPlatformTransform().
setTransform(t0);
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private static class InterpolatorData
{
private final List<Point3f> positions = new ArrayList<Point3f>();
private final List<Quat4f> orientations = new ArrayList<Quat4f>();
void add(Point3f p, float angleDeg)
{
positions.add(p);
AxisAngle4f a = new AxisAngle4f(
0.0f, 1.0f, 0.0f, (float) Math.toRadians(angleDeg));
Quat4f q = new Quat4f();
q.set(a);
orientations.add(q);
}
Point3f[] getPositions()
{
return positions.toArray(new Point3f[0]);
}
Quat4f[] getOrientations()
{
return orientations.toArray(new Quat4f[0]);
}
float[] getAlphas()
{
float alphas[] = new float[positions.size()];
float delta = 1.0f / (alphas.length - 1);
for (int i=0; i<alphas.length; i++)
{
alphas[i] = i * delta;
}
return alphas;
}
}
private static void createContents(BranchGroup rootBranchGroup)
{
Alpha alpha = new Alpha(-1, Alpha.INCREASING_ENABLE,
0, 0, 6000, 0, 0, 0, 0, 0);
TransformGroup target = new TransformGroup();
target.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
Transform3D axisOfTransform = new Transform3D();
InterpolatorData i = new InterpolatorData();
i.add(new Point3f(-2.0f, 0.0f, 2.0f), 0.0f);
i.add(new Point3f(-2.0f, 0.0f, -2.0f), 0.0f);
i.add(new Point3f(-2.0f, 0.0f, -2.0f), 90.0f);
i.add(new Point3f( 2.0f, 0.0f, -2.0f), 90.0f);
i.add(new Point3f( 2.0f, 0.0f, -2.0f), 180.0f);
i.add(new Point3f( 2.0f, 0.0f, 2.0f), 180.0f);
i.add(new Point3f( 2.0f, 0.0f, 2.0f), 270.0f);
i.add(new Point3f(-2.0f, 0.0f, 2.0f), 270.0f);
i.add(new Point3f(-2.0f, 0.0f, 2.0f), 0.0f);
RotPosPathInterpolator interpolator = new RotPosPathInterpolator(
alpha, target, axisOfTransform,
i.getAlphas(), i.getOrientations(), i.getPositions());
interpolator.setSchedulingBounds(
new BoundingSphere(new Point3d(), 100.0));
rootBranchGroup.addChild(target);
target.addChild(interpolator);
target.addChild(new ColorCube(0.4));
}
}
另一条评论:使用这样的实用程序 class,此解决方案可能没问题,但对于更复杂的路径和行为,人们可能会为路径处理创建专用基础结构。
我试图让一个物体在我的场景中飞过一个正方形(它做对了)但我希望它也面向它要去的地方...
问题是当前物体在飞行,并且在飞行时旋转(这是不自然的)。我想让它飞到一个点,然后停下来旋转,然后飞到下一个点,然后再旋转等等。
我正在尝试使用 Java3D 函数实现此目的: RotPosPathInterpolator
这就是我正在做的事情:
Alpha alphaNave = new Alpha( -1, Alpha.INCREASING_ENABLE, 0,0,6000,0,0,0,0,0 );
TransformGroup target = new TransformGroup();
Transform3D axisOfRotPos = new Transform3D();
float[] alphas = {0.0f, 0.25f, 0.50f, 0.75f, 1.0f};
Quat4f[] quats = new Quat4f[5];
Point3f[] positions = new Point3f[5];
target.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
quats[0] = new Quat4f(0.0f, 1.0f, 0.0f, (float) Math.toRadians(0));
quats[1] = new Quat4f(0.0f, 1.0f, 0.0f, (float) Math.toRadians(90));
quats[2] = new Quat4f(0.0f, 1.0f, 0.0f, (float) Math.toRadians(180));
quats[3] = new Quat4f(0.0f, 1.0f, 0.0f, (float) Math.toRadians(270));
quats[4] = quats[0];
positions[0]= new Point3f( -20.0f, 0.0f, 20.0f);
positions[1]= new Point3f( -20.0f, 0.0f, -20.0f);
positions[2]= new Point3f( 20.0f, 0.0f, -20.0f);
positions[3]= new Point3f( 20.0f, 0.0f, 20.0f);
positions[4]= positions[0];
RotPosPathInterpolator rotPosPath = new RotPosPathInterpolator(
alphaNave, target, axisOfRotPos, alphas, quats, positions);
首先是一个简短的旁注:创建四元数时,最后一个分量是而不是只是角度。为了创建描述绕某个轴旋转的四元数,大约某个角度,最简单的方法是遍历 AxisAngle4f
class.
AxisAngle4f a = new AxisAngle4f(0.0f, 1.0f, 0.0f, angleInRadians);
Quat4f q = new Quat4f();
q.set(a);
(不幸的是,没有方便的构造函数。我建议将这 3 行包装在实用方法中,returns 适当的四元数)。
关于实际问题:如果我理解正确,则期望的行为是这样的:
(这是根据我在下面添加的 MCVE 创建的)。
如果你只想有一个运动(没有旋转),那么你必须在插值路径中插入两个点,只有位置发生变化,但旋转保持不变。同样,当您只需要旋转时,您必须创建两个点,其中只有旋转发生变化,但位置保持不变。当然,您始终必须相应地调整 alpha
值。
对于这个例子,您的路径将包含 9 个点。手动添加这些点并计算所需的 alpha
值很麻烦。我建议为此创建一个小实用程序 class。以下 MCVE 允许将点(每个点由一个位置和一个角度组成)添加到 InterpolatorData
class,然后为插值器提供数据。
import java.awt.GraphicsConfiguration;
import java.util.ArrayList;
import java.util.List;
import javax.media.j3d.Alpha;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.RotPosPathInterpolator;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.vecmath.AxisAngle4f;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
import javax.vecmath.Quat4f;
import javax.vecmath.Vector3d;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.SimpleUniverse;
public class RotPosPathInterpolatorTest
{
public static void main(String[] args)
{
System.setProperty("sun.awt.noerasebackground", "true");
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);;
GraphicsConfiguration config =
SimpleUniverse.getPreferredConfiguration();
Canvas3D canvas = new Canvas3D(config);
frame.getContentPane().add(canvas);
SimpleUniverse simpleUniverse = new SimpleUniverse(canvas);
BranchGroup rootBranchGroup = new BranchGroup();
createContents(rootBranchGroup);
simpleUniverse.addBranchGraph(rootBranchGroup);
Transform3D t0 = new Transform3D();
t0.rotX(Math.toRadians(-45));
Transform3D t1 = new Transform3D();
t1.setTranslation(new Vector3d(0,0,10));
t0.mul(t1);
simpleUniverse.
getViewingPlatform().
getViewPlatformTransform().
setTransform(t0);
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private static class InterpolatorData
{
private final List<Point3f> positions = new ArrayList<Point3f>();
private final List<Quat4f> orientations = new ArrayList<Quat4f>();
void add(Point3f p, float angleDeg)
{
positions.add(p);
AxisAngle4f a = new AxisAngle4f(
0.0f, 1.0f, 0.0f, (float) Math.toRadians(angleDeg));
Quat4f q = new Quat4f();
q.set(a);
orientations.add(q);
}
Point3f[] getPositions()
{
return positions.toArray(new Point3f[0]);
}
Quat4f[] getOrientations()
{
return orientations.toArray(new Quat4f[0]);
}
float[] getAlphas()
{
float alphas[] = new float[positions.size()];
float delta = 1.0f / (alphas.length - 1);
for (int i=0; i<alphas.length; i++)
{
alphas[i] = i * delta;
}
return alphas;
}
}
private static void createContents(BranchGroup rootBranchGroup)
{
Alpha alpha = new Alpha(-1, Alpha.INCREASING_ENABLE,
0, 0, 6000, 0, 0, 0, 0, 0);
TransformGroup target = new TransformGroup();
target.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
Transform3D axisOfTransform = new Transform3D();
InterpolatorData i = new InterpolatorData();
i.add(new Point3f(-2.0f, 0.0f, 2.0f), 0.0f);
i.add(new Point3f(-2.0f, 0.0f, -2.0f), 0.0f);
i.add(new Point3f(-2.0f, 0.0f, -2.0f), 90.0f);
i.add(new Point3f( 2.0f, 0.0f, -2.0f), 90.0f);
i.add(new Point3f( 2.0f, 0.0f, -2.0f), 180.0f);
i.add(new Point3f( 2.0f, 0.0f, 2.0f), 180.0f);
i.add(new Point3f( 2.0f, 0.0f, 2.0f), 270.0f);
i.add(new Point3f(-2.0f, 0.0f, 2.0f), 270.0f);
i.add(new Point3f(-2.0f, 0.0f, 2.0f), 0.0f);
RotPosPathInterpolator interpolator = new RotPosPathInterpolator(
alpha, target, axisOfTransform,
i.getAlphas(), i.getOrientations(), i.getPositions());
interpolator.setSchedulingBounds(
new BoundingSphere(new Point3d(), 100.0));
rootBranchGroup.addChild(target);
target.addChild(interpolator);
target.addChild(new ColorCube(0.4));
}
}
另一条评论:使用这样的实用程序 class,此解决方案可能没问题,但对于更复杂的路径和行为,人们可能会为路径处理创建专用基础结构。