def generate_city( self, buildingShader, building_textures, building_shaders, lanternShader, lantern_textures, lantern_shaders, ): """Generate a cityscape Arguments: buildingShader {shader} -- Default shader to use for buildings building_textures {dict} -- Texture info for buildings building_shaders {dict} -- Shader material info for buildings lanternShader {shader} -- Default shaders to use for lanterns lantern_textures {dict} -- Texture info for lanterns lantern_shaders {dict} -- Shader material info for lanterns """ # Load building models models = [ load_obj("models/building1.obj"), load_obj("models/building2.obj") ] # Load lamp model lamp_model = load_obj("models/lantern.obj") # Create buildings and lampposts at each 'city block' for xx in range(-300, 300, 200): for zz in range(-300, 300, 200): # This position marks the center of each concrete block position = gltypes.vec3(xx, 0, zz) # Building positions - four in the centre of the block for bpos in [(-45, -45), (-45, 45), (45, -45), (45, 45)]: building_pos = position + gltypes.vec3(bpos[0], 0, bpos[1]) self.add_model( random.choice(models), buildingShader, building_pos, building_textures, building_shaders, ) # Lantern positions - eight around the edge of the block for lpos in [ (-70, -70), (-70, 0), (-70, 70), (70, -70), (70, 0), (70, 70), (0, -70), (0, 70), ]: lantern_pos = position + gltypes.vec3(lpos[0], 0, lpos[1]) self.add_model( lamp_model, lanternShader, lantern_pos, lantern_textures, lantern_shaders, )
class Object: """Basic object class This has some basic things that all objects can derive from Most useful functionality will be in the ObjModel class """ position = gltypes.vec3(0, 0, 0) shader = None material_textures = {} material_shaders = {} def ui(self): """Super lame UI for adjusting the position of the object """ if True: return if imgui.tree_node("Object", imgui.TREE_NODE_DEFAULT_OPEN): _, x = imgui.slider_float("X", self.position[0], -10, 10) _, y = imgui.slider_float("Y", self.position[1], -10, 10) _, z = imgui.slider_float("Z", self.position[2], -10, 10) self.position = gltypes.vec3(x, y, z) imgui.tree_pop() def bindTextures(self, shader, material): """Bind all relevant textures for a material to the given shader Arguments: shader {int} -- Shader material {str} -- Material name to assign textures to """ if material not in self.material_textures: return tex_data = self.material_textures[material] if isinstance(tex_data, dict): # Dictionary of textures, unpack if "diffuse" in tex_data: self.bindDiffuseTexture(shader, tex_data["diffuse"]) if "specular" in tex_data: self.bindSpecularTexture(shader, tex_data["specular"]) else: self.bindSpecularTexture(shader, -1) else: # Single texture, treat as diffuse only self.bindDiffuseTexture(shader, tex_data) def bindDiffuseTexture(self, shader, texture): """Bind a single diffuse texture to a shader Arguments: shader {int} -- Shader texture {int} -- Texture ID to assign """ shaders.setUniform(shader, "diffuseTexture", TEX_DIFFUSE) shaders.bindTexture(TEX_DIFFUSE, texture, GL_TEXTURE_2D) def bindSpecularTexture(self, shader, texture): """Bind a single specular texture to a shader Arguments: shader {int} -- Shader texture {int} -- Texture ID to assign """ shaders.setUniform(shader, "specularTexture", TEX_SPECULAR) shaders.bindTexture(TEX_SPECULAR, texture, GL_TEXTURE_2D) def applyShaderUniforms(self, shader, transforms): """Utility function to assign a list of uniforms to a shader Arguments: shader {int} -- Shader transforms {dict} -- Name, value pairs of uniforms to assign """ for name, value in transforms.items(): shaders.setUniform(shader, name, value)
def getWorldToViewMatrix(self): return gltypes.make_lookAt(self.position, gltypes.vec3(0, 0, 0), self.up)
def __init__(self, target=gltypes.vec3(0, 0, 0)): self.target = target
class FreeCamera(Camera): """More complicated freeform camera mode Controlled by WASD for movement and arrow keys for angle control """ yaw = 10 pitch = -30 rotate_speed = 60 pitch_speed = 60 move_speed = 50 position = gltypes.vec3(50, 10, 0) def __init__(self, target=gltypes.vec3(0, 0, 0)): self.target = target def update(self, dt, keys): """Camera update function Arrow keys for angular rotation WASD for freeform movement Arguments: dt {float} -- Time, in seconds, since the last update keys {dict} -- Mapping of keys currently pressed """ forwardSpeed = 0 strafeSpeed = 0 yawSpeed = 0 pitchSpeed = 0 # Handle angular movement if keys["UP"]: pitchSpeed -= self.pitch_speed if keys["DOWN"]: pitchSpeed += self.pitch_speed if keys["RIGHT"]: yawSpeed += self.rotate_speed if keys["LEFT"]: yawSpeed -= self.rotate_speed # Handle positional movement if keys["W"]: forwardSpeed += self.move_speed if keys["S"]: forwardSpeed -= self.move_speed if keys["D"]: strafeSpeed -= self.move_speed if keys["A"]: strafeSpeed += self.move_speed # Rotate self.yaw += yawSpeed * dt self.pitch = min(60, max(-60, self.pitch + pitchSpeed * dt)) # Generate rotation self.cameraRotation = Mat3( gltypes.make_rotation_y(math.radians(self.yaw))) * Mat3( gltypes.make_rotation_x(math.radians(self.pitch))) # Movement self.position += np.array( self.cameraRotation * [0, 0, 1]) * forwardSpeed * dt self.position += np.array( self.cameraRotation * [1, 0, 0]) * strafeSpeed * dt def ui(self): """No UI for this camera because I'm lazy See the above function for controls """ pass def getWorldToViewMatrix(self): """Generate a worldToViewTransform matrix This is a simple looking in the direction of the camera """ return self.make_lookFrom(self.cameraRotation * [0, 0, 1])