# Java3D-Ungeeignet für 3D Spiele wegen Heap Space=?



## Developer_X (9. Okt 2009)

Hi, ich habe ein Problem,
ich habe eine library gedownloaded, und kann sie ganz einfach verwenden.
Diese Library kann 3ds obj und viele mehr in die Java3D Welt einbauen.

Nun zu meinem Problem:
Ich will ein Model einmal laden, und dann dieses model 5 mal nebeneinander in die 3D-Welt einbauen, es geht um ein StarWars Trooper Model, sie sollen wie im Krieg nebeneinander stehen. 
Doch das Problem :
Der Heap Space meldet sich schon nach 2 nebeneinander gestellten Troopern.

Ich habe mir mal überlegt wie ich das am besten machen könnte:

```
public void loadData(TransformGroup branchgroup)
        {
            try
            {  
                ModelLoader modelloader = new ModelLoader();
                Scene scene1 = modelloader.load(importfile);
                
                BranchGroup[] branchgroup1 = new BranchGroup[10];
                BoundingBox[] boundingbox = new BoundingBox[10];
                Point3d[] point3d = new Point3d[10];
                
                Transform3D[] transform3d = new Transform3D[10];
                TransformGroup[] transformgroup = new TransformGroup[10];
                
                if(scene1 != null)
                {
                	int i = 0;
                	while(i<branchgroup1.length)
                	{
                    	branchgroup1[i] = scene1.getSceneGroup();
                    	
                    	boundingbox[i] = new BoundingBox(branchgroup1[i].getBounds());
                    	
                    	point3d[i] = new Point3d();
                    	boundingbox[i].getLower(point3d[i]);
                    	
                    	Point3d point3d1 = new Point3d();
                    	boundingbox[i].getUpper(point3d1);
                    	
                    	double d = 0.0D;
                    	if(((Tuple3d) (point3d1)).x - ((Tuple3d) (point3d[i])).x > d)
                    		d = ((Tuple3d) (point3d1)).x - ((Tuple3d) (point3d[i])).x;
                    	if(((Tuple3d) (point3d1)).y - ((Tuple3d) (point3d[i])).y > d)
                    		d = ((Tuple3d) (point3d1)).y - ((Tuple3d) (point3d[i])).y;
                    	if(((Tuple3d) (point3d1)).x - ((Tuple3d) (point3d[i])).x > d)
                    		d = ((Tuple3d) (point3d1)).z - ((Tuple3d) (point3d[i])).z;
                    	double d1 = 10D / d;
                    	if(d1 < 0.00050000000000000001D)
                    		d1 = 0.00050000000000000001D;
                    	
                    	transform3d[i] = new Transform3D();
                    	transform3d[i].rotX(-1.5707963267948966D);
                    	transform3d[i].setTranslation(new Vector3d(i*3.0D, -1D, -2D));
                    	transform3d[i].setScale(new Vector3d(d1, d1, d1));
                    	
                    	transformgroup[i] = new TransformGroup(transform3d[i]);
                    	transformgroup[i].addChild(branchgroup1[i]);
                    	branchgroup.addChild(transformgroup[i]);
                	
                    	System.out.println(i);
                    	i++;
                	}
                } 
                else
                {
                    System.out.println("File load error.  There was something wrong with the file: " + importfile);
                }
            }
            catch(IOException ioexception)
            {
                System.err.println("Could not find object file: " + importfile);
            }
        }
```
Doch wenn ich das so mache, dann wird mir folgendes gemeldet:

```
0
Exception in thread "main" javax.media.j3d.MultipleParentException: Group.addChild: child already has a parent
	at javax.media.j3d.GroupRetained.checkValidChild(GroupRetained.java:452)
	at javax.media.j3d.GroupRetained.addChild(GroupRetained.java:461)
	at javax.media.j3d.Group.addChild(Group.java:271)
	at Test.Test_Class.loadData(Test_Class.java:107)
	at Test.Test_Class.addTroup(Test_Class.java:58)
	at Test.Test_Class.createSceneGraph(Test_Class.java:41)
	at Test.Test_Class.<init>(Test_Class.java:129)
	at Test.Test_Class.main(Test_Class.java:145)
```


Was im Klartext heißt:
Dass Scene, schon mal geadded wurde, und deshalb nicht noch einmal verwendet werden kann, das heißt ich müsste in die Schleife dieses Laden einbauen, damit Scene jedes ma was neues ist, doch das würde den Heap Space überlasten, ganz klar.

Also was soll ich machen?
Kann mir jemand helfen?


----------



## newcron (9. Okt 2009)

Es ist schwer, aus dem bisschen Quellcode, den du da hast zu sehen, wo dein Problem genau ist. Allerdings hier ein paar Anhaltspunkte: 

Prinzipiell solltest du ein Model nur einmal Laden und nicht zweimal. Ich weiß nicht, wie Java 3D das macht, aber es gibt eigentlich immer einen Weg, ein Model an verschiedenen Positionen mit verschiedenen Transformationen darzustellen. 

Das größere Problem ist jedoch vermutlich, dass sich das Model, dass du verwendest nicht für spiele eignet. Ich kann mir gut vorstellen, dass es zu viele Polygone oder zu große Texturen hat. Das trifft auf die meisten Models, die du im Internet findest, zu. Es gibt zwar Programme, die Polygonanzahl reduzieren und Texturen verkleinern können, soweit ich weiß, sehen die Ergebnisse allerdings ziemlich bescheiden aus. 

Fazit: Wenn du ein 3D Spiel machen willst, brauchst du entweder Geld (Spielemodels kosten!), einen 3D Designer oder musst dich selbst mit 3D Studio Max, Maya oder ähnlichem vertraut machen.


----------



## Developer_X (9. Okt 2009)

Mein gesamter Quellcode:

```
package Test;

import java.awt.BorderLayout;
import java.awt.GraphicsConfiguration;
import java.io.IOException;

import com.sun.j3d.loaders.Scene;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.swing.JFrame;
import javax.vecmath.*;

import ncsa.j3d.loaders.ModelLoader;

import com.sun.j3d.utils.behaviors.vp.*;       
	
	@SuppressWarnings("serial")
	public class Test_Class extends JFrame 
	{       
		String importfile = "models/clonejmep2.3ds";
		
    private SimpleUniverse universe ;
    private Canvas3D canvas;
    private BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 10.0);
    
      public void setupView() 
      { 
    	OrbitBehavior orbit = new OrbitBehavior(canvas,
                OrbitBehavior.REVERSE_ALL|OrbitBehavior.STOP_ZOOM);
        orbit.setSchedulingBounds(bounds);
        ViewingPlatform viewingPlatform = universe.getViewingPlatform();
        
        viewingPlatform.setNominalViewingTransform();
        viewingPlatform.setViewPlatformBehavior(orbit);       
        }       
          
        public BranchGroup createSceneGraph() {
        BranchGroup objRoot = new BranchGroup();       
        
  //hier!!!
        addTroup(objRoot);
  //hier!!!      
        Color3f lightColor = new Color3f(.6f,.6f,.6f);
        AmbientLight ambientLight= new AmbientLight(lightColor);
        ambientLight.setInfluencingBounds(bounds);
        objRoot.addChild(ambientLight);
        DirectionalLight directionalLight = new DirectionalLight();
        directionalLight.setColor(lightColor);
        directionalLight.setInfluencingBounds(bounds);
        objRoot.addChild(directionalLight);     
                
        
        return objRoot;       
    }       
        public void addTroup(BranchGroup g)
        {
        	TransformGroup Transform = new TransformGroup();
        	loadData(Transform);
        	g.addChild(Transform);
        }
        public void loadData(TransformGroup branchgroup)
        {
            try
            {  
                ModelLoader modelloader = new ModelLoader();
                Scene scene1 = modelloader.load(importfile);
                
                BranchGroup[] branchgroup1 = new BranchGroup[10];
                BoundingBox[] boundingbox = new BoundingBox[10];
                Point3d[] point3d = new Point3d[10];
                
                Transform3D[] transform3d = new Transform3D[10];
                TransformGroup[] transformgroup = new TransformGroup[10];
                
                if(scene1 != null)
                {
                	int i = 0;
                	while(i<branchgroup1.length)
                	{
                    	branchgroup1[i] = scene1.getSceneGroup();
                    	
                    	boundingbox[i] = new BoundingBox(branchgroup1[i].getBounds());
                    	
                    	point3d[i] = new Point3d();
                    	boundingbox[i].getLower(point3d[i]);
                    	
                    	Point3d point3d1 = new Point3d();
                    	boundingbox[i].getUpper(point3d1);
                    	
                    	double d = 0.0D;
                    	if(((Tuple3d) (point3d1)).x - ((Tuple3d) (point3d[i])).x > d)
                    		d = ((Tuple3d) (point3d1)).x - ((Tuple3d) (point3d[i])).x;
                    	if(((Tuple3d) (point3d1)).y - ((Tuple3d) (point3d[i])).y > d)
                    		d = ((Tuple3d) (point3d1)).y - ((Tuple3d) (point3d[i])).y;
                    	if(((Tuple3d) (point3d1)).x - ((Tuple3d) (point3d[i])).x > d)
                    		d = ((Tuple3d) (point3d1)).z - ((Tuple3d) (point3d[i])).z;
                    	double d1 = 10D / d;
                    	if(d1 < 0.00050000000000000001D)
                    		d1 = 0.00050000000000000001D;
                    	
                    	transform3d[i] = new Transform3D();
                    	transform3d[i].rotX(-1.5707963267948966D);
                    	transform3d[i].setTranslation(new Vector3d(i*3.0D, -1D, -2D));
                    	transform3d[i].setScale(new Vector3d(d1, d1, d1));
                    	
                    	transformgroup[i] = new TransformGroup(transform3d[i]);
                    	transformgroup[i].addChild(branchgroup1[i]);
                    	branchgroup.addChild(transformgroup[i]);
                	
                    	System.out.println(i);
                    	i++;
                	}
                } 
                else
                {
                    System.out.println("File load error.  There was something wrong with the file: " + importfile);
                }
            }
            catch(IOException ioexception)
            {
                System.err.println("Could not find object file: " + importfile);
            }
        }
    public Test_Class()
    {
    	setVisible(true);
    	
          
         BranchGroup scene = createSceneGraph();       
         setLayout(new BorderLayout());
         
         GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
         canvas = new Canvas3D(config);
         add("Center", canvas);       
        
         universe = new SimpleUniverse(canvas);       
         setupView();       
         universe.addBranchGraph(scene);
         
         setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }       
   
    public static void main(String[] args) 
    {
    	new Test_Class();
   }
}
```

Könnt ihr mir jetzt helfen?


----------



## Developer_X (9. Okt 2009)

also einer sieht so aus


----------



## Marco13 (9. Okt 2009)

Je nachdem, wie groß das Modell ist, musst du halt
java -Xmx1000m DasProgramm
machen...


----------



## Developer_X (10. Okt 2009)

Marco13, kannst du mir vielleicht sagen wie ich ein object mehrmals in der 3D-Welt platzieren kann?


----------



## Soulfly (10. Okt 2009)

Die Methode dafür nennt sich Level of Detail. Ein, in einem 3D-Modeller erstelltes, 3D-Objekt hat viel zu viele Vertices (Eckpunkte) um sie einfach in einer 3D-Engine darzustellen. Die Anzahl muss durch geeignete Berechnungen verkleinert werden. Einige 3D-Modeller helfen dabei.

Dabei werden überflüssige Facetten eines 3D-Mesh weg berechnet und die Speichernutzung kann dadurch sehr gut verringert werden. Dies wird bei Spielen überall genutzt.


----------



## -MacNuke- (10. Okt 2009)

Ist das so schwer seine Frage zu verstehen? Eure Antworten haben nichts mit seiner Frage zu tun...

@ Developer_X



> Attempting to add a scenegraph node to a scenegraph that already has an assigned parent (i.e., a node that has already been added to the scenegraph) will result in a run-time exception. *I discuss reusing scenegraph branches using a SharedGroup and a Link later in this chapter.*



Java 3D Programming.Chapter 5

Kannst du hier vllt. was finden?


----------



## newcron (10. Okt 2009)

MacNuke, wir haben ihn auf das Problem hingewiesen, als ihm eine Frage zu beantworten, deren antwort ihm nicht weiterhelfen wird. 
Hat das Modell zu viele Polygone, wird er wohl eher eine FPM statt ne FPS rate haben, die Modell-Geometrie in nem Scenegraph zu teilen hilft da nichts. Ich kann mir nämlich gut vorstellen, dass es in seinem Spiel außer Stormtroopers noch andere Models geben soll. (AT-ATs, AT-STs, Jediritter,...) die gleichzeitig dargestellt werden. Und dann? Du siehst, deine Antwort ist es, die nichts mit seinem Problem zu tun hat 



DeveloperX: Ganz eindeutig hat das Modell viel zu viele Polygone. Dass siehst du beispielsweise an den Beinen, dass in den Rundungen keine Ecken zu sehen sind. Versuch mal, die Polygonmenge für dieses Modell um 70% zu reduzieren. Das wird es vermutlich recht klobig machen, aber dann solltest du keine Probleme mit der Einbindung in dein Spiel haben.


----------



## Developer_X (10. Okt 2009)

kann ich euch dazu was fragen?
Gut, ihr habt gesagt ich soll das ganze etwas reduzieren, kapiert.
Aber muss ich die Modelle immer wieder neu laden, wenn ich sie platzieren will?
Kann mir einer dazu was sagen?

Noch was-
Ich habe kein 3D Programm, mit dem ich die Figuren ändern oder erstellen kann.
Ich hab sie von wo gedownloaded, ich meine ich als Normi, wenn ich ein Spiel für mich Privat erstellen will, habe keine Lust, jahrelang die modelle für mein Spiel zu machen, da ich ja alleine an dem projekt arbeite.

Könntet ihr das reduzieren?
http://www.raymansssa.kilu.de/star/C_TROOPR.zip
hier findet ihr die datei


----------



## Developer_X (10. Okt 2009)

Naja, das kriege ich noch alle male hin


----------



## Developer_X (10. Okt 2009)

-MacNuke- hat gesagt.:


> Ist das so schwer seine Frage zu verstehen? Eure Antworten haben nichts mit seiner Frage zu tun...
> 
> @ Developer_X
> 
> ...



Danke erstma für den Link, in diesem "Chapter" war die Rede von einer Klasse namens, 
SwitchTest.java
diese habe ich beim googlen aufgestöbert.
Aber solche TUtorial Klassen sind immer Mist. Der größte Dreck den ich je gesehen habe.
Ein Tutorial sollte nicht groß aufgebaut sein, sondern ganz einfach sein, und sich nur auf eine sache beziehen, so viel dazu.

Kann mir jemand ein Beispiel geben, wo zum Beispiel ein Sphere,
von 2 verschiedenen TransformGroups geadded wird?
Oder so?

Und warum gibts diese blöde Sperre bei Java3D auch`?
Child has already a parent.
Ich finde das quatsch, das ist doch voll umständlich oder net?


----------



## Marco13 (10. Okt 2009)

@-MacNuke-: Ist es so schwer unsere Antworten zu verstehen?  Ja, zugegeben, meine war ziemlich lapidar, aber ... du kennst ja DeveloperX ... so ein Thread kann sich ziiieeehhhenn..... So eine SharedGroup, die wohl auf das rausläuft, was sich eine Ebene drunter dann "instancing" nennt, wäre vielleicht eine Möglichkeit, aber nur, wenn es wirklich so sein soll - der Thread mit dem Titel "Mehrere Modelle bewegen sich gleich, obwohl nur eins davon verändert wird" liegt dann ja schon latent in der Luft 



Developer_X hat gesagt.:


> Und warum gibts diese blöde Sperre bei Java3D auch`?
> Child has already a parent.
> Ich finde das quatsch, das ist doch voll umständlich oder net?



Wenn man so etwas sieht, was einem unnötig umständlich erscheint, hat das meistens einen von 2 Gründen, nämlich entweder 1.: derjenige, der das gemacht hat, hatte keine Ahnung, was er da macht, und eine unnötig umständliche Lösung zusammengefrickelt, oder 2.: Es gibt Gründe für diese "Umständlichkeit"/Komplexität, die über den eigenen Horizont hinausgehen. Wenn eine Kugel mehrfach in einer Szene auftaucht, könnTen z.B. Uneindeutigkeiten beim Picking o.ä. auftreten... Aber wenn du "instancing" haben willst, kannst du dir wirklich mal SharedGroup (Java 3D API) ansehen...


----------



## Developer_X (11. Okt 2009)

kannst du mir dazu ein beispiel geben bitte?


----------



## MrWhite (11. Okt 2009)

Wieso nimmst du nicht einfach die JMonkey-Engine. Die ist um einiges einfacher zu benutzen als Java3D und auch sehr maechtig.


----------



## newcron (14. Okt 2009)

DevX, das mit den Models ist ein problem. Ich kann dir auch nicht sagen, wie man die polygonzahlen reduziert. ich weiß nur, dass dein Model viel zu viele Polygone hat. Leider ist es so, dass du - um eigene spiele zu entwickeln - jemanden brauchst, der sich damit auskennt. Dein Spiel soll letzten Endes ja noch mehr als nur einen Stormtrooper enthalten - und alle Objekte im Spiel müssen irgendwie erzeugt werden. Der Einstieg in 3d-Modelling ist jedenfalls nicht sehr leicht. Gerade Menschen zu erzeugen ist schwierig. 

Wenn du spiele machen willst, fang doch lieber bei 2D Spielen wie Jump n' Runs, 2D Shootern (als schönes Beispiel sei hier Crimsonland genannt) oder 2D RPGs an. 
2D Grafiken sind nicht nur viel einfacher zu erzeugen, sie lassen sich im Internet auch viel einfacher finden: Die Grafiken aller Animationen von Spieleklassikern wie Super Mario Land findest du im Internet wenn du nach "Sprites" suchst. 

Solche Spiele Ansich sind schon Projekte, die aufwändig genug sind - 3D Spiele liegen dann ganz einfach in einer komplett anderen Liga.


----------



## Spacerat (14. Okt 2009)

Der HeapSpace kann kein Grund dafür sein, dass Java3D für Spiele ungeeignet ist. Es sind doch ausschliesslich die eigenen Programmmierkenntnisse, die den Umgang mit einer Engine oder API bestimmen. Und wenn man genug Kennnisse von seiner Umgebung hat, können sogar Spiele wie Chrome dabei rauskommen. Wärest du (DevX) schon 16, könntest du dir ja mal dieses Game besorgen um einen Blick in den Quellcode werfen zu können. Du würdest die mit Sicherheit schon angesichts der Klassen-Anzahl die Haare raufen. Andererseits hättest du genug zum Kopieren und Einfügen.


----------



## Evil-Devil (14. Okt 2009)

Chrome nutzt Java aber nur für die ScriptEngine. Die reine GameEngine ist plain C/C++ mit DirectX.

Da sind Beispiele wie Tribal Trouble schon anschaulicher


----------



## Spacerat (14. Okt 2009)

@EvilDevil: Ich weiß. Hab' das Game selber und damit auch den Java-Code. Ich hab' mir deswegen auch schon die Haare gerauft, als ich versuchte, die 3D-Engine in eine Java-Basierende zu ersetzen . Hab's dann irgendwann aufgegeben. Iwie machen die es anders als erwartet. Nicht aus Java per JNI die Engine programmieren, sondern aus der Engine heraus werden die Java-Klassen aufgerufen. Im Endeffekt ist der Java-Code zwar sehr aufschlussreich aber ohne die 3D-Engine nicht (weiter) zu gebrauchen.


----------



## Evil-Devil (14. Okt 2009)

Wie ist es denn so? Das Game gibt es ja für 2,99? im Grabbeltisch und bisher wusste ich nie ob die 3€ gut oder schlecht angelegt seien.


----------



## Spacerat (14. Okt 2009)

Naja... Action hält sich in Grenzen und das ganze ist auch nicht unbedingt mein Genre. Frag mich aber, warum das ab 16 ist. Für mich war eigentlich auch nur der Quellcode interessant.


----------



## Gastredner (14. Okt 2009)

Chrome wird _mit_ Quellcode ausgeliefert?


----------



## Spacerat (14. Okt 2009)

Ich hab das aus einer Gamestar-Zeitschrift. Auf der DVD war der Quelltext jedenfalls mit drauf.


----------



## EgonOlsen (14. Okt 2009)

Wobei der grauenhaft ist...man sieht deutlich, dass hier reine C++-Jünger sich an Java gewagt haben. Zum Lernen taugt er nichts IMHO.


----------

