Java3D: Ikosaeder mit unterschiedlich gefärbten Flächen

Stefan1971HH

Mitglied
Hi,

ich möchte einen Ikosaeder kontruieren, bei dem jede der 20 Flächen eine andere Farbe hat.
Problem: Egal, ob ich einen TriangleArray oder einen IndexedTriangleArray nutze -
ich kann (falls ich es richtg verstanden habe...) im Daten-Array nur soviele verschiedene Farben speichern, wie es Vertices gibt (nämlich 12).
Vermutlich deswegen wird folgendes mit einer IndexOutOfBounds-Exception und Verweis auf Zeile 84 quittiert:
Java:
public class IcosahedronGeo extends TriangleArray {

  Color3f red = new Color3f(1.0f, 0.0f, 0.0f);
   Color3f green = new Color3f(0.0f, 1.0f, 0.0f);
   Color3f blue = new Color3f(0.0f, 0.0f, 1.0f);
  Color3f yellow = new Color3f(1.0f, 1.0f, 0.0f);
  Color3f cyan = new Color3f(0.0f, 1.0f, 1.0f);
  Color3f magenta = new Color3f(1.0f, 0.0f, 1.0f);
 Color3f white = new Color3f(1.0f, 1.0f, 1.0f);
 Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
 Color3f grey = new Color3f(0.2f, 0.2f, 0.2f);
  Color3f darkRed = new Color3f(0.2f, 0.0f, 0.0f);
   Color3f brown = new Color3f(0.35f, 0.29f, 0.0f);
   Color3f darkBrown = new Color3f(0.15f, 0.1f, 0.0f);
     Color3f darkGrey = new Color3f(0.2f, 0.2f, 0.2f);
    Color3f darkYellow = new Color3f(0.3f, 0.3f, 0.0f);
   Color3f darkGreen = new Color3f(0.0f, 0.3f, 0.0f);
   Color3f darkBlue = new Color3f(0.0f, 0.0f, 0.3f);
    Color3f color1 = new Color3f(0.8f, 0.6f, 0.4f);
    Color3f color2 = new Color3f(0.6f, 0.2f, 0.2f);
    Color3f color3 = new Color3f(0.2f, 0.6f, 0.6f); 
    Color3f color4 = new Color3f(0.9f, 0.5f, 0.3f);
    
    Point3d p0 = new Point3d(0, 0, 1);
    Point3d p1 = new Point3d(0.894, 0, 0.447);
    Point3d p2 = new Point3d(0.276, 0.851, 0.447);
    Point3d p3 = new Point3d(-0.724, 0.526, 0.447);
    Point3d p4 = new Point3d(-0.724, -0.526, 0.447);
    Point3d p5 = new Point3d(0.276, -0.851, 0.447);
    Point3d p6 = new Point3d(0.724, 0.526, -0.447);
    Point3d p7 = new Point3d(-0.276, 0.851, -0.447);
    Point3d p8 = new Point3d(-0.894, 0.000, -0.447);
    Point3d p9 = new Point3d(-0.276, -0.851, -0.447);
    Point3d p10 = new Point3d(0.724, -0.526, -0.447);
    Point3d p11 = new Point3d(0.000, 0.000, -1.000);
    Point3d[] vertices = 
                    {p0,p1,p2,
                     p0,p2,p3,
                     p0,p3,p4,
                     p0,p4,p5,
                     p0,p5,p1,
                     p11,p6,p7,
                     p11,p7,p8,
                     p11,p8,p9,
                     p11,p9,p10,
                     p11,p10,p6,
                     p1,p2,p6,
                     p2,p3,p7,
                     p3,p4,p8,
                     p4,p5,p9,
                     p5,p1,p10,
                     p6,p7,p2,
                     p7,p8,p3,
                     p8,p9,p4,
                     p9,p10,p5,
                     p10,p6,p1};
    
    
    
   Color3f[] colors =
    {red,red,red,
green,green, green,
blue, blue,blue, 
yellow,yellow,yellow,
cyan, cyan, cyan,
darkBrown,darkBrown,darkBrown,
magenta,magenta,magenta,
white,white,white,
black, black,black,
grey,grey,grey,
darkRed,darkRed,darkRed ,
brown, brown,brown, 
darkGrey,darkGrey, darkGrey,
darkYellow,darkYellow,darkYellow,
darkGreen,darkGreen,darkGreen,
darkBlue,darkBlue,darkBlue,
color1,color1,color1,
color2,color2,color2,
color3,color3,
color4,color4,color4};
    
 public IcosahedronGeo(){
        super (12,TriangleArray.COORDINATES | TriangleArray.NORMALS |TriangleArray.COLOR_3);
setCoordinates(0, vertices);

setColors(0, colors);

    }
}
Gibts hier eine schöne Lösung?.danke
 
Zuletzt bearbeitet:
Danke Marco13, aber ich hatte es auch schon mit einem IndexedTriangleArray probiert.
Da hatte ich aber auch das Problem, dass die indizierten Arrays alle gleich lang
sein müssen (d.h. die Daten-Arrays, die dann von den IndexedArrays referenziert
werde). Ich kann also nur 12 verschieden Farben referenzieren, so dass für 20 Flächen
8 Farben doppelt verwendet (referenziert)werden müssten. Bei den anderen platonischen Körpern
ergibt sich dieses Problem nicht, weil der Ikosaeder als einziger mehr Flächen als Ecken hat.
Diese Version sieht so aus:
Java:
package platonicSolids;

import javax.media.j3d.IndexedTriangleArray;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;

/**
 *
 * @author Stefan
 */
public class IcosahedronGeo extends IndexedTriangleArray {

    Color3f white = new Color3f(1.0f, 1.0f, 1.0f);
    Color3f gray = new Color3f(0.7f, 0.7f, 0.7f);
    Color3f darkGray = new Color3f(0.2f, 0.2f, 0.2f);
    Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
    Color3f red = new Color3f(1.0f, 0.0f, 0.0f);
    Color3f darkRed = new Color3f(0.3f, 0.0f, 0.0f);
    Color3f yellow = new Color3f(1.0f, 1.0f, 0.0f);
    Color3f darkYellow = new Color3f(0.3f, 0.3f, 0.0f);
    Color3f green = new Color3f(0.0f, 1.0f, 0.0f);
    Color3f darkGreen = new Color3f(0.0f, 0.3f, 0.0f);
    Color3f cyan = new Color3f(0.0f, 1.0f, 1.0f);
    Color3f blue = new Color3f(0.0f, 0.0f, 1.0f);
    Color3f darkBlue = new Color3f(0.0f, 0.0f, 0.3f);
    Color3f magenta = new Color3f(1.0f, 0.0f, 1.0f);
    Color3f magenta2 = new Color3f(0.8f, 0.0f, 0.8f);
    Color3f cyan2 = new Color3f(0.0f, 0.3f, 0.3f);
    Color3f color1 = new Color3f(0.8f, 0.6f, 0.4f);
    Color3f color2 = new Color3f(0.6f, 0.2f, 0.2f);
    Color3f color3 = new Color3f(0.2f, 0.6f, 0.6f); 
    Color3f color4 = new Color3f(0.9f, 0.5f, 0.3f);
    
    Point3d p0 = new Point3d(0, 0, 1);
    Point3d p1 = new Point3d(0.894, 0, 0.447);
    Point3d p2 = new Point3d(0.276, 0.851, 0.447);
    Point3d p3 = new Point3d(-0.724, 0.526, 0.447);
    Point3d p4 = new Point3d(-0.724, -0.526, 0.447);
    Point3d p5 = new Point3d(0.276, -0.851, 0.447);
    Point3d p6 = new Point3d(0.724, 0.526, -0.447);
    Point3d p7 = new Point3d(-0.276, 0.851, -0.447);
    Point3d p8 = new Point3d(-0.894, 0.000, -0.447);
    Point3d p9 = new Point3d(-0.276, -0.851, -0.447);
    Point3d p10 = new Point3d(0.724, -0.526, -0.447);
    Point3d p11 = new Point3d(0.000, 0.000, -1.000);
    Point3d[] vertices = {p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11};
    int[]vertInd = {0,1,2,
                    0,2,3,
                    0,3,4,
                    0,4,5,
                    0,5,1,
                    11,6,7,
                    11,7,8,
                    11,8,9,
                    11,9,10,
                    11,10,6,
                    1,2,6,
                    2,3,7,
                    3,4,8,
                    4,5,9,
                    5,1,10,
                    6,7,2,
                    7,8,3,
                    8,9,4,
                    9,10,5,
                    10,6,1};
    Color3f[] colors =
    {white,gray,darkGray,black,red,darkRed,yellow,darkYellow,green,darkGreen,cyan,blue}; 
    
    int[] colorInd = {0,0,0,
                      1,1,1,
                      2,2,2,
                      3,3,3,
                      4,4,4,
                      5,5,5,
                      6,6,6,
                      7,7,7,
                      8,8,8,
                      9,9,9,
                     10,10,10,
                     11,11,11,
                     0,0,0,
                      1,1,1,
                      2,2,2,
                      3,3,3,
                      4,4,4,
                      5,5,5,
                      6,6,6,
                      8,8,8};
    
    
    
    public IcosahedronGeo(){
        super (12, IndexedTriangleArray.COORDINATES | IndexedTriangleArray.NORMALS |IndexedTriangleArray.COLOR_3,60);
setCoordinates(0, vertices);
setCoordinateIndices(0, vertInd);
setColors(0, colors);
setColorIndices(0, colorInd);
    }
}
Es sind zwar 20 Farben definiert, aber wie kann ich mehr als 12 davon verfügbar machen?
Nofalls könnte man den Vertex-Array um 8 Dummy-Vertices erweitern - aber das muss doch
wohl eleganter gehen? Sorry, falls ich deinen Hinweis nicht vollständig erfasst haben sollte.
 
Ahja, sorry, ist schon eine Weile her, und solche Details weiß man nicht unbedingt auswendig 😳 (BTW: Ein Oktaeder hat auch mehr Flächen als Ecken).

Da die GeometryArrays ihre Daten Vertexbasiert speichern, wird man kaum drumherumkommen, die vertices zu duplizieren (wüßte ich jetzt auch kaum eine andere Möglichkeit). Man würde also das ganze "Flächenweise" zu definieren, ähnlich wie es auch beim "ColorCube" gemacht ist ( z.B. java3d 0.0.cvs.20090202.dfsg, ColorCube_8java-source.html ).

Ganz pragmatisch könnte man das natürlich mit sowas machen wie
Java:
    public IcosahedronGeo(){
        super (60, IndexedTriangleArray.COORDINATES | IndexedTriangleArray.COLOR_3, 60);
        
		int numFaces = vertInd.length / 3;
		
		Point3d resultVertices[] = new Point3d[numFaces * 3];
		int resultVertexIndices[] = new int[numFaces * 3];
		
		Color3f resultColors[] = new Color3f[numFaces * 3];
		int resultColorIndices[] = new int[numFaces * 3];
		
		for (int i=0; i<numFaces; i++)
		{
			for (int j=0; j<3; j++)
			{
				int index = i * 3 + j;
				
				int vertexIndex = vertInd[index];
				Point3d v = vertices[vertexIndex];
				resultVertices[index] = v;
				resultVertexIndices[index] = index;
				
				int colorIndex = colorInd[index];
				Color3f c = colors[colorIndex];
				resultColors[index] = c;
				resultColorIndices[index] = index;
			}
		}
		setCoordinates(0, resultVertices);
		setCoordinateIndices(0, resultVertexIndices);
		setColors(0, resultColors);
		setColorIndices(0, resultColorIndices);
        
    }
aber eigentlich braucht man dann gar keinen speziell Indizierten array mehr, d.h. es würde ein GeometryArray schon tun. (Wenn man das für mehrere Fälle braucht, könnte man aber nach so einem Schema eine Methode basteln, der man die Daten in der "gewünschten Form" (d.h. in Form der vorhanderen Arrays) übergibt, und die einem dann durch so ein bißchen Umkopieren+Duplizieren einen passenden GeometryArray ausspuckt... (ich erwähne das nur, um zu verhindern, dass jemand versucht, die Flächen einzeln in den Code zu schreiben, wie es beim ColorCube gemacht ist 😉 ))
 

Zurück
Oben