procedurally generated city driving scene (3 textures)

Pretty simple city scene. Procedurally generated from just 3 textures, 0 models.


Not depicted of course is the driving. NodePaths are “retreated” in the scene over time. The camera stays fixed.

Very cool. I would love to see the code, if you are perhaps willing to share with the rest of us? (Please consider this an expression of interest in seeing it. :smiley: )

As soon as I posted that, I started editing it. It’s being edited!

One texture is in the Panda models. The other two are linked below. If you have my ‘asynchronous live control’ module you can play with the speed and such with assignment statements on the console; the import and initialization for ‘panda_async’ are commented out near the first and last lines.

from panda3d.core import loadPrcFileData
loadPrcFileData("", "show-frame-rate-meter 1")

import direct.directbase.DirectStart
from panda3d.core import *
from direct.interval.IntervalGlobal import *
from pandac.PandaModules import Filename
#import panda_async
import random as ran
import time
import sys

windtex= loader.loadTexture( 'window.png' )
windtex.setWrapU(Texture.WMRepeat)
windtex.setWrapV(Texture.WMRepeat)
windtex.setMinfilter(Texture.FTLinearMipmapLinear)
windtex.setAnisotropicDegree(2)

streettex= loader.loadTexture( 'street.png' )
streettex.setWrapU(Texture.WMClamp)
streettex.setWrapV(Texture.WMClamp)
streettex.setAnisotropicDegree(2)

skytex= loader.loadTexture( r'samples/Carousel/models/env_sky.jpg' )
skytex.setMinfilter(Texture.FTLinearMipmapLinear)

base.cam.setPos( 2.5, 0, 7 )

objs= [ ]
cardmaker= CardMaker( 'cardmaker' )

skynode= cardmaker.generate( )
sky= render.attachNewNode( skynode )
skydist= 500
sky.setScale( skydist* 2, skydist, skydist )
sky.setPos( -skydist, 1000, 0 )
sky.setTexture( skytex )

class Globals:
    pause= False
    atten= Point3( .003, .003, .003 ) # attenuation on streetlights
    lightpos= [ 1, None, 16 ] # positioning on streelights (symmetrical)
    lightcol= Point4( 1, .75, 0, 1 ) # color on streetlights
    nightambient= Point4(.1,.05,0,1) # nighttime ambient
    lightspacing= 125 # spacing between lights
    speed= 5.0
    nextposL= 0
    nextposR= 0
    nextposB= 0
    nextlightL= 0
    nextlightR= lightspacing/ 2.0

def task( taskob ):
    if Globals.pause:
        return taskob.cont
    rear= 500
    speed= Globals.speed

    _newobjs= [ ]
    for obj in objs: # move all objects
        obj.setPos( obj, 0, -speed, 0 )
        if obj.getY( )> -30:
            _newobjs.append( obj )
        else:
            if obj.getName( ).startswith( 'streetlight' ):
                render.clearLight( obj )
            obj.removeNode( )
    objs[ : ]= _newobjs

    Globals.nextposL-= speed
    Globals.nextposR-= speed
    Globals.nextposB-= speed
    Globals.nextlightL-= speed
    Globals.nextlightR-= speed

    while Globals.nextposB< rear: # replace the street cards
        width= 20
        height= 20
        Globals.nextposB+= height

        group= NodePath( 'group' )
        group.reparentTo( render )
        objs.append( group )

        cardmaker.setUvRange( Point2( 0, 0 ), Point2( 1, 1 ) )
        cardnode= cardmaker.generate( )
        obj= NodePath( cardnode )
        obj.reparentTo( group )

        group.setPos( -width/ 2, Globals.nextposB, 5 )
        obj.setHpr( 0, -90, 0 )

        obj.setColor( 1, 1, 1 )
        obj.setScale( width, 1, height )
        obj.setTexture( streettex )

    while 1: # replace the streetlights (as necessary)
        if Globals.nextlightL< rear:
            which= 'L'
        elif Globals.nextlightR< rear:
            which= 'R'
        else:
            break
        light= PointLight( 'streetlight pointlight' )
        light.setColor( Globals.lightcol )
        light.setAttenuation( Globals.atten )
        group= NodePath( light )
        render.setLight( group )
        group.reparentTo( render )
        objs.append( group )

        width= Globals.lightspacing
        if which== 'L':
            group.setPos( -Globals.lightpos[ 0 ], Globals.nextlightL, Globals.lightpos[ 2 ] )
            Globals.nextlightL+= width
        elif which== 'R':
            group.setPos( Globals.lightpos[ 0 ], Globals.nextlightR, Globals.lightpos[ 2 ] )
            Globals.nextlightR+= width

    while 1: # replace the buildings
        if Globals.nextposL< rear:
            which= 'L'
        elif Globals.nextposR< rear:
            which= 'R'
        else:
            break

        group= NodePath( 'group' )
        group.reparentTo( render )
        objs.append( group )

        cardmaker.setUvRange( Point2( 0, 0 ), Point2( ran.randint( 2, 20 ), ran.randint( 2, 20 ) ) )

        r, g= ran.uniform( .5, 1 ), ran.uniform( .5, 1 )
        b= 2- r- g
        width= ran.uniform( 10, 20 )
        height= ran.uniform( 10, 20 )

        cardnode= cardmaker.generate( )
        obj= NodePath( cardnode )
        obj.reparentTo( group )
        obj.setColor( r, g, b )
        if which== 'L':
            group.setPos( -10, Globals.nextposL, 5 )
            obj.setHpr( 90, 0, 0 )
            Globals.nextposL+= width
        elif which== 'R':
            group.setPos( 10, Globals.nextposR+ width, 5 )
            obj.setHpr( 270, 0, 0 )
            Globals.nextposR+= width
        obj.setScale( width, 1, height )
        obj.setTexture( windtex )

        cardside= cardmaker.generate( )
        obj= NodePath( cardside )
        obj.reparentTo( group )
        obj.setColor( r, g, b )
        obj.setScale( width, 1, height )
        if which== 'L':
            obj.setPos( -width, 0, 0 )
        elif which== 'R':
            obj.setPos( 0, -width, 0 )

    return taskob.cont

base.cam.node( ).getLens( ).setNear( 1 )
base.cam.node( ).getLens( ).setFar( 1001 )
taskMgr.add( task, 'roll task' )

def slow( task ):
    time.sleep( .05 )
    return task.cont
taskMgr.add( slow, 'slow' )

ambientLight = AmbientLight('ambientLight')
ambientLightNP = render.attachNewNode(ambientLight)
render.setLight(ambientLightNP)

def setlightf( t ):
    c1= Point4(1.2,1.2,1.2,1)
    c2= Globals.nightambient
    c= (c2-c1)*t+c1
    ambientLight.setColor( c )

Globals.lightinterval= Sequence(
    LerpFunc( setlightf, fromData= 0, toData= 1, duration= 5.0, blendType= 'easeInOut' ),
    LerpFunc( setlightf, fromData= 1, toData= 0, duration= 5.0, blendType= 'easeInOut' )
)
Globals.lightinterval.loop( )

def pausefun( ):
    Globals.pause= not Globals.pause
    if Globals.pause:
        Globals.lightinterval.pause( )
    else:
        Globals.lightinterval.resume( )

base.accept( 'f7', lambda: base.win.saveScreenshot( Filename( 'driving scene 1.png' ) ) )
base.accept( 'f8', lambda: base.win.saveScreenshot( Filename( 'driving scene 2.png' ) ) )
base.accept( 'pause', pausefun )
base.accept( 'escape', sys.exit )
#panda_async.G.__dict__.update( globals( ) )

run( )

Window panes: (border matches background)

Street tileage:

Images not loading (they use to my first view).

Cool none the less!

Ah yes I hard coded the images’ paths in the preamble. They’re relative now in an edit of the code.

Thank you very much! I’m sure I’ll find some interesting stuff in there.

I’m trying to add streetlights and I’m getting infuriated. I can’t get the right relative motion… the same formula doesn’t work as for the cards (buildings) because the lights are rotated to face downward. Though pointlights were working.