python - pygames - glDrawElements para dibujar un cubo en PyOpenGL
python opengl mac (1)
Recientemente comencé a aprender OpenGL a través de Python gracias a varios tutoriales (especialmente el de Nicolas P. Rougier: http://www.labri.fr/perso/nrougier/teaching/opengl/ ).
Ahora estoy cambiando a 3D y estoy tratando de dibujar un cubo.
Por lo tanto, logro obtener algunos triángulos que no generan un cubo (esto parece ser normal ya que no duplico mis vértices y uso la función glDrawArrays).
Sin embargo, después, construyo un "vector" de índice para seguir usando la función glDrawElements para renderizar mi cubo. Como resultado, no aparece ningún error, pero no aparece nada en la pantalla.
¡Espero que puedas ser de alguna ayuda!
Aquí está mi código:
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import ctypes
import numpy as np
import OpenGL.GL as gl
import OpenGL.GLUT as glut
vertex_code = """
uniform float scale;
uniform mat4 matCam;
attribute vec4 color;
attribute vec3 position;
varying vec4 v_color;
void main()
{
gl_Position = matCam*vec4(scale*position, 1.0);
v_color = color;
} """
fragment_code = """
varying vec4 v_color;
void main()
{
gl_FragColor = v_color;
} """
def display():
gl.glClear(gl.GL_COLOR_BUFFER_BIT)
#gl.glDrawArrays(gl.GL_TRIANGLES, 0, 12)
gl.glDrawElements(gl.GL_TRIANGLES, len(index), gl.GL_UNSIGNED_INT, index) # render nothing (i.e. only the background color)
glut.glutSwapBuffers()
def reshape(width,height):
gl.glViewport(0, 0, width, height)
def keyboard( key, x, y ):
if key == ''/033'':
sys.exit( )
def timer(fps):
global clock
clock += 0.0005*1000.0/fps
print(clock)
# eye = np.array([0,0,1])
# center = np.array([0,clock,0])
# up = np.array([0,1,0])
# mat = computeLookAtMatrix(eye, center, up)
theta = clock;
mat = np.array([[np.cos(theta), 0, np.sin(theta), 0],
[0, 1, 0, 0],
[-np.sin(theta), 0, np.cos(theta), 0],
[0, 0, 0, 1]])
loc = gl.glGetUniformLocation(program, "matCam")
gl.glUniformMatrix4fv(loc, 1, False, mat)
glut.glutTimerFunc(1000/fps, timer, fps)
glut.glutPostRedisplay()
# GLUT init
# --------------------------------------
glut.glutInit()
glut.glutInitDisplayMode(glut.GLUT_DOUBLE | glut.GLUT_RGBA)
glut.glutCreateWindow(''Hello world!'')
glut.glutReshapeWindow(512,512)
glut.glutReshapeFunc(reshape)
glut.glutDisplayFunc(display)
glut.glutKeyboardFunc(keyboard)
glut.glutTimerFunc(1000/60, timer, 60)
# Build data
# --------------------------------------
data = np.zeros(8, [("position", np.float32, 3),
("color", np.float32, 4)])
data[''color''] = [ (1,0,0,1), (0,1,0,1), (0,0,1,1), (1,1,0,1),
(1,0,0,1), (0,1,0,1), (0,0,1,1), (1,1,0,1) ]
data[''position''] = [ (-1,-1,1),
(1,-1,1),
(1,1,1),
(-1,1,1),
(-1,-1,-1),
(1,-1,-1),
(1,1,-1),
(-1,1,-1)]
index = np.array([0,1,2,
2,3,0,
1,5,6,
6,2,1,
7,6,5,
5,4,7,
4,0,3,
3,7,4,
4,5,1,
1,0,4,
3,2,6,
6,7,3])
# Build & activate program
# --------------------------------------
# Request a program and shader slots from GPU
program = gl.glCreateProgram()
vertex = gl.glCreateShader(gl.GL_VERTEX_SHADER)
fragment = gl.glCreateShader(gl.GL_FRAGMENT_SHADER)
# Set shaders source
gl.glShaderSource(vertex, vertex_code)
gl.glShaderSource(fragment, fragment_code)
# Compile shaders
gl.glCompileShader(vertex)
gl.glCompileShader(fragment)
# Attach shader objects to the program
gl.glAttachShader(program, vertex)
gl.glAttachShader(program, fragment)
# Build program
gl.glLinkProgram(program)
# Get rid of shaders (no more needed)
gl.glDetachShader(program, vertex)
gl.glDetachShader(program, fragment)
# Make program the default program
gl.glUseProgram(program)
# Build buffer
# --------------------------------------
# Request a buffer slot from GPU
buffer = gl.glGenBuffers(1)
# Make this buffer the default one
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, buffer)
# Upload data
gl.glBufferData(gl.GL_ARRAY_BUFFER, data.nbytes, data, gl.GL_DYNAMIC_DRAW)
# same for index buffer
buffer_index= gl.glGenBuffers(1)
gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, buffer_index)
gl.glBufferData(gl.GL_ELEMENT_ARRAY_BUFFER, index.nbytes, index, gl.GL_STATIC_DRAW)
# Bind attributes
# --------------------------------------
stride = data.strides[0]
offset = ctypes.c_void_p(0)
loc = gl.glGetAttribLocation(program, "position")
gl.glEnableVertexAttribArray(loc)
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, buffer)
gl.glVertexAttribPointer(loc, 3, gl.GL_FLOAT, False, stride, offset)
offset = ctypes.c_void_p(data.dtype["position"].itemsize)
loc = gl.glGetAttribLocation(program, "color")
gl.glEnableVertexAttribArray(loc)
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, buffer)
gl.glVertexAttribPointer(loc, 4, gl.GL_FLOAT, False, stride, offset)
gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, buffer_index)
# Bind uniforms
# --------------------------------------
loc = gl.glGetUniformLocation(program, "scale")
gl.glUniform1f(loc, 0.5)
clock = 0
loc = gl.glGetUniformLocation(program, "matCam")
print(loc)
gl.glUniformMatrix4fv(loc, 1, False, np.eye(4))
# Enter mainloop
# --------------------------------------
glut.glutMainLoop()
gl.glDrawElements(gl.GL_TRIANGLES, len(index), gl.GL_UNSIGNED_INT, index)
El argumento de índice tiene dos significados diferentes dependiendo de si un ELEMENT_ARRAY_BUFFER
está vinculado o no:
- If no bound: Luego especifica un puntero a la memoria del cliente donde se almacenan los índices
- Si un
ELEMENT_ARRAY_BUFFER
está vinculado, entonces el parámetro de índice especifica un desplazamiento en este búfer. Esto define dónde comienzan los índices en el búfer.
En su caso, un buffer está vinculado, por lo que le dice a OpenGL que comience en algún lugar del buffer. Pero lo que desea es comenzar al principio del búfer, por lo tanto, debe establecer el índice en 0.
gl.glDrawElements(gl.GL_TRIANGLES, len(index), gl.GL_UNSIGNED_INT, ctypes.c_void_p(0))