Esempio n. 1
0
    def test_failed_build(self):
        vert = VertexShader("A")
        frag = FragmentShader("B")

        program = Program(verts = vert)
        with self.assertRaises(ValueError):
            program.activate()

        program = Program(frags = frag)
        with self.assertRaises(ValueError):
            program.activate()
Esempio n. 2
0
class FramebufferDrawer(object):

    DRAW_PIXELS = 1
    DRAW_QUAD = 2
    BLIT = 3

    VERTEX = """
    attribute vec2 a_position;
    varying vec2 v_texcoord;
    void main()
    {
        gl_Position = vec4(a_position, 0.0, 1.0);
        v_texcoord = (a_position + 1.0) / 2.0;
    }
    """

    FRAGMENT = """
    uniform float u_color_scale;
    uniform float u_color_offset;
    uniform sampler2D u_texture;
    varying vec2 v_texcoord;
    void main()
    {
        vec4 color = texture2D(u_texture, v_texcoord);
        color = vec4(u_color_offset + u_color_scale * color.xyz, color.w);
        gl_FragColor = clamp(color, 0, 1);
    }
    """

    def __init__(self, framebuffer, color_index=0, draw_mode=DRAW_PIXELS):
        self._draw_mode = draw_mode
        self._framebuffer = framebuffer
        self._color_offset = 0.0
        self._color_scale = 1.0
        if self._draw_mode == self.DRAW_PIXELS:
            self._color_index = color_index
        elif self._draw_mode == self.DRAW_QUAD:
            self._quad = Program(self.VERTEX, self.FRAGMENT, count=4)
            self._quad["a_position"] = (-1, -1), (-1, +1), (+1, -1), (+1, +1)
            self._quad["u_texture"] = self._framebuffer.color_attachments[
                color_index]
        elif self._draw_mode == self.BLIT:
            self._color_index = color_index
        else:
            raise RuntimeError("Unknown drawing mode: {}".format(
                self._draw_mode))

    def set_color_offset(self, offset):
        assert self._draw_mode == self.DRAW_PIXELS or self._draw_mode == self.DRAW_QUAD
        self._color_offset = offset

    def set_color_scale(self, scale):
        assert self._draw_mode == self.DRAW_PIXELS or self._draw_mode == self.DRAW_QUAD
        self._color_scale = scale

    def draw(self, projection, view, width, height):
        if self._draw_mode == self.DRAW_PIXELS:
            np_type = self._framebuffer.color_attachments[
                self._color_index].dtype
            gl_type = opengl_utils.get_gl_type(np_type)
            pixels = self._framebuffer.read_rgba_pixels(self._color_index)
            if self._color_scale != 1.0:
                pixels *= self._color_scale
            if self._color_offset != 1.0:
                pixels += self._color_offset
            width = min(width, self._framebuffer.width)
            height = min(height, self._framebuffer.height)
            gl.glDrawPixels(width, height, gl.GL_RGBA, gl_type, pixels)
        elif self._draw_mode == self.DRAW_QUAD:
            gl.glDisable(gl.GL_DEPTH_TEST)
            gl.glDisable(gl.GL_CULL_FACE)
            with self._quad.activate():
                self._quad["u_color_offset"] = self._color_offset
                self._quad["u_color_scale"] = self._color_scale
                self._quad.draw(gl.GL_TRIANGLE_STRIP)
            gl.glEnable(gl.GL_CULL_FACE)
            gl.glEnable(gl.GL_DEPTH_TEST)
        elif self._draw_mode == self.BLIT:
            gl.glBindFramebuffer(gl.GL_READ_FRAMEBUFFER,
                                 self._framebuffer.native_framebuffer.handle)
            gl.glReadBuffer(gl.GL_COLOR_ATTACHMENT0 + self._color_index)
            gl.glBindFramebuffer(gl.GL_DRAW_FRAMEBUFFER, 0)
            gl.glBlitFramebuffer(0, 0, self._framebuffer.width,
                                 self._framebuffer.height, 0, 0, width, height,
                                 gl.GL_COLOR_BUFFER_BIT, gl.GL_LINEAR)
        else:
            raise RuntimeError("Unknown drawing mode")
Esempio n. 3
0
class MeshDrawer(object):

    # Shader type
    FLAT = 1
    PHONG = 2

    FLAT_VERTEX = """
    uniform vec4 u_color_scale;
    uniform mat4 u_view_model_normal_matrix;
    uniform mat4 u_view_model_matrix;
    //uniform mat4 u_view;
    //uniform mat4 u_model;
    uniform mat4 u_projection;
    in vec3 a_vertex;
    in vec4 a_color;
    in vec3 a_normal;
    out vec4 v_color;
    out vec4 v_position;
    out vec4 v_cs_position;
    out vec3 v_normal;
    void main()
    {
        v_color = u_color_scale * a_color;
        //vec4 cs_position = u_view * u_model * vec4(a_vertex, 1.0);
        vec4 cs_position = u_view_model_matrix * vec4(a_vertex, 1.0);
        //mat3 view_model_normal_matrix = transpose(inverse(mat3(u_view_model_matrix)));
        //vec3 cs_normal = normalize(view_model_normal_matrix * a_normal);
        vec3 cs_normal = vec3(u_view_model_normal_matrix * vec4(a_normal, 0));
        //vec3 cs_normal = a_normal;
        v_cs_position = cs_position;
        v_normal = cs_normal;
        vec4 screen_position = u_projection * cs_position;
        v_position = screen_position;
        gl_Position = screen_position;
    }
    """

    FLAT_FRAGMENT = """
    uniform float u_depth_scale;
    uniform vec3 u_normal_scale;
    in vec4 v_color;
    in vec4 v_position;
    in vec4 v_cs_position;
    in vec3 v_normal;
    void main()
    {
        float z_distance = abs(v_cs_position.z);
        float z_depth = u_depth_scale * z_distance;
        vec3 normal = u_normal_scale * v_normal;
        gl_FragData[0] = v_color;
        gl_FragData[1] = vec4(z_depth, z_depth, z_depth, 1);
        gl_FragData[2] = vec4(normal, 1);
    }
    """

    PHONG_VERTEX = """
    // Color uniforms
    uniform vec4 u_color_scale;

    // Model view projection uniforms
    uniform mat4 u_view_model_normal_matrix;
    uniform mat4 u_view_model_matrix;
    //uniform mat4 u_view;
    //uniform mat4 u_model;
    uniform mat4 u_projection;

    // Light uniforms
    uniform vec3 u_light_position;

    // Vertex attributes
    layout(location = 0) in vec3 a_vertex;
    layout(location = 1) in vec4 a_color;
    layout(location = 2) in vec3 a_normal;

    // Outputs to fragment shader
    out vec4 v_color;
    out vec4 v_screen_position;
    out vec4 v_cs_position;
    out vec3 v_cs_normal;
    out vec4 v_cs_light_position;

    void main()
    {
        v_color = u_color_scale * a_color;
        //vec4 cs_position = u_view * u_model * vec4(a_vertex, 1.0);
        v_cs_position = u_view_model_matrix * vec4(a_vertex, 1.0);
        // TODO: This should be done as a uniform
        v_cs_light_position = u_view_model_matrix * vec4(u_light_position, 1.0);
        //mat3 view_model_normal_matrix = transpose(inverse(mat3(u_view_model_matrix)));
        v_cs_normal = vec3(u_view_model_normal_matrix * vec4(a_normal, 0));
        v_screen_position = u_projection * v_cs_position;
        gl_Position = v_screen_position;
    }
    """

    PHONG_FRAGMENT = """
    #define USE_HALF_VECTOR 0
    #define USE_DERIVATIVE_FOR_NORMAL 1

    uniform float u_depth_scale;
    uniform vec3 u_normal_scale;

    // Light uniforms
    //uniform vec3 u_light_intensity;
    uniform vec3 u_light_ambient_intensity;
    uniform vec3 u_light_diffuse_intensity;
    uniform vec3 u_light_specular_intensity;

    // Material uniforms
    uniform vec3 u_material_ambient;
    uniform vec3 u_material_diffuse;
    uniform vec3 u_material_specular;
    uniform float u_material_shininess;

    in vec4 v_color;
    in vec4 v_position;
    in vec4 v_cs_position;
    in vec3 v_cs_normal;
    in vec4 v_cs_light_position;

    layout(location = 0) out vec4 out_color;
    layout(location = 1) out vec4 out_depth;
    layout(location = 2) out vec4 out_normal;

    vec3 ambient_light()
    {
        return u_material_ambient * u_light_ambient_intensity;
    }

    vec3 diffuse_light(in vec3 normal, in vec3 light_direction)
    {
        normal = normalize(normal);
        light_direction = normalize(light_direction);
        // calculation as for Lambertian reflection
        float diffuse_term = clamp(dot(normal, light_direction), 0, 1) ;
        return u_material_diffuse * u_light_diffuse_intensity * diffuse_term;
    }

    vec3 specular_light(in vec3 normal, in vec3 light_direction, in vec3 position)
    {
        normal = normalize(normal);
        light_direction = normalize(light_direction);

        float specular_term = 0.0;
#if USE_HALF_VECTOR
        vec3 v = normalize(-position);
        vec3 h = normalize(v + light_direction);
        if (dot(normal, light_direction) > 0) {
            specular_term = pow(max(dot(h, normal), 0.0), u_material_shininess); 
        }
#else
        vec3 v = normalize(-position);
        vec3 r = reflect(-light_direction, normal);
        if (dot(normal, light_direction) > 0) {
            specular_term = pow(max(dot(r, v), 0.0), u_material_shininess);
        }
#endif

        return u_material_specular * u_light_specular_intensity * specular_term;
    }

    void main()
    {
#if USE_DERIVATIVE_FOR_NORMAL
        vec3 dFdxPos = dFdx(v_cs_position.xyz);
        vec3 dFdyPos = dFdy(v_cs_position.xyz);
        vec3 cs_normal = normalize(cross(dFdxPos, dFdyPos));
#else
        vec3 cs_normal = v_cs_normal;
#endif

        // Vector to light source
        vec3 cs_light_distance_vec = v_cs_light_position.xyz - v_cs_position.xyz;
        // Calculate the cosine of the angle of incidence (brightness)
        float brightness = dot(cs_normal, cs_light_distance_vec) /
                            (length(cs_light_distance_vec) * length(cs_normal));
        brightness = max(min(brightness, 1.0), 0.0);

        vec3 cs_light_direction = v_cs_light_position.xyz - v_cs_position.xyz;
        vec3 ambient_light_vec = ambient_light();
        vec3 diffuse_light_vec = diffuse_light(cs_normal, cs_light_direction);
        vec3 specular_light_vec = specular_light(cs_normal, cs_light_direction, v_cs_position.xyz);
        out_color.xyz = v_color.xyz * (ambient_light_vec + diffuse_light_vec + specular_light_vec);

        // TODO: Vectors should be dehomogenized (i.e. w = 1)
        float z_distance = abs(v_cs_position.z);

        //out_color = v_color * brightness * vec4(u_light_intensity, 1);
        out_color.a = v_color.a;
        out_depth = vec4(u_depth_scale * vec3(z_distance, z_distance, z_distance), 1);
        out_normal = vec4(u_normal_scale * cs_normal, 1);
    }
    """

    def __init__(self,
                 mesh,
                 use_depth_test=True,
                 use_face_culling=True,
                 shader_type=PHONG):
        self.use_depth_test = use_depth_test
        self.use_face_culling = use_face_culling
        # Compile shaders
        if shader_type == self.FLAT:
            self._program = Program(self.FLAT_VERTEX,
                                    self.FLAT_FRAGMENT,
                                    version="330")
        elif shader_type == self.PHONG:
            self._program = Program(self.PHONG_VERTEX,
                                    self.PHONG_FRAGMENT,
                                    version="330")
        else:
            raise RuntimeError("Unknown shader type: {}".format(shader_type))
        self._shader_type = shader_type
        # Get mesh attributes
        self._vertices_vbo = np.core.records.fromarrays(
            [mesh.vertices],
            dtype=[('a_vertex', np.float32, (3, ))]).view(gloo.VertexBuffer)
        if mesh.colors is None:
            print("Mesh has no color. Using default color [0.5, 0, 0, 1].")
            mesh_colors = np.zeros((self._vertices_vbo.shape[0], 4),
                                   dtype=np.float32)
            mesh_colors[:, :] = [0.5, 0, 0, 1]
        else:
            mesh_colors = mesh.colors
        self._colors_vbo = np.core.records.fromarrays(
            [mesh_colors],
            dtype=[('a_color', np.float32, (4, ))]).view(gloo.VertexBuffer)
        if mesh.normals is None:
            print("Mesh has no normals. Using default normals [0, 0, 0].")
            mesh_normals = np.zeros((self._vertices_vbo.shape[0], 3),
                                    dtype=np.float32)
            mesh_normals[:, :] = [0, 0.5, 0]
        else:
            mesh_normals = mesh.normals
        self._normals_vbo = np.core.records.fromarrays(
            [mesh_normals],
            dtype=[('a_normal', np.float32, (3, ))]).view(gloo.VertexBuffer)
        # self._texcoords_vbo = np.core.records.fromarrays([mesh.texcoords], dtype=[('a_texcoords', np.float32, (2,))]).view(gloo.VertexBuffer)
        self._faces = mesh.faces.view(gloo.IndexBuffer)

        # Bind vertex attributes
        self._program.bind(self._vertices_vbo)
        self._program.bind(self._colors_vbo)
        self._program.bind(self._normals_vbo)
        # self._program.bind(self._texcoords_vbo)
        # Create and fill index buffer
        self._gl_index_buffer = gl.glGenBuffers(1)
        gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, self._gl_index_buffer)
        gl.glBufferData(gl.GL_ELEMENT_ARRAY_BUFFER, self._faces.nbytes,
                        self._faces, gl.GL_STATIC_DRAW)
        gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, 0)
        # Initialize uniforms
        self._color_scale = np.array([1, 1, 1, 1])
        self._normal_scale = np.array([1, 1, 1])
        self._depth_scale = 1.0
        self._light_position = np.array([-25, -25, 50.])
        self._light_intensity = 3
        self._material = np.array([0.5, 0.5, 0.5])
        self._transform = pvm.ModelTransform()

    @property
    def light_position(self):
        return self._light_position

    @light_position.setter
    def light_position(self, light_position):
        assert light_position.ndim == 1
        assert len(light_position) == 3
        self._light_position = light_position

    @property
    def light_intensity(self):
        return self._light_intensity

    @light_intensity.setter
    def light_intensity(self, light_intensity):
        self._light_intensity = light_intensity

    @property
    def material(self):
        return self._material

    @material.setter
    def material(self, material):
        assert material.ndim == 1
        assert len(material) == 3
        self._material = material

    @property
    def color_scale(self):
        return self._color_scale

    @color_scale.setter
    def color_scale(self, color_scale):
        if not isinstance(color_scale, np.ndarray) and not isinstance(
                color_scale, list):
            self._color_scale[:] = color_scale
        else:
            assert color_scale.ndim == 1
            assert len(color_scale) == 4
            self._color_scale = color_scale

    @property
    def normal_scale(self):
        return self._normal_scale

    @normal_scale.setter
    def normal_scale(self, normal_scale):
        if not isinstance(normal_scale, np.ndarray) and not isinstance(
                normal_scale, list):
            self._normal_scale[:] = normal_scale
        else:
            assert normal_scale.ndim == 1
            assert len(normal_scale) == 3
            self._normal_scale = normal_scale

    @property
    def depth_scale(self):
        return self._depth_scale

    @depth_scale.setter
    def depth_scale(self, depth_scale):
        self._depth_scale = depth_scale

    @property
    def transform(self):
        return self._transform

    @property
    def model_matrix(self):
        return self._model

    def update_transform(self, transform):
        self._transform = transform

    def draw(self, projection, view, width, height):
        model_matrix = self._transform.matrix

        # Set uniforms
        self._program["u_projection"] = projection
        # Note: OpenGL matrix multiplication works on column-major oriented storage (as least for pre-multiplication).
        # Also glumpy.glm is using column-major assumption for its operations.
        view_model_matrix = np.transpose(
            np.matmul(np.transpose(view), np.transpose(model_matrix)))
        self._program["u_view_model_matrix"] = view_model_matrix
        # self._program["u_view"] = view
        # self._program["u_model"] = self._model
        view_model_normal_matrix = np.transpose(
            np.linalg.inv(view_model_matrix))
        self._program["u_view_model_normal_matrix"] = view_model_normal_matrix
        self._program["u_color_scale"] = self._color_scale
        self._program["u_normal_scale"] = self._normal_scale
        self._program["u_depth_scale"] = self._depth_scale
        if self._shader_type == self.PHONG:
            self._program["u_light_position"] = self._light_position
            self._program[
                "u_light_ambient_intensity"] = 0.4 * self._light_intensity
            self._program[
                "u_light_diffuse_intensity"] = 0.4 * self._light_intensity
            self._program[
                "u_light_specular_intensity"] = 0.2 * self._light_intensity
            self._program["u_material_ambient"] = self._material
            self._program["u_material_diffuse"] = self._material
            self._program["u_material_specular"] = self._material
            self._program["u_material_shininess"] = 32

        with self._program.activate():
            # Bind index buffer and draw
            if self.use_depth_test:
                gl.glEnable(gl.GL_DEPTH_TEST)
            else:
                gl.glDisable(gl.GL_DEPTH_TEST)
            if self.use_face_culling:
                gl.glFrontFace(gl.GL_CCW)
                gl.glCullFace(gl.GL_BACK)
                gl.glEnable(gl.GL_CULL_FACE)
            else:
                gl.glDisable(gl.GL_CULL_FACE)
            gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, self._gl_index_buffer)
            gl.glDrawElements(gl.GL_TRIANGLES, 3 * len(self._faces),
                              opengl_utils.get_gl_type(self._faces), None)
            gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, 0)
            # gl.glDrawArrays(gl.GL_TRIANGLES, 0, 3 * len(self._faces))
            # self._program.draw(gl.GL_TRIANGLES, self._faces)

    def tick(self, dt):
        pass