Hi,
I can't find the solution to my problem in any of the other posts, so I'm
writing in a new thread.
For a lighting event here in Eindhoven (NL) our company is going to project an image on a
building using big ass beamers. It's an event which follows up after Glow
(http://www.gloweindhoven.nl/). Our idea was to have an interactive application running
between two users and the image projected by the big ass beamer. We're going to capture
the movements of two users that are "throwing paint" at a building. All the
user does is make the gesture, and my application extrapolates the course the paint will
fly at the building. To round it off; a nice animated splash of paint is then projected
on the building.
So I decided OSG would be a decent way to make this happen. Well... I got most
things in place. Someone supplied a sequence of transparent PNG images for me
to display. I used libpng to load them and put them in a osg::Image object
which I then proceed to put in an osg::ImageSequence object. I then proceed to
do some things I read on these forums to make the loaded PNG appear as a
transparent texture-on-a-quad in my view.
And this actually works:
Code:
SplashContainer
LichtStadEindhovenApp::Splash(
osg::Vec3f position,
osg::Vec2f scale,
DWORD color,
float speed,
int nsplash)
{
SplashContainer cont;
osg::ref_ptr<osg::ImageSequence> tmpImageSequence = new
osg::ImageSequence();
for ( int k = 0 ; k < splash[nsplash]->size() ; k += 1 )
{
tmpImageSequence->addImage(LoadBitmapPNG(splash[nsplash]->operator
[](k).c_str(), color));
}
osg::ref_ptr<osg::Geode> geode = new osg::Geode();
osg::ref_ptr<osg::PositionAttitudeTransform> texPAT = new
osg::PositionAttitudeTransform();
osg::ref_ptr<osg::Geometry> quad1 = createTexturedQuadGeometry(
osg::Vec3d(0.0, 0.0, 0.0), //Center vector
osg::Vec3d(0.0, 0.0, scale.x()), //Width vector
osg::Vec3d(scale.y(), 0.0, 0.0), //Height vector
1.0,
//Texture coordinates left
1.0);
//Texture coordinatse top
texPAT->setPosition(position);
mNavTrans->addChild(texPAT.get());
texPAT->addChild(geode);
osg::Quat q(osg::DegreesToRadians(90.0f), osg::Vec3f(0.0f, 1.0f, 0.0f));
texPAT->setAttitude(q);
geode->addDrawable(quad1.get());
osg::ref_ptr<osg::Texture2D> splashTexture = new
osg::Texture2D(tmpImageSequence);
osg::ref_ptr<osg::StateSet> stateset = quad1->getOrCreateStateSet();
stateset->setTextureAttributeAndModes(0, splashTexture.get(),
osg::StateAttribute::ON);
stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
osg::ref_ptr<osg::BlendFunc> texture_blending_function = new
osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA);
stateset->setAttributeAndModes(texture_blending_function.get(),
osg::StateAttribute::ON);
stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
osg::ref_ptr<osg::AlphaFunc> alpha_transparency_function = new
osg::AlphaFunc();
alpha_transparency_function->setFunction(osg::AlphaFunc::ComparisonFunction::ALWAYS,
0.5);
stateset->setAttributeAndModes(alpha_transparency_function.get(),
osg::StateAttribute::ON );
stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
quad1->setStateSet(stateset.get());
cont.geode = geode;
cont.imgseq = tmpImageSequence;
cont.pos = texPAT;
cont.f_incr = speed;
cont.f_time = 0.0f;
if ( nsplash == 1 || nsplash == 2 )
cont.bSaveLastFrame = false;
else
cont.bSaveLastFrame = true;
printf("ptr count 1: %d\n", tmpImageSequence->referenceCount());
m_vecSplashes.push_back(cont);
printf("ptr count 2: %d\n",
m_vecSplashes[m_vecSplashes.size()-1].imgseq->referenceCount());
nThrown += 1;
return cont;
}
My problem is is that I also want this quad to be 70% transparent. So that when
a new quad is placed in front of it, a little bit of the image farther away
remains visible.
I've read several posts all of which say I should add this piece of code
somewhere.
Code:
osg::Material* mat =
(osg::Material*)stateset->getAttribute(osg::StateAttribute::MATERIAL);
if ( !mat )
mat = new osg::Material();
mat->setAlpha(osg::Material::FRONT_AND_BACK, 0.70f);
stateset->setAttribute(mat, osg::StateAttribute::ON);
however adding it to the function I described above does nothing to achieve
anything at all. My tree looks like this
Code:
// texPAT -- geode
-- quad
// /
// mRoot -- mPos -- mTrans -- mNavTrans
// \ \ \
// \ \ texPAT -- geode
-- quad
// \ texPAT -- geode --
quad
// texPAT -- geode -- quad
I tried setting the state of mNavTrans to make all underlying objects
transparent. That didn't work, but I think that's because the individual PNG
transparency code will override any changes made in the parent node.
At the moment all my images are displayed with correct transparency in the
image. However I also want to achieve the effect where the quad on which that
image is printed also becomes transparent. Nothing I do seems to be able to
change that. Does anybody have any suggestions?
Here's some more interesting code that might shed some more light on my project.
Code:
osg::Image*
LichtStadEindhovenApp::LoadBitmapPNG(
LPCTSTR szFile,
DWORD col)
{
osg::Image* image = new osg::Image();
HBITMAP hbm = NULL;
bool retVal = false;
bool shouldWeLoad = true;
int size = 0;
int index = 0;
int i = 0;
while ( i < loadedPNGs.size() )
{
if ( strcmp(loadedPNGs[i].file.c_str(), szFile) == 0 )
{
//printf("PNG's already loaded, do not load again!\n");
shouldWeLoad = false;
index = i;
break;
}
i += 1;
}
if ( shouldWeLoad == true )
{
// check the header first
FILE *fp = fopen(szFile, "rb");
if (!fp)
return false;
BYTE header[8];
fread(header, 1, 8, fp);
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fclose(fp);
if (png_sig_cmp(header, 0, 8))
return false;
// now allocate stuff
png_structp png_ptr =
png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, user_error_fn,
user_warning_fn);
if (!png_ptr)
return false;
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{
png_destroy_read_struct(&png_ptr, (png_infopp)NULL,
(png_infopp)NULL);
return false;
}
png_infop end_info = png_create_info_struct(png_ptr);
if (!end_info)
{
png_destroy_read_struct(&png_ptr, &info_ptr,
(png_infopp)NULL);
return false;
}
fp = fopen(szFile, "rb");
if (fp == NULL)
return NULL;
png_init_io(png_ptr, fp);
// should really use png_set_rows() to allocate space first, rather than doubling up
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING, NULL);
fclose(fp);
struct PNGInfo pinfo;
pinfo.file = std::string(szFile);
pinfo.end_info = end_info;
pinfo.info_ptr = info_ptr;
pinfo.png_ptr = png_ptr;
loadedPNGs.push_back(pinfo);
index = loadedPNGs.size() - 1;
}
png_bytep* row_pointers = png_get_rows(loadedPNGs[index].png_ptr, loadedPNGs[index].info_ptr);
// now for a tonne of ugly DIB setup crap
int width = loadedPNGs[index].info_ptr->width;
int height = loadedPNGs[index].info_ptr->height;
int bpp = loadedPNGs[index].info_ptr->channels * 8;
int memWidth = (width * (bpp >> 3) + 3) & ~3;
LPBITMAPINFO lpbi = (LPBITMAPINFO) new char[sizeof(BITMAPINFOHEADER) + (256 * sizeof(RGBQUAD))];
// create a greyscale palette
for (int a_i = 0; a_i < 256; a_i++)
{
lpbi->bmiColors[a_i].rgbRed = (BYTE)a_i;
lpbi->bmiColors[a_i].rgbGreen = (BYTE)a_i;
lpbi->bmiColors[a_i].rgbBlue = (BYTE)a_i;
lpbi->bmiColors[a_i].rgbReserved = (BYTE)a_i;
}
lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
lpbi->bmiHeader.biWidth = width;
lpbi->bmiHeader.biHeight = -height; // must be negative for top down
lpbi->bmiHeader.biPlanes = 1;
lpbi->bmiHeader.biBitCount = bpp;
lpbi->bmiHeader.biCompression = BI_RGB;
lpbi->bmiHeader.biSizeImage = memWidth * height;
lpbi->bmiHeader.biXPelsPerMeter = 0;
lpbi->bmiHeader.biYPelsPerMeter = 0;
lpbi->bmiHeader.biClrUsed = 0;
lpbi->bmiHeader.biClrImportant = 0;
BYTE * pixelData = NULL;
hbm = ::CreateDIBSection(NULL, lpbi, DIB_RGB_COLORS, (void
**)&pixelData, NULL, 0 );
if (hbm && pixelData)
{
// now copy the rows
for (int i = 0; i < height; i++)
{
int bitesize = width *
loadedPNGs[index].info_ptr->channels;
BYTE* buff = new BYTE[bitesize];
memset(buff, 0, bitesize);
memcpy(buff, row_pointers[i], bitesize);
for ( int g = 0 ; g < width ; g += 1 )
{
buff[(g * loadedPNGs[index].info_ptr->channels)
+ 0] = GetRValue(col);
buff[(g * loadedPNGs[index].info_ptr->channels)
+ 1] = GetGValue(col);
buff[(g * loadedPNGs[index].info_ptr->channels)
+ 2] = GetBValue(col);
buff[(g * loadedPNGs[index].info_ptr->channels)
+ 3] = 128;
}
memcpy(pixelData + memWidth * i, buff, bitesize);
delete [] buff;
buff = NULL;
}
}
// Create data to hold the destination image
BYTE* ptrDestImage = new unsigned char[width * height * 4];
BYTE* ptrSourceRow = NULL;
BYTE* ptrDestRow = NULL;
int iWidth = width;
int iHeight = height;
// Copy the System::Drawing::Bitmap instance over line by line - this gets around the
// lack of stride support in the osg::Image.
for (int i = 0; i < iHeight; i++)
{
// Get the source row pointer
ptrSourceRow = pixelData + (i * (iWidth * 4));
// Get the destination row pointer
ptrDestRow = ptrDestImage + (i * (iWidth * 4));
// Copy the source row to the destination row
memcpy(ptrDestRow, ptrSourceRow, iWidth * 4);
}
// Set the data on the osg::Image
image->setImage(
iWidth,
iHeight,
1,
GL_RGBA,
GL_RGBA,
GL_UNSIGNED_BYTE,
ptrDestImage,
osg::Image::AllocationMode::USE_NEW_DELETE);
//delete [] ptrDestImage;
::DeleteObject(hbm);
delete (char*) lpbi;
//png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
return image;
}
Thank you!
Cheers,
Rene[/code]
------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=18680#18680
_______________________________________________
osg-users mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org