Code Monkey home page Code Monkey logo

texture-spaceship-opengl's Introduction

GitHub language count Repository size Application Status GitHub last commit License Stargazers

space

NextJs + opengl

texture-spaceship-opengl

Nave com OpenGl

Explorando o uso de texturas no OpenGL com Python.


Sobre ℹ️

O trabalho tem como objetivo fazer o uso da biblioteca pyopenGL para a criação de um sólido de nossa escolha (no nossa caso uma nave) para realizar as operações de translação, rotação e escalonamento

As orientações estão divididas nos seguintes tópicos:


Funcionalidades ⚙️

  • Mover nave nos eixos (X,Y);
  • Rotaciona a nave nos eixos (X,Y);
  • Rotaciona nave no eixo Z;
  • Move câmera cima/baixo;
  • Move câmera esquerda/direita;
  • Move câmera frente/trás;
  • Aumenta/diminui escala da nave;

Etapas

O projeto possui o arquivo -main.py que é responsável por inicializar a aplicação, em conjunto com um pseudo MVC, composto pelos arquivos view.py (responsável por renderizar os componentes, sendo eles o ambiente e a nave), controller.py (responsável por receber as teclas pressionadas do teclado e aplicar as transformações ao sólido) e por fim o model.py (onde é definido 2 classes, uma que representa a nave e outra que representa o chão)

Construção da View Nave - Polígono

  • A nave é uma matriz que forma o polígono de uma pirâmide de base triangular e as asas são dois triângulos planos;

  • Para evitar a definição de várias matrizes para cada triângulo, apenas uma matriz estrutural principal é utilizada e os índices são utilizados para construir o polígono com triângulos;

  • As linhas também foram adicionadas com largura maior para ressaltar as arestas;

  • O processo de renderização apenas da nave é:

    • Definir a geometria;
    def create_geometry(self):
        # Pontos no espaço
        self.vertices = [
            [0.0, 1.0, 0.0],   # Topo
            [-1.0, -1.0, 1.0], # Frente esquerda
            [1.0, -1.0, 1.0],  # Frente direita
            [1.0, -1.0, -1.0], # Traseira direita
            [-1.0, -1.0, -1.0] # Traseira esquerda
        ]
        # Ligar os pontos
        self.indices = [
            0, 1, 2,
            0, 2, 3,
            0, 3, 4,
            0, 4, 1,
            1, 2, 3,
            1, 3, 4
        ]
        # Textura
        self.tex_coords = [
            [0.5, 1.0], # Topo
            [0.0, 0.0], # Frente esquerda
            [1.0, 0.0], # Frente direita
            [1.0, 1.0], # Traseira direita
            [0.0, 1.0]  # Traseira esquerda
        ]
        # Linhas
        self.edges = [
            [0, 1], [0, 2], [0, 3], [0, 4],
            [1, 2], [2, 3], [3, 4], [4, 1]
        ]
    • Criar instância da nave;
    • Renderizar na View (pirâmide, textura e linhas).
    def render_spacecraft(self):
        glBindTexture(GL_TEXTURE_2D, self.spacecraft_texture_id)
        glPushMatrix()
        glTranslatef(*self.spacecraft.position)
        glRotatef(self.spacecraft.rotation[0], 1.0, 0.0, 0.0)
        glRotatef(self.spacecraft.rotation[1], 0.0, 1.0, 0.0)
        glRotatef(self.spacecraft.rotation[2], 0.0, 0.0, 1.0)
        glScalef(*self.spacecraft.scale)
    
        glBegin(GL_TRIANGLES)
        for i in range(0, len(self.spacecraft.indices), 3):
            for j in range(3):
                glTexCoord2f(*self.spacecraft.tex_coords[self.spacecraft.indices[i + j]])
                vertex = self.spacecraft.vertices[self.spacecraft.indices[i + j]]
                glVertex3f(*vertex)
        glEnd()
    
        glLineWidth(4.0)
        glColor3f(1.0, 0.0, 0.0)
        glBegin(GL_LINES)
        for edge in self.spacecraft.edges:
            for vertex in edge:
                glVertex3f(*self.spacecraft.vertices[vertex])
        glEnd()
        glColor3f(1.0, 1.0, 1.0)
        glPopMatrix()

Textura da Nave

  • A aplicação de textura envolve o uso de coordenadas de textura (UV mapping), que mapeiam uma imagem de textura aos vértices do objeto 3D;

  • Cada face do triângulo recebe a mesma textura;

  • As transformações aplicadas à nave (translação, rotação e escala) são aplicadas à matriz de modelagem. Em OpenGL, essas transformações afetam todas as operações de desenho subsequentes, incluindo as coordenadas de vértice e as coordenadas de textura.

  • É feito um bind da textura com glBindTexture(GL_TEXTURE_2D, self.spacecraft_texture_id), vale ressaltar que com o bind das cordenadas de textura 2D as operações de glTranslatef, glRotatef e glScalef também serão aplicadas para textura conforme texto supracitado.

  • O processo de renderização da nave com textura é:

    • Renderização padrão da nave;
    • Bind de textura;
    • Definir as matrizes de tranformação;
      glPushMatrix()
      glTranslatef(*self.spacecraft.position)
      glRotatef(self.spacecraft.rotation[0], 1.0, 0.0, 0.0)
      glRotatef(self.spacecraft.rotation[1], 0.0, 1.0, 0.0)
      glRotatef(self.spacecraft.rotation[2], 0.0, 0.0, 1.0)
      glScalef(*self.spacecraft.scale)
    • Renderizar com as coordenadas de textura
      glBegin(GL_TRIANGLES)
      for i in range(0, len(self.spacecraft.indices), 3):
          for j in range(3):
              glTexCoord2f(*self.spacecraft.tex_coords[self.spacecraft.indices[i + j]])
              vertex = self.spacecraft.vertices[self.spacecraft.indices[i + j]]
              glVertex3f(*vertex)
      glEnd()

Construção da View Chão - Plano 2D

  • O chão consiste uma matriz que forma um quadrado plano a partir de dois triângulos;

  • O processo de renderização do chão é:

    • Definir a geometria;
    class Ground:
        def __init__(self):
            # Vértices no espaço
            self.vertices = np.array([
                [-40.0, -8.0, -40.0],
                [40.0, -8.0, -40.0],
                [40.0, -8.0, 40.0],
                [-40.0, -8.0, 40.0]
            ], dtype=np.float32)
    
            # Indices dos vértices para ligar os pontos e formar os triângulos
            self.indices = np.array([
                0, 1, 2,
                2, 3, 0
            ], dtype=np.uint32)
    
            # Textura
            self.tex_coords = np.array([
                [0.0, 0.0],
            ])
    • Criar instância do chão;
    • Renderizar na View (plano e textura).
    def render_ground(self):
          glBindTexture(GL_TEXTURE_2D, self.ground_texture_id)
          glPushMatrix()
          glBegin(GL_QUADS)
          for i, vertex in enumerate(self.ground.vertices):
              glTexCoord2f((i % 2) + self.ground_texture_offset, (i // 2) + self.ground_texture_offset)
              glVertex3f(*vertex)
          glEnd()
          glPopMatrix()

Textura do chão

  • A textura do chão é formada a partir da imagem space.png, que é carregada e aplicada objeto

  • É feito um bind da textura com glBindTexture(GL_TEXTURE_2D, self.ground_texture_id)

  • O processo de renderização do chão com textura é:

    • Renderização padrão do chão;
    • Bind de textura;
    • Renderizar com as coordenadas de textura
      glPushMatrix()
      glBegin(GL_QUADS)
      for i, vertex in enumerate(self.ground.vertices):
          glTexCoord2f((i % 2) + self.ground_texture_offset, (i // 2) + self.ground_texture_offset)
          glVertex3f(*vertex)
      glEnd()
      glPopMatrix()

Controles da Nave

O código controlller.py é responsável pela movimentação da nave. através da classe Controller, o método process_input() é responsável por fazer todas as tranformações de escala, rotação e translação do modelo.

Movimentação do Modelo
  • W / S / A / D: Movimentam o modelo para cima, baixo, esquerda e direita, respectivamente, alterando suas coordenadas de transladação no plano XY.
Rotação do Modelo
  • Setas Direcionais (↑ / ↓ / ← / →): Rotacionam o modelo ao redor dos eixos X e Y. As teclas de setas para cima e para baixo controlam a rotação em torno do eixo X, enquanto as teclas para esquerda e direita controlam a rotação em torno do eixo Y.
  • Q / E: Rotacionam o modelo ao redor do eixo Z, com a tecla Q para rotação no sentido anti-horário e a tecla E para rotação no sentido horário.
Movimentação da Câmera
  • I / K / J / L / U / O: Movem a posição da câmera. As teclas I e K controlam o movimento vertical da câmera, J e L controlam o movimento horizontal, e U e O controlam o movimento na profundidade (zoom) da câmera.
Escala do Modelo
  • = (igual) / - (traço): Aumentam e diminuem a escala do modelo. A tecla = aumenta a escala em todas as direções (x, y, z), enquanto a tecla - diminui a escala, mantendo um valor mínimo de escala de 0.1 para cada eixo.

Este controlador permite uma interação dinâmica com a cena 3D, oferecendo controle sobre o modelo e a visualização através da câmera, facilitando a navegação e manipulação do ambiente virtual criado com OpenGL.

Código do controlller.py:

O código do controller é quem define que ações serão feitas com base na tecla que for pressionada, centralizando todas as ações,assim chamando as funções de rotação, translação ou escala no model ou alterando a posição da câmera na view.

No model:

As funções abaixo são definidas no model e são responsáveis pela escala, translação e rotação do modelo.

def translate(self, dx, dy, dz):
        self.position += np.array([dx, dy, dz], dtype=np.float32)

    def rotate(self, angle, axis):
        self.rotation += np.array(angle) * np.array(axis)

    def scale(self, sx, sy, sz):
        self.scale *= np.array([sx, sy, sz], dtype=np.float32)

Na view:

Para a movimentaçã oda câmera, a variavel camera_position é alterada.

class View:
    def __init__(self, spacecraft, ground, spacecraft_texture_path, ground_texture_path):
        self.spacecraft = spacecraft
        self.ground = ground
        self.spacecraft_texture_path = spacecraft_texture_path
        self.ground_texture_path = ground_texture_path
        self.camera_position = [0.0, 2.0, 25.0]
        self.camera_target = [0.0, 0.0, 0.0]
        self.camera_up = [0.0, 1.0, 0.0]
        self.spacecraft_texture_id = None
        self.ground_texture_id = None
        self.ground_texture_offset = 0.0

Animação do Chão

Para fazer a animação do chão, foi se utilizado uma estratégia utilizando o tempo, conforme o tempo passa a textura é renderizada em uma posição, dessa maneira dando a impressao de que o chão, no caso as estrelas, estão se movendo.

Função update_ground_texture_offset

A função update_ground_texture_offset(self, delta_time) é responsável por atualizar o deslocamento da textura do chão ao longo do tempo. Ela recebe delta_time, que representa o tempo decorrido desde a última atualização, e utiliza esse valor para calcular o novo deslocamento da textura:

def update_ground_texture_offset(self, delta_time):
    self.ground_texture_offset += delta_time * 0.01  # velocidade animação do chão

A variável self.ground_texture_offset armazena a posição atual da textura do chão. Multiplicando delta_time por 0.01, a função define a velocidade da animação do chão.

Função render_ground

A função render_ground(self) desenha o chão na cena utilizando OpenGL. Ela vincula a textura do chão (self.ground_texture_id) e utiliza self.ground_texture_offset para aplicar o deslocamento na textura:

def render_ground(self):
    glBindTexture(GL_TEXTURE_2D, self.ground_texture_id)
    glPushMatrix()
    glBegin(GL_QUADS)
    for i, vertex in enumerate(self.ground.vertices):
        glTexCoord2f((i % 2) + self.ground_texture_offset, (i // 2) + self.ground_texture_offset)
        glVertex3f(*vertex)
    glEnd()
    glPopMatrix()

glBindTexture(GL_TEXTURE_2D, self.ground_texture_id): Vincula a textura do chão para uso.

glTexCoord2f((i % 2) + self.ground_texture_offset, (i // 2) + self.ground_texture_offset): Define as coordenadas de textura para cada vértice do chão, aplicando o deslocamento (self.ground_texture_offset) para criar a ilusão de movimento da textura.

Função render

A função render(self) é o ponto de entrada para renderizar a cena completa. Ela é chamada repetidamente para atualizar e desenhar todos os elementos na janela OpenGL:

def render(self):
    current_time = time.time()
    if not hasattr(self, 'last_time'):
        self.last_time = current_time
    delta_time = current_time - self.last_time
    self.last_time = current_time

    self.update_ground_texture_offset(delta_time)

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    glLoadIdentity()
    gluLookAt(
        self.camera_position[0], self.camera_position[1], self.camera_position[2],
        self.camera_target[0], self.camera_target[1], self.camera_target[2],
        self.camera_up[0], self.camera_up[1], self.camera_up[2]
    )

    self.render_ground()
    self.render_spacecraft()
    self.render_commands()

    glfw.swap_buffers(self.window)

self.update_ground_texture_offset(delta_time): Chama a função de atualização para mover a textura do chão com base no tempo decorrido desde o último quadro (delta_time).

self.render_ground(): Renderiza o chão na posição atualizada, aplicando o deslocamento da textura conforme calculado em update_ground_texture_offset.

glfw.swap_buffers(self.window): Troca os buffers para exibir a cena renderizada na janela.

Essas funções trabalham juntas para criar uma animação contínua e fluida da textura do chão, proporcionando um efeito visual dinâmico à cena 3D renderizada com OpenGL.

Configuração de ambiente

# Clone o repo
git clone https://github.com/MatMB115/texture-spaceship-opengl.git

# Acessar path
cd texture-spaceship-opengl

# Crie o env python
python -m venv nave_env

# Ativar o enviroment
source nave_env/bin/activate

# Instale as depedências
pip install -r requirements.txt

# Executar o projeto
python main.py

# Desativar o env
deactivate

Tecnologias 🧑‍💻

O ponto de início deste projeto é um enviroment python, as dependências utilizadas estão presentes no requirements.txt.

Aplicação

glfw==2.7.0

numpy==1.26.4

pillow==10.3.0

PyOpenGL==3.1.7


Utilitários

Visual Studio Code 1.89.1


Contribuidores


Bruno Vercelli

🧑‍💻

Gabriel Ciriaco

🧑‍💻

Luiz Fernando

🧑‍💻

Matheus Martins

🧑‍💻

texture-spaceship-opengl's People

Contributors

matmb115 avatar lfseibel avatar gabrielciriaco avatar bjmvercelli avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.