My objective is to import a terrain map, more specific a GeoTIFF file, and assign colors or textures to the terrain. I also want to be able to fly through the terrain using key inputs and mouse movement.
Input data:
self.vertices = numpy.array(vertices, dtype = 'f'): vertices = (x, y, z, r, g, b, tc1, tc2)
self.indices = numpy.array(triangle, dtype = numpy.int32): triangle = (indices for vertices)
I assigned (1, 0, 0) for all the vertex colors and (0, 1) for texture coordinates. This is just to see whether the color change to red.
What I have done:
I already managed to create a terrain using a vertex array object (VAO) which contains a vertex buffer object (VBO) and assigned attributes for the vertex positions, colors and texture (not yet assigned). I also managed to set up the environment to be able to fly through the terrain using key inputs and mouse movement. By running the code below one should be able to see and fly around a small grey mesh with black triangle outlines.
from pygame.constants import *
from OpenGL.GLU import *
import pygame
import numpy
numpy.set_printoptions(suppress=True)
from OpenGL.GL import *
from OpenGL.GL.shaders import compileProgram, compileShader
class Meshi():
def __init__(self):
#Gert vertices and triangles
if not pygame.init():
raise TypeError('Unable to initalize pygame')
#Get vertices and triangles
vertices, triangles = self.getVertTri()
z_scale = 0.00005
#change z-scale
for i in range(0, len(vertices)):
if vertices[i][2] < 0:
vertices[i][2] = 0
else:
vertices[i][2] = vertices[i][2] * z_scale
#Add colour and texture coordinates to mesh
vert = []
color_in = [1.0, 0.0, 0.0, 0.0, 1.0]
for ver in vertices:
vert.append(ver + color_in)
vertices = vert
self.vertices = numpy.array(vertices, dtype = 'f')
self.indices = numpy.array(triangles,dtype = numpy.int32)
#Run pygame
self.pygame_view()
# Function that keeps all the vertices and triangle sides
def getVertTri(self):
vert_str=[[18.427083,-34.104583,14.097592],[18.427917,-34.104583,13.813885],[18.42875,-34.104583,11.798318],[18.429583,-34.104583,12.170123],[18.430417,-34.104583,13.23494],[18.43125,-34.104583,12.263627],[18.432083,-34.104583,10.543183],[18.432917,-34.104583,9.150859],[18.43375,-34.104583,7.531989],[18.434583,-34.104583,5.370541],[18.435417,-34.104583,4.947286],
[18.43625,-34.104583,4.369431],[18.437083,-34.104583,9.29184],[18.437917,-34.104583,11.300546],[18.43875,-34.104583,9.590596],[18.439583,-34.104583,7.006906],[18.427083,-34.105417,17.277378],[18.427917,-34.105417,12.070671],[18.42875,-34.105417,9.0447],[18.429583,-34.105417,7.853086],[18.430417,-34.105417,7.927739],[18.43125,-34.105417,8.325415],
[18.432083,-34.105417,8.505657],[18.432917,-34.105417,7.904904],[18.43375,-34.105417,7.7015],[18.434583,-34.105417,7.362363],[18.435417,-34.105417,7.08594],[18.43625,-34.105417,6.692467],[18.437083,-34.105417,1.177889],[18.437917,-34.105417,6.393278],[18.43875,-34.105417,8.610809],[18.439583,-34.105417,9.748986],[18.427083,-34.10625,29.354589],
[18.427917,-34.10625,24.616703],[18.42875,-34.10625,18.529903],[18.429583,-34.10625,13.677365],[18.430417,-34.10625,10.466432],[18.43125,-34.10625,9.469019],[18.432083,-34.10625,7.960031],[18.432917,-34.10625,7.115651],[18.43375,-34.10625,6.465553],[18.434583,-34.10625,5.50102],[18.435417,-34.10625,5.712739],[18.43625,-34.10625,6.946383],
[18.437083,-34.10625,4.263526],[18.437917,-34.10625,2.732419],[18.43875,-34.10625,5.488115],[18.439583,-34.10625,6.902328],[18.427083,-34.107083,30.979712],[18.427917,-34.107083,30.684374],[18.42875,-34.107083,26.90592],[18.429583,-34.107083,22.378777],[18.430417,-34.107083,19.191908],[18.43125,-34.107083,16.608807],[18.432083,-34.107083,13.171669],
[18.432917,-34.107083,10.77886],[18.43375,-34.107083,11.478356],[18.434583,-34.107083,11.300546],[18.435417,-34.107083,9.737173],[18.43625,-34.107083,6.484625],[18.437083,-34.107083,5.185645],[18.437917,-34.107083,3.770918],[18.43875,-34.107083,4.11032],[18.439583,-34.107083,4.947286],[18.427083,-34.107917,30.013678],[18.427917,-34.107917,32.894321],
[18.42875,-34.107917,31.857147],[18.429583,-34.107917,26.9683],[18.430417,-34.107917,21.895006],[18.43125,-34.107917,16.907623],[18.432083,-34.107917,12.721774],[18.432917,-34.107917,11.510896],[18.43375,-34.107917,14.044291],[18.434583,-34.107917,13.438006],[18.435417,-34.107917,12.538547],[18.43625,-34.107917,11.562454],[18.437083,-34.107917,9.263826],
[18.437917,-34.107917,6.071107],[18.43875,-34.107917,4.289905],[18.439583,-34.107917,4.057948],[18.427083,-34.10875,25.226519],[18.427917,-34.10875,26.609413],[18.42875,-34.10875,29.121534],[18.429583,-34.10875,27.900227],[18.430417,-34.10875,24.414494],[18.43125,-34.10875,20.20229],[18.432083,-34.10875,14.686948],[18.432917,-34.10875,10.620943],
[18.43375,-34.10875,11.136961],[18.434583,-34.10875,9.067697],[18.435417,-34.10875,9.031256],[18.43625,-34.10875,11.842289],[18.437083,-34.10875,14.412585],[18.437917,-34.10875,14.026602],[18.43875,-34.10875,10.77886],[18.439583,-34.10875,7.479022],[18.427083,-34.109583,24.316551],[18.427917,-34.109583,4.027079],[18.42875,-34.109583,13.726677],
[18.429583,-34.109583,23.883642],[18.430417,-34.109583,28.826719],[18.43125,-34.109583,29.248907],[18.432083,-34.109583,24.62047],[18.432917,-34.109583,14.576126],[18.43375,-34.109583,10.270979],[18.434583,-34.109583,9.1116],[18.435417,-34.109583,8.978557],[18.43625,-34.109583,10.877857],[18.437083,-34.109583,13.952817],[18.437917,-34.109583,17.318939],
[18.43875,-34.109583,18.3776],[18.439583,-34.109583,16.823097],[18.427083,-34.110417,31.066404],[18.427917,-34.110417,27.124994],[18.42875,-34.110417,14.584773],[18.429583,-34.110417,6.256494],[18.430417,-34.110417,14.902382],[18.43125,-34.110417,23.147758],[18.432083,-34.110417,26.993055],[18.432917,-34.110417,22.765322],[18.43375,-34.110417,17.905703],
[18.434583,-34.110417,13.544991],[18.435417,-34.110417,11.899844],[18.43625,-34.110417,14.348012],[18.437083,-34.110417,16.262051],[18.437917,-34.110417,17.542927],[18.43875,-34.110417,21.157032],[18.439583,-34.110417,23.491091],[18.427083,-34.11125,12.909849],[18.427917,-34.11125,20.651325],[18.42875,-34.11125,24.733046],[18.429583,-34.11125,22.71829],
[18.430417,-34.11125,12.409415],[18.43125,-34.11125,4.794024],[18.432083,-34.11125,14.560322],[18.432917,-34.11125,19.986332],[18.43375,-34.11125,21.261787],[18.434583,-34.11125,18.94504],[18.435417,-34.11125,17.467054],[18.43625,-34.11125,17.029078],[18.437083,-34.11125,15.266393],[18.437917,-34.11125,14.918492],[18.43875,-34.11125,16.444849],
[18.439583,-34.11125,18.332243],[18.427083,-34.112083,14.870467],[18.427917,-34.112083,10.946778],[18.42875,-34.112083,9.536969],[18.429583,-34.112083,17.428055],[18.430417,-34.112083,20.116079],[18.43125,-34.112083,14.013614],[18.432083,-34.112083,4.487359],[18.432917,-34.112083,4.302343],[18.43375,-34.112083,9.771387],[18.434583,-34.112083,11.65025],
[18.435417,-34.112083,11.8523],[18.43625,-34.112083,10.677254],[18.437083,-34.112083,8.148099],[18.437917,-34.112083,7.58765],[18.43875,-34.112083,5.033905],[18.439583,-34.112083,3.151809],[18.427083,-34.112917,4.697855],[18.427917,-34.112917,5.462211],[18.42875,-34.112917,6.136745],[18.429583,-34.112917,6.001783],[18.430417,-34.112917,9.035099],
[18.43125,-34.112917,13.059889],[18.432083,-34.112917,13.085486],[18.432917,-34.112917,11.08321],[18.43375,-34.112917,6.319217],[18.434583,-34.112917,4.270484],[18.435417,-34.112917,4.372147],[18.43625,-34.112917,4.910031],[18.437083,-34.112917,4.54907],[18.437917,-34.112917,3.606416],[18.43875,-34.112917,6.188358],[18.439583,-34.112917,10.144054],
[18.427083,-34.11375,8.589212],[18.427917,-34.11375,8.18161],[18.42875,-34.11375,7.444539],[18.429583,-34.11375,6.263077],[18.430417,-34.11375,5.025665],[18.43125,-34.11375,4.281593],[18.432083,-34.11375,4.90037],[18.432917,-34.11375,9.216936],[18.43375,-34.11375,10.723666],[18.434583,-34.11375,11.447696],[18.435417,-34.11375,11.056483],
[18.43625,-34.11375,10.136135],[18.437083,-34.11375,6.79003],[18.437917,-34.11375,2.968766],[18.43875,-34.11375,1.72892],[18.439583,-34.11375,6.459183]]
tri_str = [[0,16,17],[0,17,1],[1,17,18],[1,18,2],[2,18,19],[2,19,3],[3,19,20],[3,20,4],[4,20,21],[4,21,5],[5,21,22],
[5,22,6],[6,22,23],[6,23,7],[7,23,24],[7,24,8],[8,24,25],[8,25,9],[9,25,26],[9,26,10],[10,26,27],[10,27,11],
[11,27,28],[11,28,12],[12,28,29],[12,29,13],[13,29,30],[13,30,14],[14,30,31],[14,31,15],[16,32,33],[16,33,17],[17,33,34],
[17,34,18],[18,34,35],[18,35,19],[19,35,36],[19,36,20],[20,36,37],[20,37,21],[21,37,38],[21,38,22],[22,38,39],[22,39,23],
[23,39,40],[23,40,24],[24,40,41],[24,41,25],[25,41,42],[25,42,26],[26,42,43],[26,43,27],[27,43,44],[27,44,28],[28,44,45],
[28,45,29],[29,45,46],[29,46,30],[30,46,47],[30,47,31],[32,48,49],[32,49,33],[33,49,50],[33,50,34],[34,50,51],[34,51,35],
[35,51,52],[35,52,36],[36,52,53],[36,53,37],[37,53,54],[37,54,38],[38,54,55],[38,55,39],[39,55,56],[39,56,40],[40,56,57],
[40,57,41],[41,57,58],[41,58,42],[42,58,59],[42,59,43],[43,59,60],[43,60,44],[44,60,61],[44,61,45],[45,61,62],[45,62,46],
[46,62,63],[46,63,47],[48,64,65],[48,65,49],[49,65,66],[49,66,50],[50,66,67],[50,67,51],[51,67,68],[51,68,52],[52,68,69],
[52,69,53],[53,69,70],[53,70,54],[54,70,71],[54,71,55],[55,71,72],[55,72,56],[56,72,73],[56,73,57],[57,73,74],[57,74,58],
[58,74,75],[58,75,59],[59,75,76],[59,76,60],[60,76,77],[60,77,61],[61,77,78],[61,78,62],[62,78,79],[62,79,63],[64,80,81],
[64,81,65],[65,81,82],[65,82,66],[66,82,83],[66,83,67],[67,83,84],[67,84,68],[68,84,85],[68,85,69],[69,85,86],[69,86,70],
[70,86,87],[70,87,71],[71,87,88],[71,88,72],[72,88,89],[72,89,73],[73,89,90],[73,90,74],[74,90,91],[74,91,75],[75,91,92],
[75,92,76],[76,92,93],[76,93,77],[77,93,94],[77,94,78],[78,94,95],[78,95,79],[80,96,97],[80,97,81],[81,97,98],[81,98,82],
[82,98,99],[82,99,83],[83,99,100],[83,100,84],[84,100,101],[84,101,85],[85,101,102],[85,102,86],[86,102,103],[86,103,87],[87,103,104],
[87,104,88],[88,104,105],[88,105,89],[89,105,106],[89,106,90],[90,106,107],[90,107,91],[91,107,108],[91,108,92],[92,108,109],[92,109,93],
[93,109,110],[93,110,94],[94,110,111],[94,111,95],[96,112,113],[96,113,97],[97,113,114],[97,114,98],[98,114,115],[98,115,99],[99,115,116],
[99,116,100],[100,116,117],[100,117,101],[101,117,118],[101,118,102],[102,118,119],[102,119,103],[103,119,120],[103,120,104],[104,120,121],[104,121,105],
[105,121,122],[105,122,106],[106,122,123],[106,123,107],[107,123,124],[107,124,108],[108,124,125],[108,125,109],[109,125,126],[109,126,110],[110,126,127],
[110,127,111],[112,128,129],[112,129,113],[113,129,130],[113,130,114],[114,130,131],[114,131,115],[115,131,132],[115,132,116],[116,132,133],[116,133,117],
[117,133,134],[117,134,118],[118,134,135],[118,135,119],[119,135,136],[119,136,120],[120,136,137],[120,137,121],[121,137,138],[121,138,122],[122,138,139],
[122,139,123],[123,139,140],[123,140,124],[124,140,141],[124,141,125],[125,141,142],[125,142,126],[126,142,143],[126,143,127],[128,144,145],[128,145,129],
[129,145,146],[129,146,130],[130,146,147],[130,147,131],[131,147,148],[131,148,132],[132,148,149],[132,149,133],[133,149,150],[133,150,134],[134,150,151],
[134,151,135],[135,151,152],[135,152,136],[136,152,153],[136,153,137],[137,153,154],[137,154,138],[138,154,155],[138,155,139],[139,155,156],[139,156,140],
[140,156,157],[140,157,141],[141,157,158],[141,158,142],[142,158,159],[142,159,143],[144,160,161],[144,161,145],[145,161,162],[145,162,146],[146,162,163],
[146,163,147],[147,163,164],[147,164,148],[148,164,165],[148,165,149],[149,165,166],[149,166,150],[150,166,167],[150,167,151],[151,167,168],[151,168,152],
[152,168,169],[152,169,153],[153,169,170],[153,170,154],[154,170,171],[154,171,155],[155,171,172],[155,172,156],[156,172,173],[156,173,157],[157,173,174],
[157,174,158],[158,174,175],[158,175,159],[160,176,177],[160,177,161],[161,177,178],[161,178,162],[162,178,179],[162,179,163],[163,179,180],[163,180,164],
[164,180,181],[164,181,165],[165,181,182],[165,182,166],[166,182,183],[166,183,167],[167,183,184],[167,184,168],[168,184,185],[168,185,169],[169,185,186],
[169,186,170],[170,186,187],[170,187,171],[171,187,188],[171,188,172],[172,188,189],[172,189,173],[173,189,190],[173,190,174],[174,190,191],[174,191,175]]
return vert_str, tri_str
# Game movement
def key_pressed(self, keypress):
if keypress[pygame.K_w]:
glTranslatef(0, 0, 0.001)
if keypress[pygame.K_s]:
glTranslatef(0, 0, -0.001)
if keypress[pygame.K_d]:
glTranslatef(-0.00025, 0, 0)
if keypress[pygame.K_a]:
glTranslatef(0.00025, 0, 0)
if keypress[pygame.K_e]:
glTranslatef(0, 0.0004, 0)
if keypress[pygame.K_q]:
glTranslatef(0, -0.0004, 0)
def draw_mesh_vbo(self):
vertex_src = """
# version 330
in layout(location = 0) vec3 a_position;
in layout(location = 1) vec3 a_color;
out vec3 v_color;
void main()
{
gl_Position = vec4(a_position, 1.0);
v_color = a_color;
}
"""
fragment_src = """
# version 330
in vec3 v_color;
out vec4 out_color;
void main()
{
out_color = vec4(v_color, 1.0);
}
"""
shader = compileProgram(compileShader(vertex_src, GL_VERTEX_SHADER), compileShader(fragment_src, GL_FRAGMENT_SHADER))
self.ter_vao = glGenVertexArrays(1)
glBindVertexArray(self.ter_vao)
VBO = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, VBO)
glBufferData(GL_ARRAY_BUFFER, self.vertices.itemsize * len(self.vertices) * 8, self.vertices, GL_STATIC_DRAW)
EBO = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, self.indices.itemsize * len(self.indices) * 3, self.indices, GL_STATIC_DRAW)
#pos = glGetAttribLocation(shader, "a_position")
# position
glEnableVertexAttribArray(0)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, self.vertices.itemsize * 8, ctypes.c_void_p(0))
# color
#col = glGetAttribLocation(shader, "a_color")
glEnableVertexAttribArray(1)
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, self.vertices.itemsize * 8, ctypes.c_void_p(12))
# texture
#textr = glGetAttribLocation(shader, "a_text")
# glEnableVertexAttribArray(2)
# glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, self.vertices.itemsize * 8, ctypes.c_void_p(24))
glBindVertexArray(0)
self.shady = shader
glClearColor(0, 0.3, 0.1, 1)
def pygame_loop(self, run, paused, displayCenter, up_down_angle, viewMatrix):
clock = pygame.time.Clock()
self.draw_mesh_vbo()
#glUseProgram(self.shader)
while run:
clock.tick(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE or event.key == pygame.K_RETURN:
run = False
if event.key == pygame.K_PAUSE or event.key == pygame.K_p:
paused = not paused
pygame.mouse.set_pos(displayCenter)
if not paused:
if event.type == pygame.MOUSEMOTION:
mouseMove = [event.pos[i] - displayCenter[i] for i in range(2)]
pygame.mouse.set_pos(displayCenter)
if not paused:
# get keys
keypress = pygame.key.get_pressed()
# init model view matrix
glLoadIdentity()
# apply the look up and down
up_down_angle += mouseMove[1] * 0.1
glRotatef(up_down_angle, 1.0, 0.0, 0.0)
# init the view matrix
glPushMatrix()
glLoadIdentity()
# apply the movment
self.key_pressed(keypress)
# apply the left and right rotation
glRotatef(mouseMove[0] * 0.02, 0.0, 1.0, 0.0)
glMultMatrixf(viewMatrix)
viewMatrix = glGetFloatv(GL_MODELVIEW_MATRIX)
glPopMatrix()
# Close init the view matrix
# Update current view
glMultMatrixf(viewMatrix)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glBindVertexArray(self.ter_vao)
#glUseProgram(self.shady)
glColor3f(0,0,0)
glDrawElements(GL_LINES, len(self.indices) * 3, GL_UNSIGNED_INT, None)
glColor4f(0.8, 0.8, 0.8, 0.0)
glDrawElements(GL_TRIANGLES, len(self.indices) * 3, GL_UNSIGNED_INT, None)
#glUseProgram(0)
glBindVertexArray(0)
pygame.display.set_caption("FPS: %.2f" % clock.get_fps())
pygame.display.flip()
pygame.time.wait(20)
def pygame_view(self):
#Pygame Start
pygame.init()
#Create a "first person" environment
display = (1000, 600)
scree = pygame.display.set_mode(display, DOUBLEBUF | OPENGL)
glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING)
glShadeModel(GL_SMOOTH)
glEnable(GL_COLOR_MATERIAL)
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE)
glEnable(GL_LIGHT0)
glLightfv(GL_LIGHT0, GL_AMBIENT, [0.5, 0.5, 0.5, 1])
glLightfv(GL_LIGHT0, GL_DIFFUSE, [1.0, 1.0, 1.0, 1])
sphere = gluNewQuadric()
glMatrixMode(GL_PROJECTION)
gluPerspective(15, (1 * display[0] / display[1]), 0.001, 3000.0)
glMatrixMode(GL_MODELVIEW)
gluLookAt(self.vertices[50][0], self.vertices[50][1], 0, 0, -180, 0, 0, 0, 1)
viewMatrix = glGetFloatv(GL_MODELVIEW_MATRIX)
glLoadIdentity()
# init mouse movement and center mouse on screen
displayCenter = [scree.get_size()[i] // 2 for i in range(2)]
mouseMove = [0, 0]
pygame.mouse.set_pos(displayCenter)
up_down_angle = 0.0
paused = False
run = True
self.aspectratio = (1 * display[0] / display[1])
#Run Pygame
self.pygame_loop(run, paused, displayCenter, up_down_angle, viewMatrix)
pygame.quit()
if __name__ == '__main__':
mesh_dem = Meshi()
Next step:
Before I even try to implement textures, I first want to understand how shaders work by displaying the colors assigned to each vertex. The expected outcome in this example is to see a red mesh.
What I have tried:
Shader setup:
vertex_src = """
# version 330
in layout(location = 0) vec3 a_position;
in layout(location = 1) vec3 a_color;
out vec3 v_color;
void main()
{
gl_Position = vec4(a_position, 1.0);
v_color = a_color;
}
"""
fragment_src = """
# version 330
in vec3 v_color;
out vec4 out_color;
void main()
{
out_color = vec4(v_color, 1.0);
}
"""
shader = compileProgram(compileShader(vertex_src, GL_VERTEX_SHADER), compileShader(fragment_src, GL_FRAGMENT_SHADER))
self.shady = shader
Implementing shader in while loop:
glBindVertexArray(self.ter_vao)
glUseProgram(self.shady)
glDrawElements(GL_TRIANGLES, len(self.indices) * 3, GL_UNSIGNED_INT, None)
glUseProgram(0)
glBindVertexArray(0)
When I use glUseProgram(shader) I only see the background color. I suspect it is becuase glUseProgram disables the model view, projections etc. Do I have to change the shaders to include the projections, place glUseProgram somewhere else or am I way off?
UPDATE: Thanks to Rabbid76 and Atilla Toth's OpenGL in Python Youtube series I created a workable programmable pipeline example (see answer below). I have not implemented GLM's matrix transformations yet but for now pyrr works fine. The example creates a mesh from coordinates and displays different colors based on height.