Malt Rendering Framework

repository·Development·Indexed 22 days ago

https://github.com/bnpr/malt

A real-time rendering framework for animation and illustration, specifically tailored for stylized non-photorealistic rendering (NPR). Written in Python and OpenGL, Malt treats GLSL and Python as first-class citizens for pipeline and shader creation. It includes BlenderMalt, a host designed for Blender that synchronizes scene data, meshes, and textures via a Bridge instance and implements the standard Blender RenderEngine interface.

Tokens
35K
Snippets
49
Records
155
Agent score
77%

What's inside Malt

  1. Overview of Malt features

    Development

    Malt is a real-time rendering framework designed for animation and illustration, specifically optimized for stylized non-photorealistic rendering (NPR).

    Key capabilities include:

    • Blender Integration: Complete integration within the Blender ecosystem.
    • Code-Centric Workflow:
      • Automatic reloading of code.
      • VSCode integration with GLSL autocompletion.
      • Automatic generation of nodes from GLSL functions.
      • Automatic UI generation for Shader and Pipeline parameters.
      • 100% customizable Python Render Pipelines.
  2. What is Malt and how does it work?

    Development

    Malt is a customizable rendering framework written in Python and OpenGL. It is designed as a real-time renderer that prioritizes image quality, flexibility, and simplicity over raw performance, making it suitable for offline rendering in animation and stylized, non-photo-realistic (NPR) illustration.

    Core Architecture

    • Pipelines: The central logic of Malt. Developers write custom Pipeline classes to define how a scene is rendered.
    • Host Application: Malt is intended to be used by a host (e.g., BlenderMalt). The host is responsible for preparing and sending Scene data, including Meshes, Shaders, and Textures to Malt.
    • Scene: A data container that provides information to the Pipeline. Pipelines can declare custom Parameters for scene objects which the host then exposes to users.
    • Materials: Defined as a Python dictionary of Shaders. Pipelines are responsible for compiling these materials using conditional compilation (via a preprocessor) to share source code across different shader types.
  3. What is Malt?

    Development

    Malt is a fully customizable real-time rendering framework designed for animation and illustration. It is specifically optimized for stylized non-photorealistic rendering (NPR) and provides a workflow similar to 'Shadertoy' but integrated directly within Blender.

    Key capabilities include:

    • Stylized NPR Pipeline: Includes built-in support for stylized shading models, light groups, and line rendering.
    • Node-Based Customization: Users can customize materials, light shaders, screen shaders, and the render pipeline itself using nodes.
    • Code-Centric Workflow: Supports auto-reloading for code, VSCode integration (with GLSL intellisense), and Renderdoc integration.
    • Extensibility: Allows for automatic generation of nodes from plain GLSL functions and provides 100% customizable Python render pipelines.
  4. Overview of the Render Library

    Development

    The Render Library provides pipeline-agnostic rendering utilities that require logic beyond pure GLSL. It contains a variety of tools ranging from simple data structures to complex lighting systems.

    Key components include:

    • Uniform Buffer Objects: Managed via Common.py.
    • Python Utilities: Such as Sampling.py for pure Python-based logic.
    • Lighting and Shadowmaps: Complex features implemented in Lighting.py.

    Note that Render modules do not follow a single strict API; while similar features often share similar interfaces, each module is free to implement the interface most appropriate for its specific requirements.

  5. What is BlenderMalt

    Development
    BlenderMalt is a Malt Host specifically designed for Blender. It manages the loading and synchronization of Scene data and provides a minimal UI optimized for code-centric workflows. It facilitates communication between Blender and Malt via a Bridge instance.
  6. How to use the Malt Shader Library

    Development

    The Malt Shader Library is a collection of GLSL code designed to be pipeline/renderer agnostic. Functions are implemented so they can be copied into other GLSL-supported rendering engines.

    Key organizational principles:

    • Include Guards: All shader files use standard include guard macros instead of #pragma once. This allows user code to override built-in Malt code by redefining macros.
    • Common Code: Common.glsl provides the foundation for all pipelines, including vertex attribute layouts, the COMMON_UNIFORMS block, and batch rendering uniform blocks.
    • Math & Utilities: The Common/ folder contains 3D math and rendering utility functions.
    • Lighting: The Lighting/ folder contains basic lighting and shadow mapping implementations intended for extension.
    • Shading: The Shading/ folder provides building blocks for implementing BRDFs.
    • Filters: The Filters/ folder contains texture processing functions (e.g., Blur, AO).
    • Passes: Standalone texture processing or shaders that do not fit the library pattern are located in Passes/.
    • Pipelines: Pipeline-specific code should be placed in dedicated folders within Pipelines/.
  7. Compare Malt and BEER to choose the right tool

    Development

    Decide between Malt and BEER based on your target workflow and technical requirements:

    • Choose Malt if: You are an advanced user who prefers a workflow combining Code & Nodes and requires an OpenGL backend. It is optimized for animation and illustration, prioritizing flexibility and image quality.
    • Choose BEER if: You want a tool accessible to everyone using a Layers/Stacks workflow.
  8. How the BlenderMalt RenderEngine works

    Development

    The MaltRenderEngine.py module implements the standard Blender RenderEngine interface. It automates the following workflow:

    1. Generates a Malt Scene from the Blender DepsGraph.
    2. Sends the scene to the Bridge for rendering.
    3. Passes the resulting render back to Blender.
  9. How Meshes and Textures are synchronized

    Development

    BlenderMalt provides optimized synchronization for geometry and image data:

    • Meshes: MaltMeshes.py retrieves Blender geometry as vertex and index buffers to send to the Bridge. It is optimized for real-time editing and can retrieve vertex data directly from Blender's internal C data using the CBlenderMalt library.
    • Textures: MaltTextures.py handles the transmission of 1D and 2D texture pixel data to the Bridge.
  10. Customize render pipelines with plugins

    Development

    Malt allows you to customize render pipelines using plugins. Plugins can extend the system in three ways:

    1. Add new node libraries to Pipeline Graphs.
    2. Add new Pipeline Parameters.
    3. Add new PipelineGraph types.

    Plugins can be installed either globally via the Addon Settings or specifically for a single world via the World Panel.

  11. GLSL Syntax: Variables and Types

    Development

    Variables in GLSL are declared with a type, a name, and an optional value. Common types used in Malt include:

    • float: Single-precision floating-point numbers (e.g., 1.0, -0.5).
    • vec2, vec3, vec4: Vectors containing 2, 3, or 4 floats. Used for positions (vec3), UVs (vec2), and colors (vec3 or vec4).

    Accessing Vector Components: You can access individual components using dot notation. For colors, you can use .r, .g, .b, .a. For spatial coordinates, you can use .x, .y, .z, .w. These are interchangeable (e.g., .x is the same as .r).

    float x_pos = position_3d.x;
    float red_channel = color.r;
    // Swizzling: selecting multiple components
    vec2 uv = position_3d.xy;
    vec3 rgb = semi_transparent_red.rgb;
  12. GLSL Syntax: Functions and Parameters

    Development

    Functions are blocks of code that perform tasks and return values. They are similar to nodes in a node-based editor.

    • Return Values: Declare the return type before the function name. Use the return keyword to output a value.
    • Void Functions: If a function returns nothing, use the void type.
    • Input Parameters: Defined inside parentheses with their types.
    • Output Parameters (inout): Use the inout keyword to allow a function to modify a variable passed to it.
    // Function with return value
    float add(float a, float b) {
        return a + b;
    }
    
    // Function with output parameter
    void get_colors(inout vec3 color1, inout vec3 color2) {
        color1 = vec3(1,0,0);
        color2 = vec3(0,1,0);
    }