BGE VideoTexture: add depth buffer access to ImageViewport and ImageRender.

2 new attributes to ImageViewport and ImageRender object:
depth: set to True to retrieve the depth buffer as an array of float
       (not suitable for texture source).
zbuff: set to True to retrieve the depth buffer as a grey scale pixel array
       (suitable for texture source).

A new mode 'F' is added to VideoTexture.imageToArray() to allow returning the image
buffer as a one dimensional array of float. This mode should only be used to retrieve
the depth buffer of ImageViewport and ImageRender objects.

Example:

viewport = VideoTexture.ImageViewport()
viewport.depth = True
depth = VideoTexture.imageToArray(viewport,'F')
# show depth of bottom left pixel
# 1.0 = infinite, 0.0 = on near clip plane.
print(depth[0])
This commit is contained in:
Benoit Bolsee 2012-10-20 22:28:44 +00:00
parent 7deb8d8a26
commit 4213eca5fc
7 changed files with 204 additions and 5 deletions

@ -351,6 +351,15 @@ When the texture object is deleted, the new texture is deleted and the old textu
use whole viewport to render
.. attribute:: depth
use depth component of render as array of float - not suitable for texture source,
should only be used with bge.texture.imageToArray(mode='F')
.. attribute:: zbuff
use depth component of render as grey scale color - suitable for texture source
.. class:: ImageViewport()
Image source from viewport
@ -399,6 +408,15 @@ When the texture object is deleted, the new texture is deleted and the old textu
use whole viewport to capture
.. attribute:: depth
use depth component of viewport as array of float - not suitable for texture source,
should only be used with bge.texture.imageToArray(mode='F')
.. attribute:: zbuff
use depth component of viewport as grey scale color - suitable for texture source
.. class:: Texture(gameObj)
Texture objects
@ -518,13 +536,16 @@ When the texture object is deleted, the new texture is deleted and the old textu
0 to force a fixed 0 color channel and 1 to force a fixed 255 color channel.
Example: "BGR" will return 3 bytes per pixel with the Blue, Green and Red channels in that order.
"RGB1" will return 4 bytes per pixel with the Red, Green, Blue channels in that order and the alpha channel forced to 255.
A special mode "F" allows to return the image as an array of float. This mode should only be used to retrieve
the depth buffer of the ImageViewport and ImageRender object.
The default mode is "RGBA".
:type mode: string
:rtype: :class:`~bgl.buffer`
:return: A object representing the image as one dimensional array of bytes of size (pixel_size*width*height),
line by line starting from the bottom of the image. The pixel size and format is determined by the mode
parameter.
parameter. For mode 'F', the array is a one dimensional array of float of size (width*height).
.. function:: materialID(object,name)

@ -95,6 +95,10 @@ protected:
virtual unsigned int filter (unsigned int * src, short x, short y,
short * size, unsigned int pixSize, unsigned int val = 0)
{ return val; }
/// filter pixel, source float buffer
virtual unsigned int filter (float * src, short x, short y,
short * size, unsigned int pixSize, unsigned int val = 0)
{ return val; }
/// get source pixel size
virtual unsigned int getPixelSize (void) { return 1; }

@ -31,7 +31,6 @@ http://www.gnu.org/copyleft/lesser.txt.
#include "FilterBase.h"
/// class for RGB24 conversion
class FilterRGB24 : public FilterBase
{
@ -97,6 +96,65 @@ protected:
{ VT_RGBA(val,src[2],src[1],src[0],0xFF); return val; }
};
/// class for Z_buffer conversion
class FilterZZZA : public FilterBase
{
public:
/// constructor
FilterZZZA (void) {}
/// destructor
virtual ~FilterZZZA (void) {}
/// get source pixel size
virtual unsigned int getPixelSize (void) { return 1; }
protected:
/// filter pixel, source float buffer
virtual unsigned int filter (float * src, short x, short y,
short * size, unsigned int pixSize, unsigned int val)
{
// calculate gray value
// convert float to unsigned char
unsigned int depth = int(src[0] * 255);
// return depth scale value
VT_R(val) = depth;
VT_G(val) = depth;
VT_B(val) = depth;
VT_A(val) = 0xFF;
return val;
}
};
/// class for Z_buffer conversion
class FilterDEPTH : public FilterBase
{
public:
/// constructor
FilterDEPTH (void) {}
/// destructor
virtual ~FilterDEPTH (void) {}
/// get source pixel size
virtual unsigned int getPixelSize (void) { return 1; }
protected:
/// filter pixel, source float buffer
virtual unsigned int filter (float * src, short x, short y,
short * size, unsigned int pixSize, unsigned int val)
{
// Copy the float value straight away
// The user can retrieve the original float value by using
// 'F' mode in BGL buffer
memcpy(&val, src, sizeof (unsigned int));
return val;
}
};
/// class for YV12 conversion
class FilterYV12 : public FilterBase
{

@ -49,6 +49,8 @@ extern "C" {
// constructor
ImageBase::ImageBase (bool staticSrc) : m_image(NULL), m_imgSize(0),
m_avail(false), m_scale(false), m_scaleChange(false), m_flip(false),
m_zbuff(false),
m_depth(false),
m_staticSources(staticSrc), m_pyfilter(NULL)
{
m_size[0] = m_size[1] = 0;
@ -402,6 +404,18 @@ PyObject *Image_getImage (PyImage *self, char * mode)
{
buffer = BGL_MakeBuffer( GL_BYTE, 1, &dimensions, image);
}
else if (!strcasecmp(mode, "F"))
{
// this mode returns the image as an array of float.
// This makes sense ONLY for the depth buffer:
// source = VideoTexture.ImageViewport()
// source.depth = True
// depth = VideoTexture.imageToArray(source, 'F')
// adapt dimension from byte to float
dimensions /= sizeof(float);
buffer = BGL_MakeBuffer( GL_FLOAT, 1, &dimensions, image);
}
else
{
int i, c, ncolor, pixels;
@ -532,6 +546,52 @@ int Image_setFlip (PyImage *self, PyObject *value, void *closure)
return 0;
}
// get zbuff
PyObject * Image_getZbuff (PyImage * self, void * closure)
{
if (self->m_image != NULL && self->m_image->getZbuff()) Py_RETURN_TRUE;
else Py_RETURN_FALSE;
}
// set zbuff
int Image_setZbuff (PyImage * self, PyObject * value, void * closure)
{
// check parameter, report failure
if (value == NULL || !PyBool_Check(value))
{
PyErr_SetString(PyExc_TypeError, "The value must be a bool");
return -1;
}
// set scale
if (self->m_image != NULL) self->m_image->setZbuff(value == Py_True);
// success
return 0;
}
// get depth
PyObject * Image_getDepth (PyImage * self, void * closure)
{
if (self->m_image != NULL && self->m_image->getDepth()) Py_RETURN_TRUE;
else Py_RETURN_FALSE;
}
// set depth
int Image_setDepth (PyImage * self, PyObject * value, void * closure)
{
// check parameter, report failure
if (value == NULL || !PyBool_Check(value))
{
PyErr_SetString(PyExc_TypeError, "The value must be a bool");
return -1;
}
// set scale
if (self->m_image != NULL) self->m_image->setDepth(value == Py_True);
// success
return 0;
}
// get filter source object
PyObject *Image_getSource (PyImage *self, PyObject *args)

@ -78,6 +78,14 @@ public:
bool getFlip (void) { return m_flip; }
/// set vertical flip
void setFlip (bool flip) { m_flip = flip; }
/// get Z buffer
bool getZbuff (void) { return m_zbuff; }
/// set Z buffer
void setZbuff (bool zbuff) { m_zbuff = zbuff; }
/// get depth
bool getDepth (void) { return m_depth; }
/// set depth
void setDepth (bool depth) { m_depth = depth; }
/// get source object
PyImage * getSource (const char * id);
@ -111,6 +119,10 @@ protected:
bool m_scaleChange;
/// flip image vertically
bool m_flip;
/// use the Z buffer as a texture
bool m_zbuff;
/// extract the Z buffer with unisgned int precision
bool m_depth;
/// source image list
ImageSourceList m_sources;
@ -347,7 +359,15 @@ int Image_setFlip (PyImage *self, PyObject *value, void *closure);
PyObject *Image_getSource (PyImage *self, PyObject *args);
// set filter source object
PyObject *Image_setSource (PyImage *self, PyObject *args);
// get Z buffer
PyObject * Image_getZbuff (PyImage * self, void * closure);
// set Z buffer
int Image_setZbuff (PyImage * self, PyObject * value, void * closure);
// get depth
PyObject * Image_getDepth (PyImage * self, void * closure);
// set depth
int Image_setDepth (PyImage * self, PyObject * value, void * closure);
// get pixel filter object
PyObject *Image_getFilter (PyImage *self, void *closure);
// set pixel filter object

@ -385,6 +385,8 @@ static PyGetSetDef imageRenderGetSets[] =
{(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL},
{(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbor)", NULL},
{(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL},
{(char*)"zbuff", (getter)Image_getZbuff, (setter)Image_setZbuff, (char*)"use depth buffer as texture", NULL},
{(char*)"depth", (getter)Image_getDepth, (setter)Image_setDepth, (char*)"get depth information from z-buffer using unsigned int precision", NULL},
{(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL},
{NULL}
};
@ -547,6 +549,8 @@ static PyGetSetDef imageMirrorGetSets[] =
{(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL},
{(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbor)", NULL},
{(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL},
{(char*)"zbuff", (getter)Image_getZbuff, (setter)Image_setZbuff, (char*)"use depth buffer as texture", NULL},
{(char*)"depth", (getter)Image_getDepth, (setter)Image_setDepth, (char*)"get depth information from z-buffer using unsigned int precision", NULL},
{(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL},
{NULL}
};

@ -50,6 +50,8 @@ ImageViewport::ImageViewport (void) : m_alpha(false), m_texInit(false)
//glGetIntegerv(GL_VIEWPORT, m_viewport);
// create buffer for viewport image
// Warning: this buffer is also used to get the depth buffer as an array of
// float (1 float = 4 bytes per pixel)
m_viewportImage = new BYTE [4 * getViewportSize()[0] * getViewportSize()[1]];
// set attributes
setWhole(false);
@ -57,7 +59,9 @@ ImageViewport::ImageViewport (void) : m_alpha(false), m_texInit(false)
// destructor
ImageViewport::~ImageViewport (void)
{ delete [] m_viewportImage; }
{
delete [] m_viewportImage;
}
// use whole viewport to capture image
@ -131,7 +135,7 @@ void ImageViewport::calcImage (unsigned int texId, double ts)
}
// if texture can be directly created
if (texId != 0 && m_pyfilter == NULL && m_capSize[0] == calcSize(m_capSize[0])
&& m_capSize[1] == calcSize(m_capSize[1]) && !m_flip)
&& m_capSize[1] == calcSize(m_capSize[1]) && !m_flip && !m_zbuff && !m_depth)
{
// just copy current viewport to texture
glBindTexture(GL_TEXTURE_2D, texId);
@ -142,6 +146,32 @@ void ImageViewport::calcImage (unsigned int texId, double ts)
// otherwise copy viewport to buffer, if image is not available
else if (!m_avail)
{
if (m_zbuff)
{
// Use read pixels with the depth buffer
// *** misusing m_viewportImage here, but since it has the correct size
// (4 bytes per pixel = size of float) and we just need it to apply
// the filter, it's ok
glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1],
GL_DEPTH_COMPONENT, GL_FLOAT, m_viewportImage);
// filter loaded data
FilterZZZA filt;
filterImage(filt, (float *)m_viewportImage, m_capSize);
}
else
if (m_depth)
{
// Use read pixels with the depth buffer
// See warning above about m_viewportImage.
glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1],
GL_DEPTH_COMPONENT, GL_FLOAT, m_viewportImage);
// filter loaded data
FilterDEPTH filt;
filterImage(filt, (float *)m_viewportImage, m_capSize);
}
else
// get frame buffer data
if (m_alpha)
{
@ -310,6 +340,8 @@ static PyGetSetDef imageViewportGetSets[] =
{(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL},
{(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbor)", NULL},
{(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL},
{(char*)"zbuff", (getter)Image_getZbuff, (setter)Image_setZbuff, (char*)"use depth buffer as texture", NULL},
{(char*)"depth", (getter)Image_getDepth, (setter)Image_setDepth, (char*)"get depth information from z-buffer as array of float", NULL},
{(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL},
{NULL}
};