Example #1
0
def createSquare(textureCoordMax):
    
    # set up the Geometry.
    geom = osg.Geometry()

    coords = osg.Vec3Array(4)
    (*coords)[0].set(-1.0,0.0,1.0)
    (*coords)[1].set(-1.0,0.0,-1.0)
    (*coords)[2].set(1.0,0.0,-1.0)
    (*coords)[3].set(1.0,0.0,1.0)
    geom.setVertexArray(coords)

    norms = osg.Vec3Array(1)
    (*norms)[0].set(0.0,-1.0,0.0)
    geom.setNormalArray(norms, osg.Array.BIND_OVERALL)

    tcoords = osg.Vec2Array(4)
    (*tcoords)[0].set(0.0,textureCoordMax)
    (*tcoords)[1].set(0.0,0.0)
    (*tcoords)[2].set(textureCoordMax,0.0)
    (*tcoords)[3].set(textureCoordMax,textureCoordMax)
    geom.setTexCoordArray(0,tcoords)

    geom.addPrimitiveSet(osg.DrawArrays(osg.PrimitiveSet.QUADS,0,4))

    return geom
def createTextureQuad(texture):

    
    vertices = osg.Vec3Array()
    vertices.push_back(osg.Vec3(-0.8, 0.0, -0.8))
    vertices.push_back(osg.Vec3(0.8, 0.0, -0.8))
    vertices.push_back(osg.Vec3(0.8, 0.0, 0.8))
    vertices.push_back(osg.Vec3(-0.8, 0.0, 0.8))

    texcoord = osg.Vec2Array()
    texcoord.push_back(osg.Vec2(0.0, 0.0))
    texcoord.push_back(osg.Vec2(1.0, 0.0))
    texcoord.push_back(osg.Vec2(1.0, 1.0))
    texcoord.push_back(osg.Vec2(0.0, 1.0))

    geom = osg.Geometry()
    geom.setVertexArray(vertices)
    geom.setTexCoordArray(0, texcoord)
    geom.addPrimitiveSet(osg.DrawArrays(GL_QUADS, 0, 4))

    geode = osg.Geode()
    geode.addDrawable(geom)
    geode.getOrCreateStateSet().setTextureAttributeAndModes(0, texture, osg.StateAttribute.ON)

    return geode
Example #3
0
def createTexturedQuadGeometry(corner, widthVec, heightVec, l, b, r, t):
    g = osg.Geometry()

    # Create vertex array
    vertices = osg.Vec3Array()
    vertices.append(corner + widthVec)
    vertices.append(corner)
    vertices.append(corner + heightVec)
    vertices.append(corner + widthVec + heightVec)
    g.setVertexArray(vertices)

    # Create texcoord array
    texcoords = osg.Vec2Array()
    texcoords.append(osg.Vec2f(l, t))
    texcoords.append(osg.Vec2f(l, b))
    texcoords.append(osg.Vec2f(r, b))
    texcoords.append(osg.Vec2f(r, t))
    g.setTexCoordArray(0, texcoords)

    # Create color array (single value, white)
    colors = osg.Vec4Array()
    colors.append(osg.Vec4f(1, 1, 1, 1))
    g.setColorArray(colors)
    g.colorBinding = osg.Geometry.BIND_OVERALL

    # Create normal array (single value for all vertices)
    normals = osg.Vec3Array()
    normals.append(osg.Vec3f(0, -1, 0))
    g.setNormalArray(normals)
    g.normalBinding = osg.Geometry.BIND_OVERALL

    # Add primitive set
    g.addPrimitiveSet(osg.DrawArrays(osg.PrimitiveSet.QUADS, 0, 4))

    return g
Example #4
0
def createMirrorSurface(xMin,xMax,yMin,yMax,z):
    #// set up the drawstate.

    #// set up the Geometry.
    geom = osg.Geometry();

    coords = osg.Vec3Array();
    coords.append(osg.Vec3f(xMin,yMax,z))
    coords.append(osg.Vec3f(xMin,yMin,z))
    coords.append(osg.Vec3f(xMax,yMin,z))
    coords.append(osg.Vec3f(xMax,yMax,z))
    geom.setVertexArray(coords);

    norms = osg.Vec3Array();
    norms.append(osg.Vec3f(0.0,0.0,1.0))
    geom.setNormalArray(norms);
    geom.normalBinding = osg.Geometry.BIND_OVERALL

    tcoords = osg.Vec2Array()
    tcoords.append(osg.Vec2f(0.0,1.0))
    tcoords.append(osg.Vec2f(0.0,0.0))
    tcoords.append(osg.Vec2f(1.0,0.0))
    tcoords.append(osg.Vec2f(1.0,1.0))
    geom.setTexCoordArray(0,tcoords);

    colours = osg.Vec4Array();
    colours.append(osg.Vec4f(1.0,1.0,1.0,1.0))
    geom.setColorArray(colours);
    geom.colorBinding = osg.Geometry.BIND_OVERALL;

    geom.addPrimitiveSet(osg.DrawArrays(osg.PrimitiveSet.QUADS,0,4));

    return geom;
Example #5
0
def createMirrorSurface(xMin, xMax, yMin, yMax, z):


    

    # set up the drawstate.

    # set up the Geometry.
    geom = osg.Geometry()

    coords = osg.Vec3Array(4)
    (*coords)[0].set(xMin,yMax,z)
    (*coords)[1].set(xMin,yMin,z)
    (*coords)[2].set(xMax,yMin,z)
    (*coords)[3].set(xMax,yMax,z)
    geom.setVertexArray(coords)

    norms = osg.Vec3Array(1)
    (*norms)[0].set(0.0,0.0,1.0)
    geom.setNormalArray(norms, osg.Array.BIND_OVERALL)

    tcoords = osg.Vec2Array(4)
    (*tcoords)[0].set(0.0,1.0)
    (*tcoords)[1].set(0.0,0.0)
    (*tcoords)[2].set(1.0,0.0)
    (*tcoords)[3].set(1.0,1.0)
    geom.setTexCoordArray(0,tcoords)

    colours = osg.Vec4Array(1)
    (*colours)[0].set(1.0,1.0,1.0,1.0)
    geom.setColorArray(colours, osg.Array.BIND_OVERALL)

    geom.addPrimitiveSet(osg.DrawArrays(osg.PrimitiveSet.QUADS,0,4))

    return geom
Example #6
0
def createSquare(corner, width, height, image):
    
    # set up the Geometry.
    geom = osg.Geometry()

    coords = osg.Vec3Array(4)
    (*coords)[0] = corner
    (*coords)[1] = corner+width
    (*coords)[2] = corner+width+height
    (*coords)[3] = corner+height


    geom.setVertexArray(coords)

    norms = osg.Vec3Array(1)
    (*norms)[0] = width^height
    (*norms)[0].normalize()

    geom.setNormalArray(norms, osg.Array.BIND_OVERALL)

    tcoords = osg.Vec2Array(4)
    (*tcoords)[0].set(0.0,0.0)
    (*tcoords)[1].set(1.0,0.0)
    (*tcoords)[2].set(1.0,1.0)
    (*tcoords)[3].set(0.0,1.0)
    geom.setTexCoordArray(0,tcoords)

    colours = osg.Vec4Array(1)
    (*colours)[0].set(1.0,1.0,1.0,1.0)
    geom.setColorArray(colours, osg.Array.BIND_OVERALL)


    geom.addPrimitiveSet(osg.DrawArrays(osg.PrimitiveSet.QUADS,0,4))

    if image :
        stateset = osg.StateSet()
        texture = osg.Texture2D()
        texture.setImage(image)
        stateset.setTextureAttributeAndModes(0,texture,osg.StateAttribute.ON)
        stateset.setMode(GL_LIGHTING, osg.StateAttribute.OFF)
        stateset.setMode(GL_BLEND, osg.StateAttribute.ON)
        stateset.setRenderingHint(osg.StateSet.TRANSPARENT_BIN)
        geom.setStateSet(stateset)

    return geom
Example #7
0
def createSectorForImage(image, texmat, s, t, radius, height, length):


    
    flip = image.getOrigin()==osg.Image.TOP_LEFT

    numSegments = 20
    Theta = length/radius
    dTheta = Theta/(float)(numSegments-1)

    ThetaZero = height*s/(t*radius)

    # set up the texture.
    texture = osg.Texture2D()
    texture.setFilter(osg.Texture2D.MIN_FILTER,osg.Texture2D.LINEAR)
    texture.setFilter(osg.Texture2D.MAG_FILTER,osg.Texture2D.LINEAR)
    texture.setWrap(osg.Texture2D.WRAP_S,osg.Texture2D.CLAMP_TO_BORDER)
    texture.setWrap(osg.Texture2D.WRAP_T,osg.Texture2D.CLAMP_TO_BORDER)
    texture.setResizeNonPowerOfTwoHint(False)
    texture.setImage(image)

    # set up the drawstate.
    dstate = osg.StateSet()
    dstate.setMode(GL_CULL_FACE,osg.StateAttribute.OFF)
    dstate.setMode(GL_LIGHTING,osg.StateAttribute.OFF)
    dstate.setTextureAttributeAndModes(0, texture,osg.StateAttribute.ON)
    dstate.setTextureAttribute(0, texmat)

    # set up the geoset.
    geom = osg.Geometry()
    geom.setStateSet(dstate)

    coords = osg.Vec3Array()
    tcoords = osg.Vec2Array()

    i = int()
    angle = -Theta/2.0
    for(i=0
        i<numSegments
        ++i, angle+=dTheta)
        coords.push_back(osg.Vec3(sinf(angle)*radius,cosf(angle)*radius,height*0.5)) # top
        coords.push_back(osg.Vec3(sinf(angle)*radius,cosf(angle)*radius,-height*0.5)) # bottom.

        tcoords.push_back(osg.Vec2(angle/ThetaZero+0.5,  0.0 if (flip) else  1.0)) # top
        tcoords.push_back(osg.Vec2(angle/ThetaZero+0.5,  1.0 if (flip) else  0.0)) # bottom.
Example #8
0
def createPyramid():
    pyramidGeode = osg.Geode()
    pyramidGeometry = osg.Geometry()
    pyramidGeode.addDrawable(pyramidGeometry)

    # Specify the vertices:
    pyramidVertices = osg.Vec3Array()
    pyramidVertices.append(osg.Vec3(0, 0, 0))  # front left
    pyramidVertices.append(osg.Vec3(2, 0, 0))  # front right
    pyramidVertices.append(osg.Vec3(2, 2, 0))  # back right
    pyramidVertices.append(osg.Vec3(0, 2, 0))  # back left
    pyramidVertices.append(osg.Vec3(1, 1, 2))  # peak

    # Associate this set of vertices with the geometry associated with the
    # geode we added to the scene.
    pyramidGeometry.setVertexArray(pyramidVertices)

    # Create a QUAD primitive for the base by specifying the
    # vertices from our vertex list that make up this QUAD:
    pyramidBase = osg.DrawElementsUInt(osg.PrimitiveSet.QUADS, 0)
    pyramidBase.append(3)
    pyramidBase.append(2)
    pyramidBase.append(1)
    pyramidBase.append(0)

    # Add this primitive to the geometry:
    # pyramidGeometry.addPrimitiveSet(pyramidBase)
    # code to create other faces goes here!
    pyramidGeometry.addPrimitiveSet(pyramidBase)
    # Repeat the same for each of the four sides. Again, vertices are specified in counter-clockwise order.
    pyramidFaceOne = osg.DrawElementsUInt(osg.PrimitiveSet.TRIANGLES, 0)
    pyramidFaceOne.append(0)
    pyramidFaceOne.append(1)
    pyramidFaceOne.append(4)
    pyramidGeometry.addPrimitiveSet(pyramidFaceOne)

    pyramidFaceTwo = osg.DrawElementsUInt(osg.PrimitiveSet.TRIANGLES, 0)
    pyramidFaceTwo.append(1)
    pyramidFaceTwo.append(2)
    pyramidFaceTwo.append(4)
    pyramidGeometry.addPrimitiveSet(pyramidFaceTwo)

    pyramidFaceThree = osg.DrawElementsUInt(osg.PrimitiveSet.TRIANGLES, 0)
    pyramidFaceThree.append(2)
    pyramidFaceThree.append(3)
    pyramidFaceThree.append(4)
    pyramidGeometry.addPrimitiveSet(pyramidFaceThree)

    pyramidFaceFour = osg.DrawElementsUInt(osg.PrimitiveSet.TRIANGLES, 0)
    pyramidFaceFour.append(3)
    pyramidFaceFour.append(0)
    pyramidFaceFour.append(4)
    pyramidGeometry.addPrimitiveSet(pyramidFaceFour)

    colors = osg.Vec4Array()
    colors.append(osg.Vec4(1.0, 0.0, 0.0, 1.0))  #index 0 red
    colors.append(osg.Vec4(0.0, 1.0, 0.0, 1.0))  #index 1 green
    colors.append(osg.Vec4(0.0, 0.0, 1.0, 1.0))  #index 2 blue
    colors.append(osg.Vec4(1.0, 1.0, 1.0, 1.0))  #index 3 white
    colors.append(osg.Vec4(1.0, 0.0, 0.0, 1.0))  #index 4 red

    pyramidGeometry.setColorArray(colors)
    pyramidGeometry.setColorBinding(osg.Geometry.BIND_PER_VERTEX)

    # Since the mapping from vertices to texture coordinates is 1:1,
    # we don't need to use an index array to map vertices to texture
    # coordinates. We can do it directly with the 'setTexCoordArray'
    # method of the Geometry class.
    # This method takes a variable that is an array of two dimensional
    # vectors (osg.Vec2). This variable needs to have the same
    # number of elements as our Geometry has vertices. Each array element
    # defines the texture coordinate for the cooresponding vertex in the
    # vertex array.
    texcoords = osg.Vec2Array(5)
    texcoords[0].set(0.00, 0.0)  # tex coord for vertex 0
    texcoords[1].set(0.25, 0.0)  # tex coord for vertex 1
    texcoords[2].set(0.50, 0.0)  # ""
    texcoords[3].set(0.75, 0.0)  # ""
    texcoords[4].set(0.50, 1.0)  # ""
    pyramidGeometry.setTexCoordArray(0, texcoords)

    return pyramidGeode
Example #9
0
        grid = osg.HeightField()
        grid.allocate(numColumns,numRows)
        grid.setOrigin(origin)
        grid.setXInterval(size.x()/(float)(numColumns-1))
        grid.setYInterval(size.y()/(float)(numRows-1))

        for(r=0r<numRows++r)
            for(c=0c<numColumns++c)
                grid.setHeight(c,r,(vertex[r+c*numRows][2]-min_z)*scale_z)

        geode.addDrawable(osg.ShapeDrawable(grid))
    else:
        geometry = osg.Geometry()

        v = *(osg.Vec3Array(numColumns*numRows))
        t = *(osg.Vec2Array(numColumns*numRows))
        color = *(osg.Vec4ubArray(1))

        color[0].set(255,255,255,255)

        rowCoordDelta = size.y()/(float)(numRows-1)
        columnCoordDelta = size.x()/(float)(numColumns-1)

        rowTexDelta = 1.0/(float)(numRows-1)
        columnTexDelta = 1.0/(float)(numColumns-1)

        pos = origin
        tex = osg.Vec2(0.0,0.0)
        vi = 0
        for(r=0r<numRows++r)
            pos.x() = origin.x()
# The quad geometry is used by the render to texture camera to generate multiple textures.
def createRTTQuad(tex_width, tex_height, useHDR):
    
    top_group = osg.Group()

    quad_geode = osg.Geode()

    quad_coords = osg.Vec3Array() # vertex coords
    # counter-clockwise
    quad_coords.push_back(osg.Vec3d(0, 0, -1))
    quad_coords.push_back(osg.Vec3d(1, 0, -1))
    quad_coords.push_back(osg.Vec3d(1, 1, -1))
    quad_coords.push_back(osg.Vec3d(0, 1, -1))

    quad_tcoords = osg.Vec2Array() # texture coords
    quad_tcoords.push_back(osg.Vec2(0, 0))
    quad_tcoords.push_back(osg.Vec2(tex_width, 0))
    quad_tcoords.push_back(osg.Vec2(tex_width, tex_height))
    quad_tcoords.push_back(osg.Vec2(0, tex_height))

    quad_geom = osg.Geometry()
    quad_da = osg.DrawArrays(osg.PrimitiveSet.QUADS,0,4)

    quad_colors = osg.Vec4Array()
    quad_colors.push_back(osg.Vec4(1.0,1.0,1.0,1.0))

    quad_geom.setVertexArray(quad_coords)
    quad_geom.setTexCoordArray(0, quad_tcoords)
    quad_geom.addPrimitiveSet(quad_da)
    quad_geom.setColorArray(quad_colors, osg.Array.BIND_OVERALL)
Example #11
0
        (*colours)[0] = color
        sPlanetSphere.setColorArray(colours, osg.Array.BIND_OVERALL)


        # now set up the coords, normals and texcoords for geometry
        numX = 100
        numY = 50
        numVertices = numX*numY

        coords = osg.Vec3Array(numVertices)
        sPlanetSphere.setVertexArray(coords)

        normals = osg.Vec3Array(numVertices)
        sPlanetSphere.setNormalArray(normals, osg.Array.BIND_PER_VERTEX)

        texcoords = osg.Vec2Array(numVertices)
        sPlanetSphere.setTexCoordArray(0,texcoords)
        sPlanetSphere.setTexCoordArray(1,texcoords)

        delta_elevation = osg.PI / (double)(numY-1)
        delta_azim = 2.0*osg.PI / (double)(numX-1)
        delta_tx = 1.0 / (float)(numX-1)
        delta_ty = 1.0 / (float)(numY-1)

        elevation = -osg.PI*0.5
        ty = 0.0
        vert = 0
        j = unsigned()
        for(j=0
            j<numY
            ++j, elevation+=delta_elevation, ty+=delta_ty )
Example #12
0
class IntersectionUpdateCallback (osg.NodeCallback) :
virtual void operator()(osg.Node* #node, osg.NodeVisitor* nv)
            if  not root_  or   not terrain_  or   not ss_  or   not intersectionGroup_ :
                osg.notify(osg.NOTICE), "IntersectionUpdateCallback not set up correctly."
                return

            #traverse(node,nv)
            frameCount_++
            if frameCount_ > 200 :
                # first we need find the transformation matrix that takes
                # the terrain into the coordinate frame of the sphere segment.
                terrainLocalToWorld = osg.Matrixd()
                terrain_worldMatrices = terrain_.getWorldMatrices(root_)
                if terrain_worldMatrices.empty() : terrainLocalToWorld.makeIdentity()
                elif terrain_worldMatrices.size()==1 : terrainLocalToWorld = terrain_worldMatrices.front()
                else:
                    osg.notify(osg.NOTICE), "IntersectionUpdateCallback: warning cannot interestect with multiple terrain instances, just uses first one."
                    terrainLocalToWorld = terrain_worldMatrices.front()

                # sphere segment is easier as this callback is attached to the node, so the node visitor has the unique path to it already.
                ssWorldToLocal = osg.computeWorldToLocal(nv.getNodePath())

                # now we can compute the terrain to ss transform
                possie = terrainLocalToWorld*ssWorldToLocal

                lines = ss_.computeIntersection(possie, terrain_)
                if  not lines.empty() :
                    if intersectionGroup_.valid() :
                        # now we need to place the intersections which are in the SphereSegmenet's coordinate frame into
                        # to the final position.
                        mt = osg.MatrixTransform()
                        mt.setMatrix(osg.computeLocalToWorld(nv.getNodePath()))
                        intersectionGroup_.addChild(mt)

                        # print "matrix = ", mt.getMatrix()

                        geode = osg.Geode()
                        mt.addChild(geode)

                        geode.getOrCreateStateSet().setMode(GL_LIGHTING,osg.StateAttribute.OFF)

                        for(osgSim.SphereSegment.LineList.iterator itr=lines.begin()
                           not = lines.end()
                           ++itr)
                            geom = osg.Geometry()
                            geode.addDrawable(geom)

                            vertices = itr
                            geom.setVertexArray(vertices)
                            geom.addPrimitiveSet(osg.DrawArrays(GL_LINE_STRIP, 0, vertices.getNumElements()))
                else:
                       osg.notify(osg.NOTICE), "No intersections found"


                frameCount_ = 0
    root_ = osg.observer_ptr<osg.Group>()
    terrain_ = osg.observer_ptr<osg.Geode>()
    ss_ = osg.observer_ptr<osgSim.SphereSegment>()
    intersectionGroup_ = osg.observer_ptr<osg.Group>()
    frameCount_ = unsigned()


class RotateUpdateCallback (osg.NodeCallback) :
    RotateUpdateCallback()  i=0
        virtual void operator()(osg.Node* node, osg.NodeVisitor* nv)
            ss = dynamic_cast<osgSim.SphereSegment *>(node)
            if ss :
                ss.setArea(osg.Vec3(cos(i/(2*osg.PI)),sin(i/(2*osg.PI)),0), osg.PI_2, osg.PI_2)

                i += 0.1

    i = float()


def createMovingModel(center, radius, terrainGeode, root, createMovingRadar):

    
    animationLength = 10.0

    animationPath = createAnimationPath(center,radius,animationLength)

    model = osg.Group()

    glider = osgDB.readNodeFile("glider.osgt")
    if glider :
        bs = glider.getBound()

        size = radius/bs.radius()*0.3
        positioned = osg.MatrixTransform()
        positioned.setDataVariance(osg.Object.STATIC)
        positioned.setMatrix(osg.Matrix.translate(-bs.center())*
                                     osg.Matrix.scale(size,size,size)*
                                     osg.Matrix.rotate(osg.inDegrees(-90.0),0.0,0.0,1.0))

        positioned.addChild(glider)

        xform = osg.PositionAttitudeTransform()
        xform.getOrCreateStateSet().setMode(GL_NORMALIZE, osg.StateAttribute.ON)
        xform.setUpdateCallback(osg.AnimationPathCallback(animationPath,0.0,1.0))
        xform.addChild(positioned)
        model.addChild(xform)

    if createMovingRadar :
        # The IntersectionUpdateCallback has to have a safe place to put all its generated geometry into,
        # and this group can't be in the parental chain of the callback otherwise we will end up invalidating
        # traversal iterators.
        intersectionGroup = osg.Group()
        root.addChild(intersectionGroup)

        xform = osg.PositionAttitudeTransform()
        xform.setUpdateCallback(osg.AnimationPathCallback(animationPath,0.0,1.0))

        ss = osgSim.SphereSegment(osg.Vec3d(0.0,0.0,0.0),
                                700.0, # radius
                                osg.DegreesToRadians(135.0),
                                osg.DegreesToRadians(240.0),
                                osg.DegreesToRadians(-60.0),
                                osg.DegreesToRadians(-40.0),
                                60)

        iuc = IntersectionUpdateCallback()
        iuc.frameCount_ = 0
        iuc.root_ = root
        iuc.terrain_ = terrainGeode
        iuc.ss_ = ss
        iuc.intersectionGroup_ = intersectionGroup
        ss.setUpdateCallback(iuc)
        ss.setAllColors(osg.Vec4(1.0,1.0,1.0,0.5))
        ss.setSideColor(osg.Vec4(0.5,1.0,1.0,0.1))
        xform.addChild(ss)
        model.addChild(xform)

    cessna = osgDB.readNodeFile("cessna.osgt")
    if cessna :
        bs = cessna.getBound()

        text = osgText.Text()
        size = radius/bs.radius()*0.3

        text.setPosition(bs.center())
        text.setText("Cessna")
        text.setAlignment(osgText.Text.CENTER_CENTER)
        text.setAxisAlignment(osgText.Text.SCREEN)
        text.setCharacterSize(40.0)
        text.setCharacterSizeMode(osgText.Text.OBJECT_COORDS)

        geode = osg.Geode()
        geode.addDrawable(text)

        lod = osg.LOD()
        lod.setRangeMode(osg.LOD.PIXEL_SIZE_ON_SCREEN)
        lod.setRadius(cessna.getBound().radius())
        lod.addChild(geode,0.0,100.0)
        lod.addChild(cessna,100.0,10000.0)


        positioned = osg.MatrixTransform()
        positioned.getOrCreateStateSet().setMode(GL_NORMALIZE, osg.StateAttribute.ON)
        positioned.setDataVariance(osg.Object.STATIC)
        positioned.setMatrix(osg.Matrix.translate(-bs.center())*
                                     osg.Matrix.scale(size,size,size)*
                                     osg.Matrix.rotate(osg.inDegrees(180.0),0.0,0.0,1.0))

        #positioned.addChild(cessna)
        positioned.addChild(lod)

        xform = osg.MatrixTransform()
        xform.setUpdateCallback(osg.AnimationPathCallback(animationPath,0.0,2.0))
        xform.addChild(positioned)

        model.addChild(xform)

    return model

def createOverlay(center, radius):

    
    group = osg.Group()

    # create a grid of lines.
        geom = osg.Geometry()

        num_rows = 10

        left = center+osg.Vec3(-radius,-radius,0.0)
        right = center+osg.Vec3(radius,-radius,0.0)
        delta_row = osg.Vec3(0.0,2.0*radius/float(num_rows-1),0.0)

        top = center+osg.Vec3(-radius,radius,0.0)
        bottom = center+osg.Vec3(-radius,-radius,0.0)
        delta_column = osg.Vec3(2.0*radius/float(num_rows-1),0.0,0.0)

        vertices = osg.Vec3Array()
        for(unsigned int i=0 i<num_rows ++i)
            vertices.push_back(left)
            vertices.push_back(right)
            left += delta_row
            right += delta_row

            vertices.push_back(top)
            vertices.push_back(bottom)
            top += delta_column
            bottom += delta_column

        geom.setVertexArray(vertices)

        color = *(osg.Vec4ubArray(1))
        color[0].set(0,0,0,255)
        geom.setColorArray(color, osg.Array.BIND_OVERALL)

        geom.addPrimitiveSet(osg.DrawArrays(GL_LINES,0,vertices.getNumElements()))

        geom.getOrCreateStateSet().setMode(GL_LIGHTING,osg.StateAttribute.OFF)

        geode = osg.Geode()
        geode.addDrawable(geom)
        group.addChild(geode)

    return group

def computeTerrainIntersection(subgraph, x, y):

    
    bs = subgraph.getBound()
    zMax = bs.center().z()+bs.radius()
    zMin = bs.center().z()-bs.radius()

    intersector = osgUtil.LineSegmentIntersector(osg.Vec3(x,y,zMin),osg.Vec3(x,y,zMax))

    iv = osgUtil.IntersectionVisitor(intersector)

    subgraph.accept(iv)

    if intersector.containsIntersections() :
        return intersector.getFirstIntersection().getWorldIntersectPoint()

    return osg.Vec3(x,y,0.0)


#######################################
# MAIN SCENE GRAPH BUILDING FUNCTION
#######################################

def build_world(root, testCase, useOverlay, technique):

    

    # create terrain
    terrainGeode = 0
        terrainGeode = osg.Geode()

        stateset = osg.StateSet()
        image = osgDB.readImageFile("Images/lz.rgb")
        if image :
            texture = osg.Texture2D()
            texture.setImage(image)
            stateset.setTextureAttributeAndModes(0,texture,osg.StateAttribute.ON)

        terrainGeode.setStateSet( stateset )


            numColumns = 38
            numRows = 39
            unsigned int r, c

            origin = osg.Vec3(0.0,0.0,0.0)
            size = osg.Vec3(1000.0,1000.0,250.0)

            geometry = osg.Geometry()

            v = *(osg.Vec3Array(numColumns*numRows))
            tc = *(osg.Vec2Array(numColumns*numRows))
            color = *(osg.Vec4ubArray(1))

            color[0].set(255,255,255,255)

            rowCoordDelta = size.y()/(float)(numRows-1)
            columnCoordDelta = size.x()/(float)(numColumns-1)

            rowTexDelta = 1.0/(float)(numRows-1)
            columnTexDelta = 1.0/(float)(numColumns-1)

            # compute z range of z values of grid data so we can scale it.
            min_z = FLT_MAX
            max_z = -FLT_MAX
            for(r=0r<numRows++r)
                for(c=0c<numColumns++c)
                    min_z = osg.minimum(min_z,vertex[r+c*numRows][2])
                    max_z = osg.maximum(max_z,vertex[r+c*numRows][2])

            scale_z = size.z()/(max_z-min_z)

            pos = origin
            tex = osg.Vec2(0.0,0.0)
            vi = 0
            for(r=0r<numRows++r)
                pos.x() = origin.x()
                tex.x() = 0.0
                for(c=0c<numColumns++c)
                    v[vi].set(pos.x(),pos.y(),pos.z()+(vertex[r+c*numRows][2]-min_z)*scale_z)
                    tc[vi] = tex
                    pos.x()+=columnCoordDelta
                    tex.x()+=columnTexDelta
                    ++vi
                pos.y() += rowCoordDelta
                tex.y() += rowTexDelta

            geometry.setVertexArray(v)
            geometry.setTexCoordArray(0, tc)
            geometry.setColorArray(color, osg.Array.BIND_OVERALL)

            for(r=0r<numRows-1++r)
                drawElements = *(osg.DrawElementsUShort(GL_QUAD_STRIP,2*numColumns))
                geometry.addPrimitiveSet(drawElements)
                ei = 0
                for(c=0c<numColumns++c)
                    drawElements[ei++] = (r+1)*numColumns+c
                    drawElements[ei++] = (r)*numColumns+c

            smoother = osgUtil.SmoothingVisitor()
            smoother.smooth(*geometry)

            terrainGeode.addDrawable(geometry)



    # create sphere segment
    ss = 0

        terrainToSS = osg.Matrix()

        switch(testCase)
            case(0):
                ss = osgSim.SphereSegment(
                                computeTerrainIntersection(terrainGeode,550.0,780.0), # center
                                510.0, # radius
                                osg.DegreesToRadians(135.0),
                                osg.DegreesToRadians(240.0),
                                osg.DegreesToRadians(-10.0),
                                osg.DegreesToRadians(30.0),
                                60)
                root.addChild(ss)
                break
            case(1):
                ss = osgSim.SphereSegment(
                                computeTerrainIntersection(terrainGeode,550.0,780.0), # center
                                510.0, # radius
                                osg.DegreesToRadians(45.0),
                                osg.DegreesToRadians(240.0),
                                osg.DegreesToRadians(-10.0),
                                osg.DegreesToRadians(30.0),
                                60)
                root.addChild(ss)
                break
            case(2):
                ss = osgSim.SphereSegment(
                                computeTerrainIntersection(terrainGeode,550.0,780.0), # center
                                510.0, # radius
                                osg.DegreesToRadians(5.0),
                                osg.DegreesToRadians(355.0),
                                osg.DegreesToRadians(-10.0),
                                osg.DegreesToRadians(30.0),
                                60)
                root.addChild(ss)
                break
            case(3):
                ss = osgSim.SphereSegment(
                                computeTerrainIntersection(terrainGeode,550.0,780.0), # center
                                510.0, # radius
                                osg.DegreesToRadians(0.0),
                                osg.DegreesToRadians(360.0),
                                osg.DegreesToRadians(-10.0),
                                osg.DegreesToRadians(30.0),
                                60)
                root.addChild(ss)
                break
            case(4):
                ss = osgSim.SphereSegment(osg.Vec3d(0.0,0.0,0.0),
                                700.0, # radius
                                osg.DegreesToRadians(135.0),
                                osg.DegreesToRadians(240.0),
                                osg.DegreesToRadians(-60.0),
                                osg.DegreesToRadians(-40.0),
                                60)

                mt = osg.MatrixTransform()

                mt.setMatrix(osg.Matrix(-0.851781, 0.156428, -0.5, 0,
                                          -0.180627, -0.983552, -6.93889e-18, 0,
                                          -0.491776, 0.0903136, 0.866025, 0,
                                          598.217, 481.957, 100, 1))
                mt.addChild(ss)

                terrainToSS.invert(mt.getMatrix())

                root.addChild(mt)
                break
            case(5):
                ss = osgSim.SphereSegment(osg.Vec3d(0.0,0.0,0.0),
                                700.0, # radius
                                osg.DegreesToRadians(35.0),
                                osg.DegreesToRadians(135.0),
                                osg.DegreesToRadians(-60.0),
                                osg.DegreesToRadians(-40.0),
                                60)

                mt = osg.MatrixTransform()

                mt.setMatrix(osg.Matrix(-0.851781, 0.156428, -0.5, 0,
                                          -0.180627, -0.983552, -6.93889e-18, 0,
                                          -0.491776, 0.0903136, 0.866025, 0,
                                          598.217, 481.957, 100, 1))
                mt.addChild(ss)

                terrainToSS.invert(mt.getMatrix())

                root.addChild(mt)
                break
            case(6):
                ss = osgSim.SphereSegment(osg.Vec3d(0.0,0.0,0.0),
                                700.0, # radius
                                osg.DegreesToRadians(-45.0),
                                osg.DegreesToRadians(45.0),
                                osg.DegreesToRadians(-60.0),
                                osg.DegreesToRadians(-40.0),
                                60)

                mt = osg.MatrixTransform()

                mt.setMatrix(osg.Matrix(-0.851781, 0.156428, -0.5, 0,
                                          -0.180627, -0.983552, -6.93889e-18, 0,
                                          -0.491776, 0.0903136, 0.866025, 0,
                                          598.217, 481.957, 100, 1))
                mt.addChild(ss)

                terrainToSS.invert(mt.getMatrix())

                root.addChild(mt)
                break
            case(7):
                ss = osgSim.SphereSegment(
                                computeTerrainIntersection(terrainGeode,550.0,780.0), # center
                                510.0, # radius
                                osg.DegreesToRadians(-240.0),
                                osg.DegreesToRadians(-135.0),
                                osg.DegreesToRadians(-10.0),
                                osg.DegreesToRadians(30.0),
                                60)
                ss.setUpdateCallback(RotateUpdateCallback())
                root.addChild(ss)
                break
        

        if ss.valid() :
            ss.setAllColors(osg.Vec4(1.0,1.0,1.0,0.5))
            ss.setSideColor(osg.Vec4(0.0,1.0,1.0,0.1))

            if  not ss.getParents().empty() :
                ss.getParent(0).addChild(ss.computeIntersectionSubgraph(terrainToSS, terrainGeode))



    if useOverlay :
        overlayNode = osgSim.OverlayNode(technique)
        overlayNode.getOrCreateStateSet().setTextureAttribute(1, osg.TexEnv(osg.TexEnv.DECAL))

        bs = terrainGeode.getBound()
        overlaySubgraph = createOverlay(bs.center(), bs.radius()*0.5)
        overlaySubgraph.addChild(ss)
        overlayNode.setOverlaySubgraph(overlaySubgraph)
        overlayNode.setOverlayTextureSizeHint(1024)
        overlayNode.setOverlayBaseHeight(0.0)
        overlayNode.addChild(terrainGeode)

        root.addChild(overlayNode)
    else:
      root.addChild(terrainGeode)

    # create particle effects
        position = computeTerrainIntersection(terrainGeode,100.0,100.0)

        explosion = osgParticle.ExplosionEffect(position, 10.0)
        smoke = osgParticle.SmokeEffect(position, 10.0)
        fire = osgParticle.FireEffect(position, 10.0)

        root.addChild(explosion)
        root.addChild(smoke)
        root.addChild(fire)

    # create particle effects
        position = computeTerrainIntersection(terrainGeode,200.0,100.0)

        explosion = osgParticle.ExplosionEffect(position, 1.0)
        smoke = osgParticle.SmokeEffect(position, 1.0)
        fire = osgParticle.FireEffect(position, 1.0)

        root.addChild(explosion)
        root.addChild(smoke)
        root.addChild(fire)


    createMovingRadar = True

    # create the moving models.
        root.addChild(createMovingModel(osg.Vec3(500.0,500.0,500.0),100.0, terrainGeode, root, createMovingRadar))


#######################################
# main()
#######################################


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 demonstrates use of particle systems.")
    arguments.getApplicationUsage().setCommandLineUsage(arguments.getApplicationName()+" [options] image_file_left_eye image_file_right_eye")
    arguments.getApplicationUsage().addCommandLineOption("-h or --help","Display this information")


    # construct the viewer.
    viewer = osgViewer.Viewer(arguments)

    # if user request help write it out to cout.
    testCase = 0
    while arguments.read("-t", testCase) : 

    useOverlay = False
    technique = osgSim.OverlayNode.OBJECT_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY
    while arguments.read("--object") :  useOverlay = True technique = osgSim.OverlayNode.OBJECT_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY 
    while arguments.read("--ortho")  or  arguments.read("--orthographic") :  useOverlay = True technique = osgSim.OverlayNode.VIEW_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY 
    while arguments.read("--persp")  or  arguments.read("--perspective") :  useOverlay = True technique = osgSim.OverlayNode.VIEW_DEPENDENT_WITH_PERSPECTIVE_OVERLAY 


    # if user request help write it out to cout.
    if arguments.read("-h")  or  arguments.read("--help") :
        arguments.getApplicationUsage().write(std.cout)
        return 1

    # any option left unread are converted into errors to write out later.
    arguments.reportRemainingOptionsAsUnrecognized()

    # report any errors if they have occurred when parsing the program arguments.
    if arguments.errors() :
        arguments.writeErrorMessages(std.cout)
        return 1

    root = osg.Group()
    build_world(root, testCase, useOverlay, technique)

    # add a viewport to the viewer and attach the scene graph.
    viewer.setSceneData(root)

    return viewer.run()


if __name__ == "__main__":
    main(sys.argv)
Example #13
0
        polyGeom.setSupportsDisplayList(False)

        origin = osg.Vec3(0.0,0.0,0.0)
        xAxis = osg.Vec3(1.0,0.0,0.0)
        yAxis = osg.Vec3(0.0,0.0,1.0)
        zAxis = osg.Vec3(0.0,-1.0,0.0)
        height = 100.0
        width = 200.0
        noSteps = 20

        vertices = osg.Vec3Array()
        bottom = origin
        top = origin top.z()+= height
        dv = xAxis*(width/((float)(noSteps-1)))

        texcoords = osg.Vec2Array()

        # note, when we use TextureRectangle we have to scale the tex coords up to compensate.
        bottom_texcoord = osg.Vec2(0.0,0.0)
        top_texcoord = osg.Vec2(0.0,  tex_height if (useTextureRectangle) else  1.0)
        dv_texcoord =  tex_width if (osg.Vec2((useTextureRectangle) else  1.0)/(float)(noSteps-1),0.0)

        for(int i=0i<noSteps++i)
            vertices.push_back(top)
            vertices.push_back(bottom)
            top+=dv
            bottom+=dv

            texcoords.push_back(top_texcoord)
            texcoords.push_back(bottom_texcoord)
            top_texcoord+=dv_texcoord
        coords = osg.Vec3Array(4)

        if  not dr._backPage :
            (*coords)[0] = dr._center - halfWidthVector + halfHeightVector
            (*coords)[1] = dr._center - halfWidthVector - halfHeightVector
            (*coords)[2] = dr._center + halfWidthVector - halfHeightVector
            (*coords)[3] = dr._center + halfWidthVector + halfHeightVector
        else:
            (*coords)[3] = dr._center - halfWidthVector + halfHeightVector
            (*coords)[2] = dr._center - halfWidthVector - halfHeightVector
            (*coords)[1] = dr._center + halfWidthVector - halfHeightVector
            (*coords)[0] = dr._center + halfWidthVector + halfHeightVector
        geom.setVertexArray(coords)

        tcoords = osg.Vec2Array(4)
        (*tcoords)[0].set(0.0,1.0)
        (*tcoords)[1].set(0.0,0.0)
        (*tcoords)[2].set(1.0,0.0)
        (*tcoords)[3].set(1.0,1.0)
        geom.setTexCoordArray(0,tcoords)

        colours = osg.Vec4Array(1)
        (*colours)[0].set(1.0,1.0,1.0,1.0)
        geom.setColorArray(colours, osg.Array.BIND_OVERALL)

        geom.addPrimitiveSet(osg.DrawArrays(osg.PrimitiveSet.QUADS,0,4))

        # set up the geode.
        geode = osg.Geode()
        geode.addDrawable(geom)
def createDistortionSubgraph(subgraph, clearColour):

    
    distortionNode = osg.Group()

    tex_width = 1024
    tex_height = 1024

    texture = osg.Texture2D()
    texture.setTextureSize(tex_width, tex_height)
    texture.setInternalFormat(GL_RGBA)
    texture.setFilter(osg.Texture2D.MIN_FILTER,osg.Texture2D.LINEAR)
    texture.setFilter(osg.Texture2D.MAG_FILTER,osg.Texture2D.LINEAR)

    # set up the render to texture camera.
        camera = osg.Camera()

        # set clear the color and depth buffer
        camera.setClearColor(clearColour)
        camera.setClearMask(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)

        # just inherit the main cameras view
        camera.setReferenceFrame(osg.Transform.RELATIVE_RF)
        camera.setProjectionMatrix(osg.Matrixd.identity())
        camera.setViewMatrix(osg.Matrixd.identity())

        # set viewport
        camera.setViewport(0,0,tex_width,tex_height)

        # set the camera to render before the main camera.
        camera.setRenderOrder(osg.Camera.PRE_RENDER)

        # tell the camera to use OpenGL frame buffer object where supported.
        camera.setRenderTargetImplementation(osg.Camera.FRAME_BUFFER_OBJECT)

        # attach the texture and use it as the color buffer.
        camera.attach(osg.Camera.COLOR_BUFFER, texture)

        # add subgraph to render
        camera.addChild(subgraph)

        distortionNode.addChild(camera)

    # set up the hud camera
        # create the quad to visualize.
        polyGeom = osg.Geometry()

        polyGeom.setSupportsDisplayList(False)

        origin = osg.Vec3(0.0,0.0,0.0)
        xAxis = osg.Vec3(1.0,0.0,0.0)
        yAxis = osg.Vec3(0.0,1.0,0.0)
        height = 1024.0
        width = 1280.0
        noSteps = 50

        vertices = osg.Vec3Array()
        texcoords = osg.Vec2Array()
        colors = osg.Vec4Array()

        bottom = origin
        dx = xAxis*(width/((float)(noSteps-1)))
        dy = yAxis*(height/((float)(noSteps-1)))

        bottom_texcoord = osg.Vec2(0.0,0.0)
        dx_texcoord = osg.Vec2(1.0/(float)(noSteps-1),0.0)
        dy_texcoord = osg.Vec2(0.0,1.0/(float)(noSteps-1))

        int i,j
        for(i=0i<noSteps++i)
            cursor = bottom+dy*(float)i
            texcoord = bottom_texcoord+dy_texcoord*(float)i
            for(j=0j<noSteps++j)
def createPyramid():
   pyramidGeode = osg.Geode()
   pyramidGeometry = osg.Geometry()
   pyramidGeode.addDrawable(pyramidGeometry) 
   pyramidVertices = osg.Vec3Array()
   pyramidVertices.append( osg.Vec3(0, 0, 0) ) # front left 
   pyramidVertices.append( osg.Vec3(2, 0, 0) ) # front right 
   pyramidVertices.append( osg.Vec3(2, 2, 0) ) # back right 
   pyramidVertices.append( osg.Vec3( 0,2, 0) ) # back left 
   pyramidVertices.append( osg.Vec3( 1, 1,2) ) # peak
   # Associate this set of vertices with the geometry associated with the 
   # geode we added to the scene.
   pyramidGeometry.setVertexArray( pyramidVertices )
   pyramidBase = osg.DrawElementsUInt(osg.PrimitiveSet.QUADS, 3)
   pyramidBase.append(3)
   pyramidBase.append(2)
   pyramidBase.append(1)
   pyramidBase.append(0)
   pyramidGeometry.addPrimitiveSet(pyramidBase)

   pyramidFaceOne = osg.DrawElementsUInt(osg.PrimitiveSet.TRIANGLES, 0)
   pyramidFaceOne.append(0)
   pyramidFaceOne.append(1)
   pyramidFaceOne.append(4)
   pyramidGeometry.addPrimitiveSet(pyramidFaceOne)

   pyramidFaceTwo = osg.DrawElementsUInt(osg.PrimitiveSet.TRIANGLES, 0)
   pyramidFaceTwo.append(1)
   pyramidFaceTwo.append(2)
   pyramidFaceTwo.append(4)
   pyramidGeometry.addPrimitiveSet(pyramidFaceTwo)

   pyramidFaceThree = osg.DrawElementsUInt(osg.PrimitiveSet.TRIANGLES, 0)
   pyramidFaceThree.append(2)
   pyramidFaceThree.append(3)
   pyramidFaceThree.append(4)
   pyramidGeometry.addPrimitiveSet(pyramidFaceThree)

   pyramidFaceFour = osg.DrawElementsUInt(osg.PrimitiveSet.TRIANGLES, 0)
   pyramidFaceFour.append(3)
   pyramidFaceFour.append(0)
   pyramidFaceFour.append(4)
   pyramidGeometry.addPrimitiveSet(pyramidFaceFour)

   colors = osg.Vec4Array()
   colors.append(osg.Vec4(1.0, 0.0, 0.0, 1.0) ) #index 0 red
   colors.append(osg.Vec4(0.0, 1.0, 0.0, 1.0) ) #index 1 green
   colors.append(osg.Vec4(0.0, 0.0, 1.0, 1.0) ) #index 2 blue
   colors.append(osg.Vec4(1.0, 1.0, 1.0, 1.0) ) #index 3 white

   colorIndexArray = osg.UIntArray()
   colorIndexArray.append(0) # vertex 0 assigned color array element 0
   colorIndexArray.append(1) # vertex 1 assigned color array element 1
   colorIndexArray.append(2) # vertex 2 assigned color array element 2
   colorIndexArray.append(3) # vertex 3 assigned color array element 3
   colorIndexArray.append(0) # vertex 4 assigned color array element 0

   pyramidGeometry.setColorArray(colors)
   pyramidGeometry.setColorIndices(colorIndexArray)
   pyramidGeometry.setColorBinding(osg.Geometry.BIND_PER_VERTEX)

   texcoords = osg.Vec2Array(5)
   texcoords[0].set(0.00,0.0)
   texcoords[1].set(0.25,0.0)
   texcoords[2].set(0.50,0.0)
   texcoords[3].set(0.75,0.0)
   texcoords[4].set(0.50,1.0)

   pyramidGeometry.setTexCoordArray(0,texcoords)
   return pyramidGeode
Example #17
0
    if _showAllLayers : 
        tileSpan /= numTiles
        tileOffsetX = tileSpan * (layerNumber%numTiles)
        tileOffsetY = 1 - tileSpan * (1 + layerNumber/numTiles)

    vertices = osg.Vec3Array()

    vertices.push_back(osg.Vec3f(tileOffsetX           , tileOffsetY            , 0))
    vertices.push_back(osg.Vec3f(tileOffsetX           , tileOffsetY  + tileSpan, 0))
    vertices.push_back(osg.Vec3f(tileOffsetX + tileSpan, tileOffsetY  + tileSpan, 0))
    vertices.push_back(osg.Vec3f(tileOffsetX + tileSpan, tileOffsetY            , 0))

    colors = osg.Vec3Array()
    colors.push_back(osg.Vec3(1, 1, 1))

    texcoords = osg.Vec2Array()
    texcoords.push_back(osg.Vec2f(0, 0))
    texcoords.push_back(osg.Vec2f(0, 1))
    texcoords.push_back(osg.Vec2f(1, 1))
    texcoords.push_back(osg.Vec2f(1, 0))

    geometry = osg.Geometry()
    geometry.setVertexArray(vertices)
    geometry.setTexCoordArray(0, texcoords)

    geometry.setColorArray(colors, osg.Array.BIND_OVERALL)

    geometry.addPrimitiveSet(osg.DrawArrays(GL_QUADS, 0, 4))

    geode = osg.Geode()
    geode.addDrawable(geometry)
Example #18
0
    normals = osg.Vec3Array()
    normals.push_back(osg.Vec3(0.0,-1.0,0.0))
    polyGeom.setNormalArray(normals, osg.Array.BIND_OVERALL)

    osg.Vec2 myTexCoords[] =
        osg.Vec2(0,1),
        osg.Vec2(0,0),
        osg.Vec2(1,0),
        osg.Vec2(1,1)
    

    numTexCoords = sizeof(myTexCoords)/sizeof(osg.Vec2)

    # pass the created tex coord array to the points geometry object,
    # and use it to set texture unit 0.
    polyGeom.setTexCoordArray(0,osg.Vec2Array(numTexCoords,myTexCoords))

    # well use indices and DrawElements to define the primitive this time.
    unsigned short myIndices[] =
        0,
        1,
        3,
        2
    

    numIndices = sizeof(myIndices)/sizeof(unsigned short)

    # There are three variants of the DrawElements osg.Primitive, UByteDrawElements which
    # contains unsigned char indices, UShortDrawElements which contains unsigned short indices,
    # and UIntDrawElements which contains ... unsigned int indices.
    # The first parameter to DrawElements is
def createRectangle(bb, filename):


    
    top_left = osg.Vec3(bb.xMin(),bb.yMax(),bb.zMax())
    bottom_left = osg.Vec3(bb.xMin(),bb.yMax(),bb.zMin())
    bottom_right = osg.Vec3(bb.xMax(),bb.yMax(),bb.zMin())
    top_right = osg.Vec3(bb.xMax(),bb.yMax(),bb.zMax())

    # create geometry
    geom = osg.Geometry()

    vertices = osg.Vec3Array(4)
    (*vertices)[0] = top_left
    (*vertices)[1] = bottom_left
    (*vertices)[2] = bottom_right
    (*vertices)[3] = top_right
    geom.setVertexArray(vertices)

    texcoords = osg.Vec2Array(4)
    (*texcoords)[0].set(0.0, 0.0)
    (*texcoords)[1].set(1.0, 0.0)
    (*texcoords)[2].set(1.0, 1.0)
    (*texcoords)[3].set(0.0, 1.0)
    geom.setTexCoordArray(0,texcoords)

    normals = osg.Vec3Array(1)
    (*normals)[0].set(0.0,-1.0,0.0)
    geom.setNormalArray(normals, osg.Array.BIND_OVERALL)

    colors = osg.Vec4Array(1)
    (*colors)[0].set(1.0,1.0,1.0,1.0)
    geom.setColorArray(colors, osg.Array.BIND_OVERALL)

    geom.addPrimitiveSet(osg.DrawArrays(GL_QUADS, 0, 4))

    # disable display list so our modified tex coordinates show up
    geom.setUseDisplayList(False)

    # load image
    img = osgDB.readImageFile(filename)

    # setup texture
    texture = osg.TextureRectangle(img)

    texmat = osg.TexMat()
    texmat.setScaleByTextureRectangleSize(True)

    # setup state
    state = geom.getOrCreateStateSet()
    state.setTextureAttributeAndModes(0, texture, osg.StateAttribute.ON)
    state.setTextureAttributeAndModes(0, texmat, osg.StateAttribute.ON)

    # turn off lighting
    state.setMode(GL_LIGHTING, osg.StateAttribute.OFF)

    # install 'update' callback
    geode = osg.Geode()
    geode.addDrawable(geom)
    geode.setUpdateCallback(TexturePanCallback(texmat))

    return geode