Add an example which uses the Python bindings
This is more or less a copy of the BasicExample but using ever so slightly more modern OpenGL (>=3.0). I've tried to comment this as much as possible. In addition to this simple example I will go on to develop a more complex application as discussed in issue #21
This commit is contained in:
parent
d50e9dfebc
commit
8ad0cae89a
@ -82,6 +82,7 @@ IF(ENABLE_EXAMPLES AND QT_QTOPENGL_FOUND)
|
|||||||
ADD_SUBDIRECTORY(examples/Paging)
|
ADD_SUBDIRECTORY(examples/Paging)
|
||||||
ADD_SUBDIRECTORY(examples/OpenGL)
|
ADD_SUBDIRECTORY(examples/OpenGL)
|
||||||
ADD_SUBDIRECTORY(examples/SmoothLOD)
|
ADD_SUBDIRECTORY(examples/SmoothLOD)
|
||||||
|
ADD_SUBDIRECTORY(examples/Python)
|
||||||
SET(BUILD_EXAMPLES ON)
|
SET(BUILD_EXAMPLES ON)
|
||||||
ELSE()
|
ELSE()
|
||||||
SET(BUILD_EXAMPLES OFF)
|
SET(BUILD_EXAMPLES OFF)
|
||||||
|
26
examples/Python/CMakeLists.txt
Normal file
26
examples/Python/CMakeLists.txt
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# Copyright (c) 2010-2013 Matt Williams
|
||||||
|
#
|
||||||
|
# This software is provided 'as-is', without any express or implied
|
||||||
|
# warranty. In no event will the authors be held liable for any damages
|
||||||
|
# arising from the use of this software.
|
||||||
|
#
|
||||||
|
# Permission is granted to anyone to use this software for any purpose,
|
||||||
|
# including commercial applications, and to alter it and redistribute it
|
||||||
|
# freely, subject to the following restrictions:
|
||||||
|
#
|
||||||
|
# 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
# claim that you wrote the original software. If you use this software
|
||||||
|
# in a product, an acknowledgment in the product documentation would be
|
||||||
|
# appreciated but is not required.
|
||||||
|
#
|
||||||
|
# 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
# misrepresented as being the original software.
|
||||||
|
#
|
||||||
|
# 3. This notice may not be removed or altered from any source
|
||||||
|
# distribution.
|
||||||
|
|
||||||
|
PROJECT(PythonExample)
|
||||||
|
|
||||||
|
SOURCE_GROUP("Sources" FILES PythonExample.py)
|
||||||
|
|
||||||
|
configure_file(PythonExample.py PythonExample.py COPYONLY)
|
257
examples/Python/PythonExample.py
Executable file
257
examples/Python/PythonExample.py
Executable file
@ -0,0 +1,257 @@
|
|||||||
|
#! /usr/bin/env python
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Copyright (c) 2013 Matt Williams
|
||||||
|
#
|
||||||
|
# This software is provided 'as-is', without any express or implied
|
||||||
|
# warranty. In no event will the authors be held liable for any damages
|
||||||
|
# arising from the use of this software.
|
||||||
|
#
|
||||||
|
# Permission is granted to anyone to use this software for any purpose,
|
||||||
|
# including commercial applications, and to alter it and redistribute it
|
||||||
|
# freely, subject to the following restrictions:
|
||||||
|
#
|
||||||
|
# 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
# claim that you wrote the original software. If you use this software
|
||||||
|
# in a product, an acknowledgment in the product documentation would be
|
||||||
|
# appreciated but is not required.
|
||||||
|
#
|
||||||
|
# 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
# misrepresented as being the original software.
|
||||||
|
#
|
||||||
|
# 3. This notice may not be removed or altered from any source
|
||||||
|
# distribution.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
import sys
|
||||||
|
sys.path.append("../../library/bindings/") #This is just to point to the generated bindings
|
||||||
|
|
||||||
|
import PolyVoxCore as pv
|
||||||
|
|
||||||
|
#Create a 64x64x64 volume of integers
|
||||||
|
r = pv.Region(pv.Vector3Dint32_t(0,0,0), pv.Vector3Dint32_t(63,63,63))
|
||||||
|
vol = pv.SimpleVolumeuint8(r)
|
||||||
|
|
||||||
|
#Now fill the volume with our data (a sphere)
|
||||||
|
v3dVolCenter = pv.Vector3Dint32_t(vol.getWidth() / 2, vol.getHeight() / 2, vol.getDepth() / 2)
|
||||||
|
sphereRadius = 30
|
||||||
|
#This three-level for loop iterates over every voxel in the volume
|
||||||
|
for z in range(vol.getDepth()):
|
||||||
|
for y in range(vol.getHeight()):
|
||||||
|
for x in range(vol.getWidth()):
|
||||||
|
#Store our current position as a vector...
|
||||||
|
v3dCurrentPos = pv.Vector3Dint32_t(x,y,z)
|
||||||
|
#And compute how far the current position is from the center of the volume
|
||||||
|
fDistToCenter = (v3dCurrentPos - v3dVolCenter).length()
|
||||||
|
|
||||||
|
uVoxelValue = 0
|
||||||
|
|
||||||
|
#If the current voxel is less than 'radius' units from the center then we make it solid.
|
||||||
|
if(fDistToCenter <= sphereRadius):
|
||||||
|
#Our new voxel value
|
||||||
|
uVoxelValue = 255
|
||||||
|
|
||||||
|
#Write the voxel value into the volume
|
||||||
|
vol.setVoxelAt(x, y, z, uVoxelValue);
|
||||||
|
|
||||||
|
#Create a mesh, pass it to the extractor and generate the mesh
|
||||||
|
mesh = pv.SurfaceMeshPositionMaterialNormal()
|
||||||
|
extractor = pv.CubicSurfaceExtractorWithNormalsSimpleVolumeuint8(vol, r, mesh)
|
||||||
|
extractor.execute()
|
||||||
|
|
||||||
|
#That's all of the PolyVox generation done, now to convert the output to something OpenGL can read efficiently
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
indices = np.array(mesh.getIndices(), dtype='uint32') #Throw in the vertex indices into an array
|
||||||
|
#The vertices and normals are placed in an interpolated array like [vvvnnn,vvvnnn,vvvnnn]
|
||||||
|
vertices = np.array([[vertex.getPosition().getX(), vertex.getPosition().getY(), vertex.getPosition().getZ(),
|
||||||
|
vertex.getNormal().getX(), vertex.getNormal().getY(), vertex.getNormal().getZ()]
|
||||||
|
for vertex in mesh.getVertices()],
|
||||||
|
dtype='f')
|
||||||
|
|
||||||
|
#Now that we have our data, everything else here is just OpenGL
|
||||||
|
|
||||||
|
import OpenGL
|
||||||
|
|
||||||
|
from OpenGL.GL import shaders
|
||||||
|
from OpenGL.arrays import vbo
|
||||||
|
from OpenGL.GL import glClear, glEnable, glDepthFunc, GLuint, glEnableVertexAttribArray, glVertexAttribPointer, glDisableVertexAttribArray, \
|
||||||
|
glDrawElements, glGetUniformLocation, glUniformMatrix4fv, glDepthMask, glDepthRange, glGetString, glBindAttribLocation, \
|
||||||
|
GL_COLOR_BUFFER_BIT, GL_TRIANGLES, GL_DEPTH_TEST, GL_LEQUAL, GL_FLOAT, \
|
||||||
|
GL_DEPTH_BUFFER_BIT, GL_ELEMENT_ARRAY_BUFFER, GL_UNSIGNED_INT, GL_STATIC_DRAW, \
|
||||||
|
GL_FALSE, GL_TRUE, GL_VERTEX_SHADER, GL_FRAGMENT_SHADER, GL_CULL_FACE, \
|
||||||
|
GL_VENDOR, GL_RENDERER, GL_VERSION, GL_SHADING_LANGUAGE_VERSION
|
||||||
|
from OpenGL.raw.GL.ARB.vertex_array_object import glGenVertexArrays, glBindVertexArray
|
||||||
|
|
||||||
|
import pygame
|
||||||
|
|
||||||
|
from math import sin, cos, tan, radians
|
||||||
|
|
||||||
|
SCREEN_SIZE = (800, 800)
|
||||||
|
|
||||||
|
def run():
|
||||||
|
#Start OpenGL and ask it for an OpenGL context
|
||||||
|
pygame.init()
|
||||||
|
clock = pygame.time.Clock()
|
||||||
|
screen = pygame.display.set_mode(SCREEN_SIZE, pygame.HWSURFACE|pygame.OPENGL|pygame.DOUBLEBUF)
|
||||||
|
|
||||||
|
#The first thing we do is print some OpenGL details and check that we have a good enough version
|
||||||
|
print "OpenGL Implementation Details:"
|
||||||
|
if glGetString(GL_VENDOR):
|
||||||
|
print "\tGL_VENDOR:", glGetString(GL_VENDOR)
|
||||||
|
if glGetString(GL_RENDERER):
|
||||||
|
print "\tGL_RENDERER:", glGetString(GL_RENDERER)
|
||||||
|
if glGetString(GL_VERSION):
|
||||||
|
print "\tGL_VERSION:", glGetString(GL_VERSION)
|
||||||
|
if glGetString(GL_SHADING_LANGUAGE_VERSION):
|
||||||
|
print "\tGL_SHADING_LANGUAGE_VERSION:", glGetString(GL_SHADING_LANGUAGE_VERSION)
|
||||||
|
|
||||||
|
major_version = int(glGetString(GL_VERSION).split()[0].split('.')[0])
|
||||||
|
minor_version = int(glGetString(GL_VERSION).split()[0].split('.')[1])
|
||||||
|
if major_version < 3 or (major_version < 3 and minor_version < 0):
|
||||||
|
print "OpenGL version must be at least 3.0 (found {0})".format(glGetString(GL_VERSION).split()[0])
|
||||||
|
|
||||||
|
#Now onto the OpenGL initialisation
|
||||||
|
|
||||||
|
#Set up depth culling
|
||||||
|
glEnable(GL_CULL_FACE)
|
||||||
|
glEnable(GL_DEPTH_TEST)
|
||||||
|
glDepthMask(GL_TRUE)
|
||||||
|
glDepthFunc(GL_LEQUAL)
|
||||||
|
glDepthRange(0.0, 1.0)
|
||||||
|
|
||||||
|
#We create out shaders which do little more than set a flat colour for each face
|
||||||
|
|
||||||
|
VERTEX_SHADER = shaders.compileShader("""
|
||||||
|
#version 130
|
||||||
|
|
||||||
|
in vec4 position;
|
||||||
|
in vec4 normal;
|
||||||
|
|
||||||
|
uniform mat4 cameraToClipMatrix;
|
||||||
|
uniform mat4 worldToCameraMatrix;
|
||||||
|
uniform mat4 modelToWorldMatrix;
|
||||||
|
|
||||||
|
flat out float theColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 temp = modelToWorldMatrix * position;
|
||||||
|
temp = worldToCameraMatrix * temp;
|
||||||
|
gl_Position = cameraToClipMatrix * temp;
|
||||||
|
|
||||||
|
theColor = clamp(abs(dot(normalize(normal.xyz), normalize(vec3(0.9,0.1,0.5)))), 0, 1);
|
||||||
|
}
|
||||||
|
""", GL_VERTEX_SHADER)
|
||||||
|
|
||||||
|
FRAGMENT_SHADER = shaders.compileShader("""
|
||||||
|
#version 130
|
||||||
|
|
||||||
|
flat in float theColor;
|
||||||
|
|
||||||
|
out vec4 outputColor;
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
outputColor = vec4(1.0, 0.5, theColor, 1.0);
|
||||||
|
}
|
||||||
|
""", GL_FRAGMENT_SHADER)
|
||||||
|
|
||||||
|
shader = shaders.compileProgram(VERTEX_SHADER, FRAGMENT_SHADER)
|
||||||
|
|
||||||
|
#And then grab our attribute locations from it
|
||||||
|
glBindAttribLocation(shader, 0, "position")
|
||||||
|
glBindAttribLocation(shader, 1, "normal")
|
||||||
|
|
||||||
|
#Create the Vertex Array Object to hold our volume mesh
|
||||||
|
vertexArrayObject = GLuint(0)
|
||||||
|
glGenVertexArrays(1, vertexArrayObject)
|
||||||
|
glBindVertexArray(vertexArrayObject)
|
||||||
|
|
||||||
|
#Create the index buffer object
|
||||||
|
indexPositions = vbo.VBO(indices, target=GL_ELEMENT_ARRAY_BUFFER, usage=GL_STATIC_DRAW)
|
||||||
|
#Create the VBO
|
||||||
|
vertexPositions = vbo.VBO(vertices, usage=GL_STATIC_DRAW)
|
||||||
|
|
||||||
|
#Bind our VBOs and set up our data layout specifications
|
||||||
|
with indexPositions, vertexPositions:
|
||||||
|
glEnableVertexAttribArray(0)
|
||||||
|
glVertexAttribPointer(0, 3, GL_FLOAT, False, 6*vertices.dtype.itemsize, vertexPositions+(0*vertices.dtype.itemsize))
|
||||||
|
glEnableVertexAttribArray(1)
|
||||||
|
glVertexAttribPointer(1, 3, GL_FLOAT, False, 6*vertices.dtype.itemsize, vertexPositions+(3*vertices.dtype.itemsize))
|
||||||
|
|
||||||
|
glBindVertexArray(0)
|
||||||
|
glDisableVertexAttribArray(0)
|
||||||
|
|
||||||
|
#Now grab out transformation martix locations
|
||||||
|
modelToWorldMatrixUnif = glGetUniformLocation(shader, "modelToWorldMatrix")
|
||||||
|
worldToCameraMatrixUnif = glGetUniformLocation(shader, "worldToCameraMatrix")
|
||||||
|
cameraToClipMatrixUnif = glGetUniformLocation(shader, "cameraToClipMatrix")
|
||||||
|
|
||||||
|
modelToWorldMatrix = np.array([[1.0,0.0,0.0,-32.0],[0.0,1.0,0.0,-32.0],[0.0,0.0,1.0,-32.0],[0.0,0.0,0.0,1.0]], dtype='f')
|
||||||
|
worldToCameraMatrix = np.array([[1.0,0.0,0.0,0.0],[0.0,1.0,0.0,0.0],[0.0,0.0,1.0,-50.0],[0.0,0.0,0.0,1.0]], dtype='f')
|
||||||
|
cameraToClipMatrix = np.array([[0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0]], dtype='f')
|
||||||
|
|
||||||
|
#These next few lines just set up our camera frustum
|
||||||
|
fovDeg = 45.0
|
||||||
|
frustumScale = 1.0 / tan(radians(fovDeg) / 2.0)
|
||||||
|
|
||||||
|
zNear = 1.0
|
||||||
|
zFar = 1000.0
|
||||||
|
|
||||||
|
cameraToClipMatrix[0][0] = frustumScale
|
||||||
|
cameraToClipMatrix[1][1] = frustumScale
|
||||||
|
cameraToClipMatrix[2][2] = (zFar + zNear) / (zNear - zFar)
|
||||||
|
cameraToClipMatrix[2][3] = -1.0
|
||||||
|
cameraToClipMatrix[3][2] = (2 * zFar * zNear) / (zNear - zFar)
|
||||||
|
|
||||||
|
#worldToCameraMatrix and cameraToClipMatrix don't change ever so just set them once here
|
||||||
|
with shader:
|
||||||
|
glUniformMatrix4fv(cameraToClipMatrixUnif, 1, GL_TRUE, cameraToClipMatrix)
|
||||||
|
glUniformMatrix4fv(worldToCameraMatrixUnif, 1, GL_TRUE, worldToCameraMatrix)
|
||||||
|
|
||||||
|
#These are used to track the rotation of the volume
|
||||||
|
LastFrameMousePos = (0,0)
|
||||||
|
CurrentMousePos = (0,0)
|
||||||
|
xRotation = 0
|
||||||
|
yRotation = 0
|
||||||
|
|
||||||
|
while True:
|
||||||
|
clock.tick()
|
||||||
|
|
||||||
|
for event in pygame.event.get():
|
||||||
|
if event.type == pygame.QUIT:
|
||||||
|
return
|
||||||
|
if event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE:
|
||||||
|
return
|
||||||
|
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
|
||||||
|
CurrentMousePos = event.pos
|
||||||
|
LastFrameMousePos = CurrentMousePos
|
||||||
|
if event.type == pygame.MOUSEMOTION and 1 in event.buttons:
|
||||||
|
CurrentMousePos = event.pos
|
||||||
|
diff = (CurrentMousePos[0] - LastFrameMousePos[0], CurrentMousePos[1] - LastFrameMousePos[1])
|
||||||
|
xRotation += event.rel[0]
|
||||||
|
yRotation += event.rel[1]
|
||||||
|
LastFrameMousePos = CurrentMousePos
|
||||||
|
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
|
||||||
|
|
||||||
|
#Perform the rotation of the mesh
|
||||||
|
moveToOrigin = np.array([[1.0,0.0,0.0,-32.0],[0.0,1.0,0.0,-32.0],[0.0,0.0,1.0,-32.0],[0.0,0.0,0.0,1.0]], dtype='f')
|
||||||
|
rotateAroundX = np.array([[1.0,0.0,0.0,0.0],[0.0,cos(radians(yRotation)),-sin(radians(yRotation)),0.0],[0.0,sin(radians(yRotation)),cos(radians(yRotation)),0.0],[0.0,0.0,0.0,1.0]], dtype='f')
|
||||||
|
rotateAroundY = np.array([[cos(radians(xRotation)),0.0,sin(radians(xRotation)),0.0],[0.0,1.0,0.0,0.0],[-sin(radians(xRotation)),0.0,cos(radians(xRotation)),0.0],[0.0,0.0,0.0,1.0]], dtype='f')
|
||||||
|
|
||||||
|
modelToWorldMatrix = rotateAroundY.dot(rotateAroundX.dot(moveToOrigin))
|
||||||
|
|
||||||
|
with shader:
|
||||||
|
glUniformMatrix4fv(modelToWorldMatrixUnif, 1, GL_TRUE, modelToWorldMatrix)
|
||||||
|
glBindVertexArray(vertexArrayObject)
|
||||||
|
|
||||||
|
glDrawElements(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, None)
|
||||||
|
|
||||||
|
glBindVertexArray(0)
|
||||||
|
|
||||||
|
# Show the screen
|
||||||
|
pygame.display.flip()
|
||||||
|
|
||||||
|
run()
|
Loading…
x
Reference in New Issue
Block a user