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

