Skip to content
Snippets Groups Projects
Commit 9cef12c2 authored by Paul McCarthy's avatar Paul McCarthy
Browse files

Tensors are now drawn with only the unique vertices, and an index array.

parent dc5cc572
No related branches found
No related tags found
No related merge requests found
...@@ -29,6 +29,7 @@ class TensorOpts(vectoropts.VectorOpts): ...@@ -29,6 +29,7 @@ class TensorOpts(vectoropts.VectorOpts):
# Tensor ellipsoid resolution # Tensor ellipsoid resolution
tensorResolution = props.Int(default=10) tensorResolution = props.Int(default=10)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
......
...@@ -12,6 +12,7 @@ import numpy as np ...@@ -12,6 +12,7 @@ import numpy as np
import OpenGL.GL as gl import OpenGL.GL as gl
import OpenGL.raw.GL._types as gltypes import OpenGL.raw.GL._types as gltypes
import OpenGL.GL.ARB.instanced_arrays as arbia import OpenGL.GL.ARB.instanced_arrays as arbia
import OpenGL.GL.ARB.draw_instanced as arbdi
import fsl.utils.transform as transform import fsl.utils.transform as transform
import fsl.fsleyes.gl.resources as glresources import fsl.fsleyes.gl.resources as glresources
...@@ -63,6 +64,7 @@ def init(self): ...@@ -63,6 +64,7 @@ def init(self):
setattr(self, '{}Texture'.format(name), tex) setattr(self, '{}Texture'.format(name), tex)
self.vertexBuffer = gl.glGenBuffers(1) self.vertexBuffer = gl.glGenBuffers(1)
self.indexBuffer = gl.glGenBuffers(1)
self.voxelBuffer = gl.glGenBuffers(1) self.voxelBuffer = gl.glGenBuffers(1)
self.shaders = None self.shaders = None
...@@ -73,6 +75,7 @@ def init(self): ...@@ -73,6 +75,7 @@ def init(self):
def destroy(self): def destroy(self):
gl.glDeleteBuffers(1, gltypes.GLuint(self.vertexBuffer)) gl.glDeleteBuffers(1, gltypes.GLuint(self.vertexBuffer))
gl.glDeleteBuffers(1, gltypes.GLuint(self.indexBuffer))
gl.glDeleteBuffers(1, gltypes.GLuint(self.voxelBuffer)) gl.glDeleteBuffers(1, gltypes.GLuint(self.voxelBuffer))
gl.glDeleteProgram(self.shaders) gl.glDeleteProgram(self.shaders)
...@@ -189,14 +192,23 @@ def updateShaderState(self): ...@@ -189,14 +192,23 @@ def updateShaderState(self):
# shader will transform these vertices # shader will transform these vertices
# into the tensor ellipsoid for each # into the tensor ellipsoid for each
# voxel. # voxel.
vertices = glroutines.unitSphere(resolution).ravel('C') vertices, indices = glroutines.unitSphere(resolution)
self.nVertices = len(vertices) / 3 self.nVertices = len(indices)
vertices = vertices.ravel('C')
gl.glUseProgram(0)
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.vertexBuffer) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.vertexBuffer)
gl.glBufferData( gl.glBufferData(
gl.GL_ARRAY_BUFFER, vertices.nbytes, vertices, gl.GL_STATIC_DRAW) gl.GL_ARRAY_BUFFER, vertices.nbytes, vertices, gl.GL_STATIC_DRAW)
gl.glUseProgram(0)
gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, self.indexBuffer)
gl.glBufferData(
gl.GL_ELEMENT_ARRAY_BUFFER, indices.nbytes, indices, gl.GL_STATIC_DRAW)
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)
gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, 0)
def preDraw(self): def preDraw(self):
...@@ -239,20 +251,23 @@ def draw(self, zpos, xform=None): ...@@ -239,20 +251,23 @@ def draw(self, zpos, xform=None):
voxels = transform.transform(voxels, d2vMat) voxels = transform.transform(voxels, d2vMat)
nVoxels = len(voxels) nVoxels = len(voxels)
voxels = np.array(voxels, dtype=np.float32).ravel('C')
voxels = np.array(voxels, dtype=np.float32).ravel('C') # Copy the voxel coordinates to the voxel buffer
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.voxelBuffer) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.voxelBuffer)
gl.glBufferData( gl.glBufferData(
gl.GL_ARRAY_BUFFER, voxels.nbytes, voxels, gl.GL_STATIC_DRAW) gl.GL_ARRAY_BUFFER, voxels.nbytes, voxels, gl.GL_STATIC_DRAW)
gl.glVertexAttribPointer( gl.glVertexAttribPointer(
self.voxelPos, 3, gl.GL_FLOAT, gl.GL_FALSE, 0, None) self.voxelPos, 3, gl.GL_FLOAT, gl.GL_FALSE, 0, None)
# Use one set of voxel coordinates for every sphere drawn
arbia.glVertexAttribDivisorARB(self.voxelPos, 1) arbia.glVertexAttribDivisorARB(self.voxelPos, 1)
# Bind the vertex buffer # Bind the vertex buffer
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.vertexBuffer) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.vertexBuffer)
gl.glVertexAttribPointer( gl.glVertexAttribPointer(
self.vertexPos, 3, gl.GL_FLOAT, gl.GL_FALSE, 0, None) self.vertexPos, 3, gl.GL_FLOAT, gl.GL_FALSE, 0, None)
if xform is None: xform = v2dMat if xform is None: xform = v2dMat
else: xform = transform.concat(v2dMat, xform) else: xform = transform.concat(v2dMat, xform)
...@@ -260,12 +275,17 @@ def draw(self, zpos, xform=None): ...@@ -260,12 +275,17 @@ def draw(self, zpos, xform=None):
xform = np.array(xform, dtype=np.float32).ravel('C') xform = np.array(xform, dtype=np.float32).ravel('C')
gl.glUniformMatrix4fv(self.voxToDisplayMatPos, 1, False, xform) gl.glUniformMatrix4fv(self.voxToDisplayMatPos, 1, False, xform)
gl.glDrawArraysInstanced(gl.GL_QUADS, 0, self.nVertices, nVoxels) # And the vertex index buffer
gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, self.indexBuffer)
arbdi.glDrawElementsInstancedARB(
gl.GL_QUADS, self.nVertices, gl.GL_UNSIGNED_INT, None, nVoxels)
def postDraw(self): def postDraw(self):
gl.glUseProgram(0) gl.glUseProgram(0)
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0) gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)
gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, 0)
self.v1Texture.unbindTexture() self.v1Texture.unbindTexture()
self.v2Texture.unbindTexture() self.v2Texture.unbindTexture()
self.v3Texture.unbindTexture() self.v3Texture.unbindTexture()
......
...@@ -648,14 +648,74 @@ def unitSphere(res): ...@@ -648,14 +648,74 @@ def unitSphere(res):
:arg res: Resolution - the number of angles to sample. :arg res: Resolution - the number of angles to sample.
:returns: A tuple comprising:
- a ``numpy.float32`` array of size ``((res + 1)**2, 3)``
containing a set of ``(x, y, z)`` vertices which define
the ellipsoid surface.
- A ``numpy.uint32`` array of size ``(4 * res * res)``
containing a list of indices into the vertex array,
defining a vertex ordering that can be used to draw
the ellipsoid using the OpenGL ``GL_QUAD`` primitive type.
"""
ustep = np.pi / res
vstep = np.pi * 2.0 / res
# All angles to be sampled
u = np.linspace(-np.pi / 2, np.pi / 2 + ustep, res + 1, dtype=np.float32)
v = np.linspace(-np.pi, np.pi + vstep, res + 1, dtype=np.float32)
cosu = np.cos(u)
cosv = np.cos(v)
sinu = np.sin(u)
sinv = np.sin(v)
cucv = np.outer(cosu, cosv)
cusv = np.outer(cosu, sinv)
vertices = np.zeros(((res + 1) ** 2, 3), dtype=np.float32)
# All x coordinates are of the form cos(u) * cos(v),
# y coordinates are of the form cos(u) * sin(v),
# and z coordinates of the form sin(u).
vertices[:, 0] = cucv.flatten()
vertices[:, 1] = cusv.flatten()
vertices[:, 2] = sinu.repeat(res + 1)
# Generate a list of indices which join the
# vertices so they can be used to draw the
# sphere as GL_QUADs.
#
# The vertex locations for each quad follow
# this pattern:
#
# 1. (u, v)
# 2. (u + ustep, v)
# 3. (u + ustep, v + vstep)
# 4. (u, v + vstep)
nquads = res * res
quadIdxs = np.array([0, res + 1, res + 2, 1], dtype=np.uint32)
indices = np.tile(quadIdxs, nquads)
indices += np.arange(nquads, dtype=np.uint32).repeat(4)
indices += np.arange(res, dtype=np.uint32).repeat(4 * res)
return vertices, indices
def fullUnitSphere(res):
"""Generates a unit sphere in the same way as :func:`unitSphere`, but
returns all vertices, instead of the unique vertices and an index array.
:arg res: Resolution - the number of angles to sample.
:returns: A ``numpy.float32`` array of size ``(4 * res**2, 3)`` containing :returns: A ``numpy.float32`` array of size ``(4 * res**2, 3)`` containing
the ``(x, y, z)`` vertices which can be used to draw a unit the ``(x, y, z)`` vertices which can be used to draw a unit
sphere (using the ``GL_QUAD`` primitive type). sphere (using the ``GL_QUAD`` primitive type).
""" """
# TODO Eliminate duplicate vertices,
# and return an index array
ustep = np.pi / res ustep = np.pi / res
vstep = np.pi * 2.0 / res vstep = np.pi * 2.0 / res
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment