Source code for model


"""
This module processes uniform attributes for the appropriate model
"""

# Import Python modules
if __name__ == '__main__':
    import glm


[docs] class BaseModel: """ Base class for all 3D models with position, rotation, and scale. Provides fundamental model matrix calculations and rendering functionality. """ def __init__(self, app, vao_name, tex_id, pos=(0, 0, 0), rot=(0, 0, 0), scale=(1, 1, 1)): """ Initialize base model with transformation properties and rendering data. :param app: Reference to main application :type app: Application :param vao_name: Name of vertex array object to use :type vao_name: str :param tex_id: Texture identifier :type tex_id: str :param pos: Position in world coordinates (x, y, z) :type pos: tuple :param rot: Rotation in degrees (x, y, z) :type rot: tuple :param scale: Scale factors (x, y, z) :type scale: tuple """ self.app = app self.pos = pos self.vao_name = vao_name self.rot = glm.vec3([glm.radians(a) for a in rot]) self.scale = scale self.m_model = self.get_model_matrix() self.tex_id = tex_id self.vao = app.mesh.vao.vaos[vao_name] self.program = self.vao.program self.camera = self.app.camera
[docs] def update(self): """ Update model state before rendering. Subclasses override this method for custom behavior. """ pass
[docs] def get_model_matrix(self): """ Calculate model matrix combining translation, rotation, and scale. :return: Model transformation matrix :rtype: mat4 """ # NOTE: This is just an identity matrix m_model = glm.mat4() # Translate m_model = glm.translate(m_model, self.pos) # Rotate m_model = glm.rotate(m_model, self.rot.z, glm.vec3(0, 0, 1)) m_model = glm.rotate(m_model, self.rot.y, glm.vec3(0, 1, 0)) m_model = glm.rotate(m_model, self.rot.x, glm.vec3(1, 0, 0)) # Scale m_model = glm.scale(m_model, self.scale) return m_model
[docs] def render(self): """ Update model state and render using associated VAO. """ self.update() self.vao.render()
[docs] class ExtendedBaseModel(BaseModel): """ Subclass for an application's main objects """ def __init__(self, app, vao_name, tex_id, pos, rot, scale): super().__init__(app, vao_name, tex_id, pos, rot, scale) self.on_init()
[docs] def update(self): """ Update dynamic uniform attributes """ self.texture.use(location=0) self.program['camPos'].write(self.camera.position) self.program['m_view'].write(self.camera.m_view) self.program['m_model'].write(self.m_model)
[docs] def update_shadow(self): self.shadow_program['m_model'].write(self.m_model)
[docs] def render_shadow(self): self.update_shadow() self.shadow_vao.render()
[docs] def on_init(self): self.program['m_view_light'].write(self.app.light.m_view_light) # Viewport resolution self.program['u_resolution'].write(glm.vec2(self.app.WIN_SIZE)) # Depth texture self.depth_texture = self.app.mesh.texture.textures['depth_texture'] self.program['shadowMap'] = 1 self.depth_texture.use(location=1) # Shadow self.shadow_vao = self.app.mesh.vao.vaos['shadow_' + self.vao_name] self.shadow_program = self.shadow_vao.program self.shadow_program['m_proj'].write(self.camera.m_proj) self.shadow_program['m_view_light'].write(self.app.light.m_view_light) self.shadow_program['m_model'].write(self.m_model) # Texture self.texture = self.app.mesh.texture.textures[self.tex_id] self.program['u_texture_0'] = 0 self.texture.use(location=0) # Matrices # NOTE: .write(x) is a function that gives the shader program a specified attribute self.program['m_proj'].write(self.camera.m_proj) self.program['m_view'].write(self.camera.m_view) self.program['m_model'].write(self.m_model) # Light uniform attributes self.program['light.position'].write(self.app.light.position) self.program['light.Ia'].write(self.app.light.Ia) self.program['light.Id'].write(self.app.light.Id) self.program['light.Is'].write(self.app.light.Is)
[docs] class Cube(ExtendedBaseModel): """ Basic cube model with texture and lighting support. """ def __init__(self, app, vao_name='cube', tex_id=0, pos=(0, 0, 0), rot=(0, 0, 0), scale=(1, 1, 1)): """ Initialize cube model with default parameters. :param app: Reference to main application :type app: Application :param vao_name: Name of vertex array object (default: 'cube') :type vao_name: str :param tex_id: Texture identifier (default: 0) :type tex_id: int :param pos: Position in world coordinates (default: origin) :type pos: tuple :param rot: Rotation in degrees (default: no rotation) :type rot: tuple :param scale: Scale factors (default: unit scale) :type scale: tuple """ super().__init__(app, vao_name, tex_id, pos, rot, scale)
[docs] class MovingCube(Cube): """ Animated cube that rotates continuously. """ def __init__(self, *args, **kwargs): """ Initialize moving cube with same parameters as base cube. """ super().__init__(*args, **kwargs)
[docs] def update(self): """ Update cube rotation based on application time. Creates continuous spinning animation. """ self.m_model = self.get_model_matrix() super().update()
[docs] class Cat(ExtendedBaseModel): """ Cat model with specific orientation and texture. """ def __init__(self, app, vao_name='cat', tex_id='cat', pos=(0, 0, 0), rot=(-90, 0, 0), scale=(1, 1, 1)): """ Initialize cat model with default orientation. :param app: Reference to main application :type app: Application :param vao_name: Name of vertex array object (default: 'cat') :type vao_name: str :param tex_id: Texture identifier (default: 'cat') :type tex_id: str :param pos: Position in world coordinates (default: origin) :type pos: tuple :param rot: Rotation in degrees (default: -90° X rotation) :type rot: tuple :param scale: Scale factors (default: unit scale) :type scale: tuple """ super().__init__(app, vao_name, tex_id, pos, rot, scale)
[docs] class SkyBox(BaseModel): """ Basic skybox that renders a cubemap texture. Uses simplified view matrix to prevent skybox rotation with camera. """ def __init__(self, app, vao_name='skybox', tex_id='skybox', pos=(0, 0, 0), rot=(0, 0, 0), scale=(1, 1, 1)): """ Initialize skybox with cubemap texture. :param app: Reference to main application :type app: Application :param vao_name: Name of vertex array object (default: 'skybox') :type vao_name: str :param tex_id: Texture identifier (default: 'skybox') :type tex_id: str :param pos: Position in world coordinates (default: origin) :type pos: tuple :param rot: Rotation in degrees (default: no rotation) :type rot: tuple :param scale: Scale factors (default: unit scale) :type scale: tuple """ super().__init__(app, vao_name, tex_id, pos, rot, scale) # NOTE: Initialize the model's attributes here self.on_init()
[docs] def update(self): """ Update skybox view matrix to remove camera rotation. Prevents skybox from rotating with camera movement. """ self.program['m_view'].write(glm.mat4(glm.mat3(self.camera.m_view)))
[docs] def on_init(self): """ Initialize skybox textures and matrices. Sets up cubemap texture and projection/view matrices. """ # Assign uniform textures to a shader program self.texture = self.app.mesh.texture.textures[self.tex_id] self.program['u_texture_skybox'] = 0 self.texture.use(location=0) # Assign uniform matrices to a shader program self.program['m_proj'].write(self.camera.m_proj) self.program['m_view'].write(glm.mat4(glm.mat3(self.camera.m_view)))
[docs] class AdvancedSkyBox(BaseModel): """ Advanced skybox with proper perspective projection. Uses inverse projection-view matrix for accurate cubemap sampling. """ def __init__(self, app, vao_name='advanced_skybox', tex_id='skybox', pos=(0, 0, 0), rot=(0, 0, 0), scale=(1, 1, 1)): """ Initialize advanced skybox with cubemap texture. :param app: Reference to main application :type app: Application :param vao_name: Name of vertex array object (default: 'advanced_skybox') :type vao_name: str :param tex_id: Texture identifier (default: 'skybox') :type tex_id: str :param pos: Position in world coordinates (default: origin) :type pos: tuple :param rot: Rotation in degrees (default: no rotation) :type rot: tuple :param scale: Scale factors (default: unit scale) :type scale: tuple """ super().__init__(app, vao_name, tex_id, pos, rot, scale) # NOTE: Initialize the model's attributes here self.on_init()
[docs] def update(self): """ Update inverse projection-view matrix for proper cubemap sampling. Converts clip coordinates back to world space for accurate texture lookup. """ m_view = glm.mat4(glm.mat3(self.camera.m_view)) self.program['m_invProjView'].write(glm.inverse(self.camera.m_proj * m_view))
[docs] def on_init(self): """ Initialize skybox textures. Sets up cubemap texture for advanced rendering. """ # Assign uniform textures to a shader program self.texture = self.app.mesh.texture.textures[self.tex_id] self.program['u_texture_skybox'] = 0 self.texture.use(location=0)