Merge branch 'develop' into feature/large-volume-work

This commit is contained in:
Daviw Williams 2013-02-07 16:11:03 +01:00
commit 36968bdd79
9 changed files with 391 additions and 20 deletions

View File

@ -82,6 +82,7 @@ IF(ENABLE_EXAMPLES AND QT_QTOPENGL_FOUND)
ADD_SUBDIRECTORY(examples/Paging)
ADD_SUBDIRECTORY(examples/OpenGL)
ADD_SUBDIRECTORY(examples/SmoothLOD)
ADD_SUBDIRECTORY(examples/Python)
SET(BUILD_EXAMPLES ON)
ELSE()
SET(BUILD_EXAMPLES OFF)

View 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
View 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()

View File

@ -26,13 +26,12 @@ namespace PolyVox
// We try to avoid duplicate vertices by checking whether a vertex has already been added at a given position.
// However, it is possible that vertices have the same position but different materials. In this case, the
// vertices are not true duplicates and both must be added to the mesh. As far as I can tell, it is possible to have
// at most six vertices with the same position but different materials. This worst-case scenario happens when we
// have a 2x2x2 group of voxels (all with different materials) and then we delete two voxels from opposing corners.
// The vertex position at the center of this group is then going to be used by six quads all with different materials.
// One futher note - we can actually have eight quads sharing a vertex position (imagine two 1x1x10 rows of voxels
// sharing a common edge) but in this case all eight quads will not have different materials.
// at most eight vertices with the same position but different materials. For example, this worst-case scenario
// happens when we have a 2x2x2 group of voxels, all with different materials and some/all partially transparent.
// The vertex position at the center of this group is then going to be used by all eight voxels all with different
// materials.
template<typename VolumeType, typename IsQuadNeeded>
const uint32_t CubicSurfaceExtractor<VolumeType, IsQuadNeeded>::MaxVerticesPerPosition = 6;
const uint32_t CubicSurfaceExtractor<VolumeType, IsQuadNeeded>::MaxVerticesPerPosition = 8;
template<typename VolumeType, typename IsQuadNeeded>
CubicSurfaceExtractor<VolumeType, IsQuadNeeded>::CubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh<PositionMaterial>* result, WrapMode eWrapMode, typename VolumeType::VoxelType tBorderValue, bool bMergeQuads, IsQuadNeeded isQuadNeeded)

View File

@ -5,4 +5,5 @@
%include "CubicSurfaceExtractor.h"
EXTRACTORS(CubicSurfaceExtractor)
%template(CubicSurfaceExtractorSimpleVolumeuint8) PolyVox::CubicSurfaceExtractor<PolyVox::SimpleVolume<uint8_t>, PolyVox::DefaultIsQuadNeeded<uint8_t> >;
//EXTRACTORS(CubicSurfaceExtractor)

View File

@ -1,13 +1,8 @@
%module CubicSurfaceExtractorWithNormals
%{
#include "SimpleVolume.h"
//#include "CubicSurfaceExtractor.h"
#include "CubicSurfaceExtractorWithNormals.h"
%}
%include "SimpleVolume.h"
//%include "CubicSurfaceExtractor.h"
%include "CubicSurfaceExtractorWithNormals.h"
%template(CubicSurfaceExtractorWithNormalsMaterial8) PolyVox::CubicSurfaceExtractorWithNormals<PolyVox::Material8>;
%template(CubicSurfaceExtractorWithNormalsDensity8) PolyVox::CubicSurfaceExtractorWithNormals<PolyVox::Density8>;
%template(CubicSurfaceExtractorWithNormalsSimpleVolumeuint8) PolyVox::CubicSurfaceExtractorWithNormals<PolyVox::SimpleVolume<uint8_t>, PolyVox::DefaultIsQuadNeeded<uint8_t> >;

View File

@ -84,5 +84,6 @@ EXTRACTOR(shortname, LargeVolume)
%include "VertexTypes.i"
%include "SurfaceMesh.i"
%include "MarchingCubesSurfaceExtractor.i"
//%include "CubicSurfaceExtractor.i"
%include "CubicSurfaceExtractor.i"
%include "CubicSurfaceExtractorWithNormals.i"
%include "Raycast.i"

View File

@ -12,7 +12,15 @@ PROPERTY(PolyVox::Vector, y, getY, setY)
PROPERTY(PolyVox::Vector, z, getZ, setZ)
#endif
%rename(Plus) operator +;
%rename(Minus) operator -;
%rename(Multiply) operator *;
%rename(Divide) operator /;
%rename(Equal) operator ==;
%rename(NotEqual) operator !=;
%extend PolyVox::Vector {
#ifdef SWIGPYTHON
PolyVox::Vector __add__(const PolyVox::Vector& rhs) {
return *$self + rhs;
}
@ -31,6 +39,7 @@ PROPERTY(PolyVox::Vector, z, getZ, setZ)
PolyVox::Vector __mul__(const StorageType& rhs) {
return *$self * rhs;
}
#endif
STR()
};
@ -42,6 +51,56 @@ PROPERTY(PolyVox::Vector, z, getZ, setZ)
//%csattributes PolyVox::Vector::operator< "[System.Obsolete(\"deprecated\")]"
%define VECTOR3(StorageType,OperationType,ReducedStorageType)
#if SWIGCSHARP
%extend PolyVox::Vector<3,StorageType,OperationType> {
PolyVox::Vector<3,StorageType,OperationType> operator+(const PolyVox::Vector<3,StorageType,OperationType>& rhs) {return *$self + rhs;}
PolyVox::Vector<3,StorageType,OperationType> operator-(const PolyVox::Vector<3,StorageType,OperationType>& rhs) {return *$self - rhs;}
PolyVox::Vector<3,StorageType,OperationType> operator*(const PolyVox::Vector<3,StorageType,OperationType>& rhs) {return *$self * rhs;}
PolyVox::Vector<3,StorageType,OperationType> operator/(const PolyVox::Vector<3,StorageType,OperationType>& rhs) {return *$self / rhs;}
PolyVox::Vector<3,StorageType,OperationType> operator*(const StorageType& rhs) {return *$self * rhs;}
PolyVox::Vector<3,StorageType,OperationType> operator/(const StorageType& rhs) {return *$self / rhs;}
};
%typemap(cscode) PolyVox::Vector<3,StorageType,OperationType> %{
public static Vector3D##StorageType operator+(Vector3D##StorageType lhs, Vector3D##StorageType rhs) {
Vector3D##StorageType newVec = new Vector3D##StorageType();
newVec = lhs.Plus(rhs);
return newVec;
}
public static Vector3D##StorageType operator-(Vector3D##StorageType lhs, Vector3D##StorageType rhs) {
Vector3D##StorageType newVec = new Vector3D##StorageType();
newVec = lhs.Minus(rhs);
return newVec;
}
public static Vector3D##StorageType operator*(Vector3D##StorageType lhs, Vector3D##StorageType rhs) {
Vector3D##StorageType newVec = new Vector3D##StorageType();
newVec = lhs.Multiply(rhs);
return newVec;
}
public static Vector3D##StorageType operator/(Vector3D##StorageType lhs, Vector3D##StorageType rhs) {
Vector3D##StorageType newVec = new Vector3D##StorageType();
newVec = lhs.Divide(rhs);
return newVec;
}
public static Vector3D##StorageType operator*(Vector3D##StorageType lhs, $typemap(cstype, StorageType) rhs) {
Vector3D##StorageType newVec = new Vector3D##StorageType();
newVec = lhs.Multiply(rhs);
return newVec;
}
public static Vector3D##StorageType operator/(Vector3D##StorageType lhs, $typemap(cstype, StorageType) rhs) {
Vector3D##StorageType newVec = new Vector3D##StorageType();
newVec = lhs.Divide(rhs);
return newVec;
}
public bool Equals(Vector3D##StorageType rhs) {
if ((object)rhs == null)
{
return false;
}
return Equal(rhs);
}
%}
%ignore PolyVox::Vector<3,StorageType,OperationType>::operator<; //This is deprecated
#endif
%ignore PolyVox::Vector<3,StorageType,OperationType>::Vector(ReducedStorageType,ReducedStorageType,ReducedStorageType,ReducedStorageType);
%ignore PolyVox::Vector<3,StorageType,OperationType>::Vector(ReducedStorageType,ReducedStorageType);
%ignore PolyVox::Vector<3,StorageType,OperationType>::getW() const;

View File

@ -0,0 +1,32 @@
using System.Diagnostics;
public class test
{
public static void Main()
{
Region r = new Region(new Vector3Dint32_t(0,0,0), new Vector3Dint32_t(31,31,31));
SimpleVolumeuint8 vol = new SimpleVolumeuint8(r);
//Set one single voxel to have a reasonably high density
vol.setVoxelAt(new Vector3Dint32_t(5, 5, 5), 200);
SurfaceMeshPositionMaterialNormal mesh = new SurfaceMeshPositionMaterialNormal();
MarchingCubesSurfaceExtractorSimpleVolumeuint8 extractor = new MarchingCubesSurfaceExtractorSimpleVolumeuint8(vol, r, mesh);
extractor.execute();
Debug.Assert(mesh.getNoOfVertices() == 6);
Vector3Dint32_t v1 = new Vector3Dint32_t(1,2,3);
Vector3Dint32_t v2 = new Vector3Dint32_t(6,8,12);
Vector3Dint32_t v3 = v1 + v2;
Vector3Dint32_t v11 = new Vector3Dint32_t(1,2,3);
Debug.Assert(v3.getX() == 7);
Debug.Assert((v3*5).getX() == 35);
Debug.Assert(v1.Equals(v11));
Debug.Assert(v1 != v11);
Debug.Assert(!v1.Equals(v2));
Debug.Assert(!v1.Equals(null));
System.Console.WriteLine("Success");
}
}