From 96f2062115b7fd3959a2dc265e9561896c28f21c Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 7 May 2008 14:17:15 +0000 Subject: [PATCH] From Miguel Escriva, "Attached to this mail you will find some files to work with the Philips WOWvx displays. It's implemented in the same way that 3D Spherical Display and Panoramic Spherical Display. You can test it running: osgviewer --wowvx-20 cow.osg osgviewer --wowvx-42 cow.osg depending on the size of your Philips WOWvx display (20" or 42") Other arguments you can use to control the 3D effect are: --wow-content This value defines the kind of content that can be: 0: No depth 1: Signage 2: Movie 3: CGI 4: Still --wow-factor Percentage of the display recommended depth value. Default 64, Range [0-255] --wow-offset Amount of range behind the screen. Default 128, Range [0-255] 0: Range is shifted in the direction of the viewer. 128: Range is equally divided in front and behind the screen. 255: Range is shifted away from the viewer. " --- include/osgViewer/View | 3 + src/osgViewer/View.cpp | 250 +++++++++++++++++++++++++++++++++++++++ src/osgViewer/Viewer.cpp | 33 +++++- 3 files changed, 285 insertions(+), 1 deletion(-) diff --git a/include/osgViewer/View b/include/osgViewer/View index 884e751ed..5e17cd88b 100644 --- a/include/osgViewer/View +++ b/include/osgViewer/View @@ -166,6 +166,9 @@ class OSGVIEWER_EXPORT View : public osg::View, public osgGA::GUIActionAdapter /** Convenience method for spherical display by rendering main scene to as panoramic 2:1 texture and then doing distortion correction to present onto a spherical display.*/ void setUpViewForPanoramicSphericalDisplay(double radius=1.0, double collar=0.45, unsigned int screenNum=0, osg::Image* intensityMap=0, const osg::Matrixd& projectorMatrix = osg::Matrixd()); + /** Convenience method for autostereoscopic Philips WoWvx display.*/ + void setUpViewForWoWVxDisplay(unsigned int screenNum, unsigned char wow_content, unsigned char wow_factor, unsigned char wow_offset, float wow_disparity_Zd, float wow_disparity_vz, float wow_disparity_M, float wow_disparity_C); + /** Return true if this view contains a specified camera.*/ bool containsCamera(const osg::Camera* camera) const; diff --git a/src/osgViewer/View.cpp b/src/osgViewer/View.cpp index 05ec6421f..687c60383 100644 --- a/src/osgViewer/View.cpp +++ b/src/osgViewer/View.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -1364,6 +1365,255 @@ void View::setUpViewForPanoramicSphericalDisplay(double radius, double collar, u } } +void View::setUpViewForWoWVxDisplay(unsigned int screenNum, unsigned char wow_content, unsigned char wow_factor, unsigned char wow_offset, float wow_disparity_Zd, float wow_disparity_vz, float wow_disparity_M, float wow_disparity_C) +{ + osg::notify(osg::INFO)<<"View::setUpViewForWoWVxDisplay(...)"<getScreenResolution(si, width, height); + + osg::ref_ptr traits = new osg::GraphicsContext::Traits; + traits->hostName = si.hostName; + traits->displayNum = si.displayNum; + traits->screenNum = si.screenNum; + traits->x = 0; + traits->y = 0; + traits->width = width; + traits->height = height; + traits->windowDecoration = false; + traits->doubleBuffer = true; + traits->sharedContext = 0; + + + osg::ref_ptr gc = osg::GraphicsContext::createGraphicsContext(traits.get()); + if (!gc) + { + osg::notify(osg::NOTICE)<<"GraphicsWindow has not been created successfully."<setTextureSize(tex_width, tex_height); + texture->setInternalFormat(GL_RGB); + texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); + texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); + + osg::Texture2D* textureD = new osg::Texture2D; + textureD->setTextureSize(tex_width, tex_height); + textureD->setInternalFormat(GL_DEPTH_COMPONENT); + textureD->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); + textureD->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); + +#if 0 + osg::Camera::RenderTargetImplementation renderTargetImplementation = osg::Camera::SEPERATE_WINDOW; + GLenum buffer = GL_FRONT; +#else + osg::Camera::RenderTargetImplementation renderTargetImplementation = osg::Camera::FRAME_BUFFER_OBJECT; + GLenum buffer = GL_FRONT; +#endif + + // front face + { + osg::ref_ptr camera = new osg::Camera; + camera->setName("Front face camera"); + camera->setGraphicsContext(gc.get()); + camera->setViewport(new osg::Viewport(0,0,camera_width, camera_height)); + camera->setDrawBuffer(buffer); + camera->setReadBuffer(buffer); + camera->setAllowEventFocus(false); + // tell the camera to use OpenGL frame buffer object where supported. + camera->setRenderTargetImplementation(renderTargetImplementation); + + // attach the texture and use it as the color buffer. + camera->attach(osg::Camera::COLOR_BUFFER, texture); + camera->attach(osg::Camera::DEPTH_BUFFER, textureD); + + addSlave(camera.get(), osg::Matrixd(), osg::Matrixd()); + } + + // WoW display set up. + { + osg::Texture1D *textureHeader = new osg::Texture1D(); + // Set up the header + { + unsigned char header[]= {0xF1,wow_content,wow_factor,wow_offset,0x00,0x00,0x00,0x00,0x00,0x00}; + // Calc the CRC32 + { + unsigned long _register = 0; + for(int i = 0; i < 10; ++i) { + unsigned char mask = 0x80; + unsigned char byte = header[i]; + for (int j = 0; j < 8; ++j) + { + bool topBit = (_register & 0x80000000) != 0; + _register <<= 1; + _register ^= ((byte & mask) != 0? 0x1: 0x0); + if (topBit) + { + _register ^= 0x04c11db7; + } + mask >>= 1; + } + } + unsigned char *p = (unsigned char*) &_register; + for(size_t i = 0; i < 4; ++i) + { + header[i+6] = p[3-i]; + } + } + + osg::ref_ptr imageheader = new osg::Image(); + imageheader->allocateImage(256,1,1,GL_LUMINANCE,GL_UNSIGNED_BYTE); + { + unsigned char *cheader = imageheader->data(); + for (int x=0; x<256; ++x){ + cheader[x] = 0; + } + for (int x=0; x<=9; ++x){ + for (int y=7; y>=0; --y){ + int i = 2*(7-y)+16*x; + cheader[i] = (((1<<(y))&(header[x])) << (7-(y))); + } + } + } + textureHeader->setImage(imageheader.get()); + } + + // Create the Screen Aligned Quad + osg::Geode* geode = new osg::Geode(); + { + osg::Geometry* geom = new osg::Geometry; + + osg::Vec3Array* vertices = new osg::Vec3Array; + vertices->push_back(osg::Vec3(0,height,0)); + vertices->push_back(osg::Vec3(0,0,0)); + vertices->push_back(osg::Vec3(width,0,0)); + vertices->push_back(osg::Vec3(width,height,0)); + geom->setVertexArray(vertices); + + osg::Vec2Array* tex = new osg::Vec2Array; + tex->push_back(osg::Vec2(0,1)); + tex->push_back(osg::Vec2(0,0)); + tex->push_back(osg::Vec2(1,0)); + tex->push_back(osg::Vec2(1,1)); + geom->setTexCoordArray(0,tex); + + geom->addPrimitiveSet(new osg::DrawArrays(GL_QUADS,0,4)); + geode->addDrawable(geom); + + // new we need to add the textures to the quad, and setting up the shader. + osg::StateSet* stateset = geode->getOrCreateStateSet(); + stateset->setTextureAttributeAndModes(0, textureHeader,osg::StateAttribute::ON); + stateset->setTextureAttributeAndModes(1, texture,osg::StateAttribute::ON); + stateset->setTextureAttributeAndModes(2, textureD,osg::StateAttribute::ON); + stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF); + + osg::ref_ptr programShader = new osg::Program(); + stateset->setAttribute(programShader.get(), osg::StateAttribute::ON); + stateset->addUniform( new osg::Uniform("wow_width", (int)width)); + stateset->addUniform( new osg::Uniform("wow_height", (int)height)); + stateset->addUniform( new osg::Uniform("wow_disparity_M", wow_disparity_M)); + stateset->addUniform( new osg::Uniform("wow_disparity_Zd", wow_disparity_Zd)); + stateset->addUniform( new osg::Uniform("wow_disparity_vz", wow_disparity_vz)); + stateset->addUniform( new osg::Uniform("wow_disparity_C", wow_disparity_C)); + + stateset->addUniform(new osg::Uniform("wow_header", 0)); + stateset->addUniform(new osg::Uniform("wow_tcolor", 1)); + stateset->addUniform(new osg::Uniform("wow_tdepth", 2)); + + osg::Shader *frag = new osg::Shader(osg::Shader::FRAGMENT); + frag->setShaderSource(" "\ + " uniform sampler1D wow_header; " \ + " uniform sampler2D wow_tcolor; " \ + " uniform sampler2D wow_tdepth; " \ + " " \ + " uniform int wow_width; " \ + " uniform int wow_height; " \ + " uniform float wow_disparity_M; " \ + " uniform float wow_disparity_Zd; " \ + " uniform float wow_disparity_vz; " \ + " uniform float wow_disparity_C; " \ + " " \ + " float disparity(float Z) " \ + " { " \ + " return (wow_disparity_M*(1.0-(wow_disparity_vz/(Z-wow_disparity_Zd+wow_disparity_vz))) " \ + " + wow_disparity_C) / 255.0; " \ + " } " \ + " " \ + " void main() " \ + " { " \ + " vec2 pos = (gl_FragCoord.xy / vec2(wow_width/2,wow_height) ); " \ + " if (gl_FragCoord.x > float(wow_width/2)) " \ + " { " \ + " gl_FragColor = vec4(disparity(( texture2D(wow_tdepth, pos - vec2(1,0))).z)); " \ + " } " \ + " else{ " \ + " gl_FragColor = texture2D(wow_tcolor, pos); " \ + " } " \ + " if ( (gl_FragCoord.y >= float(wow_height-1)) && (gl_FragCoord.x < 256.0) ) " \ + " { " \ + " float pos = gl_FragCoord.x/256.0; " \ + " float blue = texture1D(wow_header, pos).b; " \ + " if ( blue < 0.5) " \ + " gl_FragColor.b -=0.5; " \ + " else " \ + " gl_FragColor.b += 0.5; " \ + " } " \ + " } " ); + + programShader->addShader(frag); + } + + // Create the Camera + { + osg::ref_ptr camera = new osg::Camera; + camera->setGraphicsContext(gc.get()); + camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT ); + camera->setClearColor( osg::Vec4(0.0,0.0,0.0,1.0) ); + camera->setViewport(new osg::Viewport(0, 0, width, height)); + GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT; + camera->setDrawBuffer(buffer); + camera->setReadBuffer(buffer); + camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); + camera->setAllowEventFocus(false); + camera->setInheritanceMask(camera->getInheritanceMask() & ~osg::CullSettings::CLEAR_COLOR & ~osg::CullSettings::COMPUTE_NEAR_FAR_MODE); + //camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR); + + camera->setProjectionMatrixAsOrtho2D(0,width,0,height); + camera->setViewMatrix(osg::Matrix::identity()); + + // add subgraph to render + camera->addChild(geode); + + camera->setName("WoWCamera"); + + addSlave(camera.get(), osg::Matrixd(), osg::Matrixd(), false); + } + } +} + + void View::assignSceneDataToCameras() { diff --git a/src/osgViewer/Viewer.cpp b/src/osgViewer/Viewer.cpp index e10b2e9e9..f54d96ad0 100644 --- a/src/osgViewer/Viewer.cpp +++ b/src/osgViewer/Viewer.cpp @@ -76,7 +76,38 @@ Viewer::Viewer(osg::ArgumentParser& arguments) while (arguments.read("--window",x,y,width,height)) {} bool ss3d = false; - if ((ss3d=arguments.read("--3d-sd")) || arguments.read("--panoramic-sd")) + bool wowvx20 = false; + bool wowvx42 = false; + if ((wowvx20=arguments.read("--wowvx-20")) || (wowvx42=arguments.read("--wowvx-42")) || arguments.read("--wowvx")) + { + int wow_content=0x02, wow_factor=0x40, wow_offset=0x80; + float wow_Zd, wow_vz, wow_M, wow_C; + if (wowvx20){ + wow_Zd = 0.459813f; + wow_vz = 6.180772f; + wow_M = -1586.34f; + wow_C = 127.5f; + } + else if (wowvx42){ + wow_Zd = 0.467481f; + wow_vz = 7.655192f; + wow_M = -1960.37f; + wow_C = 127.5f; + } + + while (arguments.read("--wow-content",wow_content)) {} + while (arguments.read("--wow-factor",wow_factor)) {} + while (arguments.read("--wow-offset",wow_offset)) {} + while (arguments.read("--wow-zd",wow_Zd)) {} + while (arguments.read("--wow-vz",wow_vz)) {} + while (arguments.read("--wow-M",wow_M)) {} + while (arguments.read("--wow-C",wow_C)) {} + + if (screenNum<0) screenNum = 0; + + setUpViewForWoWVxDisplay( screenNum, wow_content, wow_factor, wow_offset, wow_Zd, wow_vz, wow_M, wow_C ); + } + else if ((ss3d=arguments.read("--3d-sd")) || arguments.read("--panoramic-sd")) { double radius = 1.0; while (arguments.read("--radius",radius)) {}