示例#1
0
文件: vao.py 项目: yoyonel/demosys-py
    def instance(self, program: moderngl.Program) -> moderngl.VertexArray:
        """
        Obtain the ``moderngl.VertexArray`` instance for the program.
        The instance is only created once and cached internally.

        Returns: ``moderngl.VertexArray`` instance
        """
        vao = self.vaos.get(program.glo)
        if vao:
            return vao

        program_attributes = [
            name for name, attr in program._members.items()
            if isinstance(attr, moderngl.Attribute)
        ]

        # Make sure all attributes are covered
        for attrib_name in program_attributes:
            # Ignore built in attributes for now
            if attrib_name.startswith('gl_'):
                continue

            # Do we have a buffer mapping to this attribute?
            if not sum(
                    buffer.has_attribute(attrib_name)
                    for buffer in self.buffers):
                raise VAOError(
                    "VAO {} doesn't have attribute {} for program {}".format(
                        self.name, attrib_name, program.name))

        vao_content = []

        # Pick out the attributes we can actually map
        for buffer in self.buffers:
            content = buffer.content(program_attributes)
            if content:
                vao_content.append(content)

        # Any attribute left is not accounted for
        if program_attributes:
            for attrib_name in program_attributes:
                if attrib_name.startswith('gl_'):
                    continue

                raise VAOError("Did not find a buffer mapping for {}".format(
                    [n for n in program_attributes]))

        # Create the vao
        if self._index_buffer:
            vao = context.ctx().vertex_array(program, vao_content,
                                             self._index_buffer,
                                             self._index_element_size)
        else:
            vao = context.ctx().vertex_array(program, vao_content)

        self.vaos[program.glo] = vao
        return vao
示例#2
0
文件: vao.py 项目: binaryf/demosys-py
    def _create_vao_instance(self, shader):
        """
        Create a VAO based on the shader's attribute specification.
        This is called by ``bind(shader)`` and should not be messed with
        unless you are absolutely sure about what you are doing.

        :param shader: The shader we are generating the combo for
        :return: A new VAOCombo object with the correct attribute binding
        """
        # Return the combo if already generated
        vao = self.vaos.get(shader.vao_key)
        if vao:
            return vao

        # Make sure all attributes are covered
        for attrib in shader.attribute_list:
            if attrib.name in SYSTEM_ATTRIBS:
                continue

            if not sum(b.has_attribute(attrib.name) for b in self.buffers):
                raise VAOError(
                    "VAO {} doesn't have attribute {} for program {}".format(
                        self.name, attrib.name, shader.name))

        attributes = [a.name for a in shader.attribute_list]
        vao_content = []

        for buffer in self.buffers:
            content = buffer.content(attributes)
            if content:
                vao_content.append(content)

        if len(attributes) > 0:
            for attrib in attributes:
                if attrib not in SYSTEM_ATTRIBS:
                    raise VAOError(
                        "Did not find a buffer mapping for {}".format(
                            [n for n in attributes]))

        if self._index_buffer:
            vao = context.ctx().vertex_array(shader.program, vao_content,
                                             self._index_buffer,
                                             self._index_element_size)
        else:
            vao = context.ctx().vertex_array(shader.program, vao_content)
        self.vaos[shader.vao_key] = vao

        return vao
示例#3
0
    def _init_texture2d_draw(self):
        """Initialize geometry and shader for drawing FBO layers"""
        if not TextureHelper._quad:
            TextureHelper._quad = geometry.quad_fs()

        # Shader for drawing color layers
        TextureHelper._texture2d_shader = context.ctx().program(
            vertex_shader="""
                #version 330

                in vec3 in_position;
                in vec2 in_uv;
                out vec2 uv;
                uniform vec2 offset;
                uniform vec2 scale;

                void main() {
                    uv = in_uv;
                    gl_Position = vec4((in_position.xy + vec2(1.0, 1.0)) * scale + offset, 0.0, 1.0);
                }
            """,
            fragment_shader="""
                #version 330

                out vec4 out_color;
                in vec2 uv;
                uniform sampler2D texture0;

                void main() {
                    out_color = texture(texture0, uv);
                }
            """)

        TextureHelper._texture2d_sampler = self.ctx.sampler(
            filter=(moderngl.LINEAR, moderngl.LINEAR), )
示例#4
0
class DemosysTestCase(TestCase):

    window = context.window()
    ctx = context.ctx()

    def create_shader(self, source=None, path=None):
        """
        Create a shader from source or file
        """
        program = ShaderProgram(name="test", path=path)

        if source:
            program.set_source(source)
            program.prepare()

        if path:
            resources.shaders.load_shader(program)

        return program

    def get_texture(self, path):
        return resources.textures.get(path, create=True)

    def get_texture_array(self, path, layers=0):
        return resources.textures.get(path,
                                      create=True,
                                      cls=TextureArray,
                                      layers=layers)

    def get_track(self, name):
        return resources.tracks.get(name)
示例#5
0
    def __init__(self, path=None, name=None):
        """
        Create a shader using either a file path or a name
        :param path: Full file path to the shader
        :param name: Name of the shader (debug purposes)
        """
        self.ctx = context.ctx()
        if not path and not name:
            raise ShaderError("Shader must have a path or a name")

        self.path = path

        if not name:
            self.name = os.path.basename(path)
        else:
            self.name = name

        self._vertex_source = None
        self._fragment_source = None
        self._geometry_source = None

        self.program = None
        # Shader inputs
        self.uniform_map = {}

        self.attribute_list = []
        self.attribute_map = {}

        # A string of concatenated attribute names
        self.attribute_key = None
        # Unique key for VAO instances containing shader id and attributes
        self.vao_key = None
示例#6
0
文件: fbo.py 项目: binaryf/demosys-py
    def create(size, components=4, depth=False, dtype='f1', layers=1) -> 'FBO':
        """
        Create a single or multi layer FBO

        :param size: (tuple) with and height
        :param components: (tuple) number of components. 1, 2, 3, 4
        :param depth: (bool) Create a depth attachment
        :param dtype: (string) data type per r, g, b, a ...
        :param layers: (int) number of color attachments

        :return: A new FBO
        """
        instance = FBO()

        # Add N layers of color attachments
        for _ in range(layers):
            tex = Texture2D.create(size, components, dtype=dtype)
            instance.color_buffers.append(tex)

        # Set depth attachment is specified
        if depth:
            instance.depth_buffer = DepthTexture(size)

        instance.fbo = context.ctx().framebuffer(
            color_attachments=[b.mglo for b in instance.color_buffers],
            depth_attachment=instance.depth_buffer.mglo
            if instance.depth_buffer is not None else None)

        return instance
示例#7
0
class DemosysTestCase(TestCase):

    window = context.window()
    ctx = context.ctx()
    project = project.instance
    timeline = None

    apply_mocks()

    def load_program(self, path):
        return resources.programs.load(
            ProgramDescription(label=path, path=path))

    def load_texture(self, path):
        return resources.textures.load(
            TextureDescription(label=path, path=path))

    def load_texture_array(self, path, layers=0):
        return resources.textures.load(
            TextureDescription(label=path,
                               path=path,
                               loader='array',
                               layers=layers))

    def load_scene(self, path):
        return resources.scenes.load(SceneDescription(label=path, path=path))

    def load_data(self, path, loader=None):
        return resources.data.load(
            DataDescription(label=path, path=path, loader=loader))

    def get_track(self, name):
        return resources.tracks.get(name)
示例#8
0
    def create(cls,
               size,
               components=4,
               data=None,
               alignment=1,
               dtype='f1',
               mipmap=False) -> 'TextureArray':
        """
        :param size: (x, y, layers) size and layers of the texture
        :param components: The number of components 1, 2, 3 or 4
        :param data: (bytes) Content of the texture
        :param alignment: The byte alignment 1, 2, 4 or 8
        :param dtype: (str) The data type
        :param mipmap: (bool) Generate mipmaps
        """
        texture = TextureArray("create", mipmap=False, layers=size[2])
        texture.mglo = context.ctx().texture_array(
            size,
            components,
            data=data,
            alignment=alignment,
            dtype=dtype,
        )

        if mipmap:
            texture.build_mipmaps()

        return texture
示例#9
0
    def load(self, materials):
        name_map = {
            'POSITION': 'in_position',
            'NORMAL': 'in_normal',
            'TEXCOORD_0': 'in_uv',
            'TANGENT': 'in_tangent',
            'JOINTS_0': 'in_joints',
            'WEIGHTS_0': 'in_heights',
            'COLOR_0': 'in_color0',
        }

        meshes = []

        # Read all primitives as separate meshes for now
        # According to the spec they can have different materials and vertex format
        for primitive in self.primitives:

            vao = VAO(self.name, mode=primitive.mode or moderngl.TRIANGLES)

            # Index buffer
            component_type, index_vbo = self.load_indices(primitive)
            if index_vbo is not None:
                vao.index_buffer(context.ctx().buffer(index_vbo.tobytes()),
                                 index_element_size=component_type.size)

            attributes = {}
            vbos = self.prepare_attrib_mapping(primitive)

            for vbo_info in vbos:
                dtype, buffer = vbo_info.create()
                vao.buffer(
                    buffer,
                    " ".join([
                        "{}{}".format(attr[1], DTYPE_BUFFER_TYPE[dtype])
                        for attr in vbo_info.attributes
                    ]),
                    [name_map[attr[0]] for attr in vbo_info.attributes],
                )

                for attr in vbo_info.attributes:
                    attributes[attr[0]] = {
                        'name': name_map[attr[0]],
                        'components': attr[1],
                        'type': vbo_info.component_type.value,
                    }

            bbox_min, bbox_max = self.get_bbox(primitive)
            meshes.append(
                Mesh(
                    self.name,
                    vao=vao,
                    attributes=attributes,
                    material=materials[primitive.material]
                    if primitive.material is not None else None,
                    bbox_min=bbox_min,
                    bbox_max=bbox_max,
                ))

        return meshes
示例#10
0
    def __init__(self, width, height, gbuffer=None, lightbuffer=None):
        self.ctx = context.ctx()

        self.width = width
        self.height = height
        self.size = (width, height)
        self.depth_sampler = samplers.create(texture_compare_mode=False,
                                             min_filter=moderngl.LINEAR,
                                             mag_filter=moderngl.LINEAR)

        # FBOs
        self.gbuffer = gbuffer
        self.lightbuffer = lightbuffer

        # Light Info
        self.point_lights = []

        # Create geometry buffer if not supplied
        depth_buffer = DepthTexture(self.size)

        if not self.gbuffer:
            self.gbuffer = FBO.create_from_textures(
                [
                    Texture2D.create(self.size, 4, dtype='f1'),
                    Texture2D.create(self.size, 3, dtype='f2'),
                ],
                depth_buffer=depth_buffer,
            )

        if not self.lightbuffer:
            self.lightbuffer = FBO.create_from_textures(
                [Texture2D.create(self.size, 4)],
                # depth_buffer=depth_buffer,
            )

        # Unit cube for point lights (cube with radius 1.0)
        self.unit_cube = geometry.cube(width=2, height=2, depth=2)
        self.point_light_shader = resources.shaders.get(
            "deferred/light_point.glsl", create=True)

        # Debug draw lights
        self.debug_shader = resources.shaders.get("deferred/debug.glsl",
                                                  create=True)

        # Combine shader
        self.combine_shader = resources.shaders.get("deferred/combine.glsl",
                                                    create=True)
        self.quad = geometry.quad_fs()
示例#11
0
文件: vao.py 项目: binaryf/demosys-py
    def index_buffer(self, buffer, index_element_size=4):
        """
        Set the index buffer for this VAO

        :param buffer: Buffer object or ndarray
        :param index_element_size: Byte size of each element. 1, 2 or 4
        """
        if not isinstance(buffer, moderngl.Buffer) and not isinstance(
                buffer, numpy.ndarray):
            raise VAOError(
                "buffer parameter must be a moderngl.Buffer or numpy.ndarray instance"
            )

        if isinstance(buffer, numpy.ndarray):
            buffer = context.ctx().buffer(buffer.tobytes())

        self._index_buffer = buffer
        self._index_element_size = index_element_size
示例#12
0
    def _init_depth_texture_draw(self):
        """Initialize geometry and shader for drawing FBO layers"""
        from demosys import geometry

        if not TextureHelper._quad:
            TextureHelper._quad = geometry.quad_fs()

        # Shader for drawing depth layers
        TextureHelper._depth_shader = context.ctx().program(vertex_shader="""
                #version 330

                in vec3 in_position;
                in vec2 in_uv;
                out vec2 uv;
                uniform vec2 offset;
                uniform vec2 scale;

                void main() {
                    uv = in_uv;
                    gl_Position = vec4((in_position.xy + vec2(1.0, 1.0)) * scale + offset, 0.0, 1.0);
                }
            """,
                                                            fragment_shader="""
                #version 330

                out vec4 out_color;
                in vec2 uv;
                uniform sampler2D texture0;
                uniform float near;
                uniform float far;

                void main() {
                    float z = texture(texture0, uv).r;
                    float d = (2.0 * near) / (far + near - z * (far - near));
                    out_color = vec4(d);
                }
            """)

        TextureHelper._depth_sampler = self.ctx.sampler(
            filter=(moderngl.LINEAR, moderngl.LINEAR),
            compare_func='',
        )
示例#13
0
文件: vao.py 项目: binaryf/demosys-py
    def buffer(self,
               buffer,
               buffer_format: str,
               attribute_names,
               per_instance=False):
        """
        Register a buffer/vbo for the VAO. This can be called multiple times.
        adding multiple buffers (interleaved or not)

        :param buffer: The buffer object. Can be ndarray or Buffer
        :param buffer_format: The format of the buffer ('f', 'u', 'i')
        :returns: The buffer object
        """
        if not isinstance(attribute_names, list):
            attribute_names = [
                attribute_names,
            ]

        if not isinstance(buffer, moderngl.Buffer) and not isinstance(
                buffer, numpy.ndarray):
            raise VAOError(
                "buffer parameter must be a moderngl.Buffer or numpy.ndarray instance"
            )

        if isinstance(buffer, numpy.ndarray):
            buffer = context.ctx().buffer(buffer.tobytes())

        formats = buffer_format.split()
        if len(formats) != len(attribute_names):
            raise VAOError(
                "Format '{}' does not describe attributes {}".format(
                    buffer_format, attribute_names))

        self.buffers.append(
            BufferInfo(buffer,
                       buffer_format,
                       attribute_names,
                       per_instance=per_instance))
        self.vertex_count = self.buffers[-1].vertices

        return buffer
示例#14
0
文件: fbo.py 项目: binaryf/demosys-py
    def create_from_textures(color_buffers: List[Texture2D],
                             depth_buffer: DepthTexture = None) -> 'FBO':
        """
        Create FBO from existing textures

        :param color_buffers: List of textures
        :param depth_buffer: Depth texture

        :return: FBO instance
        """
        instance = FBO()
        instance.color_buffers = color_buffers
        instance.depth_buffer = depth_buffer

        instance.fbo = context.ctx().framebuffer(
            color_attachments=[b.mglo for b in color_buffers],
            depth_attachment=depth_buffer.mglo
            if depth_buffer is not None else None,
        )

        return instance
示例#15
0
文件: vao.py 项目: m4rm0k/demosys-py
    def __init__(self, name="", mode=moderngl.TRIANGLES):
        """
        Create and empty VAO

        Keyword Args:
            name (str): The name for debug purposes
            mode (int): Default draw mode
        """
        self.ctx = context.ctx()
        self.name = name
        self.mode = mode

        try:
            DRAW_MODES[self.mode]
        except KeyError:
            raise VAOError("Invalid draw mode. Options are {}".format(DRAW_MODES.values()))

        self.buffers = []
        self._index_buffer = None
        self._index_element_size = None

        self.vertex_count = 0
        self.vaos = {}
示例#16
0
 def __init__(self, program=None, **kwargs):
     self.program = program
     self.ctx = context.ctx()
示例#17
0
 def ctx(self):
     """ModernGL context"""
     return context.ctx()
示例#18
0
 def ctx(self):
     return context.ctx()
示例#19
0
 def ctx(self) -> moderngl.Context:
     """The moderngl context"""
     return context.ctx()
示例#20
0
def quad_2d(width, height, xpos=0.0, ypos=0.0) -> VAO:
    """
    Creates a 2D quad VAO using 2 triangles.

    :param width: Width of the quad
    :param height: Height of the quad
    :param xpos: Center position x
    :param ypos: Center position y
    """
    pos = context.ctx().buffer(
        numpy.array([
            xpos - width / 2.0,
            ypos + height / 2.0,
            0.0,
            xpos - width / 2.0,
            ypos - height / 2.0,
            0.0,
            xpos + width / 2.0,
            ypos - height / 2.0,
            0.0,
            xpos - width / 2.0,
            ypos + height / 2.0,
            0.0,
            xpos + width / 2.0,
            ypos - height / 2.0,
            0.0,
            xpos + width / 2.0,
            ypos + height / 2.0,
            0.0,
        ],
                    dtype=numpy.float32).tobytes())

    normals = context.ctx().buffer(
        numpy.array([
            0.0,
            0.0,
            1.0,
            0.0,
            0.0,
            1.0,
            0.0,
            0.0,
            1.0,
            0.0,
            0.0,
            1.0,
            0.0,
            0.0,
            1.0,
            0.0,
            0.0,
            1.0,
        ],
                    dtype=numpy.float32).tobytes())

    uvs = context.ctx().buffer(
        numpy.array([
            0.0,
            1.0,
            0.0,
            0.0,
            1.0,
            0.0,
            0.0,
            1.0,
            1.0,
            0.0,
            1.0,
            1.0,
        ],
                    dtype=numpy.float32).tobytes())

    vao = VAO("geometry:quad", mode=moderngl.TRIANGLES)
    vao.buffer(pos, '3f', ["in_position"])
    vao.buffer(normals, '3f', ["in_normal"])
    vao.buffer(uvs, '2f', ["in_uv"])

    return vao
示例#21
0
 def __init__(self, shader=None, **kwargs):
     self.shader = shader
     self.ctx = context.ctx()
示例#22
0
 def __init__(self):
     self.mglo = None  # Type: Union[moderngl.Texture, moderngl.TextureArray]
     self._ctx = context.ctx()
示例#23
0
 def ctx(self) -> moderngl.Context:
     """The MondernGL context"""
     return context.ctx()
示例#24
0
def sphere(radius=0.5, sectors=32, rings=16) -> VAO:
    """
    Generate a sphere

    :param radius: Radius or the sphere
    :param rings: number or horizontal rings
    :param sectors: number of vertical segments
    :return: VAO containing the sphere
    """
    R = 1.0 / (rings - 1)
    S = 1.0 / (sectors - 1)

    vertices = [0] * (rings * sectors * 3)
    normals = [0] * (rings * sectors * 3)
    uvs = [0] * (rings * sectors * 2)

    v, n, t = 0, 0, 0
    for r in range(rings):
        for s in range(sectors):
            y = math.sin(-math.pi / 2 + math.pi * r * R)
            x = math.cos(2 * math.pi * s * S) * math.sin(math.pi * r * R)
            z = math.sin(2 * math.pi * s * S) * math.sin(math.pi * r * R)

            uvs[t] = s * S
            uvs[t + 1] = r * R

            vertices[v] = x * radius
            vertices[v + 1] = y * radius
            vertices[v + 2] = z * radius

            normals[n] = x
            normals[n + 1] = y
            normals[n + 2] = z

            t += 2
            v += 3
            n += 3

    indices = [0] * rings * sectors * 6
    i = 0
    for r in range(rings - 1):
        for s in range(sectors - 1):
            indices[i] = r * sectors + s
            indices[i + 1] = (r + 1) * sectors + (s + 1)
            indices[i + 2] = r * sectors + (s + 1)

            indices[i + 3] = r * sectors + s
            indices[i + 4] = (r + 1) * sectors + s
            indices[i + 5] = (r + 1) * sectors + (s + 1)
            i += 6

    vbo_vertices = context.ctx().buffer(
        numpy.array(vertices, dtype=numpy.float32).tobytes())
    vbo_normals = context.ctx().buffer(
        numpy.array(normals, dtype=numpy.float32).tobytes())
    vbo_uvs = context.ctx().buffer(
        numpy.array(uvs, dtype=numpy.float32).tobytes())
    vbo_elements = context.ctx().buffer(
        numpy.array(indices, dtype=numpy.uint32).tobytes())

    vao = VAO("sphere", mode=mlg.TRIANGLES)
    # VBOs
    vao.buffer(vbo_vertices, '3f', ['in_position'])
    vao.buffer(vbo_normals, '3f', ['in_normal'])
    vao.buffer(vbo_uvs, '2f', ['in_uv'])
    vao.index_buffer(vbo_elements, index_element_size=4)

    return vao