package org.ntlab.radishforandroidstudio.java3d; public class Sphere extends Primitive { public static final int BODY = 0; static final int MID_REZ_DIV = 16; private float radius; int divisions; private Shape3D bodyShape = null; public Sphere(float r, Appearance ap){ divisions = MID_REZ_DIV; radius = r; // 各面のジオメトリを作成 IndexedTriangleArray bodyGeom = new IndexedTriangleArray(divisions * (divisions / 2 - 1) + 2, IndexedTriangleArray.COORDINATES | IndexedTriangleArray.NORMALS | IndexedTriangleArray.TEXTURE_COORDINATE_2, divisions * ((divisions - 2) * 6 + 2 * 3)); // 頂点座標と法線の設定 float coordinates[][] = new float[divisions * (divisions / 2 - 1) + 2][3]; for (int i = 0; i <= divisions / 2; i++) { // 緯度方向のループ(北極から南極に向かって) if (i == 0) { // 北極の場合 coordinates[0][0] = 0.0f; coordinates[0][1] = radius; coordinates[0][2] = 0.0f; bodyGeom.setNormal(0, new float[]{0.0f, 1.0f, 0.0f}); } else if (i == divisions / 2) { // 南極の場合 coordinates[divisions * (divisions / 2 - 1) + 1][0] = 0.0f; coordinates[divisions * (divisions / 2 - 1) + 1][1] = -radius; coordinates[divisions * (divisions / 2 - 1) + 1][2] = 0.0f; bodyGeom.setNormal(divisions * (divisions / 2 - 1) + 1, new float[]{0.0f, -1.0f, 0.0f}); } else { float y = r * (float) Math.cos(2 * Math.PI * ((double) i / divisions)); float r2 = r * (float) Math.sin(2 * Math.PI * ((double) i / divisions)); for (int j = 0; j < divisions; j++) { // 経度方向のループ float x = r2 * (float) Math.cos(2 * Math.PI * ((double) j / divisions)); float z = -r2 * (float) Math.sin(2 * Math.PI * ((double) j / divisions)); coordinates[(i - 1) * divisions + j + 1][0] = x; coordinates[(i - 1) * divisions + j + 1][1] = y; coordinates[(i - 1) * divisions + j + 1][2] = z; bodyGeom.setNormal((i - 1) * divisions + j + 1, new float[]{x / r, y / r, z / r}); } } } for (int i = 0; i < divisions * (divisions / 2 - 1) + 2; i++) { bodyGeom.setCoordinate(i , coordinates[i]); } int coordinateIndices[] = new int[divisions * ((divisions - 2) * 6 + 2 * 3)]; int index = 0; for (int i = 0; i < divisions / 2; i++) { for (int j = 0; j < divisions; j++) { if (i == 0) { // 北極付近 coordinateIndices[index] = 0; // 北極 coordinateIndices[index + 1] = j + 1; coordinateIndices[index + 2] = (j + 1) % divisions + 1; index += 3; } else if (i == divisions / 2 - 1) { // 南極付近 coordinateIndices[index] = (i - 1) * divisions + j + 1; coordinateIndices[index + 1] = divisions * (divisions / 2 - 1) + 1; // 南極 coordinateIndices[index + 2] = (i - 1) * divisions + (j + 1) % divisions + 1; index += 3; } else { coordinateIndices[index] = (i - 1) * divisions + j + 1; coordinateIndices[index + 1] = i * divisions + j + 1; coordinateIndices[index + 2] = i * divisions + (j + 1) % divisions + 1; coordinateIndices[index + 3] = (i - 1) * divisions + j + 1; coordinateIndices[index + 4] = i * divisions + (j + 1) % divisions + 1; coordinateIndices[index + 5] = (i - 1) * divisions + (j + 1) % divisions + 1; index += 6; } } } bodyGeom.setCoordinateIndices(0, coordinateIndices); float uv[] = { 0, 0, 1, 0, 1, 1, 0, 1, }; bodyGeom.setTextureCoordinates(0, uv); // // 表面属性の作成 if (ap == null) { ap = new Appearance(); } setAppearance(ap); bodyShape = new Shape3D(bodyGeom, ap); } public float getRadius() { return radius; } public void setRadius(float radius) { this.radius = radius; } @Override public Shape3D getShape(int partid) { switch (partid) { case BODY: return bodyShape; } return null; } @Override public Node cloneTree() { Appearance ap = getAppearance(); if (ap != null) { ap = (Appearance)ap.cloneNodeComponent(); } Sphere s = new Sphere(radius, ap); return s; } }