PDA

View Full Version : [JAVA3D] problema rotazione ambiente


Marbury
14-02-2008, 14:36
salve, ho un problema che non riesco a risolvere, in pratica disegno un cubo che non è altro che tanti Box inseriti vicini e vorrei far ruotare il sistema però non ci riesco, posto il codice e spiego perchè:


public class Cubo extends TransformGroup{
private Box box;
private static TextureLoader loader=new TextureLoader("red.jpg",null);
private static TextureLoader loader2=new TextureLoader("green.jpg",null);

public Cubo(float x, float y, float z){
super();
//System.out.println("CREA CUBO");
Transform3D transform = new Transform3D();
Vector3f vector = new Vector3f(x,y,z);
transform.setTranslation(vector);
setTransform(transform);

Appearance a = new Appearance();

a.setTexture(loader.getTexture());
TextureAttributes texAttr = new TextureAttributes();
texAttr.setTextureMode(TextureAttributes.MODULATE);
a.setTextureAttributes(texAttr);

/* Material mat = new Material();
mat.setDiffuseColor(new Color3f(1.0f, 0.0f, 0.0f));
//mat.setSpecularColor(new Color3f(1.0f, 0.0f, 0.0f));
mat.setShininess(1.0f);
a.setMaterial(mat);*/

box = new Box(0.1f, 0.1f, 0.1f, Box.GENERATE_TEXTURE_COORDS, a);
box.setAppearance(a);

addChild(box);

}



Qui disegno tutti i cubi e se inserisco il codice per la rotazione qui mi da il problema che invece di far ruotare il sistema "centralmente" ruota attorno all'ultimo cubo inserito


class GruppoCubo extends TransformGroup{
//Memorizza puntatori alle matrici che contengono i cubi
private Vector<Cubo[][]> facce = null;
private int numCubiRiga = 0;

public GruppoCubo(int n, float x, float y, float z){
numCubiRiga = n;
Cubo[][] faccia = null;

float indiceZ = 0.0f; float indiceY = 0.0f; float indiceX = 0.0f;
int i = 0; int j = 0; //mi servono per calcolare gli indici dove salvare i cubi

while(indiceZ > (-n*0.23f)){
//System.out.println("indiceZ, n = " + (-n*0.1f) + " "+indiceZ);
i = 0; j = 0;
faccia = new Cubo[n][n];

while(indiceY > (-n*0.23f)){
//System.out.println("indiceY, n = "+ (-n*0.1f)+ " " + indiceY);
while(indiceX < (n*0.23f)){
//System.out.println("indiceX, n= " + (-n*0.1f)+" " + indiceX);
faccia[i][j] = new Cubo(indiceX, indiceY, indiceZ);
if(indiceX == 0.0f) (faccia[i][j]).coloraCubo(1);
addChild(faccia[i][j]);
indiceX = indiceX + 0.23f;
i += 1;
}
indiceX=0;
i=0; j = j+1;
indiceY = indiceY - 0.23f;
}
indiceY=0;
indiceZ = indiceZ -0.23f;
}

System.out.println("OUT");


Vector3f vector = null;
Transform3D transform = new Transform3D();
transform.setScale(1);
vector = new Vector3f(x,y,z);
transform.setTranslation(vector);
setTransform(transform);
setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
setCapability(TransformGroup.ALLOW_TRANSFORM_READ);

//Crea il behavior per ruotare il cubo
/* RotazioneCubo rc = new RotazioneCubo(/*cuboGrafico*///);
/* RotazioneMouse myMouseRotate2= new RotazioneMouse(this,rc);
myMouseRotate2.setSchedulingBounds(new BoundingSphere());
addChild(myMouseRotate2);*/
}



Questa classe estende simpleUniverse e se lo scrivo qua non ruota proprio nulla!!! Credevo fosse quest'ultima soluzione quella giusta e invece... qualcuno ha qualche idea da darmi? Grazie mille


public class DrawCubo extends SimpleUniverse{
private GruppoCubo cubo;
private BranchGroup root = null;

//Riceve come parametro il num elementi di una riga
public DrawCubo(int n, Canvas3D canvas){
super(canvas);

switch (n){
case 5: cubo = new GruppoCubo(n, 0f, 0.2f, -2f);
break;
case 10: cubo = new GruppoCubo(n, 0f, 0.1f, -10f);
break;
case 15: cubo = new GruppoCubo(n, 0f, -0.1f, -19f);
break;
case 7: cubo = new GruppoCubo(n, 0f, 0.2f, -5f);
break;
case 14: cubo = new GruppoCubo(n, 0f, 0.0f, -17f);
break;
case 21: cubo = new GruppoCubo(n, 0f, -0.2f, -29f);
break;
case 9: cubo = new GruppoCubo(n, 0f, 0.2f, -9f);
break;
case 18: cubo = new GruppoCubo(n, 0f, -0.15f, -24f);
break;
case 27: cubo = new GruppoCubo(n, 0f, -0.3f, -39f);
break;
}

root = new BranchGroup();

root.addChild(cubo);
getViewingPlatform().setNominalViewingTransform();
/*
TextureLoader loader=new TextureLoader("sfondo.jpg",null);
ImageComponent2D image=loader.getImage();
Background bg = new Background(image);
BoundingSphere infinity = new BoundingSphere(new Point3d(), Double.POSITIVE_INFINITY);
bg.setApplicationBounds(infinity);

root.addChild(bg);*/

//Crea un gruppo per le trasformazioni affini
TransformGroup objRotate=new TransformGroup();
objRotate.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
objRotate.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
//Crea il behavior per ruotare il cubo
RotazioneCubo rc = new RotazioneCubo(/*cuboGrafico*/);
RotazioneMouse myMouseRotate2= new RotazioneMouse(objRotate,rc);
myMouseRotate2.setSchedulingBounds(new BoundingSphere());
root.addChild(myMouseRotate2);
root.addChild(objRotate);

root.compile();

addBranchGraph(root);

PGI-Bis
14-02-2008, 19:32
Crea un TransformGroup "ruotabile" (setCapability eccetera), chiamiamolo A. Aggiungi al TransformGroup un BranchGroup, aggiungi tutti i cubi a questo BranchGroup.

A questo punto se fai ruotare "A" ruota anche tutto quello che è agganciato ad A.

Il problema della rotazione intorno al centro lo risolvi o con una rototraslazione di A o con una rotazione semplice di A ed una distribuzione dei cubi attorno al centro di A.

Per distribuire rapidamente i cubi puoi aggiungere ad A un secondo TransformGroup B, aggiungere i cubi a B e traslare B di un vettore V = (-x/2, -y/2, -z/2), con x, y e z lunghezze dei lati del "super-cubo" formato dai tanti cubetti. A conti fatti Java3D transformerà la faccenda in una rotazione di A intorno al punto P centro del gruppo di cubi.

Marbury
14-02-2008, 20:47
grazie mille adesso provo ;)

Marbury
14-02-2008, 21:43
ho fatto cosi però non cambia nulla:

class GruppoCubo extends TransformGroup{
//Memorizza puntatori alle matrici che contengono i cubi
private Vector<Cubo[][]> facce = new Vector<Cubo[][]>();
private int numCubiRiga = 0;

public GruppoCubo(int n, float x, float y, float z){
numCubiRiga = n;
Cubo[][] faccia = null;

//Creo un BranchGroup dove attaccare i cubi
BranchGroup branch = new BranchGroup();
//Creo un nuovo TransformGroup B per la rotazione al centro
TransformGroup B = new TransformGroup();

float indiceZ = 0.0f; float indiceY = 0.0f; float indiceX = 0.0f;
int i = 0; int j = 0; //mi servono per calcolare gli indici dove salvare i cubi

while(indiceZ > (-n*0.23f)){
//System.out.println("indiceZ, n = " + (-n*0.1f) + " "+indiceZ);
i = 0; j = 0;
faccia = new Cubo[n][n];

while(indiceY > (-n*0.23f)){
//System.out.println("indiceY, n = "+ (-n*0.1f)+ " " + indiceY);
while(indiceX < (n*0.23f)){
//System.out.println("indiceX, n= " + (-n*0.1f)+" " + indiceX);
faccia[i][j] = new Cubo(indiceX, indiceY, indiceZ);
branch.addChild(faccia[i][j]);
indiceX = indiceX + 0.23f;
i += 1;
};
indiceX=0;
i=0; j = j+1;
indiceY = indiceY - 0.23f;
}
facce.add(faccia);
indiceY=0;
indiceZ = indiceZ -0.23f;
}

System.out.println("OUT");

B.addChild(branch);

Vector3f vector = null;
Transform3D transform = new Transform3D();

vector = new Vector3f((n*0.1f)/2,-(n*0.1f)/2,-(n*0.1f)/2);
transform.setTranslation(vector);
B.setTransform(transform);

transform = new Transform3D();
transform.setScale(1);
vector = new Vector3f(x,y,z);
transform.setTranslation(vector);
setTransform(transform);
setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
setCapability(TransformGroup.ALLOW_TRANSFORM_READ);

//Crea il behavior per ruotare il cubo
RotazioneCubo rc = new RotazioneCubo(/*cuboGrafico*/);
RotazioneMouse myMouseRotate2= new RotazioneMouse(this,rc);
myMouseRotate2.setSchedulingBounds(new BoundingSphere());
addChild(myMouseRotate2);
addChild(B);

Marbury
15-02-2008, 15:29
non riesco a risolvere, non è che potresti darmi una mano? Grazie

PGI-Bis
15-02-2008, 21:08
La versione più semplice è quella in cui i cubi del gruppo di cubi sono creati e distribuiti intorno al punto 0,0,0. Detta "CubeGroup" la classe che dichiara questo cubo di cubi e "getGroup()" il metodo di CubeGroup che restituisce un javax.media.j3d.node a cui sono connessi i vari cubi, il programma è semplicemente:

package cubi;

import java.awt.*;
import java.awt.event.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.behaviors.mouse.*;

public class Main implements Runnable {
public static void main(String[] args) {
EventQueue.invokeLater(new Main());
}

public void run() {
final int CUBE_COUNT = 4;
final float CUBE_EDGE = 1;

/* Questo è il gruppo di trasformazione "ruotabile" con il mouse a cui
è aggiunto il gruppo di cubi */
TransformGroup cubeGroupRotator = new TransformGroup();
cubeGroupRotator.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
cubeGroupRotator.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

/* Genero il cubo di cubi (distribuiti intorno al punto 0,0,0) e lo
aggiungo al gruppo di trasformazione "ruotabile" */
CubeGroup cubeGroup = new CubeGroup(CUBE_COUNT, CUBE_EDGE);
cubeGroupRotator.addChild(cubeGroup.getGroup());

BoundingSphere infinity = new BoundingSphere(new Point3d(), Double.POSITIVE_INFINITY);
MouseRotate rotator = new MouseRotate(cubeGroupRotator);
rotator.setSchedulingBounds(infinity);

/* Creo una radice per i miei elementi 3d... */
BranchGroup root = new BranchGroup();

/* Aggiungo alla radice il gruppo di rotazione (a cui è connesso il
cubo di cubi) */
root.addChild(cubeGroupRotator);
root.addChild(rotator);

/* Creo un canvas3d e un universo 3d, aggiungo all'universo la radice
della mia scena 3d e fine. */
Canvas3D canvas = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
SimpleUniverse universe = new SimpleUniverse(canvas);

Transform3D viewTranslation = new Transform3D();
viewTranslation.setTranslation(new Vector3f(0, 0, 5 * CUBE_COUNT * CUBE_EDGE));
universe.getViewingPlatform().getViewPlatformTransform().setTransform(viewTranslation);

universe.addBranchGraph(root);

Frame window = new Frame("Test Cubi");
window.add(canvas);
window.setSize(400, 400);
window.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) { System.exit(0); }
});
window.setVisible(true);
}
}

Giusto per provare ti incollo anche CubeGroup ma questa classe è indifferente: tu i cubi li generi come preferisci, l'importante è che il super-cubo risulti centrato rispetto all'origine degli assi.

package cubi;

import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.geometry.*;

public class CubeGroup {
private BranchGroup group = new BranchGroup();
private final float EDGE;
private final int CUBE_COUNT;

public CubeGroup(int cubeCount, float cubeEdge) {
/* Genera un cubo di cubeCount cubi, ognuno di lato cubeEdge. I cubi sono
distribuiti intorno al punto (0,0,0). */

EDGE = cubeEdge;
CUBE_COUNT = cubeCount;
float groupEdge = 2.1f * CUBE_COUNT * EDGE;
float offset = groupEdge / 2 - EDGE;
for(int x = 0; x < cubeCount; x++) {
for(int y = 0; y < cubeCount; y++) {
for(int z = 0; z < cubeCount; z++) {
Appearance appearance = new Appearance();
Material material = new Material();
Color3f color = new Color3f(x / (float)CUBE_COUNT, y / (float)CUBE_COUNT, z / (float)CUBE_COUNT);
material.setEmissiveColor(color);
appearance.setMaterial(material);
Box box = new Box(EDGE, EDGE, EDGE, appearance);
Transform3D transform = new Transform3D();
Vector3f translation = new Vector3f(offset - 2.1f * x, offset - 2.1f * y, offset - 2.1f * z);
transform.setTranslation(translation);
TransformGroup boxLocator = new TransformGroup(transform);
boxLocator.addChild(box);
group.addChild(boxLocator);
}
}
}

group.compile();
}

public BranchGroup getGroup() {
return group;
}
}

E questo è l'effetto che fa.

http://www.tukano.it/cubi.png

Marbury
15-02-2008, 21:57
grazie mille!

Ormai che ci sei volevo chiederti ancora una cosa: se provo a creare un cubo di 27*27 quindi 27*27 cubi, si pappa tutto lo heap. E' un problema di come li ho implementati e cioè uno per transformGroup?? Grazie ancora. :)


edit: secondo te è fattibile fare in modo che se uno clicca su un cubo poi può trascinare tutta la "sfoglia" all'esterno, cliccare su uno dei cubi e rimetterla "al suo posto"?

PGI-Bis
16-02-2008, 07:47
Prova ad aumentare la dimensione dell'heap. Per farlo quando lanci il programma da console aggiungi l'opzione -Xmx seguita dal numero di megabyte che pensi ti servano. Ad esempio per dare in pasto alla JVM fino a 512 megabyte di RAM:

java -Xmx512m ...eccetera

Se ritieni che la dimensione massima dell'heap sia interamente necessaria puoi usare anche l'opzione -Xms che definisce la dimensione iniziale dell'heap. Ad esempio:

java -Xmx512m -Xms512m ...eccetera

In questo caso stabilisci che la JVM possa usare al massimo 512 megabyte di ram e che tutti e 512 i megabyte siano riservati già all'avvio.

E' senz'altro possibile aggiungere il tipo di interazione che desideri ed esistono una varietà di modi per realizzarla. Uno di questi modi è usare un TransformGroup per ogni cubetto - vale a dire aggiungere il cubetto ad un TransformGroup ed aggiungere il TransformGroup al gruppo del super-cubo. Il gruppo di trasformazione opportunamente abilitato ti permette di spostare il cubetto, il resto è una questione di "picking" e collegamento tra il movimento del mouse e lo spostamento del cubo correntemente selezionato.