我需要在3D空间中实现动作效果(超高速)。为此我决定使用贴花。我以随机顺序将1000个粒子放置在有限的空间中,并使用相机位置以相反的方向移动它们以产生超高速效果。也许,它不是一个完美的解决方案,最好在相机前面创建粒子,或者使用着色器和帧缓冲器。无论如何,问题是我需要根据相机的移动将这些粒子拉伸到正确的方向。事实上,它们已经拉长,但需要旋转。为了澄清这一点,让我们看看下面的截图:
嗯,我希望主要观点很明确。另外,我想提供我的课程:
public class MotionEffect {
Camera camera;
Vector3 oldCameraPos, displacement;
Vector3 prjCamPos;
Vector3 prjOldPos;
Vector3 rotationVec;
DecalBatch decalBatch;
private Texture dustTex;
private class Particle{
float size = 1.5f;
final float areaSize = 250;
Decal decal;
float x, y, z;
float dx, dy ,dz;
float r, g, b, a;
public Particle(TextureRegion texRegion){
decal = Decal.newDecal(size, size, texRegion, true);
r=1; g=1; b=1;
init();
}
private void init() {
a = 1;
x = MathUtils.random(-areaSize, areaSize) + Settings.SunPosition.x;
y = MathUtils.random(-areaSize, areaSize) + Settings.SunPosition.y;
z = MathUtils.random(-areaSize, areaSize) + Settings.SunPosition.z;
}
public void update(Vector3 displacement, float alpha, float angle) {
dx = -displacement.x;
dy = -displacement.y;
dz = -displacement.z;
x += dx;
y += dy;
z += dz;
if ((x < -areaSize || x > areaSize) || (y < -areaSize || y > areaSize) || (z < -areaSize || z > areaSize)) init();
decal.setColor(r, g, b, 1);
decal.setPosition(x, y, z);
decal.setWidth(size * 20 * alpha);
//decal has to be always faced to the camera
decal.setRotation(camera.direction, camera.up);
decal.rotateZ(angle); //rotate decal according to the camera movement
//decal.rotateY(90); //rotate particle to forward - backward dir
}
public void render(DecalBatch decalBatch){
float distance = decal.getPosition().dst(camera.position);
if(distance>270) return;
if(distance<30) return;
decalBatch.add(decal);
}
}
int countOfParticles=1000;
Particle[] particles;
Vector2 original;
Vector2 direction;
public MotionEffect(Camera camera){
this.camera = camera;
oldCameraPos = new Vector3(camera.position);
displacement = new Vector3();
decalBatch = new DecalBatch(new DustGroupStrategy(camera));
dustTex = new Texture(Gdx.files.internal("textures/shine.png"));
TextureRegion dustTexReg = new TextureRegion(dustTex);
particles = new Particle[countOfParticles];
for(int i=0; i<countOfParticles; i++){
particles[i] = new Particle(dustTexReg);
}
rotationVec = new Vector3();
original = new Vector2(0, 10);
direction = new Vector2();
prjCamPos = new Vector3();
prjOldPos = new Vector3();
}
private float calcMovement(Camera camera, float delta) {
float lerp = 0.1f;
Vector3 cameraPosition = camera.position;
float x = (cameraPosition.x - oldCameraPos.x) * lerp ;
float y = (cameraPosition.y - oldCameraPos.y) * lerp ;
float z = (cameraPosition.z - oldCameraPos.z) * lerp ;
oldCameraPos.x += x;
oldCameraPos.y += y;
oldCameraPos.z += z;
prjCamPos.set(cameraPosition);
prjCamPos.add(.1f,.1f,.1f);
prjOldPos.set(oldCameraPos);
prjOldPos.add(.1f,.1f,.1f);
camera.project(prjCamPos);
camera.project(prjOldPos);
Gdx.app.log("sds", prjCamPos+" - "+prjOldPos);
float del = .1f;
x /= del;
y /= del;
z /= del;
displacement.set(x, y, z);
float alpha = (Math.abs(displacement.x) + Math.abs(displacement.y) + Math.abs(displacement.z)) / 3f;
if(alpha>1) alpha = 1;
return alpha;
}
//ATTEMPT TO CALC THE ANGLE
public float getAngle(Vector3 oldPoint, Vector3 newPoint) {
float angle = (float) Math.toDegrees(Math.atan2(newPoint.y - oldPoint.y, newPoint.x - oldPoint.x));
if(angle < 0){
angle += 360;
}
return -angle;
}
//ATTEMPT TO CALC THE ANGLES
float angleX, angleY, angleZ;
private void calcAngle(){
Vector3 thisPoint = oldCameraPos;
Vector3 targetPoint = camera.position;
float someSmallEpsilon = 0.01f;
Vector3 difference = targetPoint.sub(thisPoint);
angleX = 0;
if (difference.len() < someSmallEpsilon)
{
// Objects are at the same location - can't
// sensibly compute a direction to look at
return;
}
Vector3 direction = difference.nor();
Vector3 xAxis = new Vector3(1,0,0);
float dotProduct = xAxis.dot(direction);
angleX = (float) Math.acos(dotProduct);
if (angleX < someSmallEpsilon)
{
// Angle is already right. Nothing to do
return;
}
Vector3 axis = xAxis.crs(direction).nor();
Quaternion result = new Quaternion();
result.setFromAxisRad(axis, angleX);
}
public void render(Camera camera){
float alpha = calcMovement(camera, Gdx.graphics.getDeltaTime());
if(alpha<=0) return;
//calcAngle();
float angle = getAngle(prjCamPos, prjOldPos);
for(int i=0; i<countOfParticles; i++){
particles[i].update(displacement, alpha, angle);
particles[i].render(decalBatch);
}
decalBatch.flush();
}
}
任何帮助都将不胜感激。