Ir ao conteúdo
  • Cadastre-se

Vinicius Biavatti

Membro Júnior
  • Posts

    4
  • Cadastrado em

  • Última visita

posts postados por Vinicius Biavatti

  1. Pseudo 3D


     


    Olá a todos. Falarei a respeito de algo interessante na programação, o pseudo 3D. O Pseudo 3D é um método utilizado para renderização de um ambiente com uma sensação de profundidade (eixo Z) porém o efeito é apenas ilusão.


    Este método de renderização era utilizado em muitos jogos antigos como por exemplo, os jogos de corrida onde a pista da corrida parecia ter uma profundidade.


    curves1.png


     


     


    Existem tipos parecidos de renderização como o "Mode 7" onde a renderização já possui mais recursos como por exemplo, a Rotação.


    Mode_7_Test-0000.png


     


    Gostaria de falar a respeito com o pessoal do forum, para pedir se alguém possui algum material explicativo ou algum tutorial onde ensine o básico sobre esta renderização.


    Bem bacana ter conhecimento para ver como na realidade funciona o openGL por baixo dos panos. 


     


    Sei que deve existir uma lógica bem básica para isto e quero aprender, para assim, programar algo em JAVA. 


     


    Gostaria também de saber se existe um nome específico para este tipo de renderização.


     


    Código:


    Podemos utilizar uma simples JFrame em java, criar um Thread, más a lógica para que possamos gerar este eixo Z, e movimentar as faixas geradas para dar impressão 3D é o que preciso.


    O assunto é um pouco complicado para ser encontrado na internet, más o que achei foi o conteúdo deste site, porém ainda sim é um tanto complexo a explicação.


    http://www.extentofthejam.com/pseudo/


     


    Se puderem disponibilizar algo básico em java com esta lógica utilizada ajudará muito.


     


     


    Evolução:


    Tentei reproduzir um efeito simples em Pseudo3D da mesma forma utilizar para estes jogos antigos. Obtive o seguinte resultado:


    GxTAY5b.gif



    package pseudo3d;

    /**
    *
    * @author Vinicius
    */
    public class Pseudo3D {

    public static void main(String[] args) {

    new Tela();

    }
    }


    package pseudo3d;

    import java.awt.Graphics;
    import java.awt.event.KeyEvent;
    import java.awt.event.KeyListener;
    import java.awt.image.BufferedImage;
    import javax.swing.JFrame;

    /**
    *
    * @author Vinicius
    */
    public class Tela extends JFrame implements Runnable, KeyListener{

    //Constantes - Tamanho
    public static final int LARGURA = 800;
    public static final int ALTURA = 600;
    public static final int CENTRO_LARGURA = LARGURA / 2;
    public static final int CENTRO_ALTURA = ALTURA / 2;

    //Constantes - Evento
    public static final int PARADO = 0;
    public static final int CIMA = 1;
    public static final int BAIXO = 2;
    public static final int ESQUERDA = 3;
    public static final int DIREITA = 4;

    //Atributos - Imagem
    private BufferedImage imagem;
    private Graphics grafico;
    private Render3D render3D;

    //Atributos - Evento
    private int evento = PARADO;
    private int deslocamentoX = 0, deslocamentoZ = 0;

    /*
    * Construtor
    */
    public Tela()
    {
    this.setTitle("Pseudo-3D v1.0");
    this.setSize(LARGURA, ALTURA);
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setLocationRelativeTo(null);
    this.addKeyListener(this);
    this.setVisible(true);

    this.imagem = new BufferedImage(LARGURA, ALTURA, BufferedImage.TYPE_INT_RGB);
    this.grafico = this.imagem.getGraphics();

    new Thread(this).start();
    }

    /**
    * Calcular fps do sistema.
    * <p>
    * <code>long tempo = System.currentTimeMillis(); </code>
    * <p>
    * <code>while(System.currentTimeMillis() - tempo < 30);</code>
    */
    public void fps()
    {
    long tempo = System.currentTimeMillis();

    while(System.currentTimeMillis() - tempo < 30);

    //System.out.println("fps: " + (System.currentTimeMillis() - tempo));
    }

    /**
    * Verificar evento de movimentação.
    * Irá realizar validação de limite.
    */
    private void evento()
    {
    switch(this.evento)
    {
    case CIMA: this.deslocamentoZ++; break;
    case ESQUERDA: this.deslocamentoX-= 40; break;
    case DIREITA: this.deslocamentoX+= 40; break;
    }

    if(deslocamentoZ > 5)
    {
    deslocamentoZ = 0;
    }
    }

    @[member=override]
    public void run()
    {
    this.render3D = new Render3D(this);

    while(true)
    {
    this.fps();

    this.render3D.renderTeto(deslocamentoZ);
    this.render3D.renderPiso(deslocamentoZ);
    this.render3D.renderProfundidadeTeto(deslocamentoX);
    this.render3D.renderProfundidadePiso(deslocamentoX);

    this.repaint();

    this.evento();
    }
    }

    @[member=override]
    public void keyTyped(KeyEvent e)
    {
    }

    @[member=override]
    public void keyPressed(KeyEvent e)
    {
    switch(e.getKeyCode())
    {
    case KeyEvent.VK_UP: this.evento = CIMA; break;
    case KeyEvent.VK_DOWN: this.evento = BAIXO; break;
    case KeyEvent.VK_LEFT: this.evento = ESQUERDA; break;
    case KeyEvent.VK_RIGHT: this.evento = DIREITA; break;
    }
    }

    @[member=override]
    public void keyReleased(KeyEvent e)
    {
    switch(e.getKeyCode())
    {
    case KeyEvent.VK_UP:
    case KeyEvent.VK_DOWN:
    case KeyEvent.VK_LEFT:
    case KeyEvent.VK_RIGHT:
    this.evento = PARADO; break;
    }
    }

    @[member=override]
    public void paint(Graphics g)
    {
    g.drawImage(this.imagem, 0, 0, this);
    }

    /*
    * Get e Set
    */
    public BufferedImage getImagem() {
    return imagem;
    }

    public void setImagem(BufferedImage imagem) {
    this.imagem = imagem;
    }

    public Graphics getGrafico() {
    return grafico;
    }

    public void setGrafico(Graphics grafico) {
    this.grafico = grafico;
    }
    }



    package pseudo3d;

    import java.awt.Color;

    /**
    *
    * @author Vinicius
    */
    public class Render3D {

    //Atributos - Imagem
    private Tela tela;

    /**
    * Construtor da classe. Passar uma tela para que seja renderizado
    * as linhas bidimensionais.
    * @param tela
    */
    public Render3D(Tela tela)
    {
    this.tela = tela;
    }

    /**
    * Renderizar Teto na tela em perpectiva. Passar como parâmetro o deslocamento.
    * Passar 0 como valor do parâmetro para não fornecer deslocamento.
    * <p>
    * Utilizará variável "Z" para calcular a profundidade
    * @param deslocamento
    */
    public void renderTeto(int deslocamento)
    {
    int z = 2 + deslocamento;

    for(int i = this.tela.CENTRO_ALTURA; i >= 0; i--)
    {
    if(i == (this.tela.CENTRO_ALTURA - z))
    {
    this.tela.getGrafico().setColor(Color.BLACK);
    z *= 2;
    }
    else
    {
    this.tela.getGrafico().setColor(Color.GRAY);
    }

    this.tela.getGrafico().drawLine(0, i, this.tela.LARGURA, i);
    }
    }

    /**
    * Renderizar Piso na tela em perpectiva. Passar como parâmetro o deslocamento.
    * Passar 0 como valor do parâmetro para não fornecer deslocamento.
    * <p>
    * Utilizará variável "Z" para calcular a profundidade
    * @param deslocamento
    */
    public void renderPiso(int deslocamento)
    {
    int z = 2 + deslocamento;

    for(int i = this.tela.CENTRO_ALTURA; i < this.tela.ALTURA; i++)
    {
    if(i == (this.tela.CENTRO_ALTURA + z))
    {
    this.tela.getGrafico().setColor(Color.BLACK);
    z *= 2;
    }
    else
    {
    this.tela.getGrafico().setColor(Color.DARK_GRAY);
    }

    this.tela.getGrafico().drawLine(0, i, this.tela.LARGURA, i);
    }
    }

    /**
    * Renderizar profundidade do Teto na tela em perpectiva. Passar como parâmetro o deslocamento.
    * Passar 0 como valor do parâmetro para não fornecer deslocamento.
    * <p>
    * Utilizará variável "Z" para calcular a profundidade
    * @param deslocamento
    */
    public void renderProfundidadeTeto(int deslocamento)
    {
    this.tela.getGrafico().setColor(Color.BLACK);

    for(int i = (this.tela.ALTURA * this.tela.LARGURA) * -1; i < (this.tela.LARGURA * this.tela.ALTURA); i++)
    {
    if((i + deslocamento) % 600 == 0)
    {
    this.tela.getGrafico().drawLine(i, 0, this.tela.CENTRO_LARGURA, this.tela.CENTRO_ALTURA);
    }
    }
    }

    /**
    * Renderizar profundidade do Piso na tela em perpectiva. Passar como parâmetro o deslocamento.
    * Passar 0 como valor do parâmetro para não fornecer deslocamento.
    * <p>
    * Utilizará variável "Z" para calcular a profundidade
    * @param deslocamento
    */
    public void renderProfundidadePiso(int deslocamento)
    {
    this.tela.getGrafico().setColor(Color.BLACK);

    for(int i = (this.tela.ALTURA * this.tela.LARGURA) * -1; i < (this.tela.LARGURA * this.tela.ALTURA); i++)
    {
    if((i + deslocamento) % 600 == 0)
    {
    this.tela.getGrafico().drawLine(i, this.tela.ALTURA, this.tela.CENTRO_LARGURA, this.tela.CENTRO_ALTURA);
    }
    }
    }
    }


    Obs:


    Já fiz uma postagem no fórum referente a técnicas de renderização em 3D utilizando Ray Casting, e o que encontrei na internet foi um tutorial super complexo. Procurei até demais para encontrar uma simples classe java que me ajudasse a aprender, com um código básico, simples e muito melhor que o código complexo.


    Estou aqui para solicitar algo básico e se puderem ajudar :rolleyes:  estarei grato. 


     


     


    Demonstração:


    Este app foi desenvolvido por um gringo. Feito em javascript, e por possuir muitos recursos, não ficou bom para ter uma noção e sim, bom para se perder no código.


    http://codeincomplete.com/projects/racer/v1.straight.html


  2. Olá Galera! Finalmente desenvolvi meu primeiro RAYCASTING!

     

    Procurei bastante na internet, corri atrás e deu certo. Fiz algo bem básico más para mim já é interessante para compartilhar com vocês:

     

    Irei disponibilizar o código e a referência de onde consegui pegar um código para mim se basear. Agradeço ao Patrick Kelly! Obrigado irmão! Thanks brother ;) Sucessfully por you ;)

     

     

     

    Código:

     

    ** Comentei ele bastante para ficar bem fácil de entender, logo disponibilizarei ele sem os comentários pois olhando com essa montueira de comentários parece ser um código phodastico!

    package raycasting;import java.awt.Color;import java.awt.Graphics;import java.awt.event.KeyEvent;import java.awt.event.KeyListener;import java.awt.image.BufferedImage;import javax.swing.JFrame;public class RayCasting extends JFrame implements Runnable, KeyListener{    //Constantes - Tamanho da tela    public static final int WIDTH = 800;    public static final int HEIGHT = 600;        //Constantes - Centro da tela    public static final int CENTER_WIDTH = WIDTH / 2;    public static final int CENTER_HEIGHT = HEIGHT / 2;        //Constantes - Angulos    public static final int ANGULO720 = 9600;    public static final int ANGULO360 = 4800;    public static final int ANGULO180 = 2400;    public static final int ANGULO90 = 1200;    public static final int ANGULO60 = 800; //Atribuido para que o FOV (Angulo de visão do personagem) seja um angulo de 60°    public static final int ANGULO30 = 400;    public static final int ANGULO15 = 200;    public static final int ANGULO6 = 80;        //Constantes - Movimentação (EVENTO)    public static final int CIMA = 1;    public static final int BAIXO = 2;    public static final int ESQUERDA = 3;    public static final int DIREITA = 4;    public static final int PARADO = -1;    //Evento do personagem (Parado = -1, andando para frente = 1...)    private int personagemEvento = PARADO;        //Gráficos e Imagem    private BufferedImage imagem;    private Graphics grafico;        //Mapa    private int[][] mapa;        //Array de cores para as paredes    private Color[] cores = new Color[]{Color.GREEN, Color.RED, Color.BLUE, Color.ORANGE, Color.WHITE, Color.YELLOW, Color.BLACK};        /*     * Construtor     */    public RayCasting()    {        //Iniciando atributos de imagem e gráfico com o tamanho da tela onde será renderizado        this.imagem = new BufferedImage(this.WIDTH, this.HEIGHT, BufferedImage.TYPE_INT_RGB);        this.grafico = imagem.getGraphics();                //Criando mapa - Vista de cima (15 x 15)        this.mapa = new int[][]{{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},                                {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},                                {1,0,0,2,2,2,2,0,0,0,0,0,0,0,1},                                {1,0,0,0,0,0,2,0,0,0,5,5,5,0,1},                                {1,0,0,2,2,0,2,0,0,0,5,0,0,0,1},                                {1,0,0,0,0,0,2,0,0,0,5,0,0,0,1},                                {1,0,2,2,2,2,2,0,0,0,0,0,0,0,1},                                {1,0,0,0,0,0,0,0,1,1,1,0,0,0,1},                                {1,0,0,0,0,0,0,0,1,1,1,0,0,0,1},                                {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},                                {1,0,0,6,0,0,0,0,0,0,0,0,4,0,1},                                {1,6,0,6,0,0,0,0,4,4,4,4,4,0,1},                                {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},                                {1,0,6,0,6,0,0,0,0,0,0,0,0,0,1},                                {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}        };                //Criando Janela a partir desta classe ("extends JFrame")        this.setTitle("RayCasting JAVA");        this.setSize(this.WIDTH,this.HEIGHT);        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        this.setVisible(true);                //Adicionar integração com os botões ("implements KeyListener")        this.addKeyListener(this);                //Iniciando Thread para rodar método run()        new Thread(this).start();    }        /*     * Método conversor de Angulo para Radiano (Para que se possa trabalhar em radiano (Seno, Cosseno...))     */    public double converterAnguloRadiano(int angulo)    {        //Fórmula para conversão        double radiano = ((double)angulo * (Math.PI / this.ANGULO180));        return radiano;    }        /*     * Métodos run "Thread"     */    @[member="override"]    public void run()     {        //Criar posição inicial do personagem (posição X, posição Y e angulo do personagem "Angulo de visão")        double posicaoPersonagemX = 8;        double posicaoPersonagemY = 8;        int anguloPersonagem = 0;                //Angulo para lançamentos dos raios no devido angulo de visão do personagem. Definido no sistema de 60° o FOV.        //60° seria o centro da visão portando, para começar do lado esquerdo para o lado direito, é feita a diminuição de 30°        //Ao diminuir 30°, e passar pelo lançamento de raios conforme tamanho definido para 800 (this.WIDTH), é aumentado        //os graus suficientes para equivaler 60° pois 800 equivale a 60°        // -30°    60°   +30°        //  \______|______/        //   \     |     /        //    \    |    /        //     \   |   /        //      \  |  /        //       \ | /        //        \|/        int anguloRaio;                        //=================================//        //Loop para funcionamento da Thread//        //=================================//        while(true)        {                        //Decrementar angulo para realizar o lançamento dos raios (-30° oara após o lançamento de 800 raios, totalizar em 60°)            anguloRaio = anguloPersonagem - this.ANGULO30;                        //=================================================================================================//            //Iniciar lançamento de raios para buscar uma parede no mapa, calcular sua distância e renderiza-la//            //=================================================================================================//            for(int raio = 0; raio < this.ANGULO60; raio++)            {                                //Posição inicial dos raios (Obviamente é a posição do personagem)                double posicaoRaioX = posicaoPersonagemX;                double posicaoRaioY = posicaoPersonagemY;                                //Etapa para descobrir valor de X e assim efetuar a leitura do caminho do raio lançado, dentro do mapa.                //Irá ser criado uma parte de um círculo (60°) para ser jogado os 800 raios                double etapaX = Math.cos(this.converterAnguloRadiano(anguloRaio)) / 8;                double etapaY = Math.sin(this.converterAnguloRadiano(anguloRaio)) / 8;                                //====================================================================================================================\\                //Iniciar variáveis para correr no loop. Parede para quando encontrar uma parede e distância para calcular a distancia\\                //até encontrar parede                                                                                                \\                //====================================================================================================================\\                int parede = 0;                int distancia = 1; //Atribuir um para que seja no mínimo 1 a distância do personagem até a parede.                                                //Loop para procurar uma parede no mapa e calcular uma distância até a parede.                while(parede == 0)                {                                        //Realizar um traçamento do raio na incrementação das etapas calculadas no angulo                    posicaoRaioX += etapaX;                    posicaoRaioY += etapaY;                                                            //Descobrir posição no mapa. Se a posição na matriz for 1 então encontrou uma parede e sai do loop                    parede = this.mapa[(int)posicaoRaioX][(int)posicaoRaioY];                                                            //Aumentar distância                    distancia = distancia + 1;                                        //System.out.println("posicaoRaioX " + posicaoRaioX + "posicaoRaioY " + posicaoRaioY + " parede " + parede + " distancia " + distancia);                }                                                //Transformar distância em um bom redimensionamento para a altura da parede                int alturaParede = (int)(1024 / distancia);                                                //=====================================================//                //Desenhar LINHAS para representar o céu, parede e chão//                //=====================================================//                //Céu                //Atribuir cor azul                this.grafico.setColor(Color.CYAN);                this.grafico.drawLine(raio, 0, raio, CENTER_HEIGHT - alturaParede);                                                //Parede                //Atribuir cor dependendo do numero encontrado no mapa                this.grafico.setColor(this.cores[parede - 1]);                this.grafico.drawLine(raio, CENTER_HEIGHT - alturaParede, raio, CENTER_HEIGHT + alturaParede);                                                //Chão                //Atribuir cor cinza                this.grafico.setColor(Color.DARK_GRAY);                this.grafico.drawLine(raio, CENTER_HEIGHT + alturaParede, raio, this.HEIGHT);                                //==================//                //Incrementar Angulo//                //==================//                anguloRaio = anguloRaio + 1;            }                        //Repintar o cenário            this.repaint();                        //==========================//            //Movimentação do personagem//            //==========================//            double posicaoPersonagemAntigaX; //Para tratar colisões caso entrar em uma área do mapa que seja maior que 0, voltar             double posicaoPersonagemAntigaY; //para posição antiga                        switch(this.personagemEvento)            {                case CIMA:                    posicaoPersonagemAntigaX = posicaoPersonagemX; //Colisão                    posicaoPersonagemAntigaY = posicaoPersonagemY; //Colisão                                        //Incrementar posição para andar para frente (/ 128 para diminuir a velocidade de caminhada)                    posicaoPersonagemX += (Math.cos(this.converterAnguloRadiano((int)anguloPersonagem)) / 128);                    posicaoPersonagemY += (Math.sin(this.converterAnguloRadiano((int)anguloPersonagem)) / 128);                                        //Verificar colisão                    if(this.mapa[(int)posicaoPersonagemX][(int)posicaoPersonagemY] > 0)                    {                        posicaoPersonagemX = posicaoPersonagemAntigaX;                        posicaoPersonagemY = posicaoPersonagemAntigaY;                    }                break;                case BAIXO:                    posicaoPersonagemAntigaX = posicaoPersonagemX; //Colisão                    posicaoPersonagemAntigaY = posicaoPersonagemY; //Colisão                                        //Incrementar posição para andar para trás (/ 128 para diminuir a velocidade de caminhada)                    posicaoPersonagemX -= (Math.cos(this.converterAnguloRadiano((int)anguloPersonagem)) / 128);                    posicaoPersonagemY -= (Math.sin(this.converterAnguloRadiano((int)anguloPersonagem)) / 128);                                        //Verificar Colisão                    if(this.mapa[(int)posicaoPersonagemX][(int)posicaoPersonagemY] > 0)                    {                        posicaoPersonagemX = posicaoPersonagemAntigaX;                        posicaoPersonagemY = posicaoPersonagemAntigaY;                    }                break;                case ESQUERDA:                    //Diminuir o angulo do personagem (/ 16 para diminuir a velocidade de virada)                    anguloPersonagem -= (this.ANGULO6 / 16);                break;                case DIREITA:                    //Aumentar o angulo do personagem (/ 16 para diminuir a velocidade de virada)                    anguloPersonagem += (this.ANGULO6 / 16);                break;            }        }    }    /*     * Método para pintura da imagem (BufferedImage). "Subtituir método"     */    @[member="override"]    public void paint(Graphics g)    {        //Desenha imagem nas coordenadas x = 0, y = 0, nesta tela        g.drawImage(this.imagem, 0, 0, this);    }        /*     * Métodos para movimentação     */    @[member="override"]    public void keyTyped(KeyEvent e)     {    }    @[member="override"]    public void keyPressed(KeyEvent e)     {        //Condições para achar qual tecla foi clicada        switch(e.getKeyCode())        {            case KeyEvent.VK_UP: this.personagemEvento = CIMA; break;            case KeyEvent.VK_DOWN: this.personagemEvento = BAIXO; break;            case KeyEvent.VK_LEFT: this.personagemEvento = ESQUERDA; break;            case KeyEvent.VK_RIGHT: this.personagemEvento = DIREITA; break;        }    }    @[member="override"]    public void keyReleased(KeyEvent e)     {        //Condições para achar qual tecla foi clicada        switch(e.getKeyCode())        {            case KeyEvent.VK_UP: this.personagemEvento = PARADO; break;            case KeyEvent.VK_DOWN: this.personagemEvento = PARADO; break;            case KeyEvent.VK_LEFT: this.personagemEvento = PARADO; break;            case KeyEvent.VK_RIGHT: this.personagemEvento = PARADO; break;        }    }        /*     * Main     */    public static void main(String[] args) {        new RayCasting();            }}

    Imagens:

     

     

    rc2.png?1412049350

     

     

    rc3.png?1412049392

     

     

    Em anexo o .jar com o codigo!

     

    Referencia de aprendizado! Mais uma vez muito obrigado!

    http://www.iol.ie/~kellyswd/Patrick/raycaster/

    RayCasting.rar

    • Curtir 1
  3. Olá Pessoal do Clube do Hardware!

     

    RayCasting, uma forma de gerar um ambiente 3d a partir de uma matriz 2d. Gostaria de saber se alguém do fórum tem algum tipo de tutorial em português, ou algum mina algoritmo bem BÁSICO sobre o assunto. Estou muito interessado porém tenho certas dúvidas que não acho a resposta na internet. As explicações são um pouco complicadas más estou procurando muito a respeito. Alguns requisitos que estou atrás é o conhecimento da trigonometria que é essencial para o desenvolvimento e lógica de rayCasting. Já estou me adaptando e tive algumas lógicas bem interessantes para um bom início. 

     

    O que peço para vocês é que me mandem link de algum tutorial básico, algum exemplo como um programa java com o source disponível. Estou apenas atrás de conhecimento até conseguir desenvolver meu primeiro rayCasting.

     

    Procuro algo básico, pois o assunto trata diversas coisas como por exemplo, o "lighting" ou seja, a luminosidade de diversos pontos deste pseudo-3d. Más isto já vejo como avançado. O que quero é apenas construir uma matriz onde irei utilizar como mapa, criar um ângulo de raios para formar o campo de visão e renderizar os pontos onde estes raios entram em conflito com os pontos da matriz (paredes), e assim, criar o psudo-3d em um canvas (java).

     

    Sobre RayCasting: Posso dizer que é uma forma de tornar um mapa em uma visão 3d, ou melhor, com aparência 3d. digamos que tenhamos uma matriz de inteiros onde servirá como mapa:

    int[][] mapa = new int[][]{

    {2,2,2,2,2},

    {0,0,0,0,0},

    {0,0,1,0,0},

    {0,0,0,0,0},

    {0,0,0,0,0}};

     

    Os pontos 2 definimos como as paredes e o ponto 1, o personagem. O intuito é realizar o lançamento de raios em um certo ângulo de visão do personagem para verificar a distância de colisão da parede (2);

    Simple_raycasting_with_fisheye_correctio

     

    Quando o raio entra em colisão com a parede, é calculada a distância entre a posição do personagem com a parede. Podemos utilizar a trigonometria para calcular esta distância com o teorema de pitágoras.  (hipotenusa)

     

    Nesta imagem, percebe-se que existe algum efeito de luminosidade onde seria mais um complemento pro aprendizado. O que quero por exemplo é algo simples, como um algoritmo java tendo uma matriz, alguns métodos de calculo da distancia e etc e a renderização da matriz em um canvas. Algo básico como:

    raycaster101.png

     

    Pode ver que é bem simples para um bom começo :). Veja que não tem efeitos de luminosidade e textura, apenas o chateado raycasting. 

    Não possui uma grid sendo "floor", teto ou chão, apenas as paredes. No caso, o cháo é apenas uma pintura verde até o centro da tela e o azul é mesma coisa. 

    Após o conhecimento, irei aprimorar futuramente:

    raycaster201.png

     

    Esta imagem já contém algumas sombras e etc... 

     

    Já procurei muito na internet e achei na maioria tutoriais em inglês. Aprendi algo com eles, más é um tanto complicado de entender pelo volume de código que existe, pois os tutoriais na maioria das vezes ensinam a aplicar texturar e luminosidade e etc... Já outros utilizam outras linguagens como javascript e C++ porém gostaria de tratar isto com java.

     

    Já criei algum software para tentar entender um pouco do assunto e estou disponibilizando os métodos principais dele abaixo, junto com alguns comentários. É bem básico pois não existe algum tipo de angulação para movimentação e nova leitura de pontos para formação pseudo-3d. O algoritmo apenas realiza uma varredura da matriz (mapa) e procura por uma parede (2). Ao encontrar, ele calcula a hipotenusa das cordenadas da parede até com as cordenadas do personagem. Tendo esta hipotenusa, é definido o tamanho de um retângulo no canvas. Se a distancia é grande (longe), o retângulo é pequeno. Se a distancia é pequena (perto), o retângulo é grande.

     

    Aqui defino meus atributos e o mapa:

    public class Janela extends Canvas implements Runnable{        int[] pixelsFundo;    private BufferedImage img;    private int[][] mapa = new int[][]{ {2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,0,0,0,0,0,0},                                        {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},                                        {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},                                        {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2},                                        {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},                                        {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},                                        {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},                                        {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},                                            {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},                                        {0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0},                                        {0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0},                                        {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},                                        {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},                                        {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},                                        {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},                                        {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},                                        {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},                                        {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},                                        {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},                                        {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},                                        {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},                                        {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};    private int jogadorX = 11;    private int jogadorY = 11;        public Janela()    {        this.img = new BufferedImage(800, 300, BufferedImage.TYPE_INT_RGB);        this.pixelsFundo = ((DataBufferInt)img.getRaster().getDataBuffer()).getData();    }

    Este é o método de renderização no canvas, onde ele irá desenhas os retângulos no componente:

    Os parâmetros são a largura, altura e posição x, y do retângulo gerado no método calcular:

    public void render(int xPos, int yPos,int x, int y)    {        BufferStrategy bs = this.getBufferStrategy();        if(bs == null)        {            this.createBufferStrategy(2);            bs = this.getBufferStrategy();        }                Graphics g = bs.getDrawGraphics();        g.drawRect(xPos,yPos,x, y);        g.dispose();        bs.show();    }

    Este é o método de calculo. Ele que defini a distância da parede na matriz e gera um tamanho e posição para renderização dos retângulos:

    public void calcular()    {        //Posição x da parede        int posicaoX = 0;        int tamanhoParede = 35;        int alturaParede = 250;                //Varrer Mapa        for(int y = 0; y < mapa.length; y++)        {            //PosicaoX = 0 para colocar p´roxima coluna de paredes             posicaoX = 0;                        for(int x = 0; x < mapa.length; x++)            {                //Verificar se é parede                if(mapa[y][x] == 2)                {                    //Calcular Hipotenusa                    double catetoOposto = this.jogadorY - y;                    double catetoAdjacente = this.jogadorX - x;                    double hipotenusa = (catetoOposto * catetoOposto) + (catetoAdjacente * catetoAdjacente);                                        //Deixar Hipotenusa sempre positivo                    if(hipotenusa < 0)                    {                        hipotenusa = hipotenusa * -1;                    }                                        //Diminuir valor da hipotenusa                    hipotenusa = hipotenusa * 0.18;                                        //Imprimir Hipotenusa                    System.out.println("Hipotenusa: " + hipotenusa);                                        //Definir altura da parede                    int alturaParedeView = (int)(alturaParede - (hipotenusa*5));                                        //Definir posicao Y para colocar parede                    int posicaoY = (int)(300 - alturaParedeView/2);                                        //Desenhar Paredes                    this.render(posicaoX, posicaoY, tamanhoParede, alturaParedeView);                }                                //Incrementar posicao conforme tamanho do retangulo e tamanho da tela                //800 / 23 ~= 35                posicaoX += tamanhoParede;            }        }    }

    Este é um exemplo de saida do programa:

    2mh5v0l.jpg

     

    Isto é básico e programei para dar início. 

     

    Anexei o código todo a este tópico se quiserem dar uma olhada. 

     

    Pois bem gente um breve resumo:

    Gostaria de um bom tutorial ou algo que possa ensinar a programar o raycasting como por exemplo, um algoritmo pronto, básico onde so tenha a renderização das paredes e a lógica do raycasting, sem essas frescuras de luminosidade, sombra, texturas, chão, teto e etc... Como mencionei, BÁSICO. Sei que o assunto é um pouco avançado mais nem tanto quanto parece, aliás, estamos lidando com pseudo-3d, um 3d de mentira ;). Pessoal, espero que me ajudem, sou novo aqui no fórum e desculpe se publiquei algo incorretamente. Obrigado por tudo!

     

    Linguagem que utilizo: JAVA

    Cursando: Ciências da Computação.

     

    Curiosidades: O Ray casting foi utilizado no primeiro jogo em pseudo-3d da história, o Wolfstein 3d. 

    shot1.jpg

    RayCasting.rar

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

Ebook grátis: Aprenda a ler resistores e capacitores!

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!