示例#1
0
def points_random_3d(count,
                     range_x=(-10.0, 10.0),
                     range_y=(-10.0, 10.0),
                     range_z=(-10.0, 10.0),
                     seed=None) -> VAO:
    """
    Generates random positions

    :param count: Number of points
    :param range_x: min-max range for x axis
    :param range_y: min-max range for y axis
    :param range_z: min-max range for z axis
    :param seed: The random seed to be used
    """
    random.seed(seed)

    def gen():
        for i in range(count):
            yield random.uniform(*range_x)
            yield random.uniform(*range_y)
            yield random.uniform(*range_z)

    data = numpy.fromiter(gen(), count=count * 3, dtype=numpy.float32)

    vao = VAO("geometry:points_random_3d", mode=moderngl.POINTS)
    vao.buffer(data, '3f', ['in_position'])

    return vao
示例#2
0
    def init_particles(self):
        count = 50000
        area = 100.0
        speed = 5.0

        def gen():
            for _ in range(count):
                # Position
                yield random.uniform(-area, area)
                yield random.uniform(-area, area)
                yield random.uniform(-area, area)
                # Velocity
                yield random.uniform(-speed, speed)
                yield random.uniform(-speed, speed)
                yield random.uniform(-speed, speed)

        data1 = numpy.fromiter(gen(), count=count * 6, dtype=numpy.float32)
        data2 = numpy.fromiter(gen(), count=count * 6, dtype=numpy.float32)

        self.pos1 = self.ctx.buffer(data1.tobytes())
        self.particles1 = VAO("particles1", mode=mgl.POINTS)
        self.particles1.buffer(self.pos1, '3f 3f', ['in_position', 'in_velocity'])

        self.pos2 = self.ctx.buffer(data2.tobytes())
        self.particles2 = VAO("particles2", mode=mgl.POINTS)
        self.particles2.buffer(self.pos2, '3f 3f', ['in_position', 'in_velocity'])

        # Set initial start buffers
        self.particles = self.particles1
        self.pos = self.pos2
示例#3
0
    def load(self, scene, file=None):
        """Deferred loading"""
        data = pywavefront.Wavefront(file, create_materials=True)

        for name, mat in data.materials.items():

            if not mat.vertices:
                continue

            vbo = numpy.array(mat.vertices, dtype=numpy.float32)

            vao = VAO(mat.name, mode=moderngl.TRIANGLES)
            mesh = Mesh(mat.name)

            # Order: T2F, C3F, N3F and V3F
            buffer_format = []
            attributes = []

            if "T2F" in mat.vertex_format:
                buffer_format.append("2f")
                attributes.append("in_uv")
                mesh.add_attribute("TEXCOORD_0", "in_uv", 2)

            if "C3F" in mat.vertex_format:
                buffer_format.append("3f")
                attributes.append("in_color")
                mesh.add_attribute("NORMAL", "in_color", 3)

            if "N3F" in mat.vertex_format:
                buffer_format.append("3f")
                attributes.append("in_normal")
                mesh.add_attribute("NORMAL", "in_normal", 3)

            buffer_format.append("3f")
            attributes.append("in_position")
            mesh.add_attribute("POSITION", "in_position", 3)

            vao.buffer(vbo, " ".join(buffer_format), attributes)
            mesh.vao = vao

            scene.meshes.append(mesh)

            mesh.material = Material(mat.name)
            mesh.material.color = mat.diffuse
            if mat.texture:
                mesh.material.mat_texture = MaterialTexture(
                    texture=textures.get(mat.texture.path,
                                         create=True,
                                         mipmap=True),
                    sampler=samplers.create(
                        wrap_s=GL.GL_CLAMP_TO_EDGE,
                        wrap_t=GL.GL_CLAMP_TO_EDGE,
                        anisotropy=8,
                    ))

            node = Node(mesh=mesh)
            scene.root_nodes.append(node)

        return scene
示例#4
0
def plane_xz(size=(10, 10), resolution=(10, 10)) -> VAO:
    """
    Generates a plane on the xz axis of a specific size and resolution

    :param size: (x, y) tuple
    :param resolution: (x, y) tuple
    :return: VAO
    """
    sx, sz = size
    rx, rz = resolution
    dx, dz = sx / rx, sz / rz  # step
    ox, oz = -sx / 2, -sz / 2  # start offset

    def gen_pos():
        for z in range(rz):
            for x in range(rx):
                yield ox + x * dx
                yield 0
                yield oz + z * dz

    def gen_uv():
        for z in range(rz):
            for x in range(rx):
                yield x / (rx - 1)
                yield 1 - z / (rz - 1)

    def gen_normal():
        for z in range(rx * rz):
            yield 0.0
            yield 1.0
            yield 0.0

    def gen_index():
        for z in range(rz - 1):
            for x in range(rx - 1):
                # quad poly left
                yield z * rz + x + 1
                yield z * rz + x
                yield z * rz + x + rx
                # quad poly right
                yield z * rz + x + 1
                yield z * rz + x + rx
                yield z * rz + x + rx + 1

    pos_data = numpy.fromiter(gen_pos(), dtype=numpy.float32)
    uv_data = numpy.fromiter(gen_uv(), dtype=numpy.float32)
    normal_data = numpy.fromiter(gen_normal(), dtype=numpy.float32)
    index_data = numpy.fromiter(gen_index(), dtype=numpy.uint32)

    vao = VAO("plane_xz", mode=moderngl.TRIANGLES)

    vao.buffer(pos_data, '3f', ['in_position'])
    vao.buffer(uv_data, '2f', ['in_uv'])
    vao.buffer(normal_data, '3f', ['in_normal'])

    vao.index_buffer(index_data, index_element_size=4)

    return vao
示例#5
0
def points_random_3d(count,
                     range_x=(-10.0, 10.0),
                     range_y=(-10.0, 10.0),
                     range_z=(-10.0, 10.0),
                     seed=None):
    """
    Generates random positions

    :param count: Number of points
    :param range_x: min-max range for x axis
    :param range_y: min-max range for y axis
    :param range_z: min-max range for z axis
    :param seed: The random seed to be used
    """
    random.seed(seed)

    def gen():
        for i in range(count):
            yield random.uniform(*range_x)
            yield random.uniform(*range_y)
            yield random.uniform(*range_z)

    data = numpy.fromiter(gen(), count=count * 3, dtype=numpy.float32)
    pos = VBO(data)
    vao = VAO("geometry:points_random_3d", mode=GL.GL_POINTS)
    vao.add_array_buffer(GL.GL_FLOAT, pos)
    vao.map_buffer(pos, "in_position", 3)
    vao.build()
    return vao
示例#6
0
    def _post_load(self):
        """Parse font metadata after resources are loaded"""
        self._init(Meta(self._config.data))

        self._string_buffer = self.ctx.buffer(reserve=self.area[0] * 4 *
                                              self.area[1])
        self._string_buffer.clear(chunk=b'\32')
        pos = self.ctx.buffer(data=bytes([0] * 4 * 3))

        self._vao = VAO("textwriter", mode=moderngl.POINTS)
        self._vao.buffer(pos, '3f', 'in_position')
        self._vao.buffer(self._string_buffer,
                         '1u',
                         'in_char_id',
                         per_instance=True)

        self.text_lines = self._text_lines
示例#7
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
示例#8
0
    def _create_vao(self):
        data = numpy.array([
            0.0,
            -2.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            1.0,
            2.0,
            0.0,
            0.0,
            1.0,
            1.0,
            0.0,
            -2.0,
            0.0,
            0.0,
            0.0,
            2.0,
            0.0,
            0.0,
            1.0,
            1.0,
            2.0,
            -2.0,
            0.0,
            1.0,
            0.0,
        ],
                           dtype=numpy.float32)

        vao = VAO("textrenderer", mode=moderngl.TRIANGLES)
        vao.buffer(data, '3f 2f', ['in_position', 'in_uv'])
        return vao
示例#9
0
 def test_create(self):
     shader = self.create_shader(path="vf_pos.glsl")
     vao = VAO("test")
     vao.buffer(
         self.ctx.buffer(reserve=12),
         '3f',
         "in_position",
     )
     vao.draw(shader)
示例#10
0
 def test_transform(self):
     shader = self.create_shader(path="v_write_1.glsl")
     vao = VAO("transform", mode=moderngl.POINTS)
     vao.buffer(
         self.ctx.buffer(reserve=12),
         '1u',
         'in_val',
     )
     result = self.ctx.buffer(reserve=12)
     vao.transform(shader, result)
     self.assertEqual(
         result.read(),
         b'\xff\x00\x00\x00\xff\x00\x00\x00\xff\x00\x00\x00',
     )
示例#11
0
class TextWriter2D(BaseText):
    def __init__(self, area, text_lines=None, aspect_ratio=1.0):
        """
        :param area: (x, y) Text area size (number of characters)
        :param size: Text size
        :param text: Initial text lines
        """
        super().__init__()
        self.area = area
        self._text_lines = text_lines

        self._projection_bytes = None
        self._aspect_ratio = 1.0
        self.aspect_ratio = aspect_ratio

        self._vao = None
        self._texture = textures.get('demosys/text/VeraMono.png',
                                     cls=TextureArray,
                                     layers=190,
                                     create=True)
        self._shader = shaders.get('demosys/text/textwriter2d.glsl',
                                   create=True)
        self._config = data.get('demosys/text/meta.json', create=True)

        self._string_buffer = None

        data.on_loaded(self._post_load)

    def _post_load(self):
        """Parse font metadata after resources are loaded"""
        self._init(Meta(self._config.data))

        self._string_buffer = self.ctx.buffer(reserve=self.area[0] * 4 *
                                              self.area[1])
        self._string_buffer.clear(chunk=b'\32')
        pos = self.ctx.buffer(data=bytes([0] * 4 * 3))

        self._vao = VAO("textwriter", mode=moderngl.POINTS)
        self._vao.buffer(pos, '3f', 'in_position')
        self._vao.buffer(self._string_buffer,
                         '1u',
                         'in_char_id',
                         per_instance=True)

        self.text_lines = self._text_lines

    @property
    def text_lines(self):
        return self._text_lines

    @text_lines.setter
    def text_lines(self, value):
        self._text_lines = value

        for i, line in enumerate(self._text_lines):
            self.set_text_line(i, line)

    @property
    def aspect_ratio(self):
        return self._aspect_ratio

    @aspect_ratio.setter
    def aspect_ratio(self, value):
        self._aspect_ratio = value
        self._projection_bytes = matrix44.create_orthogonal_projection_matrix(
            -self.aspect_ratio,  # left
            self.aspect_ratio,  # right
            -1.0,  # bottom
            1.0,  # top
            -100.0,  # near
            100.0,  # far
            dtype=numpy.float32,
        ).tobytes()

    def set_text_line(self, line, text):
        if line >= self.area[1]:
            return

        self._string_buffer.clear(size=self.area[0] * 4,
                                  offset=self.area[0] * 4 * line,
                                  chunk=b'\32')

        self._string_buffer.write(
            numpy.fromiter(self._translate_string(text.encode('iso-8859-1'),
                                                  self.area[0]),
                           dtype=numpy.uint32).tobytes(),
            offset=(self.area[0] * 4) * line,
        )

    def draw(self, pos, length=-1, size=1.0):
        if length < 0:
            length = self.area[0] * self.area[1]
        elif length > self.area[0] * self.area[1]:
            length = self.area[0] * self.area[1]

        csize = (
            self._meta.character_width / self._meta.character_height * size,
            1.0 * size,
        )

        cpos = (
            pos[0] - self._aspect_ratio + csize[0] / 2,
            -pos[1] + 1.0 - csize[1] / 2,
        )

        self._texture.use(location=0)
        self._shader.uniform("m_proj", self._projection_bytes)
        self._shader.uniform("text_pos", cpos)
        self._shader.uniform("font_texture", 0)
        self._shader.uniform("char_size", csize)
        self._shader.uniform("line_length", self.area[0])

        self._vao.draw(self._shader, instances=length)
示例#12
0
def bbox(width=1.0, height=1.0, depth=1.0):
    """
    Generates a bounding box.
    This is simply a box with LINE_STRIP as draw mode

    :param width: Width of the box
    :param height: height of the box
    :param depth: depth of the box
    :return: VAO
    """
    width, height, depth = width / 2.0, height / 2.0, depth / 2.0
    pos = numpy.array([
        width,
        -height,
        depth,
        width,
        height,
        depth,
        -width,
        -height,
        depth,
        width,
        height,
        depth,
        -width,
        height,
        depth,
        -width,
        -height,
        depth,
        width,
        -height,
        -depth,
        width,
        height,
        -depth,
        width,
        -height,
        depth,
        width,
        height,
        -depth,
        width,
        height,
        depth,
        width,
        -height,
        depth,
        width,
        -height,
        -depth,
        width,
        -height,
        depth,
        -width,
        -height,
        depth,
        width,
        -height,
        -depth,
        -width,
        -height,
        depth,
        -width,
        -height,
        -depth,
        -width,
        -height,
        depth,
        -width,
        height,
        depth,
        -width,
        height,
        -depth,
        -width,
        -height,
        depth,
        -width,
        height,
        -depth,
        -width,
        -height,
        -depth,
        width,
        height,
        -depth,
        width,
        -height,
        -depth,
        -width,
        -height,
        -depth,
        width,
        height,
        -depth,
        -width,
        -height,
        -depth,
        -width,
        height,
        -depth,
        width,
        height,
        -depth,
        -width,
        height,
        -depth,
        width,
        height,
        depth,
        -width,
        height,
        -depth,
        -width,
        height,
        depth,
        width,
        height,
        depth,
    ],
                      dtype=numpy.float32)

    vao = VAO("geometry:cube", mode=moderngl.LINE_STRIP)
    vao.buffer(pos, '3f', ["in_position"])

    return vao
示例#13
0
def cube(width, height, depth, normals=True, uvs=True):
    """
    Generates a cube centered at 0, 0, 0

    :param width: Width of the cube
    :param height: height of the cube
    :param depth: depth of the bubs
    :param normals: (bool) Include normals
    :param uvs: (bool) include uv coordinates
    :return: VAO representing the cube
    """
    width, height, depth = width / 2, height / 2, depth / 2
    pos = VBO(
        numpy.array([
            width,
            -height,
            depth,
            width,
            height,
            depth,
            -width,
            -height,
            depth,
            width,
            height,
            depth,
            -width,
            height,
            depth,
            -width,
            -height,
            depth,
            width,
            -height,
            -depth,
            width,
            height,
            -depth,
            width,
            -height,
            depth,
            width,
            height,
            -depth,
            width,
            height,
            depth,
            width,
            -height,
            depth,
            width,
            -height,
            -depth,
            width,
            -height,
            depth,
            -width,
            -height,
            depth,
            width,
            -height,
            -depth,
            -width,
            -height,
            depth,
            -width,
            -height,
            -depth,
            -width,
            -height,
            depth,
            -width,
            height,
            depth,
            -width,
            height,
            -depth,
            -width,
            -height,
            depth,
            -width,
            height,
            -depth,
            -width,
            -height,
            -depth,
            width,
            height,
            -depth,
            width,
            -height,
            -depth,
            -width,
            -height,
            -depth,
            width,
            height,
            -depth,
            -width,
            -height,
            -depth,
            -width,
            height,
            -depth,
            width,
            height,
            -depth,
            -width,
            height,
            -depth,
            width,
            height,
            depth,
            -width,
            height,
            -depth,
            -width,
            height,
            depth,
            width,
            height,
            depth,
        ],
                    dtype=numpy.float32))
    if normals:
        normals = VBO(
            numpy.array([
                -0,
                0,
                1,
                -0,
                0,
                1,
                -0,
                0,
                1,
                0,
                0,
                1,
                0,
                0,
                1,
                0,
                0,
                1,
                1,
                0,
                0,
                1,
                0,
                0,
                1,
                0,
                0,
                1,
                0,
                0,
                1,
                0,
                0,
                1,
                0,
                0,
                0,
                -1,
                0,
                0,
                -1,
                0,
                0,
                -1,
                0,
                0,
                -1,
                0,
                0,
                -1,
                0,
                0,
                -1,
                0,
                -1,
                -0,
                0,
                -1,
                -0,
                0,
                -1,
                -0,
                0,
                -1,
                -0,
                0,
                -1,
                -0,
                0,
                -1,
                -0,
                0,
                0,
                0,
                -1,
                0,
                0,
                -1,
                0,
                0,
                -1,
                0,
                0,
                -1,
                0,
                0,
                -1,
                0,
                0,
                -1,
                0,
                1,
                0,
                0,
                1,
                0,
                0,
                1,
                0,
                0,
                1,
                0,
                0,
                1,
                0,
                0,
                1,
                0,
            ],
                        dtype=numpy.float32))
    if uvs:
        uvs = VBO(
            numpy.array([
                1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0,
                1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0,
                0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0,
                1, 1, 0, 0, 1, 0, 0, 1, 0
            ],
                        dtype=numpy.float32))

    vao = VAO("geometry:cube")
    # Add buffers
    vao.add_array_buffer(GL.GL_FLOAT, pos)
    if normals:
        vao.add_array_buffer(GL.GL_FLOAT, normals)
    if uvs:
        vao.add_array_buffer(GL.GL_FLOAT, uvs)

    # Map buffers
    vao.map_buffer(pos, "in_position", 3)
    if normals:
        vao.map_buffer(normals, "in_normal", 3)
    if uvs:
        vao.map_buffer(uvs, "in_uv", 2)

    vao.build()
    return vao
示例#14
0
def cube(width,
         height,
         depth,
         center=(0.0, 0.0, 0.0),
         normals=True,
         uvs=True) -> VAO:
    """
    Generates a cube VAO. The cube center is (0.0, 0.0 0.0) unless other is specified.

    :param width: Width of the cube
    :param height: height of the cube
    :param depth: depth of the cube
    :param center: center of the cube
    :param normals: (bool) Include normals
    :param uvs: (bool) include uv coordinates
    :return: VAO representing the cube
    """
    width, height, depth = width / 2.0, height / 2.0, depth / 2.0

    pos = numpy.array([
        center[0] + width,
        center[1] - height,
        center[2] + depth,
        center[0] + width,
        center[1] + height,
        center[2] + depth,
        center[0] - width,
        center[1] - height,
        center[2] + depth,
        center[0] + width,
        center[1] + height,
        center[2] + depth,
        center[0] - width,
        center[1] + height,
        center[2] + depth,
        center[0] - width,
        center[1] - height,
        center[2] + depth,
        center[0] + width,
        center[1] - height,
        center[2] - depth,
        center[0] + width,
        center[1] + height,
        center[2] - depth,
        center[0] + width,
        center[1] - height,
        center[2] + depth,
        center[0] + width,
        center[1] + height,
        center[2] - depth,
        center[0] + width,
        center[1] + height,
        center[2] + depth,
        center[0] + width,
        center[1] - height,
        center[2] + depth,
        center[0] + width,
        center[1] - height,
        center[2] - depth,
        center[0] + width,
        center[1] - height,
        center[2] + depth,
        center[0] - width,
        center[1] - height,
        center[2] + depth,
        center[0] + width,
        center[1] - height,
        center[2] - depth,
        center[0] - width,
        center[1] - height,
        center[2] + depth,
        center[0] - width,
        center[1] - height,
        center[2] - depth,
        center[0] - width,
        center[1] - height,
        center[2] + depth,
        center[0] - width,
        center[1] + height,
        center[2] + depth,
        center[0] - width,
        center[1] + height,
        center[2] - depth,
        center[0] - width,
        center[1] - height,
        center[2] + depth,
        center[0] - width,
        center[1] + height,
        center[2] - depth,
        center[0] - width,
        center[1] - height,
        center[2] - depth,
        center[0] + width,
        center[1] + height,
        center[2] - depth,
        center[0] + width,
        center[1] - height,
        center[2] - depth,
        center[0] - width,
        center[1] - height,
        center[2] - depth,
        center[0] + width,
        center[1] + height,
        center[2] - depth,
        center[0] - width,
        center[1] - height,
        center[2] - depth,
        center[0] - width,
        center[1] + height,
        center[2] - depth,
        center[0] + width,
        center[1] + height,
        center[2] - depth,
        center[0] - width,
        center[1] + height,
        center[2] - depth,
        center[0] + width,
        center[1] + height,
        center[2] + depth,
        center[0] - width,
        center[1] + height,
        center[2] - depth,
        center[0] - width,
        center[1] + height,
        center[2] + depth,
        center[0] + width,
        center[1] + height,
        center[2] + depth,
    ],
                      dtype=numpy.float32)

    if normals:
        normal_data = numpy.array([
            -0,
            0,
            1,
            -0,
            0,
            1,
            -0,
            0,
            1,
            0,
            0,
            1,
            0,
            0,
            1,
            0,
            0,
            1,
            1,
            0,
            0,
            1,
            0,
            0,
            1,
            0,
            0,
            1,
            0,
            0,
            1,
            0,
            0,
            1,
            0,
            0,
            0,
            -1,
            0,
            0,
            -1,
            0,
            0,
            -1,
            0,
            0,
            -1,
            0,
            0,
            -1,
            0,
            0,
            -1,
            0,
            -1,
            -0,
            0,
            -1,
            -0,
            0,
            -1,
            -0,
            0,
            -1,
            -0,
            0,
            -1,
            -0,
            0,
            -1,
            -0,
            0,
            0,
            0,
            -1,
            0,
            0,
            -1,
            0,
            0,
            -1,
            0,
            0,
            -1,
            0,
            0,
            -1,
            0,
            0,
            -1,
            0,
            1,
            0,
            0,
            1,
            0,
            0,
            1,
            0,
            0,
            1,
            0,
            0,
            1,
            0,
            0,
            1,
            0,
        ],
                                  dtype=numpy.float32)

    if uvs:
        uvs_data = numpy.array([
            1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1,
            0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
            1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0,
            0, 1, 0, 0, 1, 0
        ],
                               dtype=numpy.float32)

    vao = VAO("geometry:cube")

    # Add buffers
    vao.buffer(pos, '3f', ['in_position'])
    if normals:
        vao.buffer(normal_data, '3f', ['in_normal'])
    if uvs:
        vao.buffer(uvs_data, '2f', ['in_uv'])

    return vao
示例#15
0
def plane_xz(size=(10, 10), resolution=(10, 10)):
    """
    Generates a plane on the xz axis of a specific size and resolution

    :param size: (x, y) tuple
    :param resolution: (x, y) tuple
    :return: VAO
    """
    sx, sz = size
    rx, rz = resolution
    dx, dz = sx / rx, sz / rz  # step
    ox, oz = -sx / 2, -sz / 2  # start offset

    def gen_pos():
        for z in range(rz):
            for x in range(rx):
                yield ox + x * dx
                yield 0
                yield oz + z * dz

    def gen_uv():
        for z in range(rz):
            for x in range(rx):
                yield x / (rx - 1)
                yield 1 - z / (rz - 1)

    def gen_normal():
        for z in range(rx * rz):
            yield 0.0
            yield 1.0
            yield 0.0

    def gen_index():
        for z in range(rz - 1):
            for x in range(rx - 1):
                # quad poly left
                yield z * rz + x
                yield z * rz + x + 1
                yield z * rz + x + rx
                # quad poly right
                yield z * rz + x + rx
                yield z * rz + x + 1
                yield z * rz + x + rx + 1

    pos_data = numpy.fromiter(gen_pos(), dtype=numpy.float32)
    position_vbo = VBO(pos_data)

    uv_data = numpy.fromiter(gen_uv(), dtype=numpy.float32)
    uv_vbo = VBO(uv_data)

    normal_data = numpy.fromiter(gen_normal(), dtype=numpy.float32)
    normal_vbo = VBO(normal_data)

    index_data = numpy.fromiter(gen_index(), dtype=numpy.uint32)
    index_vbo = VBO(index_data, target="GL_ELEMENT_ARRAY_BUFFER")

    vao = VAO("plane_xz", mode=GL.GL_TRIANGLES)

    vao.add_array_buffer(GL.GL_FLOAT, position_vbo)
    vao.add_array_buffer(GL.GL_FLOAT, uv_vbo)
    vao.add_array_buffer(GL.GL_FLOAT, normal_vbo)

    vao.map_buffer(position_vbo, "in_position", 3)
    vao.map_buffer(uv_vbo, "in_uv", 2)
    vao.map_buffer(normal_vbo, "in_normal", 3)
    vao.set_element_buffer(GL.GL_UNSIGNED_INT, index_vbo)

    vao.build()
    return vao
示例#16
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
示例#17
0
class FeedbackEffect(effect.Effect):

    def __init__(self):
        self.feedback = self.get_shader("feedback/transform.glsl")
        self.shader = self.get_shader("feedback/billboards.glsl")
        self.texture = self.get_texture("feedback/particle.png")

        # VAOs representing the two different buffer bindings
        self.particles1 = None
        self.particles2 = None
        self.particles = None

        # VBOs for each position buffer
        self.pos1 = None
        self.pos2 = None
        self.pos = None
        self.init_particles()

    @effect.bind_target
    def draw(self, time, frametime, target):
        self.ctx.disable(mgl.DEPTH_TEST)
        self.ctx.enable(mgl.BLEND)
        self.ctx.blend_func = mgl.SRC_ALPHA, mgl.ONE_MINUS_SRC_ALPHA

        m_proj = self.create_projection(90.0, 1.0, 1000.0)

        # Rotate and translate
        m_mv = self.create_transformation(rotation=(time * 0.0, time * 0, time * 0),
                                          translation=(0.0, 0.0, -40.0))

        # Apply the rotation and translation from the system camera
        m_mv = matrix44.multiply(m_mv, self.sys_camera.view_matrix)

        gravity_pos = vector3.create(math.sin(time) * 5,
                                     math.cos(time) * 5,
                                     math.sin(time / 3) * 5)
        gravity_force = math.cos(time / 2) * 3.0 + 3.0
        # gravity_force = 2.0

        # Transform positions
        self.feedback.uniform("gravity_pos", gravity_pos.astype('f4').tobytes())
        self.feedback.uniform("gravity_force", gravity_force)
        self.feedback.uniform("timedelta", frametime)
        self.particles.transform(self.feedback, self.pos)

        # Draw particles
        self.shader.uniform("m_proj", m_proj.astype('f4').tobytes())
        self.shader.uniform("m_mv", m_mv.astype('f4').tobytes())
        self.texture.use(location=0)
        self.shader.uniform("texture0", 0)
        self.particles.draw(self.shader)

        # Swap buffers
        self.pos = self.pos1 if self.pos == self.pos2 else self.pos2
        self.particles = self.particles1 if self.particles == self.particles2 else self.particles2

    def init_particles(self):
        count = 50000
        area = 100.0
        speed = 5.0

        def gen():
            for _ in range(count):
                # Position
                yield random.uniform(-area, area)
                yield random.uniform(-area, area)
                yield random.uniform(-area, area)
                # Velocity
                yield random.uniform(-speed, speed)
                yield random.uniform(-speed, speed)
                yield random.uniform(-speed, speed)

        data1 = numpy.fromiter(gen(), count=count * 6, dtype=numpy.float32)
        data2 = numpy.fromiter(gen(), count=count * 6, dtype=numpy.float32)

        self.pos1 = self.ctx.buffer(data1.tobytes())
        self.particles1 = VAO("particles1", mode=mgl.POINTS)
        self.particles1.buffer(self.pos1, '3f 3f', ['in_position', 'in_velocity'])

        self.pos2 = self.ctx.buffer(data2.tobytes())
        self.particles2 = VAO("particles2", mode=mgl.POINTS)
        self.particles2.buffer(self.pos2, '3f 3f', ['in_position', 'in_velocity'])

        # Set initial start buffers
        self.particles = self.particles1
        self.pos = self.pos2
示例#18
0
def quad_2d(width, height, xpos=0.0, ypos=0.0):
    """
    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 = VBO(
        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))
    normals = VBO(
        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))
    uvs = VBO(
        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))
    vao = VAO("geometry:quad", mode=GL.GL_TRIANGLES)
    vao.add_array_buffer(GL.GL_FLOAT, pos)
    vao.add_array_buffer(GL.GL_FLOAT, normals)
    vao.add_array_buffer(GL.GL_FLOAT, uvs)
    vao.map_buffer(pos, "in_position", 3)
    vao.map_buffer(normals, "in_normal", 3)
    vao.map_buffer(uvs, "in_uv", 2)
    vao.build()
    return vao
示例#19
0
def sphere(radius=0.5, sectors=32, rings=16):
    """
    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 = VBO(numpy.array(vertices, dtype=numpy.float32))
    vbo_normals = VBO(numpy.array(normals, dtype=numpy.float32))
    vbo_uvs = VBO(numpy.array(uvs, dtype=numpy.float32))
    vbo_element = VBO(numpy.array(indices, dtype=numpy.uint32),
                      target="GL_ELEMENT_ARRAY_BUFFER")

    vao = VAO("sphere")
    # VBOs
    vao.add_array_buffer(GL.GL_FLOAT, vbo_vertices)
    vao.add_array_buffer(GL.GL_FLOAT, vbo_normals)
    vao.add_array_buffer(GL.GL_FLOAT, vbo_uvs)
    # Mapping
    vao.map_buffer(vbo_vertices, "in_position", 3)
    vao.map_buffer(vbo_normals, "in_normal", 3)
    vao.map_buffer(vbo_uvs, "in_uv", 2)
    # Index
    vao.set_element_buffer(GL.GL_UNSIGNED_INT, vbo_element)
    vao.build()
    return vao
示例#20
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