JOGL em português

Eu traduzi o código do livro Pro Java 6 3D Game Development no capítulo onde o autor introduz JOGL usando renderização ativa, que é a opção mais avançada e flexível para criação de jogos 3D usando o JOGL com a especificação JSR-231.

Com isso em mãos começa a ficar bem mais fácil entender e dominar o JOGL.

Só alterei um detalhe colocando as constantes em uma interface, e mantive um ou outro termo em inglês para manter os termos usados no JOGL.

Segue também em anexo!

[code]package cubo;

public interface Constantes {

int fpsPadrao = 60;

int larguraPainel = 512;   // tamanho do painel
int alturaPainel = 512;

float incrementoMaximo = 10.0f;   // para os incrementos de rotação
double distanciaZ = 7.0;      //para a posição da câmera

/* Constantes para estatística
 * grava estatísticas a cada 1 segundo (aproximadamente) */
long intervaloMaxStats = 1000000000L;

/* Número de interações com um atraso de adormecimento de 0 ms antes
 * da thread de animação esperar por (yield) outras treads */
final int semAtrasosPorEspera = 16;

/* Número de renderizações que podem ser "puladas" nos loops de animação
 * ou seja: o estado do jogo é atualizado, mas não renderizado */
int maxPulosRenderizacao = 5;   // was 2;

/* Quantidade de valores de FPS (frames por
 * segundo) guardados para obter uma média */
int numFps = 10;

}[/code]

[code]package cubo;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GraphicsConfiguration;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.text.DecimalFormat;

import javax.media.opengl.AWTGraphicsConfiguration;
import javax.media.opengl.AWTGraphicsDevice;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLDrawableFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class Janela extends JFrame implements WindowListener, Constantes {

private static final long serialVersionUID = 1L;

private TelaCuboGL telaCuboGL;

private JTextField rotacoesTF;   // exibe as rotações do cubo
private DecimalFormat df = new DecimalFormat("0.#");  // 1 dp

public Janela(long periodo) {
	super("CubeGL (Renderizacao Ativa)");
	
	Container c = getContentPane();
	c.setLayout( new BorderLayout() );
	c.add(criaPainelRenderizacao(periodo), BorderLayout.CENTER);
	
	rotacoesTF = new JTextField("Rotacoes: ");
	rotacoesTF.setEditable(false);
	c.add(rotacoesTF, BorderLayout.SOUTH);
	
	addWindowListener(this);
	
	pack();
	setVisible(true);
}

/** cria a tela, dentro de um JPanel */
private JPanel criaPainelRenderizacao(long periodo) {
	JPanel painelRenderizacao = new JPanel();
    painelRenderizacao.setLayout( new BorderLayout() );
    painelRenderizacao.setOpaque(false);
    painelRenderizacao.setPreferredSize(new Dimension(larguraPainel, alturaPainel));

    telaCuboGL = criaTela(periodo);
    painelRenderizacao.add(telaCuboGL, BorderLayout.CENTER);

    telaCuboGL.setFocusable(true);
    telaCuboGL.requestFocus();    // agora a tela tem o foco, então recebe os eventos de teclado

    // detecta o redimensionamento da janela, e reformata a tela de acordo
    painelRenderizacao.addComponentListener(new ComponentAdapter() {
    	public void componentResized(ComponentEvent evt) {
    		Dimension d = evt.getComponent().getSize();
    		telaCuboGL.reshape(d.width, d.height);
    	} // end of componentResized()
    });
    return painelRenderizacao;
}

private TelaCuboGL criaTela(long periodo) {
	// obtém uma configuração adequada para a tela AWT (para TelaCuboGL)
    GLCapabilities caps = new GLCapabilities();

    AWTGraphicsDevice dev = new AWTGraphicsDevice(null);
    AWTGraphicsConfiguration awtConfig =
    	(AWTGraphicsConfiguration) GLDrawableFactory.getFactory().chooseGraphicsConfiguration(caps, null, dev);

    GraphicsConfiguration config = null;
    
    if (awtConfig != null) {
    	config = awtConfig.getGraphicsConfiguration();
    }

    return new TelaCuboGL(this, periodo, larguraPainel, alturaPainel, config, caps);
}

/** chamado pela TelaCuboGL para mostrar as rotações do cubo */
public void setRots(float rotX, float rotY, float rotZ) {
	rotacoesTF.setText("Rotações: (" +
			df.format(rotX) + ", " +
			df.format(rotY) + ", " +
			df.format(rotZ) + ")");
}

// ----------------- window listener methods -------------

public void windowActivated(WindowEvent e) {
	telaCuboGL.continuaJogo();
}

public void windowDeactivated(WindowEvent e) {
	telaCuboGL.pausaJogo();
}

public void windowDeiconified(WindowEvent e) {
	telaCuboGL.continuaJogo();
}

public void windowIconified(WindowEvent e) {
	telaCuboGL.pausaJogo();
}

public void windowClosing(WindowEvent e) {
	telaCuboGL.finalizaJogo();
}

public void windowClosed(WindowEvent e) {}
public void windowOpened(WindowEvent e) {}

// -----------------------------------------

public static void main(String[] args) {
	int fps = fpsPadrao;
	if (args.length != 0)
		fps = Integer.parseInt(args[0]);
	
	long periodo = (long) 1000.0/fps;
	System.out.println("fps: " + fps + "; período: " + periodo + " ms");
	
	new Janela(periodo*1000000L); // ms --> nanosecs
}

}[/code]

[code]package cubo;

import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.text.DecimalFormat;
import java.util.Random;

import javax.media.opengl.GL;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLDrawable;
import javax.media.opengl.GLDrawableFactory;
import javax.media.opengl.glu.GLU;

public class TelaCuboGL extends Canvas implements Runnable, Constantes {

private static final long serialVersionUID = 1L;

// usado para coletar estatísticas
private long intervaloStats = 0L;    // in ns
private long tempoAnteriorStats;
private long tempoTotalUsado = 0L;
private long tempoInicioJogo;
private int tempoGastoEmJogo = 0;    // in seconds

private long contagemFrames = 0;
private double historicoFps[];
private long contagemStats = 0;
private double fpsMedio = 0.0;

private long renderizacoesPuladas = 0L;
private long totalRenderizacoesPuladas = 0L;
private double historicoUps[]; // Updates (atualizações) por segundo
private double upsMedio = 0.0;

private DecimalFormat df = new DecimalFormat("0.##");  // 2 dp
private DecimalFormat timedf = new DecimalFormat("0.####");  // 4 dp

// utilizado no fim do jogo
private volatile boolean gameOver = false;

// Vértices para um cubo com lados de 2 unidades centralizado em (0,0,0)
private float[][] verts = {
		{-1.0f,-1.0f, 1.0f},  // vértice 0
		{-1.0f, 1.0f, 1.0f},  // 1
		{ 1.0f, 1.0f, 1.0f},  // 2
		{ 1.0f,-1.0f, 1.0f},  // 3
		{-1.0f,-1.0f,-1.0f},  // 4
		{-1.0f, 1.0f,-1.0f},  // 5
		{ 1.0f, 1.0f,-1.0f},  // 6
		{ 1.0f,-1.0f,-1.0f},  // 7
};

int listaExibicaoCubo; // display list para exibir o cubo

private Janela janela;   // referência à janela principal

private long periodo; // período entre renderizações em _nanosecs_

private Thread animador; // a thread responsável pelas animações
private volatile boolean isRodando = false; // Utilizado para finalizar a thread de animação
private volatile boolean isPausado = false;

// OpenGL
private GLDrawable drawable; // a superfície de renderização
private GLContext context; // o contexto de renderização (mantém informações de estado de renderização)
private GL gl;
private GLU glu;

// variáveis de rotação
private float rotX, rotY, rotZ;     // rotações totais nos eixos x, y, z
private float incrX, incrY, incrZ;  // incrementos para as rotações x, y, z

// dimensionamento da janela
private boolean isRedimensionado = false;
private int larguraAtualPainel, alturaAtualPainel;

public TelaCuboGL(Janela janela, long periodo, int larguraPainel,
		int alturaPainel, GraphicsConfiguration config, GLCapabilities caps) {
	
	super(config);

    this.janela = janela;
    this.periodo = periodo;
    larguraAtualPainel = larguraPainel;
    alturaAtualPainel = alturaPainel;

    // Obtém uma superfície de renderização e um contexto para essa tela
    drawable = GLDrawableFactory.getFactory().getGLDrawable(this, caps, null);
    context = drawable.createContext(null);

    // inicializa as variáveis de rotação
    rotX = 0; rotY = 0; rotZ = 0;
    Random random = new Random();
    incrX = random.nextFloat()*incrementoMaximo;  // 0 - incrementoMaximo graus
    incrY = random.nextFloat()*incrementoMaximo; 
    incrZ = random.nextFloat()*incrementoMaximo; 

    // inicialização das estatísticas
    historicoFps = new double[numFps];
    historicoUps = new double[numFps];
    for (int i=0; i < numFps; i++) {
    	historicoFps[i] = 0.0;
    	historicoUps[i] = 0.0;
    }
}

/** Espera a tela ser adicionada ao JPanel antes de iniciar */
public void addNotify() {
	super.addNotify(); // torna o componente visualizável
	drawable.setRealized(true); // agora é possível renderizar na tela
	
	// inicializa e inicia a thread de animação
	if (animador == null || !isRodando) {
		animador = new Thread(this);
		animador.start();
	}
}

// ------------- métodos do ciclo de vida do jogo ------------
// Chamados pelos listeners de janela do JFrame

/** chamado quando o JFrame é ativado / desiconificado */
public void continuaJogo() {
	isPausado = false;
}

/** Chamado quando o JFrame é desativado / iconificado */
public void pausaJogo() {
	isPausado = true;
}

/** Chamado quando o JFrame está sendo fechado */
public void finalizaJogo() {
	isRodando = false;
}

// ----------------------------------------------

/** Chamado pelo ComponentListener do JFrame quando a janela é redimensionada
 * Similar ao callback do reshape() no GLEventListener (capítulo anterior) */
public void reshape(int largura, int altura) {
	isRedimensionado = true;
	
	if (altura == 0)
		altura = 1; // Para evitar divisão por zero na proporção de tamanho em resizeView()
	
	larguraAtualPainel = largura;
	alturaAtualPainel = altura;
}

/** Sobrescrevendo sem ação, já que a animação
 * ocorrerá na tela OpenGL, não no Canvas */
public void update(Graphics g) { }
public void paint(Graphics g) { }

/** Inicializando a renderização e iniciando a geração de frames */
public void run() {
	iniciaRenderizacao();
	loopRenderizacao();
	
	// descarta o contexto de renderização e sai
	context.destroy();
	System.exit(0);
} // end of run()

/** Traz o contexto de renderização para essa thread */
private void trazContexto() {
	try {
		while (context.makeCurrent() == GLContext.CONTEXT_NOT_CURRENT) {
			// Apenas uma segurança extra que nem deve chegar a executar
			System.out.println("Aguardando contexto...");
			Thread.sleep(100);
		}
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
}

/** Inicialização da renderização (similar ao callback
 * init() do GLEventListener no capítulo anterior */
private void iniciaRenderizacao() {
	trazContexto();
	
	gl = context.getGL();
	glu = new GLU();
	
	redimensionaVisualizacao();
	
	gl.glClearColor(0.17f, 0.65f, 0.92f, 0.0f);  // cor de céu no fundo
	
	// z- (profundidade) inicialização do buffer para remoção de superfícies ocultas
	gl.glEnable(GL.GL_DEPTH_TEST);
	// gl.glClearDepth(1.0f);
	// gl.glDepthFunc(GL.GL_LEQUAL); // tipo de teste de profundidade
	// gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
	
	/* Cria uma lista de exibição para desenhar o cubo
	 * É uma pré-compilação dos comandos, muito mais rápido
	 * do que executá-los a cada loop */
	listaExibicaoCubo = gl.glGenLists(1);
	gl.glNewList(listaExibicaoCubo, GL.GL_COMPILE);
		desenhaCuboColorido(gl);
	gl.glEndList();
	
	/* Libera o contexto para que a trava AWT
	 * do X11 (linux) possa ser liberada */
	context.release();
}

private void redimensionaVisualizacao() {
	gl.glViewport(0, 0, larguraAtualPainel, alturaAtualPainel); // tamanho da área de desenho
	
	gl.glMatrixMode(GL.GL_PROJECTION);
	gl.glLoadIdentity();
	
	// fov (abertura), proporção de tamanho, planos de corte próximo e distante
	glu.gluPerspective(45.0, (float)larguraAtualPainel/(float)alturaAtualPainel,  1, 100); // 5, 100);
}

// ---------------- renderização baseada em frames -----------------------

/** Repetidamente atualiza, renderiza, põe na tela e adormece,
 * mantendo um período fixo tão preciso quanto possível.
 * Obtém e exibe estatísticas */
private void loopRenderizacao() {
	// Variáveis de temporização
	long tempoAntes, tempoDepois, diferencaTempo, tempoAdormecimento;
	long tempoAdormecimentoExcedido = 0L;
	int semAtrasos = 0;
	long sobra = 0L;
	
	tempoInicioJogo = System.nanoTime(); // J3DTimer.getValue();
	tempoAnteriorStats = tempoInicioJogo;
	tempoAntes = tempoInicioJogo;
	
	isRodando = true;
	
	while(isRodando) {
		trazContexto();
		atualizaJogo();
		
		renderizaCena(); // renderizando
		
		// Troca os buffers de fundo e de frante, tornando a nova renderização visível */
		drawable.swapBuffers();  // Coloca a cena na tela
		
		tempoDepois = System.nanoTime();
		diferencaTempo = tempoDepois - tempoAntes;
		tempoAdormecimento = (periodo - diferencaTempo) - tempoAdormecimentoExcedido;
		
		if (tempoAdormecimento > 0) { // sobrou algum tempo nesse ciclo
			try {
				Thread.sleep(tempoAdormecimento/1000000L);  // nano -> ms
			} catch(InterruptedException ex){}
			tempoAdormecimentoExcedido = (System.nanoTime() - tempoDepois) - tempoAdormecimento;
		} else {
			// sleepTime <= 0; esse ciclo levou mais tempo do que o período
			sobra -= tempoAdormecimento; // guarda o valor da sobra de tempo
			tempoAdormecimentoExcedido = 0L;
			
			if (++semAtrasos >= semAtrasosPorEspera) {
				Thread.yield(); // Dá a outra thread a oportunidade de executar
				semAtrasos = 0;
			}
		}
		
		tempoAntes = System.nanoTime(); // J3DTimer.getValue();
		
		/* Se a renderização está tomando muito tempo, atualiza o estado do jogo
		 * sem renderizar a atualização, para que os updates por segundo estejam
		 * próximos da taxa de frames por segundo requerida */
		int pulos = 0;
		while((sobra > periodo) && (pulos < maxPulosRenderizacao)) {
			sobra -= periodo;
			atualizaJogo(); // atualiza, mas não renderiza
			pulos++;
		}
		
		renderizacoesPuladas += pulos;
		
		// Libera o contexto para que a trava AWT do X11 (linux) seja liberada
		context.release();
		
		armazenaStats();
	}
	
	exibeStats();
}

private void atualizaJogo() {
	if (!isPausado && !gameOver) {
		// atualiza as rotações
		rotX = (rotX + incrX) % 360.0f; // % 360 faz retornar a zero no 360
		rotY = (rotY + incrY) % 360.0f;
		rotZ = (rotZ + incrZ) % 360.0f;
		janela.setRots(rotX, rotY, rotZ);
	}
}

// ------------------ métodos de renderização -----------------------------

private void renderizaCena() {
	if (GLContext.getCurrent() == null) {
		System.out.println("O contexto atual é nulo");
		System.exit(0);
	}
	
	if (isRedimensionado) { // Redimensiona o drawable (desenhável) se necessário
		redimensionaVisualizacao();
		isRedimensionado = false;
	}
	
	// limpa a cor e os buffers de profundidade
	gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
	
	gl.glMatrixMode(GL.GL_MODELVIEW);
	gl.glLoadIdentity();
	
	glu.gluLookAt(0,0,distanciaZ, 0,0,0, 0,1,0); // posiciona a câmera
	
	// aplica rotações aos eixos x, y e z
	gl.glRotatef(rotX, 1.0f, 0.0f, 0.0f);
	gl.glRotatef(rotY, 0.0f, 1.0f, 0.0f);
	gl.glRotatef(rotZ, 0.0f, 0.0f, 1.0f);
	gl.glCallList(listaExibicaoCubo); // executa a lista de exibição pré-compilada para o cubo
	// desenhaCuboColorido(gl); // OU pode-se executar os comandos diretamente (muito mais lento)
	
	if (gameOver)
		System.out.println("Game Over");
}

// Cubo de seis lados, com uma cor diferente em cada face
private void desenhaCuboColorido(GL gl) {
	gl.glColor3f(1.0f, 0.0f, 0.0f);   // vermelho
	desenhaPoligono(gl, 0, 3, 2, 1);      // face frontal
	
	gl.glColor3f(0.0f, 1.0f, 0.0f);   // verde
	desenhaPoligono(gl, 2, 3, 7, 6);      // direita
	
	gl.glColor3f(0.0f, 0.0f, 1.0f);   // azul
	desenhaPoligono(gl, 3, 0, 4, 7);      // fundo
	
	gl.glColor3f(1.0f, 1.0f, 0.0f);   // amarelo
	desenhaPoligono(gl, 1, 2, 6, 5);      // topo
	
	gl.glColor3f(0.0f, 1.0f, 1.0f);   // azul claro
	desenhaPoligono(gl, 4, 5, 6, 7);      // atrás
	
	gl.glColor3f(1.0f, 0.0f, 1.0f);   // roxo
	desenhaPoligono(gl, 5, 4, 0, 1);      // esquerda
}

// Os vértices do polígino vêm do vetor verts[]
private void desenhaPoligono(GL gl, int vIdx0, int vIdx1, int vIdx2, int vIdx3) {
	gl.glBegin(GL.GL_POLYGON);
		gl.glVertex3f( verts[vIdx0][0], verts[vIdx0][1], verts[vIdx0][2] );
		gl.glVertex3f( verts[vIdx1][0], verts[vIdx1][1], verts[vIdx1][2] );
		gl.glVertex3f( verts[vIdx2][0], verts[vIdx2][1], verts[vIdx2][2] );
		gl.glVertex3f( verts[vIdx3][0], verts[vIdx3][1], verts[vIdx3][2] );
	gl.glEnd();
}

// ----------------- métodos de estatísticas ------------------------

/** As estatísticas:
 * 		- os períodos somados de todas as interações nesse intervalo
 * 		  (período é a quantidade de tempo que uma simples enteração deve levar),
 * 		  o tempo atual gasto nesse intervalo,
 * 		  o erro entre esses dois números;
 * 
 * 		- A contagem total de frames, que é o número total de chamadas a run();
 * 
 *  	- Os frames pulados nesse intervalo, o número total de frames
 *  	  pulados. Um pulo de frame é uma atualização do jogo sem a renderização correspondente;
 *  
 *   	- O FPS (frames por segundo) e UPS (atualizações por segundo) nesse intervalo,
 *   	  o FPS e UPS médio sobre os últimos intervalos numFps
 *   
 *   	Os dados são coletados a cada intervaloMaxStats (1 segundo).
 *   
 *   	----- MUDANÇAS -----
 *   	Não exibe a saída, deixa isso para exibeStatus(). */
private void armazenaStats() {
	contagemFrames++;
    intervaloStats += periodo;
    
    if (intervaloStats >= intervaloMaxStats) { // grava as estatísticas a cada intervaloMaxStats
    	long tempoAtual = System.nanoTime(); // J3DTimer.getValue();
    	tempoGastoEmJogo = (int) ((tempoAtual - tempoInicioJogo)/1000000000L); // ns --> secs
    	
    	long tempoUsadoReal = tempoAtual - tempoAnteriorStats; // tempo desde a última coletagem de estatísticas
    	tempoTotalUsado += tempoUsadoReal;
    	
    	double erroTemporizacao = ((double)(tempoUsadoReal - intervaloStats) / intervaloStats) * 100.0;
    	
    	totalRenderizacoesPuladas += renderizacoesPuladas;
    	
    	double fpsAtual = 0;     // calculate the latest FPS and UPS
    	double upsAtual = 0;
    	
    	if (tempoTotalUsado > 0) {
    		fpsAtual = (((double)contagemFrames / tempoTotalUsado) * 1000000000L);
    		upsAtual = (((double)(contagemFrames + totalRenderizacoesPuladas) / tempoTotalUsado) * 1000000000L);
    	}
    	
    	// sarmazena o FPS e UPS mais recentes
    	historicoFps[ (int)contagemStats % numFps ] = fpsAtual;
    	historicoUps[ (int)contagemStats % numFps ] = upsAtual;
    	contagemStats ++;
    	
    	double fpsTotal = 0.0; // totaliza os FPS e UPS armazenados
    	double upsTotal = 0.0;
    	for (int i=0; i < numFps; i++) {
    		fpsTotal += historicoFps[i];
    		upsTotal += historicoUps[i];
    	}
    	
    	if (contagemStats < numFps) { // obtém a média de FPS e UPS
    		fpsMedio = fpsTotal/contagemStats;
    		upsMedio = upsTotal/contagemStats;
    	} else {
    		fpsMedio = fpsTotal/numFps;
    		upsMedio = upsTotal/numFps;
    	}
    	
    	/*
    	System.out.println(timedf.format( (double) intervaloStats/1000000000L) + " " +
    			timedf.format((double) tempoUsadoReal/1000000000L) + "s " +
    			df.format(erroTemporizacao) + "% " +
    			contagemFrames + "c " +
    			renderizacoesPuladas + "/" + totalRenderizacoesPuladas + " skip; " +
    			df.format(fpsAtual) + " " + df.format(fpsMedio) + " afps; " +
    			df.format(upsAtual) + " " + df.format(upsMedio) + " aups" );
    	*/
    	
    	renderizacoesPuladas = 0;
    	tempoAnteriorStats = tempoAtual;
    	intervaloStats = 0L;   // reset
    }
}

private void exibeStats() {
	// System.out.println("Contagem/Perda de frames: " + contagemFrames + " / " + totalRenderizacoesPuladas);
	System.out.println("FPS Médio: " + df.format(fpsMedio));
	System.out.println("UPS Médio: " + df.format(upsMedio));
	System.out.println("Tempo Gasto: " + tempoGastoEmJogo + " secs");
}

}[/code]

Legal a iniciativa!!! Já baixei e vou testar!

Por acaso alguém sabe onde eu consigo mais exemplos utilizando JOGL?

Abracos…

No próprio site do JOGL tem vários exemplos. Vai no google e busca por JOGL que você vai encontrar o site oficial no primeiro link.

[]'s.

Boa noite!! Segue esse triangulo usando OPGL:

package org.yourorghere;

import com.sun.opengl.util.Animator;
import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
import java.awt.*;
import java.awt.event.*;
import com.sun.opengl.util.Animator;
import javax.media.opengl.GL;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLDrawableFactory;
import javax.media.opengl.GLEventListener;

public class SimpleJOGL implements GLEventListener {

    public static void main(String[] args) {
        Frame frame = new Frame("Primeiro exemplo");
        GLCanvas canvas = new GLCanvas();

        canvas.addGLEventListener(new SimpleJOGL());
        frame.add(canvas);
        frame.setSize(640, 480);
        final Animator animator = new Animator(canvas);
        frame.addWindowListener(new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {
                new Thread(new Runnable() {

                    public void run() {
                        animator.stop();
                        System.exit(0);
                    }
                }).start();
            }
        });

        frame.setLocationRelativeTo(null); //centraliza o form na tela
        frame.setVisible(true);
        animator.start();
    }

    public void init(GLAutoDrawable drawable) { }

    public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
        GL gl = drawable.getGL();
        GLU glu = new GLU();

        gl.glViewport(0, 0, 500, 500); //???
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();

        glu.gluPerspective(50.0f, 1.0, 1.0, 10.0); //???
        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();
    }

    public void display(GLAutoDrawable drawable) {
        GL gl = drawable.getGL();
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
        gl.glLoadIdentity();

        gl.glTranslatef(0.0f, 0.0f, -5.0f);   // eixo q o triangulo desloca.

        // desenhar o triangulo usando os seguintes vertices
        gl.glBegin(GL.GL_TRIANGLES);
        gl.glVertex3f(0.0f, 1.0f, 0.0f);   // topo
        gl.glVertex3f(-1.0f, -1.0f, 0.0f); // esquerda
        gl.glVertex3f(1.0f, -1.0f, 0.0f);  // direita

        gl.glEnd(); //termina de desenhar o triangulo
        gl.glFlush(); //faz a descarga
    }

    public void displayChanged(GLAutoDrawable drawable, 
                               boolean modeChanged,
                               boolean deviceChanged) { }
}

Minha dúvida está nos métodos glViewport e gluPerspective. Não estou conseguindo identificar a funcionalidade deles.

Obrigado!

Bom, aí creio que já foge do escopo do GUJ, já que isso é dúvida específica de OpenGL!

Eu recomendo esse livro, do qual estou gostando bastante:

OpenGL: uma Abordagem Prática e Objetiva

De acordo com o livro a View Port (que o comando glViewport do OpenGL define) é a janela de visualização do conteúdo de uma janela na tela (se vc quer que a visualização apareça na tela toda, ou em um quadradinho em um canto, ou até em mais de um lugar na tela). A janela (window) é a seleção da região da animação a ser exibida, e a view port é ONDE na tela essa seleção será exibida.

Existem dois tipos de projeção de conteúdo. Na projeção ortográfica o conteúdo 3D é projetado plano, “chapado” na tela. Na projeção “perspectiva” (que o comando gluPerspective do OpenGL define) o conteúdo será exibido em perspectiva, dependendo da distância entre a câmera e os objetos, entre um objeto e outro, etc… A projeção perspectiva reflete melhor a aparência de uma filmagem real (com uma câmera do mundo real).

O detalhe do JOGL é que você precisa estudar não só a interface em si que conecta a tecnologia OpenGL à linguagem Java, mas também a própria tecnologia OpenGL.

É interessante estudar OpenGL porque é muito utilizado em jogos e animações, o J2ME 3D tem um port em OpenGL e o Android usa o OpenGL para 3D, entre muitas outras aplicações.

Agora, precisa de muito QSV (Quociente de SE VIRA), porque estudar OpenGL direito tem que ser do zero, não dá pra esperar dominar os seus recursos só com tutoriaizinhos básicos!

Pra fazer o básico vc não precisa de OpenGL! 3D não é básico!

:wink:

Boa sorte!

Opa!! Muito obrigado Fox McCloud. Ajudou bastante. :smiley: