#!/usr/bin/env python import sys import math from PyOSG import * from OpenGL.GL import * refract = 1.01 # ratio of indicies of refraction fresnel = 1.1 # Fresnel multiplier vpstr = r"""!!ARBvp1.0 # Refraction ATTRIB iPos = vertex.position; #ATTRIB iCol = vertex.color.primary; ATTRIB iNormal = vertex.normal; PARAM esEyePos = { 0, 0, 0, 1 } ; PARAM const0123 = { 0, 1, 2, 3 } ; PARAM fresnel = program.local[0]; PARAM refract = program.local[1]; PARAM itMV[4] = { state.matrix.modelview.invtrans } ; PARAM MVP[4] = { state.matrix.mvp } ; PARAM MV[4] = { state.matrix.modelview } ; PARAM texmat[4] = { state.matrix.texture[0] } ; TEMP esPos; # position in eye-space TEMP esNormal; # normal in eye-space TEMP tmp, IdotN, K; TEMP esE; # eye vector TEMP esI; # incident vector (=-E) TEMP esR; # first refract- then reflect-vector OUTPUT oPos = result.position; OUTPUT oColor = result.color; OUTPUT oRefractMap = result.texcoord[0]; OUTPUT oReflectMap = result.texcoord[1]; # transform vertex to clip space DP4 oPos.x, MVP[0], iPos; DP4 oPos.y, MVP[1], iPos; DP4 oPos.z, MVP[2], iPos; DP4 oPos.w, MVP[3], iPos; # Transform the normal to eye space. DP3 esNormal.x, itMV[0], iNormal; DP3 esNormal.y, itMV[1], iNormal; DP3 esNormal.z, itMV[2], iNormal; # normalize normal DP3 esNormal.w, esNormal, esNormal; RSQ esNormal.w, esNormal.w; MUL esNormal, esNormal, esNormal.w; # transform vertex position to eye space DP4 esPos.x, MV[0], iPos; DP4 esPos.y, MV[1], iPos; DP4 esPos.z, MV[2], iPos; DP4 esPos.w, MV[3], iPos; # vertex to eye vector ADD esE, -esPos, esEyePos; #MOV esE, -esPos; # normalize eye vector DP3 esE.w, esE, esE; RSQ esE.w, esE.w; MUL esE, esE, esE.w; # calculate some handy values MOV esI, -esE; DP3 IdotN, esNormal, esI; # calculate refraction vector, Renderman style # k = 1-index*index*(1-(I dot N)^2) MAD tmp, -IdotN, IdotN, const0123.y; MUL tmp, tmp, refract.y; ADD K.x, const0123.y, -tmp; # k<0, R = [0,0,0] # k>=0, R = index*I-(index*(I dot N) + sqrt(k))*N RSQ K.y, K.x; RCP K.y, K.y; # K.y = sqrt(k) MAD tmp.x, refract.x, IdotN, K.y; MUL tmp, esNormal, tmp.x; MAD esR, refract.x, esI, tmp; # transform refracted ray by cubemap transform DP3 oRefractMap.x, texmat[0], esR; DP3 oRefractMap.y, texmat[1], esR; DP3 oRefractMap.z, texmat[2], esR; # calculate reflection vector # R = 2*N*(N dot E)-E MUL tmp, esNormal, const0123.z; DP3 esR.w, esNormal, esE; MAD esR, esR.w, tmp, -esE; # transform reflected ray by cubemap transform DP3 oReflectMap.x, texmat[0], esR; DP3 oReflectMap.y, texmat[1], esR; DP3 oReflectMap.z, texmat[2], esR; # Fresnel approximation = fresnel*(1-(N dot I))^2 ADD tmp.x, const0123.y, -IdotN; MUL tmp.x, tmp.x, tmp.x; MUL oColor, tmp.x, fresnel; END """ def CUBEMAP_FILENAME(face): # return "nvlobby_" + face + ".png" # return "Cubemap_axis/" + face + ".png" return "Cubemap_snow/" + face + ".jpg" def readCubeMap(): cubemap = osg.TextureCubeMap() imagePosX = osgDB.readImageFile(CUBEMAP_FILENAME("posx")) imageNegX = osgDB.readImageFile(CUBEMAP_FILENAME("negx")) imagePosY = osgDB.readImageFile(CUBEMAP_FILENAME("posy")) imageNegY = osgDB.readImageFile(CUBEMAP_FILENAME("negy")) imagePosZ = osgDB.readImageFile(CUBEMAP_FILENAME("posz")) imageNegZ = osgDB.readImageFile(CUBEMAP_FILENAME("negz")) if imagePosX and imageNegX and imagePosY and imageNegY and imagePosZ and imageNegZ: cubemap.setImage(osg.TextureCubeMap.POSITIVE_X, imagePosX) cubemap.setImage(osg.TextureCubeMap.NEGATIVE_X, imageNegX) cubemap.setImage(osg.TextureCubeMap.POSITIVE_Y, imagePosY) cubemap.setImage(osg.TextureCubeMap.NEGATIVE_Y, imageNegY) cubemap.setImage(osg.TextureCubeMap.POSITIVE_Z, imagePosZ) cubemap.setImage(osg.TextureCubeMap.NEGATIVE_Z, imageNegZ) cubemap.setWrap(osg.Texture.WRAP_S, osg.Texture.CLAMP_TO_EDGE) cubemap.setWrap(osg.Texture.WRAP_T, osg.Texture.CLAMP_TO_EDGE) cubemap.setWrap(osg.Texture.WRAP_R, osg.Texture.CLAMP_TO_EDGE) cubemap.setFilter(osg.Texture.MIN_FILTER, osg.Texture.LINEAR_MIPMAP_LINEAR) cubemap.setFilter(osg.Texture.MAG_FILTER, osg.Texture.LINEAR) return cubemap # Update texture matrix for cubemaps class TexMatCallback(osg.NodeCallback): def __init__(self, tm): osg.NodeCallback.__init__(self) self._texMat = tm def apply(self, node, nv): cv = osgUtil.asCullVisitor(nv) if cv: MV = cv.getModelViewMatrix() R = osg.Matrix.rotate( osg.DegreesToRadians(112.0), 0.0,0.0,1.0)*\ osg.Matrix.rotate( osg.DegreesToRadians(90.0), 1.0,0.0,0.0) q = osg.Quat() q.set(MV) C = osg.Matrix.rotate( q.inverse() ) self._texMat.setMatrix( C*R ) self.traverse(node,nv) class MoveEarthySkyWithEyePointTransform( osg.Transform_base): def __init__(self): osg.Transform_base.__init__(self) # Get the transformation matrix which moves from local coords to world coords. def computeLocalToWorldMatrix(self, matrix, nv): cv = osgUtil.asCullVisitor(nv) if cv: eyePointLocal = cv.getEyeLocal() matrix.preMult(osg.Matrix.translate(eyePointLocal)) return True # Get the transformation matrix which moves from world coords to local coords.*/ def computeWorldToLocalMatrix(self, matrix, nv): cv = osgUtil.CullVisitor(nv) if cv: eyePointLocal = cv.getEyeLocal() matrix.postMult(osg.Matrix.translate(-eyePointLocal)) return True def createSkyBox(): stateset = osg.StateSet() te = osg.TexEnv() te.setMode(osg.TexEnv.REPLACE) stateset.setTextureAttributeAndModes(0, te, osg.StateAttribute.ON) tg = osg.TexGen() tg.setMode(osg.TexGen.NORMAL_MAP) stateset.setTextureAttributeAndModes(0, tg, osg.StateAttribute.ON) tm = osg.TexMat() stateset.setTextureAttribute(0, tm) skymap = readCubeMap() stateset.setTextureAttributeAndModes(0, skymap, osg.StateAttribute.ON) stateset.setMode( GL_LIGHTING, osg.StateAttribute.OFF ) stateset.setMode( GL_CULL_FACE, osg.StateAttribute.OFF ) # clear the depth to the far plane. depth = osg.Depth() depth.setFunction(osg.Depth.ALWAYS) depth.setRange(1.0,1.0) stateset.setAttributeAndModes(depth, osg.StateAttribute.ON ) stateset.setRenderBinDetails(-1,"RenderBin") drawable = osg.ShapeDrawable(osg.Sphere(osg.Vec3(0.0,0.0,0.0),1)) geode = osg.Geode() geode.setCullingActive(False) geode.setStateSet( stateset ) geode.addDrawable(drawable) transform = MoveEarthySkyWithEyePointTransform() transform.setCullingActive(False) transform.addChild(geode) clearNode = osg.ClearNode() # clearNode.setRequiresClear(False) clearNode.setCullCallback(TexMatCallback(tm)) clearNode.addChild(transform) return clearNode def addRefractStateSet(node): stateset = osg.StateSet() reflectmap = readCubeMap() stateset.setTextureAttributeAndModes( 0, reflectmap, osg.StateAttribute.ON | osg.StateAttribute.OVERRIDE ) stateset.setTextureAttributeAndModes( 1, reflectmap, osg.StateAttribute.ON | osg.StateAttribute.OVERRIDE ) texMat = osg.TexMat() stateset.setTextureAttribute(0, texMat) # --------------------------------------------------- # Vertex Program # --------------------------------------------------- vp = osg.VertexProgram() vp.setVertexProgram( vpstr ) vp.setProgramLocalParameter( 0, osg.Vec4( fresnel, fresnel, fresnel, 1.0 ) ) vp.setProgramLocalParameter( 1, osg.Vec4( refract, refract*refract, 0.0, 0.0 ) ) stateset.setAttributeAndModes( vp, osg.StateAttribute.ON | osg.StateAttribute.OVERRIDE ) # --------------------------------------------------- # fragment = refraction*(1-fresnel) + reflection*fresnel # T0 = texture unit 0, refraction map # T1 = texture unit 1, reflection map # C.rgb = primary color, water color # C.a = primary color, fresnel factor # Cp = result from previous texture environment # --------------------------------------------------- # REPLACE function: Arg0 # = T0 te0 = osg.TexEnvCombine() te0.setCombine_RGB(osg.TexEnvCombine.REPLACE) te0.setSource0_RGB(osg.TexEnvCombine.TEXTURE0) te0.setOperand0_RGB(osg.TexEnvCombine.SRC_COLOR) # INTERPOLATE function: Arg0 * (Arg2) + Arg1 * (1-Arg2) # = T1 * C0.a + Cp * (1-C0.a) te1 = osg.TexEnvCombine() # rgb = Cp + Ct te1.setCombine_RGB(osg.TexEnvCombine.INTERPOLATE) te1.setSource0_RGB(osg.TexEnvCombine.TEXTURE1) te1.setOperand0_RGB(osg.TexEnvCombine.SRC_COLOR) te1.setSource1_RGB(osg.TexEnvCombine.PREVIOUS) te1.setOperand1_RGB(osg.TexEnvCombine.SRC_COLOR) te1.setSource2_RGB(osg.TexEnvCombine.PRIMARY_COLOR) te1.setOperand2_RGB(osg.TexEnvCombine.SRC_COLOR) stateset.setTextureAttributeAndModes(0, te0, osg.StateAttribute.ON | osg.StateAttribute.OVERRIDE) stateset.setTextureAttributeAndModes(1, te1, osg.StateAttribute.ON | osg.StateAttribute.OVERRIDE) group = osg.Group() group.addChild(node) group.setCullCallback(TexMatCallback(texMat)) group.setStateSet( stateset ) return group def main(argv): # use an ArgumentParser object to manage the program arguments. arguments = osg.ArgumentParser(argv) # set up the usage document, in case we need to print out how to use this program. arguments.getApplicationUsage().setDescription(arguments.getApplicationName()+" is the example which demonstrate support for ARB_vertex_program.") arguments.getApplicationUsage().setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...") arguments.getApplicationUsage().addCommandLineOption("-h or --help","Display this information") # construct the viewer. viewer = osgProducer.Viewer(arguments) # set up the value with sensible default event handlers. viewer.setUpViewer(osgProducer.Viewer.STANDARD_SETTINGS) # get details on keyboard and mouse bindings used by the viewer. viewer.getUsage(arguments.getApplicationUsage()) # if user request help write it out to cout. if arguments.read("-h") or arguments.read("--help"): arguments.getApplicationUsage().write() return 1 # any option left unread are converted into errors to write out later. arguments.reportRemainingOptionsAsUnrecognized() # report any errors if they have occured when parsing the program aguments. if arguments.errors(): arguments.writeErrorMessages() return 1 rootnode = osg.Group() rootnode.addChild(createSkyBox()) # load the nodes from the commandline arguments. model = osgDB.readNodeFiles(arguments) if not model: radius = 1.0 geode = osg.Geode() geode.addDrawable(osg.ShapeDrawable(osg.Sphere(osg.Vec3(0.0,0.0,0.0),radius))) model = geode # run optimization over the scene graph optimzer = osgUtil.Optimizer() optimzer.optimize(model) # create normals. smoother = osgUtil.SmoothingVisitor() model.accept(smoother) #-- osgUtil.SmoothingVisitor.smooth(model) rootnode.addChild( addRefractStateSet(model) ) # add a viewport to the viewer and attach the scene graph. viewer.setSceneData(rootnode) # create the windows and run the threads. viewer.realize() # now check to see if vertex program is supported. for contextID in range(viewer.getDisplaySettings().getMaxNumberOfGraphicsContexts()): vpExt = osg.VertexProgram.getExtensions(contextID,False) if vpExt: if not vpExt.isVertexProgramSupported(): print "Warning: ARB_vertex_program not supported by OpenGL drivers, unable to run application." return 1 while not viewer.done(): # wait for all cull and draw threads to complete. viewer.sync() # update the scene by traversing it with the the update visitor which will # call all node update callbacks and animations. viewer.update() # fire off the cull and draw traversals of the scene. viewer.frame() # wait for all cull and draw threads to complete before exit. viewer.sync() return 0 if __name__ == "__main__": main(sys.argv)