如何制作 Android 3D Carousel Drawable
How to Make an Android 3D Carousel Drawable
我正在尝试在 Android (Java) 中创建一个 3D 旋转木马,但我不能完全让它工作。这是我想要的那种轮播:
我已经尝试了几种漫长而复杂的方法来做到这一点,包括使用大量数学方法手工绘制路径,但它总是不太正确。
感觉最接近的想法是通过计算图像在圆上的位置在 x-y 平面中绘制图像轮播,然后“翻转”该平面,使轮播现在位于 x-z 方向。这似乎几乎可以工作(虽然角落不太接触),但正方形是平躺的,我需要它们站在最外边。我无法弄清楚如何进行最终旋转,但不会撤消相机之前的旋转。
这是我的结果目前的视觉效果:
我是不是走错了路?我很接近但只需要改变几件事吗?老实说,我不确定。请帮我弄清楚如何更好地做到这一点!
这是我的可绘制代码:
public class CarouselCard extends Drawable {
Paint paintBackground = null;
/* CONSTRUCTOR */
public CarouselCard() {
super();
invalidateSelf();
}
@Override
public void draw(Canvas canvas) {
if (paintBackground == null) { // Just starting
paintBackground = new Paint();
paintBackground.setStyle(Paint.Style.FILL);
paintBackground.setColor(Color.BLUE);
}
int HALF_CHORD_WIDTH = 150;
float RADIUS = 200;
float INTERIOR_ANGLE = 30;
INTERIOR_ANGLE %= 360;
int numObjects = (int) (360 / INTERIOR_ANGLE);
for (int i = 0; i < numObjects; i++) {
float theta = INTERIOR_ANGLE * i;
double rad = Math.toRadians(theta);
float circleX = (float) (RADIUS * Math.sin(rad));
float circleY = (float) (RADIUS * Math.cos(rad));
canvas.save();
canvas.translate(canvas.getWidth() / 2, canvas.getHeight() / 2);
Camera camera = new Camera();
camera.save();
camera.rotateX(80); // Approximates 90 but keeps it visible since flat
camera.rotateZ(theta);
camera.applyToCanvas(canvas);
camera.restore();
if (i % 4 == 0) paintBackground.setColor(Color.YELLOW);
if (i % 4 == 1) paintBackground.setColor(Color.GREEN);
if (i % 4 == 2) paintBackground.setColor(Color.BLUE);
if (i % 4 == 3) paintBackground.setColor(Color.GRAY);
paintBackground.setAlpha(128);
canvas.drawRect(circleX-HALF_CHORD_WIDTH, circleY-HALF_CHORD_WIDTH,
circleX+HALF_CHORD_WIDTH, circleY+HALF_CHORD_WIDTH, paintBackground);
canvas.restore();
}
}
@Override
public void setAlpha(int alpha) {}
@Override
public void setColorFilter(ColorFilter colorFilter) {}
@Override
public int getOpacity() {
return PixelFormat.UNKNOWN;
}
}
或者,我可以让所有东西都朝向正确的方向并正确定向,但前提是它们都位于旋转木马的中心。我不确定如何适当地移动它们,同时仍然保持使这张照片成为可能的转换:
此图像是通过调整上述 for 循环生成的,如下所示:
for (int i = 0; i < numObjects; i++) {
if (i % 4 == 0) paintBackground.setColor(Color.YELLOW);
if (i % 4 == 1) paintBackground.setColor(Color.GREEN);
if (i % 4 == 2) paintBackground.setColor(Color.BLUE);
if (i % 4 == 3) paintBackground.setColor(Color.GRAY);
paintBackground.setAlpha(128);
float theta = INTERIOR_ANGLE * i;
canvas.save();
canvas.translate(canvas.getWidth() / 2, canvas.getHeight() / 2);
Camera camera = new Camera();
camera.save();
camera.rotateY(theta);
camera.applyToCanvas(canvas);
camera.restore();
canvas.drawRect(
-HALF_CHORD_WIDTH,
-HALF_CHORD_WIDTH,
HALF_CHORD_WIDTH,
HALF_CHORD_WIDTH,
paintBackground);
canvas.restore();
}
我能够创建以下轮播:
它的代码是:
@Override
public void draw(Canvas canvas) {
if (paintBackground == null) { // Just starting
paintBackground = new Paint();
paintBackground.setStyle(Paint.Style.FILL);
paintBackground.setColor(Color.BLUE);
}
// ######## CRUCIAL - START - Modify constants with care!
// Decreasing chord denominator makes carousel bigger, while increasing it
// makes front side contain more squares (but gets smaller)
float HALF_CHORD_WIDTH = canvas.getWidth()/31f; // Width of each square
float RADIUS = HALF_CHORD_WIDTH; // Radius of carousel
float CAMERA_MULT = HALF_CHORD_WIDTH/10f;
// ######## CRUCIAL - END
float INTERIOR_ANGLE = 30;
INTERIOR_ANGLE %= 360;
int numObjects = (int) (360 / INTERIOR_ANGLE);
for (int i = 0; i < numObjects; i++) {
if (i % 4 == 0) paintBackground.setColor(Color.YELLOW);
if (i % 4 == 1) paintBackground.setColor(Color.GREEN);
if (i % 4 == 2) paintBackground.setColor(Color.BLUE);
if (i % 4 == 3) paintBackground.setColor(Color.GRAY);
paintBackground.setAlpha(128);
float theta = INTERIOR_ANGLE * i;
double rad = Math.toRadians(theta);
float circleX = (float) (RADIUS * Math.sin(rad));
float circleZ = (float) (RADIUS * Math.cos(rad));
canvas.save();
canvas.translate(canvas.getWidth() / 2, canvas.getHeight() / 2);
Camera camera = new Camera();
camera.save();
camera.translate(circleX*CAMERA_MULT, 0, -circleZ*CAMERA_MULT);
camera.rotateY(theta);
camera.applyToCanvas(canvas);
camera.restore();
canvas.drawRect(
-HALF_CHORD_WIDTH,
-HALF_CHORD_WIDTH,
HALF_CHORD_WIDTH,
HALF_CHORD_WIDTH,
paintBackground);
canvas.restore();
}
}
我正在尝试在 Android (Java) 中创建一个 3D 旋转木马,但我不能完全让它工作。这是我想要的那种轮播:
我已经尝试了几种漫长而复杂的方法来做到这一点,包括使用大量数学方法手工绘制路径,但它总是不太正确。
感觉最接近的想法是通过计算图像在圆上的位置在 x-y 平面中绘制图像轮播,然后“翻转”该平面,使轮播现在位于 x-z 方向。这似乎几乎可以工作(虽然角落不太接触),但正方形是平躺的,我需要它们站在最外边。我无法弄清楚如何进行最终旋转,但不会撤消相机之前的旋转。
这是我的结果目前的视觉效果:
我是不是走错了路?我很接近但只需要改变几件事吗?老实说,我不确定。请帮我弄清楚如何更好地做到这一点!
这是我的可绘制代码:
public class CarouselCard extends Drawable {
Paint paintBackground = null;
/* CONSTRUCTOR */
public CarouselCard() {
super();
invalidateSelf();
}
@Override
public void draw(Canvas canvas) {
if (paintBackground == null) { // Just starting
paintBackground = new Paint();
paintBackground.setStyle(Paint.Style.FILL);
paintBackground.setColor(Color.BLUE);
}
int HALF_CHORD_WIDTH = 150;
float RADIUS = 200;
float INTERIOR_ANGLE = 30;
INTERIOR_ANGLE %= 360;
int numObjects = (int) (360 / INTERIOR_ANGLE);
for (int i = 0; i < numObjects; i++) {
float theta = INTERIOR_ANGLE * i;
double rad = Math.toRadians(theta);
float circleX = (float) (RADIUS * Math.sin(rad));
float circleY = (float) (RADIUS * Math.cos(rad));
canvas.save();
canvas.translate(canvas.getWidth() / 2, canvas.getHeight() / 2);
Camera camera = new Camera();
camera.save();
camera.rotateX(80); // Approximates 90 but keeps it visible since flat
camera.rotateZ(theta);
camera.applyToCanvas(canvas);
camera.restore();
if (i % 4 == 0) paintBackground.setColor(Color.YELLOW);
if (i % 4 == 1) paintBackground.setColor(Color.GREEN);
if (i % 4 == 2) paintBackground.setColor(Color.BLUE);
if (i % 4 == 3) paintBackground.setColor(Color.GRAY);
paintBackground.setAlpha(128);
canvas.drawRect(circleX-HALF_CHORD_WIDTH, circleY-HALF_CHORD_WIDTH,
circleX+HALF_CHORD_WIDTH, circleY+HALF_CHORD_WIDTH, paintBackground);
canvas.restore();
}
}
@Override
public void setAlpha(int alpha) {}
@Override
public void setColorFilter(ColorFilter colorFilter) {}
@Override
public int getOpacity() {
return PixelFormat.UNKNOWN;
}
}
或者,我可以让所有东西都朝向正确的方向并正确定向,但前提是它们都位于旋转木马的中心。我不确定如何适当地移动它们,同时仍然保持使这张照片成为可能的转换:
此图像是通过调整上述 for 循环生成的,如下所示:
for (int i = 0; i < numObjects; i++) {
if (i % 4 == 0) paintBackground.setColor(Color.YELLOW);
if (i % 4 == 1) paintBackground.setColor(Color.GREEN);
if (i % 4 == 2) paintBackground.setColor(Color.BLUE);
if (i % 4 == 3) paintBackground.setColor(Color.GRAY);
paintBackground.setAlpha(128);
float theta = INTERIOR_ANGLE * i;
canvas.save();
canvas.translate(canvas.getWidth() / 2, canvas.getHeight() / 2);
Camera camera = new Camera();
camera.save();
camera.rotateY(theta);
camera.applyToCanvas(canvas);
camera.restore();
canvas.drawRect(
-HALF_CHORD_WIDTH,
-HALF_CHORD_WIDTH,
HALF_CHORD_WIDTH,
HALF_CHORD_WIDTH,
paintBackground);
canvas.restore();
}
我能够创建以下轮播:
它的代码是:
@Override
public void draw(Canvas canvas) {
if (paintBackground == null) { // Just starting
paintBackground = new Paint();
paintBackground.setStyle(Paint.Style.FILL);
paintBackground.setColor(Color.BLUE);
}
// ######## CRUCIAL - START - Modify constants with care!
// Decreasing chord denominator makes carousel bigger, while increasing it
// makes front side contain more squares (but gets smaller)
float HALF_CHORD_WIDTH = canvas.getWidth()/31f; // Width of each square
float RADIUS = HALF_CHORD_WIDTH; // Radius of carousel
float CAMERA_MULT = HALF_CHORD_WIDTH/10f;
// ######## CRUCIAL - END
float INTERIOR_ANGLE = 30;
INTERIOR_ANGLE %= 360;
int numObjects = (int) (360 / INTERIOR_ANGLE);
for (int i = 0; i < numObjects; i++) {
if (i % 4 == 0) paintBackground.setColor(Color.YELLOW);
if (i % 4 == 1) paintBackground.setColor(Color.GREEN);
if (i % 4 == 2) paintBackground.setColor(Color.BLUE);
if (i % 4 == 3) paintBackground.setColor(Color.GRAY);
paintBackground.setAlpha(128);
float theta = INTERIOR_ANGLE * i;
double rad = Math.toRadians(theta);
float circleX = (float) (RADIUS * Math.sin(rad));
float circleZ = (float) (RADIUS * Math.cos(rad));
canvas.save();
canvas.translate(canvas.getWidth() / 2, canvas.getHeight() / 2);
Camera camera = new Camera();
camera.save();
camera.translate(circleX*CAMERA_MULT, 0, -circleZ*CAMERA_MULT);
camera.rotateY(theta);
camera.applyToCanvas(canvas);
camera.restore();
canvas.drawRect(
-HALF_CHORD_WIDTH,
-HALF_CHORD_WIDTH,
HALF_CHORD_WIDTH,
HALF_CHORD_WIDTH,
paintBackground);
canvas.restore();
}
}