I'm really new to this community. I'm sorry for any mistakes in advance.I'm making a game like minecraft with GLFW and OpenGL. The problem is, it just renders three faces correctly and the other faces have a wierd glitch. Here is my code:
main.py
# imports
import glfw
from OpenGL.GL import *
from OpenGL.GLU import *
# internal imports
from core.renderer import *
from player import *
if not glfw.init():
raise Exception("glfw can not be initialized!")
window = glfw.create_window(800, 500, "PyCraft", None, None)
glfw.make_context_current(window)
renderer = TerrainRenderer(window)
player = Player(window)
renderer.texture_manager.add_from_folder("assets/textures/block/")
renderer.texture_manager.save("atlas.png")
renderer.texture_manager.bind()
glEnable(GL_DEPTH_TEST)
glEnable(GL_CULL_FACE)
glCullFace(GL_BACK)
glEnable(GL_FOG)
glFogfv(GL_FOG_COLOR, (GLfloat * int(8))(0.5, 0.69, 1.0, 10))
glHint(GL_FOG_HINT, GL_DONT_CARE)
glFogi(GL_FOG_MODE, GL_LINEAR)
glFogf(GL_FOG_START, 30)
glFogf(GL_FOG_END, 100)
# get window size
def get_window_size():
width, height = glfw.get_window_size(window)
return width, height
def _setup_3d():
w, h = get_window_size()
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(70, w / h, 0.1, 1000)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
def _update_3d():
_setup_3d()
glViewport(0, 0, *get_window_size())
def add_cube(x, y, z):
X, Y, Z = x + 1, y + 1, z + 1
renderer.add((x, Y, Z, X, Y, Z, X, Y, z, x, Y, z), renderer.texture_manager.get_texture("grass"))
renderer.add((x, y, z, X, y, z, X, y, Z, x, y, Z), renderer.texture_manager.get_texture("grass"))
renderer.add((x, y, z, x, y, Z, x, Y, Z, x, Y, z), renderer.texture_manager.get_texture("grass"))
renderer.add((X, y, Z, X, y, z, X, Y, z, X, Y, Z), renderer.texture_manager.get_texture("grass"))
renderer.add((x, y, Z, X, y, Z, X, Y, Z, x, Y, Z), renderer.texture_manager.get_texture("grass"))
renderer.add((X, y, z, x, y, z, x, Y, z, X, Y, z), renderer.texture_manager.get_texture("grass"))
add_cube(0, 0, -2)
# mainloop
while not glfw.window_should_close(window):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
_update_3d()
glClearColor(0.5, 0.7, 1, 1.0)
player.update()
renderer.render()
glfw.poll_events()
glfw.swap_buffers(window)
glfw.terminate()
renderer.py:
# imports
import glfw
from OpenGL.GL import *
from ctypes import *
from core.texture_manager import *
import threading
import numpy as np
from core.logger import *
glfw.init()
class TerrainRenderer:
def __init__(self, window):
self.event = threading.Event()
self.to_add = []
self._len = 0
self.parent = window
self.vertices = []
self.texCoords = []
self.create_vbo(window)
self.texture_manager = TextureAtlas()
glEnable(GL_TEXTURE_2D)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glEnableClientState(GL_TEXTURE_COORD_ARRAY)
glEnableClientState (GL_VERTEX_ARRAY)
def shared_context(self, window):
glfw.window_hint(glfw.VISIBLE, glfw.FALSE)
window2 = glfw.create_window(500,500, "Window 2", None, window)
glfw.make_context_current(window2)
self.event.set()
while not glfw.window_should_close(window):
if len(self.to_add) > 0:
i = self.to_add.pop(0)
vertices = np.array(i[0], dtype=np.float32)
texture_coords = np.array(i[1], dtype=np.float32)
bytes_vertices = vertices.nbytes
bytes_texCoords = texture_coords.nbytes
verts = (GLfloat * len(vertices))(*vertices)
texCoords = (GLfloat * len(texture_coords))(*texture_coords)
log_vertex_addition((vertices, texture_coords), (bytes_vertices, bytes_texCoords), self._len*4, len(self.to_add))
glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
glBufferSubData(GL_ARRAY_BUFFER, self._len, bytes_vertices, verts)
glVertexPointer (3, GL_FLOAT, 0, None)
glFlush()
glBindBuffer(GL_ARRAY_BUFFER, self.vbo_1)
glBufferSubData(GL_ARRAY_BUFFER, self._len, bytes_texCoords, texCoords)
glTexCoordPointer(2, GL_FLOAT, 0, None)
glFlush()
glVertexPointer(3, GL_FLOAT, 0, None)
glTexCoordPointer(3, GL_FLOAT, 0, None)
self.vertices += i[0]
self.texCoords += i[1]
self._len += bytes_vertices
glfw.poll_events()
glfw.swap_buffers(window2)
glfw.terminate()
def create_vbo(self, window):
self.vbo, self.vbo_1 = glGenBuffers (2)
glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
glBufferData(GL_ARRAY_BUFFER, 64000000, None, GL_STATIC_DRAW)
glBindBuffer(GL_ARRAY_BUFFER, self.vbo_1)
glBufferData(GL_ARRAY_BUFFER, 64000000, None, GL_STATIC_DRAW)
glfw.make_context_current(None)
thread = threading.Thread(target=self.shared_context, args=[window], daemon=True)
thread.start()
self.event.wait()
glfw.make_context_current(window)
def add(self, vertices, texCoords):
self.to_add.append((tuple(vertices), tuple(texCoords)))
def render(self):
glClear (GL_COLOR_BUFFER_BIT)
glEnable(GL_TEXTURE_2D)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glBindBuffer (GL_ARRAY_BUFFER, self.vbo)
glVertexPointer (3, GL_FLOAT, 0, None)
glBindBuffer(GL_ARRAY_BUFFER, self.vbo_1)
glTexCoordPointer(2, GL_FLOAT, 0, None)
glDrawArrays (GL_QUADS, 0, self._len)
glDisable(GL_TEXTURE_2D)
glDisable(GL_BLEND)
Output
It is expected that all faces of the above cube are lime.
Right now, it shows no errors, but it does not render the cube properly. The attached GIF explains what I mean.
When I use this code in renderer.py, it works just fine!
# imports
import glfw, numpy
from OpenGL.GL import *
from ctypes import *
from core.texture_manager import *
glfw.init()
class VBOManager:
def __init__(self, renderer):
self.renderer = renderer
self.run()
def run(self):
for i in self.renderer.to_add[:self.renderer.to_add_count]:
self.renderer.vertices.extend(i[0])
self.renderer.texCoords.extend(i[1])
self.renderer.to_add.remove(i)
glBindBuffer(GL_ARRAY_BUFFER, self.renderer.vbo)
glBufferData(GL_ARRAY_BUFFER, len(self.renderer.vertices) * 4, (c_float * len(self.renderer.vertices))(*self.renderer.vertices), GL_STATIC_DRAW)
glFlush()
glVertexPointer(3, GL_FLOAT, 0, None)
glTexCoordPointer(3, GL_FLOAT, 0, None)
glBindBuffer(GL_ARRAY_BUFFER, self.renderer.vbo_1)
glBufferData(GL_ARRAY_BUFFER, len(self.renderer.texCoords) * 4, (c_float * len(self.renderer.texCoords))(*self.renderer.texCoords), GL_STATIC_DRAW)
glFlush()
class TerrainRenderer:
def __init__(self, window):
self.window = window
self.vertices = []
self.texCoords = []
self.to_add = []
self.to_add_count = 256
self.vbo, self.vbo_1 = glGenBuffers (2)
glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
glBufferData(GL_ARRAY_BUFFER, 12 * 4, None, GL_STATIC_DRAW)
self.vbo_manager = VBOManager(self)
self.texture_manager = TextureAtlas()
glEnable(GL_TEXTURE_2D)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glEnableClientState(GL_TEXTURE_COORD_ARRAY)
glEnableClientState (GL_VERTEX_ARRAY)
def render(self):
try:
self.vbo_manager.run()
except RuntimeError:
pass
glClear (GL_COLOR_BUFFER_BIT)
glEnable(GL_TEXTURE_2D)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glBindBuffer (GL_ARRAY_BUFFER, self.vbo)
glVertexPointer (3, GL_FLOAT, 0, None)
glBindBuffer(GL_ARRAY_BUFFER, self.vbo_1)
glTexCoordPointer(2, GL_FLOAT, 0, None)
glDrawArrays (GL_QUADS, 0, len(self.vertices))
glDisable(GL_TEXTURE_2D)
glDisable(GL_BLEND)
def add(self, posList, texCoords):
self.to_add.append((numpy.array(posList), numpy.array(texCoords)))
def update_vbo(self):
pass
Why does this code work and not the previous one? Have I missed something?
Any help will be highly appreciated.
I noticed that texCoords have two elements per vertex and vertices have three. So I created a self._len_
variable in the TerrainRenderer
class to count the texCoord length separately. Here is my code for TerrainRenderer
:
class TerrainRenderer:
def __init__(self, window):
self.event = threading.Event()
self.to_add = []
self._len = 0
self._len_ = 0 # CHANGED
self.parent = window
self.vertices = []
self.texCoords = []
self.create_vbo(window)
self.texture_manager = TextureAtlas()
glEnable(GL_TEXTURE_2D)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
if not USING_RENDERDOC:
glEnableClientState(GL_VERTEX_ARRAY)
glEnableClientState(GL_TEXTURE_COORD_ARRAY)
def shared_context(self, window):
glfw.window_hint(glfw.VISIBLE, glfw.FALSE)
window2 = glfw.create_window(500,500, "Window 2", None, window)
glfw.make_context_current(window2)
self.event.set()
while not glfw.window_should_close(window):
if len(self.to_add) > 0:
i = self.to_add.pop(0)
vertices = np.array(i[0], dtype=np.float32)
texture_coords = np.array(i[1], dtype=np.float32)
bytes_vertices = vertices.nbytes
bytes_texCoords = texture_coords.nbytes
verts = (GLfloat * len(vertices))(*vertices)
texCoords = (GLfloat * len(texture_coords))(*texture_coords)
log_vertex_addition((vertices, texture_coords), (bytes_vertices, bytes_texCoords), self._len*4, len(self.to_add))
glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
glBufferSubData(GL_ARRAY_BUFFER, self._len, bytes_vertices, verts)
if not USING_RENDERDOC:
glVertexPointer (3, GL_FLOAT, 0, None)
glFlush()
glBindBuffer(GL_ARRAY_BUFFER, self.vbo_1)
glBufferSubData(GL_ARRAY_BUFFER, self._len_, bytes_texCoords, texCoords) # CHANGED
if not USING_RENDERDOC:
glTexCoordPointer(2, GL_FLOAT, 0, None)
glFlush()
self.vertices += i[0]
self.texCoords += i[1]
self._len += bytes_vertices
self._len_ += bytes_texCoords # CHANGED
glfw.poll_events()
glfw.swap_buffers(window2)
glfw.terminate()
def create_vbo(self, window):
self.vbo, self.vbo_1 = glGenBuffers (2)
glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
glBufferData(GL_ARRAY_BUFFER, 64000000, None, GL_STATIC_DRAW)
glBindBuffer(GL_ARRAY_BUFFER, self.vbo_1)
glBufferData(GL_ARRAY_BUFFER, 64000000, None, GL_STATIC_DRAW)
glfw.make_context_current(None)
thread = threading.Thread(target=self.shared_context, args=[window], daemon=True)
thread.start()
self.event.wait()
glfw.make_context_current(window)
def add(self, vertices, texCoords):
self.to_add.append((tuple(vertices), tuple(texCoords)))
def render(self):
glClear (GL_COLOR_BUFFER_BIT)
glEnable(GL_TEXTURE_2D)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glBindBuffer (GL_ARRAY_BUFFER, self.vbo)
if not USING_RENDERDOC:
glVertexPointer (3, GL_FLOAT, 0, None)
glBindBuffer(GL_ARRAY_BUFFER, self.vbo_1)
if not USING_RENDERDOC:
glTexCoordPointer(2, GL_FLOAT, 0, None)
glDrawArrays (GL_QUADS, 0, self._len)
glDisable(GL_TEXTURE_2D)
glDisable(GL_BLEND)