Only this pageAll pages
Powered by GitBook
Couldn't generate the PDF for 133 pages, generation stopped at 100.
Extend with 50 more pages.
1 of 100

Open Brush Docs

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Selection Options

Lights Panel

Use Lights to modify your scene's primary and secondary lighting colors and positioning.

  • The sun is your primary light, and it casts shadows.

  • The sun is the brighter light.

  • The moon is your secondary light, it doesn’t cast shadows.

  • The fill light floods the scene with an equal distribution of color and light. It's effects are most easily seen in the shadow color of your scene.

  • You can grab and move the sun and moon by selecting with the trigger.

  • You can change the color of all three light sources.

  • The lighting effect is best observed on environments with a ground and object (i.e. pedestal), and in those sketches where there are at least a few strokes.

  • The sphere the lights pivot around can be used as a representation/quick preview for placement of lights in the world.

  • Custom lights save with sketches.

Feature: Icosa Gallery Support

Status: Released to Current Beta

Download

  • (Rift, Quest via Link cable...)

  • (Vive, Index, Reverb...)

  • (Pico, Pimax etc)

No separate downloads as this feature is now part of our current

What does it do?

Tilt Brush was previously tightly integrated with - a website for publishing, sharing and browsing 3D models and Tilt Brush Sketches. This was both an easy way to allow others to view your work and a resource to find 3d elements that you can use to build your scene. It made it easy to produce sketches that combined elements drawn in with brushes in Tilt Brush with low-poly models created in Blocks.

We've created the - a replacement for the Google Poly website and restored all the publically shared artwork that was saved from the shutdown of Poly by volunteers from and other groups. We've also restored and even improved upon the integration with Open Brush and Blocks and have integration planned with Blender, Godot and other 3d apps and platforms.

How do I install it?

Download a build for your headset from the link above and unzip it. You can run the Windows exe directly. To install the Quest apk use SideQuest:

How do I use it?

TODO

Known Issues

TODO

How do I get help

Come over to the Open Brush Discord: and chat to @seethrough ).

We're mostly on UK time but we check in fairly regularly.

Can I see it in action?

Oculus Quest 1
Oculus Quest 2 or 3
Oculus PC VR
SteamVR and other PC VR
Other Builds
Code
beta release
Google Poly
Icosa Gallery
Archive Team
https://uploadvr.com/sideloading-quest-how-to/
https://discord.openbrush.app

The Open Brush config file

The Open Brush config file can be used to tweak various options for advanced users. A blank Open Brush.cfg file will be created in the Open Brush folder on application startup if one does not exist.

Example PC path: C:\Users\<username>\Documents\Open Brush\Open Brush.cfg.

On an Oculus Quest, you can find this file in /sdcard/Open Brush. You can use either adb or the SideQuest file viewer to access this file. You could also sideload a text editor if you want to edit the file directly.

The file must be valid json. If it's not working check to see if you've missed any commas or brackets. Using a JSON Validator can help if you're stuck.

Example of an empty Open Brush.cfg:

Sample contents of a Open Brush.cfg with various fields filled in:

Valid Config file Settings

"User" Section

  • Author: The name you use here will be stored in files uploaded to Icosa, Sketchfab etc.

"Brushes" Section

  • AddTagsToBrushes: See

  • RemoveTagsFromBrushes: See

  • IncludeTags: See

  • ExcludeTags: See

"Video" Section

  • Encoder: (h.264) This setting specifies the video codec used for encoding exported videos. Currently, the only supported codec is h.264.

"Flags" Section

  1. PostEffectsOnCapture: (true | false) This setting determines whether post-processing effects will be applied to captured images or videos. When set to true, effects will be applied; when set to false, they will not.

  2. ShowWatermark: (true | false) This setting controls the visibility of the Open Brush watermark on exported images and videos. When set to true, the watermark will be visible; when set to false, it will be hidden.

  3. ShowHeadset: (true | false) This setting determines whether the user's VR headset will be visible in the final exported images or videos. When set to true, the headset will be shown; when set to false, it will not.

"Import" Section

See

"Export" Section

See

  1. ExportBinaryFbx: (true | false) This setting controls whether exported FBX files will be in binary format. When set to true, binary FBX files will be exported; when set to false, ASCII FBX files will be exported.

  2. ExportFbxVersion: (FBX201600 | FBX201400 | FBX201300 | FBX2012 | FBX201100) This setting specifies the version of the FBX file format to be used when exporting 3D models. Users can choose from FBX201600, FBX201400, FBX201300, FBX2012, or FBX201100. If not specified in the config file, the default version is FBX201400. If users experience issues importing the FBX file into older software, they may need to select an older version.

  3. ExportStrokeTimestamp: (true | false) This will put timing information into texcoord2 for all GLB exports. Timestamps are a vec3: x,y = the earliest/latest timestamp in the stroke which contains that vertex. z = the timestamp for that vertex. This setting defaults to true but can be disabled to reduce file size.

Setting config values from the command line

Any of the above settings in the Open Brush.cfg file can also be specified on the command line (not applicable to Quest users). The format is --Section.Setting <value>. For example:

User Guide

UnlockScale: (true | false) This setting allows users to scale their artwork beyond the default limits. When set to true, users can scale their artwork to larger sizes; when set to false, scaling will be limited to the default range.

  • SnapshotWidth: (1 - some reasonably large number) This setting controls the width (in pixels) of exported images. Users can specify a value between 1 and a reasonably large number to set the desired image width.

  • SnapshotHeight: (1 - some reasonably large number) This setting controls the height (in pixels) of exported images. Users can specify a value between 1 and a reasonably large number to set the desired image height.

  • FOV: (1 - 179) This setting determines the field of view (FOV) for the camera used during image or video capture. Users can specify a value between 1 and 179 degrees to set the desired FOV.

  • DisableAudio: (true | false) This setting allows users to disable audio playback within Open Brush. When set to true, audio playback will be disabled; when set to false, audio playback will function as normal.

  • AdvancedKeyboardShortcuts: (true | false) Enables some extra keyboard shortcuts that were previously available in Experimental Mode

  • SkipIntro: (true | false) Skips the intro scene that appears when Open Brush finishes loading

  • EnableMonoscopicMode: (true | false) See Using Open Brush without a VR headset

  • DisableXrMode: (true | false) See Using Open Brush without a VR headset

  • Brush Tags
    Brush Tags
    Brush Tags
    Brush Tags
    Configuring Import
    Configuring Export
    {
       "User":{
          
       },
       "Brushes":{
       
       },
       "Video":{
          
       },
       "Flags":{
          
       },
       "Export":{
          
       }
    }
    {
       "User":{
          "Author":"Tiltasaurus"
       },
       "Brushes": {
          "IncludeTags": ["classroom"]
       },
       "Video":{
          "Resolution":1280,
          "OfflineResolution":1920,
          "FPS":30,
          "OfflineFPS":60,
          "ContainerType":"mp4",
          "CameraSmoothing":0.98,
          "Encoder":"h.264",
          "SaveCameraPath":true,
          "FOV":80
       },
       "Flags":{
          "PostEffectsOnCapture":true,
          "ShowWatermark":true,
          "ShowHeadset":true,
          "ShowControllers":true,
          "SnapshotWidth":1920,
          "SnapshotHeight":1080,
          "FOV":80,
          "DisableAudio":false,
          "UnlockScale":false,
          "AdvancedKeyboardShortcuts":false,
          "SkipIntro":true,
          "EnableMonoscopicMode":false,
          "DisableXrMode":false
       },
       "Export":{
          "ExportBinaryFbx":true,
          "ExportFbxVersion":"FBX201400",
          "ExportStrokeTimestamp":true
       }
    }
    --Flags.ShowWatermark true
    
    --Video.CameraSmoothing 0.99
    
    --User.Author "Captain Open Brush"

    Feature: Plugin Scripting

    Status: Experimental but lots of fun to play with.

    Download

    • (Rift, Quest via Link cable...)

    • (Vive, Index, Reverb...)

    • (Pico, Pimax etc)

    Now included in the current

    What does it do?

    Unlike the existing , plugin scripting is designed to run small scripts that directly modify the behaviour of various features while you are actually using them. For example a script might move the pointer as you are painting or add new strokes in response to your actions.

    What's it good for?

    Changing the way Open Brush responds to user actions. Adding new mirror modes or creating a new custom brush tool.

    How do I install it?

    a build for your headset from the link above and unzip it. You can run the Windows exe directly. To install the Quest apk use SideQuest:

    How do I use it?

    See

    How do I write my own plugin scripts?

    See

    Known Issues

    Some API commands are untested. Please report bugs on the plugins and scripting channel on Discord. There's lots more I want to do with this including scripted 3d object creation, better UI for parameters (different input widgets etc).

    How do I get help

    Come over to the and chat to me ( @andybak#5425 ). I'm on UK time but I check in fairly regularly.

    Can I see it in action?

    Brushes Panel

    Oculus Quest 1
    Oculus Quest 2 or 3
    Oculus PC VR
    SteamVR and other PC VR
    Other Builds
    Code
    beta version
    OpenBrush API
    Download
    https://uploadvr.com/sideloading-quest-how-to/
    Using Plugins
    Writing Plugins
    Open Brush Discord

    How to get Open Brush

    Open Brush is completely free on all platforms. (Tilt Brush is still available and is still being charged for. This is still the only way to get the app on Playstation VR)

    Only the main official release is available on most of the links below. If you want the experimental build then try Itch.io - or read about the other alternate versions that are available

    PC

    Steam Oculus Store Viveport Itch.io

    Oculus Quest

    Linux

    Mac

    There is no VR headset currently supported on the Mac but Open Brush does have some limited support for working as a .

    Oculus Applab
    SideQuest
    Itch.io
    Itch.io
    normal desktop app

    "Experimental Mode" Builds

    This page is outdated. There is no longer a separate build for this mode. The current release combines "normal" and "experimental" builds into one. You can simply flip a toggle in the settings and restart the app. See the docs on Experimental Mode

    However - there are still plenty of interesting Experimental Builds to try!

    Home

    Welcome to the Open Brush Documentation

    There is content here for both users of Open Brush and for people that want to contribute to its development.

    It's currently a massive work in progress and various links and info will be incorrect but we're just trying to get all the information currently available in one place.

    Writing good docs takes time. We'd love people to help. Hop on our Discord or just write some docs and let us know about them. There's a bunch of you out there who know more about actually using Open Brush than we as developers do and your contribution would be invaluable.

    Accessing Autosave Files

    Open Brush regularly saves your work into your Documents/Open Brush/Sketches/Autosave folder. Each sketch you make has a separate autosave file, and Open Brush keeps autosaves from your last five sketches. If you need to access an autosave, move it into your Documents/Open Brush/Sketches folder using Windows Explorer—it will have an Open Brush logo as its thumbnail in the Sketchbook.

    Old or Completed Feature Builds

    Generally - when someone is working on a new feature, they create a new build to work on until the features is ready to merge back into the main release.

    You can download these builds to try out new features. Sometimes the sketches you create with these builds won't open correctly in the main release (but not always) and like all pre-release versions these builds might contain bugs or incomplete features.\

    Selection/Erase Filter

    If you hold down your Wand trigger (the left hand if you're using Open Brush right-handed) when you first select a stroke with the Selection Tool, only brushstrokes that use that brush will be added to the selection as you continue to select strokes.

    You only have to be careful with the first stroke you select, and then after that, you can just wave the selection or erase tools with reckless abandon and it will only select strokes using the same brush type.

    Labs Panel

    More info on Labs features

    Media Library

    Extras Panel

    1. Environment Panel: You can choose a number of different virtual environments to paint in. For example, you can paint in Studio, Night Sky, Space or on a Dress Form. The lighting in the environment will affect the color of the brush stroke, but switching environments will not affect your existing brush strokes.

    2. Lights Panel

    3. Backdrop Panel

    Snap Settings Panel

    Repaint Options

    Transform Panel

    Environment Panel

    Lazy Input

    VR controllers can sometimes be a little too accurate and responsive, making it difficult to create smooth curves at low movement speeds. The Lazy Input feature will exchange responsiveness for control by applying real-time input smoothing.

    Toggle it by HOLDING your off-hand trigger and TAPPING the button marked with the rabbit/turtle.

    Camera Paths Panel

    Backdrop Panel

    Use Backdrop to modify your scene's backdrop color gradient and fog.

    • Grab anywhere on the backdrop sphere to move or turn it by selecting with the trigger

    • The backdrop sphere represents the sky dome (skybox) in the world.

    Settings Panel

    The Settings Panel can be opened from a button on the .

    1. Top row of buttons (Left to right): i. Help: Pops up links to various useful web pages ii. About: Pops up our About page iii. Contribute: Pops up a link giving info on how you can contribute iv. Ruler

    2. Second row of buttons (Left to right): i. Autosimplify ii. Experimental Mode: Toggles on or off next time you open the app iii. Swap Hands: Swaps the brush between the left and right hands iv. Reset First Use: If you click this then next time you launch Open Brush you will get the short tutorial you saw when you ran it the first time. Also turns off and switches back to Beginners Mode where most of the tools are hidden.

    Layers Panel

    Make moving creations using audio reactive brushes

    You may notice a number of brush stroke options are labeled as audio reactive. These are special types of brush strokes which can react to music or audio playing from your desktop.

    To use audio reactive brushes

    1. Begin playing audio from your computer desktop.

    Retrieving a preview image

    is a convenient endpoint you can call to get the current desktop view as a png. It will either be the headset or monoscopic user view - or the spectator camera if that is active.

    Image size is based on the current desktop window size. Combined with API commands to move the spectator camera around, this can be used to automate complex renders or your own custom camera paths.

    In a web page you can use this for a simple (nearly) realtime preview:

    Be careful calling it too often as it's not terribly efficient and will slow down Open Brush. The above example refreshes once per second. We plan to implement a much more efficient WebRTC streaming endpoint at some stage but that will be more complex for client scripts to implement so this simple endpoint will still remain useful.

    If you want to access the preview image from a different device to the one running Open Brush, you'll need to allow external connections to the API:

    Tweaking existing plugins

    A great way to get comfortable with how plugin scripting works - especially if you've never coded before - is to look at existing scripts and modify how they work in small (or maybe not so small!) ways.

    Any of the example plugins can be copied to your Open Brush plugins folder simply by clicking the copy button for that plugin type:

    (If this button isn't visible then a script of that name already exists in your plugins folder - you've probably already clicked the button for that particular plugin).

    Once a plugin script does exist in your plugins folder you can edit it. Any changes you make will take effect immediately - there's no need to restart either Open Brush or the plugin itself. Any syntax errors might stop the plugin working. If so these are displayed on the console on the back of your brush controller. They will tell you which script and which line number has the problem.

    Using Reference Images on Oculus Quest

    Reference Images allow you to view image files inside your Open Brush sketch. This can be useful for getting inspiration while drawing, or to incorporate as media in your sketch.

    Reference Images are in version 21.0+ on Oculus Quest.

    How to access the Reference Images Panel

    The Reference Images Panel can be found on the Labs Panel. The Labs Panel is located in the 'More Options...' section of the Admin Panel in Advanced Mode.

    Insominx's (michael-g) Experimental Build

    Note: Released in

    This build was intended to streamline the UI with a subset of features to:

    1. Not overwhelm the user with complexity. This essentially meant that it should look as similar to basic mode as possible.

    2. Contain only features deemed useful for classroom-style usage. This includes filtering the brushes down and rearranging several tools found in various panels into a single panel.

    Both #1 and #2 were accomplished by creating a new "classroom" panel mode in addition to the normal "basic" and "advanced".

    Bimanual Input and Revolver

    Bimanual Input

    This is a 3D-version of bimanual tape drawing sometimes used in automotive drafting.

    Holding the off-hand trigger down will constrain the brush to move in a straight line towards the off-hand controller.

    You can curve the line by using your off-hand controller to control the stroke's direction while using your main-hand controller to move the cursor closer to the off-hand controller and control the stroke's orientation.

    Feature: Snip Tool

    Status: Released in

    What does it do?

    Memory limits and brush costs

    The following gives an approximate measure of how "expensive" each brush is and how much it will contribute to your memory limit. For example you could have twice as many Duct Tape strokes (weight=1.5) as you could Disco (weight=3) before hitting your limit:

    If you are in Beginner Mode, point to the Admin Panel on your menu hand. On the bottom-left is a button to switch to Advanced Mode. Click this.

  • Once in Advanced Mode, point to the Admin Panel on your menu hand. On the bottom-right is a button that reads, 'More Options...'. Click this.

  • A popup will appear with a few choices. Click 'Labs'.

  • The Labs Panel will spin out. Point at it and find the 'Reference Images' button. Click this.

  • The Reference Images Panel will spin out.

  • Adding images to your sketch

    On the Reference Images Panel, click any thumbnail to load the image. After it loads, click it again to bring it in to your sketch.

    Adding more images

    To add more images to the Reference Images Panel, you need to connect your Oculus Quest to a PC. Use these steps to learn how to do that.

    1. Once connected to a PC, look for, 'Quest' in Windows Explorer. Click this.

    2. Navigate to '..Quest\Internal shared storage\Open Brush\Media Library\Images\'

    3. Copy image files (.jpg or .png) into this folder.

    Supported image files

    Images take up video memory inside Open Brush and including too many will cause Open Brush to crash. There are some restrictions on image files.

    1. Only .jpg and .png file types.

    2. Max image file size is 10Mb.

    3. Max image dimension (height and width) is 1024.

    Change the backdrop gradient by selecting different colors.
  • Change the fog intensity by adjusting the slider, and you can change the color by clicking on the fog rectangle.

  • Reset your environment at any time by reloading it from the environment panel.

  • Custom environments save with sketches

  • Some environments already have textured sky dome. In that case, you will be prompted to turn off that custom skybox before you can modify it.

  • Pointer Angle: This changes the angle the brush pointer is at. Find a settings you feel comfortable with.

  • Quality

  • Simplification

  • Current Sketch Cost

  • Super Secret Hidden Buttons: Absolutely nothing happens if you click here.

  • Admin Panel
    Experimental Mode
    Experimental Mode

    Point your painting controller on Brushes page and click the wavy audio reactive icon.

  • You will see a message that Open Brush is listening for audio.

  • Once audio is detected, press the trigger on your painting controller and begin to lay down your brush strokes.

  • Different types of audio reactive brush strokes react to music in various ways - like pulsing, bouncing, or lighting up. You can use them to create an audio visualizer within your artwork.

  • Guides Panel
    Media Library Panel
    Camera Paths Panel
    Snap Settings Panel
    Transform Panel
    Layers Panel

    Command Line Arguments

    (If you're not sure how to launch an app with command line arguments I found this tutorial via Google: https://www.digitalcitizen.life/shortcut-arguments-parameters-windows/ - suggestions for a better link gratefully received)

    Open Brush accepts the following command line arguments:

    • --noQuickLoad

    • --captureOds

    • --outputPath odsOutputPath

    • --outputPrefix odsOutputPrefix

    • --preview

    • --noCorrection

    • --turnTable

    • --numFrames

    • --fps

    • --export (followed by full path to .tilt file)

    • --exportPath (defaults to [Open Brush folder]/Exports

    • -batchmode / -nographics

    • --renderCameraPath

    • (filename of .tilt file in Sketches folder to load automatically)

    • (Any valid user config setting and value)

    Feature: New Monoscopic Mode

    At the time of writing - the current beta version has added a new View Sketches mode and has made Monoscopic Mode available without needing to download a separate version of Open Brush. This is probably the direction we will be taking - rather than directly incorporating Rapka's work.

    User @rapka on Github (@collige on the Discord) is working on a new, revamped version of the existing Monoscopic Mode - the mode that allows you to use Open Brush without VR using keyboard and mouse. It's still not quite ready but it's more intuitive than the existing monoscopic mode and uses the WASD keyboard controls familiar to anyone who is used to standard PC game controls.

    https://github.com/rapka/open-brush/tree/monoscopic-controls

    Example Background Plugins

    AutoSpinSymmetry

    Allows you to precisely control the spin speed of the symmetry widget

    CrossfadeLayers

    Cycles through all layers, fading one out as the next one fades in. An example of using shader parameters to fade strokes in and out

    DrawAndAnimateStrokes

    An example of drawing procedurally on startup and then using shader parameters to animate the strokes it has created

    Lines

    An example of drawing continuously. It draws random straight lines for as long as the script is active.

    RandomPanorama

    Randomly downloads a panorama from Openverse and sets it as the current skybox. Not every skybox is valid so you might need to toggle the script a few times. Also - they are quite large files. If you're short of space - make sure you have a clear out occasionally!

    Combined Testing Build

    To make trying out multiple features easier I used to maintain a "Kitchen Sink" build that combined multiple feature builds in one. I don't have a current combined build. Instead try our current beta release

    function refreshCameraPreview() {
        var image = document.getElementById("cameraPreview");
        image.src = "http://localhost:40074/cameraview?t=" + new Date().getTime();
    }
    setInterval(refreshCameraPreview, 1000);
    http://localhost:40074/cameraview
    https://docs.openbrush.app/alternate-and-experimental-builds/experimental-builds/open-brush-api#how-do-i-configure-it

    This build was successfully utilized to teach aspects of raytracing as show in the video below and its git repository can be found here.

    v1.0
    Revolver

    The Revolver adds a lathe function to the Wand Stroke Guide. Activate the Revolver by tapping the button marked with a bulls-eye icon while the Wand Stroke Guide is active.

    The radius of the revolving arc constraint is dependent on the distance between the main hand controller and the Wand Stroke Guide Axis. You can tap the bulls-eye button to adjust the radius.

    The revolver can also be made to automatically sweep around the axis by using the joystick.

    It allows you to cut strokes so they behave as if they were separate strokes.
    v2.0

    Experimental Mode

    What is Experimental Mode?

    Some features that used to require experimental mode have been made part of normal mode. The only remaining difference in experimental mode is the brushes. There is also no longer a separate build for experimental mode but we do have some experimental feature builds you can download.

    Google had various stages for a new feature to make it's way into Tilt Brush. It would start off available only to a closed group of testers and developers. After that it might be added to the in the official release. And finally it would be released as an officially supported feature.

    When Tilt Brush was released as open source, we discovered all the features that had been previously available to a select few and we made these available for everyone to try.

    Turning on Experimental Mode

    Simply open up the Settings Panel and click the button.

    Experimental Brushes

    There are - although some duplicate existing brushes and were included for technical reasons. That still leaves plenty of cool new brushes to play with. But be warned - they might not look correct when you export your sketches. Which is why they are still in "experimental mode" only.

    Compatibility Issues

    The main thing to be aware of with "Experimental Mode" builds is the new brushes. Any sketch you save that contains these new brushes may not look correct when you export it to another piece of software or load it in a non-experimental version of Open Brush.

    We are currently working on a new Unity Toolkit that has support for all the experimental brushes in conjunction with the

    Feature: Layers

    Status: Released in v2.0

    What does it do?

    Organize your sketch into layers that can be turned on and off separately. Exports use only the layers you've set as visible so you can create layer just for guides strokes or construction lines.

    How do I install it?

    Download a build for your headset from the link above and unzip it. You can run the Windows exe directly. To install the Quest apk use SideQuest:

    How do I get help

    Come over to the Open Brush Discord: and chat to me ( andybak#5425 ).

    I'm on UK time (currently UTC+1) but I check in fairly regularly.

    Feature: Brush Editing

    Status: Buggy (especially the Quest version) but powerful and worth trying

    Download

    • (Rift, Quest via Link cable...)

    • (Vive, Index, Reverb...)

    • (Pico, Pimax etc)

    What does it do?

    It's an attempt to provide a runtime UI for Tim Aidley's "User Brushes" feature:

    See:

    Currently it:

    1. Allows you to create a new user brush by duplicating an built-in brush

    2. It exposes shader parameters as sliders and shows a preview stroke changing in realtime as you adjust the sliders

    What's it good for?

    Making your own crazy brushes!

    How do I install it?

    Download a build for your headset from the link above and unzip it. You can run the Windows exe directly. To install the Quest apk use SideQuest:

    How do I use it?

    There's a new button on the Experimental Features panel that opens the Brush Editing panel. Select a brush and then click the button to create an editable duplicate. (at the moment you have to scroll to the end of the Brushes panel to select the new brush but this should happen automatically)

    Known Issues

    Lots. It's an early proof of concept

    How do I get help

    Come over to the and chat to me ( @andybak#5425 ). I'm on UK time (currently UTC+1) but I check in fairly regularly.

    Can I see it in action?

    I made a quick video showing an early stage example:

    Defining and Drawing Brush Strokes

    When you paint freehand in Open Brush, the application is constantly recording your hand's position and orientation. Therefore internally a stroke is defined as a list of transforms. Scale isn't used but the position and rotation are key in defining the shape of the resulting stroke.

    There are several situations when you might need to define a stroke when writing a plugin:

    1. The most common use-case is with Tool Plugins. The value you return from the Main() function in a Tool Plugin is drawn as a brush stroke

    2. You can paths explicitly using Path:Draw(), PathList:Draw() or the draw methods provided by classes such as SVG

    In both these cases you must define the path as a list of transforms. Both the position and rotation are used to define the shape of the stroke. It matches what happens when you draw a stroke by hand - at each point in time you control both the position of the brush and it's orientation. Orientation doesn't matter for all brushes (a tube brush looks much the same whatever the rotation of the brush controller at each point is) but other brushes such as flat stroke brushes do make use of the rotation values you provide.

    In the simple case where you are returning a value from the Main function of a Tool Plugin, you can return a normal lua array (or "table" as they are also called) containing two or more Transform instances:

    It's simple to use a lua list like this: {} but there is also a class specifically for definition a list of transforms and it's called . The advantage of using this class is that also has many useful methods for modifying paths.

    (The various Draw() methods insist that you use a Path object - so you can't use a simple lua array when you use those.)

    Open Brush usually assumes a brush stroke is drawn by hand. Some simplification is done depending on your settings but a stroke is still usually made up of a lot of points forming a smooth curve as the app samples your controller position and orientation many times a second.

    When you draw paths via code in a plugin script, you often send only the exact points you want. For example if you were drawing a square then you'd simply define the four points that make up the corners of the square (although you usually repeat the first point at the end if you want a closed shape)

    The problem is that by default Open Brush tries to smooth the path you give it so your nice precise square becomes a rounded squiggle. The end result actually varies depending on the brush you use - different brushes use different rules for how to smooth the input points.

    But generally speaking - if you want to draw a precise geometric shape then you need to add extra points - and the Path object has some useful methods to do this.

    Troubleshooting issues with Open Brush

    If you are having issues using Open Brush, check out your options below.

    Asking Questions and getting help

    You can join our Discord or post to our Github Discussions or the Tilt Brush subreddit. At the time of writing Google still hosts the old Tilt Brush Product Forum.

    Common issues

    Looking for saved files

    If you have tried to export or save a file but you don’t see anything in Open Brush, the file has probably saved to your computer. Flip over your painting controller and check the history panel. It will display a list of all of your most recent actions or exports.

    Lost artwork

    Open Brush makes saves of your work in Documents\Open Brush\Sketches\Autosave. Each new sketch you create will have a separate autosave file, and Open Brush will store autosaves from your last five sketches. If you need to access an autosave, just drag it into the Sketches folder using Windows Explorer - it will have a Open Brush logo as its thumbnail in the Sketchbook.

    After I launch Open Brush, a sad Tiltasaurus appears

    This means your Head Mounted Display is not detected, and you'll need troubleshoot your HMD. or your

    Pink screen when starting Open Brush

    This is commonly an issue with using an out-of-date version of DirectX. Make sure you're on the latest version of DirectX, and that you're running Open Brush on a PC that matches the minimum specs of the VR device you're using.

    Open Brush crashing or freezing

    Antivirus software can sometimes interfere with Open Brush. Try disabling any AV or Firewall software you're running, and try starting Open Brush again.

    If you downloaded Open Brush through Steam, try refreshing the cache by choosing to "Verify Integrity of Game Files..." for Open Brush through the Properties window.

    Finding your log files

    Every time Open Brush is run, a log file is generated "output_log.txt". That log file can typically be found at: C:\Users\<your name>\AppData\LocalLow\Icosa Foundation\Open Brush

    Guides Panel

    • Use the sphere, cube, and pill guides to create perfect shapes.

    • Guides are moved and scaled similar to other widgets, using the Grip buttons.

    Guide Settings

    Remixing and Creative Commons

    Remixing allows others to download, edit, and republish your sketch. If you allow remixing, your content will be published under a CC-BY license. We’ll automatically show attribution on any remixed content we publish.

    Creative Commons

    Creative Commons licenses provide a standard way for content creators to grant someone else permission to use their work. If you allow remixing, your content will be published under a CC BY license. These sketches are then accessible to other Open Brush Sketches users for use, even commercially, in their own sketches.

    Turning off remixing for your content

    You can choose whether your content can be remixed by selecting from the "Allow remixes" or "Don't allow remixes" options under "Remixes" each time you publish. By default this option is set to "Allow remixes". You can change this setting at any time.

    If you don't allow remixing, your content will be published under the standard Google .

    Attribution

    Attribution is required under the CC BY license. Any remix we publish will automatically show the source sketch’s title and author underneath the 3D viewer. You retain your copyright and other users get to reuse your work subject to the terms of the license.

    Deleting remixable content or changing remix settings

    If you delete content that was once remixable, or change the settings to remove remix rights, existing copies of your content used for remixes won’t be deleted.

    What's eligible for remixing

    Please understand that you may only mark your published sketches as remixable if it consists entirely of content licensable by you under the CC BY license. Some examples of such licensable content are:

    • Your originally created content

    • Other sketches marked with a CC BY license

    World Axis Unlock

    Warning, not for the easily nauseated! While holding both grab buttons to change the scale, you’ll see a padlock on one of the action buttons. Click it, and you’ll now be able to orientate the world to any position you want!

    Hiding Brushes with Brush Tags

    Currently the brush panel is cluttered with a large number of brushes and is likely to grow larger in the future. As a first step toward better organizing them, this feature serves to classify each brush with a list of tags and a couple of filtering options.

    Via OpenBrush.cfg (UserConfig), the brushes that show up in the panel can be limited by using the following options:

    1. IncludeTags - specifies all of the brushes that may be included included in the panel

    2. ExcludeTags - specifies all of the brush that must be excluded (even if they are also in "include").

    To test, try the following:

    • Declare include { "User": { }, "Brushes": { "IncludeTags": ["classroom"], }, "Video": { }, "Flags": { }, "Export": { }, } Result should be only a single page of brushes that have been tagged with "classroom".

    • Add a new tag called "test" to a few brush descriptors that also have "classroom" and then declare inlude and exclude { "User": { }, "Brushes": { "IncludeTags": ["classroom"], "ExcludeTags": ["test"] }, "Video": { }, "Flags": { }, "Export": { }, } Result should be only a single page of brushes that have been tagged with "classroom" minus the brush tagged with "test".

    • Exclude only case { "User": { }, "Brushes": { "ExcludeTags": ["classroom"] }, "Video": { }, "Flags": { }, "Export": { }, }

    In addition, tags can be added and removed. Here is an example that includes this usage:

    UI Differences Between Basic Mode and Advanced Mode

    The location of the tools differ slightly between basic mode and advanced mode. In advanced mode environment moves to the "More Tools" panel and undo/redo are removed (you can access these via your wand instead) .

    Basic Mode Tools
    Advanced Mode Tools
    More Tools

    Saving and sharing your Open Brush sketches

    When you are finished with your 3D creation, you can save your Open Brush sketch to your computer, or share it to or . You can also take snapshot, GIFs or videos of your art to send to friends or post online.

    Saving a sketch

    While painting, you can save your sketch to avoid losing changes.

    The Open Brush UI

    On your Open Brush panels, you’ll see a number of different options and features. Learn more about them in the pages that follow.

    Eraser, Dropper, Re-Color, Camera, Teleport, Selection, Mirror, and Straight Edge are all on the top level of the Tools panel. on the "More..." panel, which is originally below the Tools panel, you can access Environment, Lights, Backdrop, Guides, and Poly Library.

    At the bottom of the palette is the Menu panel which opens when you hover over it. In both Beginner and Advanced Mode, this Menu panel contains the Sketchbook, My Profile, Beginner/Advanced Mode, Clear Sketch, Save Sketch, and Upload. When you are in Advanced Mode, the "More Options..." button will also appear within the Menu panel and contains the Tips 'N Tricks, Labs, and Settings.

    Writing a Background Plugin

    Background Plugins run all the time when activated. They are useful for animating layers or continually generating new shapes. You can still check for user actions such as pressing the trigger and change the action accordingly. They are very versatile but because they run continuously in they background, they can affect performance (especially if you run several at the same time).

    Always use one of the other script types in preference if it is more suitable.

    Unlike other plugin types, Background Plugins don't expect you to return a value and they don't do anything with any values you do return.

    In contrast other plugin types use return values as follows:

    1. Pointer Plugins use the returned value to change the pointer position, rotation or scale.

    Painting with Open Brush

    Paint with Open Brush

    1. On your painting controller, use your index finger to pull the trigger.

    2. Hold the trigger down and move the controller to paint.

    Feature: Sculpting

    Made by as a project for

    Status: Experimental. Saved sketches are incompatible with official builds

    Download

    Feature: Improved GLTF Importer

    Status: This feature has now been merged into the main release

    Download

    This feature has now been merged into the main release

    Repaint Tool and Jitter

    What does it do?

    It expands on the previous Recolor tool which is now renamed to "Repaint". The following features can be used individually or in any combination:

    Recolor

    Check out Labs features

    This page isn't up to date at the moment

    To try out newer features, you can open up the Labs panel. Here you will find some of the latest additions to Open Brush.

    (If you're really interested in cutting edge features then you might also want to look at installing .)

    Getting Started

    Choosing an Editor

    In theory you could use any text editor to write and edit your plugin scripts: Notepad on Windows or TextEdit on MacOS.

    However an editor that is designed for writing code has many useful features to make your life easier. You might already have a favourite editor. However one thing to consider it whether it supports Lua properly - and also if allows you to use the autocomplete hints that we automatically provide.

    These hints will allow your editor to suggest method names, offer tooltips for parameters and even spot errors in the types you're using in your code.

    If you're not sure then the simplest thing to do is just use Visual Studio Code:

    Case Studies

    This page is a placeholder - I'm going to collect case studies and examples and expand it later into a comprehensive list of real-world examples.\


    How to help with Testing

    One of the biggest bottlenecks that stops us releasing more features more quickly is the lack of people prepared to test features that are either already in the beta version or are ready for merging into the beta version ("pull requests").

    Testing the Beta version

    The beta version is usually fairly solid but testing is invaluable - especially if you use Open Brush in depth (our testing is often from the perspective of a casual user) or you use a headset other than a Quest 2 (currently we do the bulk of our testing using Quest 2 via Link or standalone. Testing intesively on a wide range of headsets is a major chore). The best way to help test is to switch to using it instead of the normal version of Open Brush and to report any issues you find by posting to our on Discord (or if you need to chat before you're confident enough to report a bug, just post in the )

    Grid and Angle Snapping

    What does it do?

    1. Snap selections to a grid. Duplicate selections at precise positions

    Brushes

    Open Brush comes with a wide selection of brushes and there are even more if you switch on . But be warned that the experimental brushes can be more problemmatic if you need to export to other apps. See the docs on the and on for more information. We plan to move many of the experimental brushes into normal mode when we're satisfied that they work everywhere the regular brushes work.

    Customizing Brushes

    There are currently three ways to add and modify brushes:

    Example Plugins

    Open Brush (or at least currently the experimental build that supports plugins) ships with a selection of plugins that are both useful in their own right, great examples of what is possible and hopefully good starting points for people that want to write their own plugins.

    This page will list the included plugins along with a brief explanation of what each one does. It is aimed mainly at users. If you're interested in understanding how each plugin was written, then the source code is hopefully clearly written and contains enough comments to make it easy to follow.

    General Tips

    Feature: Animation Timeline

    Developed by with support from and Open Brush community

    Status: Experimental and incomplete

    Admin Panel

    How to Find the Admin Panel

    The admin panel is always attached to your wand - which is the controller in your non-dominant hand (which is your left hand by default unless you've switched hands on the )

    Installing the Beta Release

    This build is the pre-release version of Open Brush and may contain untested new features.

    Remember, these pre-release builds are labelled beta for a reason, and some features may contain bugs. Make sure to back up your important sketches before proceeding!

    Opting in to the Steam beta

    What does it do?

    The current GLTF import in Open Brush fails to open many valid GLTF files. This feature build replaces it with a much more up to date library GLTFast

    What's it good for?

    Importing a wide range of GLTF files into Open Brush including animated models.

    How do I install it?

    Download a build for your headset from the link above and unzip it. You can run the Windows exe directly. To install the Quest apk use SideQuest: https://uploadvr.com/sideloading-quest-how-to/

    How do I use it?

    Just import gltf models as you normally would.

    Known Issues

    • When you load a sketch containing GLTF models, the models do not appear. The workaround is to open the sketch a second time.

    • Some models are improperly sized in the 3D model panel and obscure other models.

    • There's no way to control the animation for animated models and selecting them can sometimes be tricky.

    How do I get help

    Come over to the Open Brush Discord and chat to me ( @andybak#5425 ). I'm on UK time (currently UTC+1) but I check in fairly regularly.

    Can I see it in action?

    Not yet.

    Try different brushes. Plugins can have wildly different results for some brush types. Try the hull brushes in particular with some of the Tool Plugins. Also try various animated brushes such as Neon Pulse or Keijiro Brush
  • You can have more than one plugin type active at once and the combinations can be wild. Try combining a Symmetry Plugin with a Pointer Plugin. Or use a Background Plugin that animates a layer whilst drawing on it with an animated Pointer Plugin. Or maybe all three at once!

  • Try spinning the Symmetry Widget with a flick of your hand while drawing. A slow spin gives very different results to a fast spin.

  • Lazy Input (the rabbit/tortoise switch on your brush) is especially effective with some plugins. The smooth strokes you can with tortoise mode can combine beautifly with animated Pointer or Symmetry plugins.

  • Many of the Symmetry Plugins have additional parameters for color shift. These allow you to create anything from a wild rainbow of different colored strokes, down to subtle shifts of your base color that gives a more natural effect.

  • Don't forget to try different parameter values. The same plugin can look massively different based on the settings you choose.

  • Use the Copy button to copy the script to your Open Brush folder and then open it up in a text editor (ideally something like VS Code). Try changing some of the values or modifying a line of lua code here or there.

  • Learn to troubleshoot your HTC Vive
    Oculus Rift.
    Terms of Service
    Labs panel
    50 new brushes
    new glb export format

    environment

    cameras

    cameras

    teleport

    teleport

    mirror

    mirror

    undo

    redo

    dropper

    recolor

    selection

    fly

    lights

    backdrop

    guides

    poly library

    camera paths

    eraser

    eraser

    straightedge

    straightedge

    environment

    This requires you to learn your way around Unity a little bit: https://lachlansleight.medium.com/customizing-tilt-brush-6e9a63bd5425 Brushes created this way won't export to other apps correctly without manual shader editing. Using them in other Unity projects via the Unity SDK is possible but requires manual editing of the Unity shaders and materials.
  • Tim Aidley has created a feature that allows editing of brushes via config files: https://github.com/TimAidley/open-brush/blob/features/simple-brushes/Docs/UserBrushes.md

  • Developed on top of Tim's work is a work-in-progress feature that allows editing brushes directly in VR. However it's experimental, doesn't currently work on the native Quest version of Open Brush and has had only a very small amount of testing so far: https://docs.openbrush.app/alternate-and-experimental-builds/brush-editing

  • This last method will eventually be the recommended method moving forwards and we hope to fully support these custom brushes in the Unity SDK and for exporting..

    Experimental Mode
    Unity Toolkit/SDK
    Exporting
    Brush List
    origin = Transform:New(Vector3:New(0, 0, 0), Rotation.forwards)
    return {origin, origin:TranslateBy(2, 2, 0)}
    origin = Transform:New(Vector3:New(0, 0, 0), Rotation.forwards)
    path = Path:New({origin, origin:TranslateBy(2, 2, 0)})
    path:RotateBy(0, 45, 0)
    return path
    Path
    Result should be all of the brushes minus those tagged with classroom.
    {
    	"User": {
    	},
    	"Brushes": {
    		"AddTagsToBrushes": {
    			"Rainbow": ["classroom", "bedazzling"],
    			"Plasma": ["classroom", "bedazzling"],
    			"testBrushNotFound": ["classroom"]
    		},
    		"RemoveTagsFromBrushes": {
    			"Rainbow": ["default", "test"],
    			"Plasma": ["default", "test"],
    			"testBrushNotFound": ["classroom"]
    		},
    		"IncludeTags": ["classroom"],
    		"ExcludeTags": ["test"] 
    	},
    	"Video": {
    	},
    	"Flags": {
    	},
    	"Export": {
    	},
    }

    Symmetry Plugins use the returned values to create multiple new pointers.

  • Tool Plugins can use the returned value as the path of a new brush stroke which is drawn immediately.

  • You can of course draw in a Background Plugin but it's left to you to do so explicitly:

    There are some potentially new details to be aware of here:

    1. We are defining our own function to generate a random position around the current brush position

    2. We are using the Random class to generate a point that is never more than a certain distance away from the origin. We then add that to the current brush position

    3. We are manually drawing the path with myPath:Draw()

    function Main()
        if Brush.triggerPressedThisFrame then
            myPath = Path:New()
            position = getRandomPosition()
            myPath:Insert(Transform:New(position))
            myPath:Insert(Transform:New(position))
            myPath:Draw()
        end
    end
    
    function getRandomPosition()
        return Brush.position + Random.insideUnitSphere
    end
    Navigate to the Tools panel in the palette, and select the Save icon:
  • Take a snapshot of your sketch to use as a thumbnail image.

  • Your sketch is now added to your Sketchbook.

  • Your sketch file is saved to your computer at Documents/Open Brush/Sketches.

  • Trouble saving sketches

    If you're having issues saving your sketch, check that you have administration privileges on your machine. Antivirus software can also sometimes interfere with the ability to save sketches.

    Sharing your Open Brush sketches

    To share your creations outside of Open Brush, click Upload to publish your sketch to Icosa. Once you have published your sketch, you can share the link to your sketch on social networks like Facebook, Twitter, and Google+.

    Save in various file formats using Cameras

    1. While in your sketch, go to Tools > Cameras.

    2. With your painting controller, swipe the thumbpad to toggle between Auto GIF, 5-second GiF, video, and snapshot.

    3. After selecting your option, your image file will save to the Documents folder on your computer.

    4. You can then share photos, videos, and GIFs or your artwork online.

    Note: Using Cameras will not save the sketch file to gallery.

    Take a 5-second GIF

    1. Select 5-second GIF from the Cameras menu.

    2. On your painting controller, hold down the trigger to start recording. You can release the trigger to reposition or paint, then hold down the trigger again to continue recording.

    3. When the recording hits 5-seconds, the GIF will be saved to your desktop under Documents/Open Brush/Snapshots.

    Take a video

    1. Select Video from the Cameras menu.

    2. On your painting controller, tap the trigger to start recording. Tap the trigger again to stop.

    3. Your captured video will be saved to your desktop under Documents/Open Brush/Videos

    If you are an advanced user, you can also generate a high resolution video using offline rendering. Detailed instructions can be found in our release notes.

    Upload a video to YouTube

    1. Select Video from the Cameras menu.

    2. On your painting controller, tap the trigger to start recording. Tap the trigger again to stop.

    3. Hold down the thumbpad after a video has finished recording to go into Preview mode.

    4. If you like the video you’ve captured, hold down the checkmark to upload.

    5. If you haven't already, you will need to sign-into your YouTube account in your default desktop browser.

    Export your sketch file to .fbx, .obj, .gltf and other formats

    .fbx is a popular format for 3D modeling, and can be used in applications like Blender and Maya.

    1. From the Tools panel, select "More Options..." > Labs > Export.

    2. A folder will be created in Open Brush/exports that contains subfolders for each 3d file format currently supported. Each folder may also contain brush textures

    For more information see Exporting Open Brush Sketches to Other Apps

    Create a 360 video

    To create a 360 video, follow the instructions here. Note: this is an advanced feature, and requires some working knowledge of the command line.

    Icosa
    Sketchfab
    The Quick Tools Panel

    Additionally, you can find the Brush, Dropper, re-color, Selection, Model Pin, and Eraser on the Quick Tools panel.

    The Quick Tools panel is accessed:

    • Most devices (eg Quest, Rift, Pico, Vive XR): From the B button if you're right handed (or more generally the secondary button on your painting hand).

    • HTC Vive: From the Menu Button on top of the thumbpad.

    • Windows Mixed Reality: From the Menu button, in between the thumbpad and thumbstick

    Note: You can switch which hand is your painting controller and which is your palette controller by tapping the bottoms of the two controllers together. This is great to use if a right and left handed person are sharing controllers.

    Using the palette

    1. On your palette controller, use your thumb to swipe left or right across the thumbpad (HTC Vive) or thumbstick (Oculus Rift and Windows Mixed Reality).

    2. This will allow you to rotate between the three faces of the palette.

    3. Using your painting controller, angle your controller towards the palette in order to select items on the palette.

    4. Focus the pointer and press trigger to make selections.

    5. You can also use the grips on your painting controller to grab panels spawned into the world, and place them onto your palette.

    Change the width of your brush strokes

    To change the width of your brush strokes:

    1. On your painting controller, slide your thumb left or right along the thumbpad (HTC Vive) or toggle the thumbstick left or right (Oculus Rift and Windows Mixed Reality).

    2. Sliding or toggling left will make the brush stroke finer. Sliding or toggling right will make the brush stroke larger.

    Undo & Redo shortcuts

    If you would like to undo or redo brush strokes you have just made, you can use Undo and Redo in the Tools Panel (in Beginner Mode) or these shortcuts (in Beginner or Advanced Mode):

    • To undo an action:

      • HTC Vive: On the palette controller, click the left side of the thumbpad.

      • Oculus Rift: On the palette controller, click the X button (right handed) or A button (left handed).

      • Windows Mixed Reality: On the palette controller, click the left side of the thumbpad.

    • To redo an action:

      • HTC Vive: On the palette controller, click the right side of the thumbpad.

      • Oculus Rift: On the palette controller, click the Y button (right handed) or B button (left handed).

      • Windows Mixed Reality: On the palette controller, click the right side of the thumbpad.

    To quickly undo or redo, press and hold the controller button specified above.

    Rotate & Resize your sketch

    To scale, rotate, or move your sketch, you can hold down both of the grip buttons on the sides of your controllers to grab the sketch. Then, move your hands to shrink, enlarge, or spin the sketch.

    Oculus Quest 2 or 3

  • Oculus PC VR(Rift, Quest via Link cable...)

  • SteamVR and other PC VR(Vive, Index, Reverb...)

  • Other Builds (Pico, Pimax etc)

  • Code

  • What does it do?

    Allows you to modify brush stroke meshes like digital clay

    How do I install it?

    Download a build for your headset from the link above and unzip it. You can run the Windows exe directly. To install the Quest apk use SideQuest: https://uploadvr.com/sideloading-quest-how-to/

    How do I use it?

    Switch to advanced mode and use the new sculpting tool on any brush strokes. Works best on hull brushes.

    Known Issues

    WARNING - Saved files are currently incompatible with official builds of Open Brush. Don't save over any sketches you want to open in other builds.

    How do I get help

    Come over to the Open Brush Discord: https://discord.openbrush.app and chat to me @andybak).

    I'm on UK time but I check in fairly regularly.

    Can I see it in action?

    TODO

    Chingiz Dadashov-Khandan
    The University of Groningen
    Oculus Quest 1
    Same as before (but see the "jitter" feature below which adds new functionality to Recolo)

    Rebrush

    Similar to "Recolor" except it repaints existings strokes with a different brush. This is the same as the"Rebrush" tool in previous experimental builds. That feature is now part of this Repaint Tool)

    Resize

    Change the brush size of existing strokes.

    Jitter

    When this option is turned on, recolor and resize will add random variations based on your current Jitter settings.

    Jitter Improvements

    In addition to the Repaint Tool, this build adds some new features to the existing "Color Jitter" settings on the Color picker (the Dice icon near the bottom)

    Jitter Brush Size

    This slider controls how much the stroke size varies from stroke to stroke. All the way to the left behaves normally. As you move the slider more to the right, each stroke will have more randomness applied to it's stroke size.

    Jitter Positions

    This slider controls how much randomness is applied to each point on a brush stroke. . All the way to the left behaves normally. As you move the slider more to the right, each point of the stroke will be randomly shifted from it's usual position. At higher settings and with some brushes this will cause the brush stroke to actually split and form multiple small strokes.

    Things to try

    1. Try a high setting for "Jitter positions" and press the trigger to draw but don't move your hand. You'll get a small spherical "squiggle" that can be very interesting with some brushes.

    2. Draw something regular with the Hull brush and make copies of it. Then use the "Repaint Tool" with a low setting for "Jitter positions" to add random variation to each copy

    3. Position jitter can cause strokes to break into many small strokes. This depends on the brush you use and amount of jitter. Try really low jitter settings, try smaller brush sizes and try different brush types such as tube brushes (they tend not to break up as much)

    What's it good for?

    Modifying parts of existing sketches. Adding random variation after you've already painted something. Trying out different brushes and reusing parts of a sketch with different properties. (try duplicating some strokes and then repainting the duplicate)

    How do I use it?

    The Recolor button on the Tools Panel has been replaced with "Repaint". When you select it, a side panel appears with 4 toggle buttons: Recolor, Resize, Rebrush and Jitter.

    Any combination of these 4 options can be selected at any time. If you choose "jitter" then set your chosen amount of jitter using the button with the dice icon at the bottom of the Color Picker Panel

    Can I see it in action?

    Hull brush drawn with the Polyhedra tool with color and position jitter added
    Accessing the Labs panel
    1. Make sure you are in Advanced Mode.

    2. Below your palette, go to the Menu panel and select "More Options...".

    3. On your paint palette, swipe to the Tools panel and select More.

    4. Select Labs.

    Labs Features:

    Multi Mirror

    Export your sketch as a 3d file

    Save Selected Strokes to use later

    Hide or show Draft Brush strokes

    View a live webcam or other video feed while drawing

    Use the "Pin" tool

    Browse and Import 3d models from the Icosa Gallery

    Switch the desktop view to a spectator camera

    Use plugins or run API scripts


    alternate or experimental builds
    Autocomplete and Intellisense for Lua scripts

    If you look in your Documents/Open Brush/Plugins folder there is a subfolder called LuaModules and in there are a few commonly used libraries, that will provide some useful features.

    However one file is different. It contains empty definitions for all available API methods and properties along with special comments that can be used by the EmmyLua plugin to give you working autocomplete, intellisense and tooltips. This makes writing scripts and finding bugs much easier.

    If you're using Visual Studio Code then follow these steps: 1. Launch the Plugins build of Open Brush at least once so that it creates the Open Brush/Plugins folder.

    1. Launch Visual Studio Code.

    2. Click on the button on the left that shows the Extensions sidebar:

    3. Search for "Lua" and look for the sumneko extension:

    1. Click to install it and wait for it to finish installing

    2. Click the small cog icon and then open the Extension Settings:

    3. Optionally you can hide a lot of spurious warnings by disabling "lowercase-global" warnings under Lua> Diagnostics: Disable: (In our plugins we're using upper and lower case initial letters to distinguish your stuff from the API supplied-things but standard lua style is to use it to differentiate local from global. Don't worry for now...)

    4. Scroll down to Lua> Workspace: Library and add the path to your LuaModules folder:

    5. Now we've finished with settings we want to make sure it all works. We will start a simple script to check the code completion is working. Create a new file in your Documents/Open Brush/Plugins folder (not inside LuaModules) and name it PointerScript.Test.lua Then start typing:

    As soon as you type the period you should see a list of suggestions that match the "App" part:

    If not - check you've followed all the steps above.

    Any variables you define via Script Parameters will show a warning saying they are Undefined Globals. This is because the Lua plugin used in Visual Studio Code doesn't understand that Open Brush will read the Parameters table and add these variables names into your script. You can ignore these warnings for your Script Parameters.

    Visual Studio Code allows you to open the entire Plugins folder as a "workspace". Although this does allow convenient navigation between scripts it does have an unintended side effect. The VS Code lua plugin assumes that all the scripts will share a single scope. Therefore it will treat global variables in one script as also existing in all other scripts. This might result in some warnings not being displayed or incorrect warnings being displayed. It's probably best if you open each plugin script separately into it's own instance of VS Code

    Next Steps

    Now you've got a code editor installed and a plugin to help make things easier, you can move on to tweaking the example plugins and maybe even writing your own plugins from scratch.

    To help you focus on testing the right things you can see a list of changes and new features in the beta version here.

    Testing Pull Requests

    "Pull Requests" are simply requests to pull in a new feature or bug fix to the main codebase. Once a pull request is approved it's automatically released as part of the current beta version.

    Testing new features is a bottleneck for us at the moment We need feedback on the feature itself and help finding bugs that are serious enough for us to fix before merging in to the beta release.

    In return you'll get to try out the real cutting edge features first and potentially influence the design choices we make.

    On Github there is a list of open pull requests. You can click on any one and then scroll down to the bottom:

    Click on any of the blue "details" links and then click "Summary" on the left followed by the number underneath "Artifacts" on the right:

    You'll then be taken to the bottom of the page where there is a list of all the builds:

    Just click on the name that matches your headset and it will begin to download a zip file.

    (You might need to sign-up/sign-in to Github first)

    Testing Experimental Builds

    Experimental builds are the real bleeding edge. Some of the features might never make it into the official release. They can vary from "nearly ready" all the way to "barely working".

    However - early on in the development of a new feature is when feedback is most likely to be useful and most likely to alter the direction a feature takes. These are the builds you want to be testing if you want to have a say in Open Brush development.

    Support Forum
    General channel
    Draw brush strokes that align with the grid (especially useful with the hull brush)
  • Snap the rotation of selections to a chosen angle (i.e. 15, 45 or 90 degrees)

  • What's it good for?

    Drawing along straight x, y or z lines. Building regular structures up by making multiple copies of brush strokes

    How do I use it?

    Click the button shown above on the Extras Panel to open the new Snap Settings panel:

    C

    Click the Snap Angle or Snap Grid buttons to cycle through angles and grid sizes.

    The Jitter button is the same as the the button on the Color Picker. It's included here for convenience as position jitter and other settings can be useful with snapped brush strokes.

    Can I see it in action?

    TODO
    Download
    • Oculus Quest 1

    • Oculus Quest 2 or 3

    • Oculus PC VR(Rift, Quest via Link cable...)

    • SteamVR and other PC VR(Vive, Index, Reverb...)

    • (Pico, Pimax etc)

    What does it do?

    Both hand-drawn ("flipbook style") animation and tweening. Inspired by the classic Flash timeline - add motion to your Open Brush sketches.

    How do I install it?

    Download a build for your headset from the link above and unzip it. You can run the Windows exe directly. To install the Quest apk use SideQuest: https://uploadvr.com/sideloading-quest-how-to/

    How do I use it?

    TODO

    Known Issues

    TODO

    How do I get help

    Come over to the Open Brush Discord: https://discord.openbrush.app and chat to @seethrough ).

    We're mostly on UK time but we check in fairly regularly.

    Can I see it in action?

    Benji Costin
    The Icosa Foundation
    An early version of the UI
    Using the Admin Panel

    The large central button opens the Sketchbook Panel.

    Around the outside are buttons for:

    1. Save Sketch\

    2. Upload Panel \

    3. The 3 dots "more" button opens this: A popup with:

      1. Tutorial

      2. (small button underneath) Reset Panels: resets all panels to their default position/visibility\

    4. Beginner/Advanced mode toggle\

    5. New Sketch\

    settings panel
    1. Right Click on Open Brush in your Steam Library and choose "Properties"

    2. Choose "Betas" on the left, and in the dropdown, select whether you want to opt into the beta or experimental mode version. You can also return to the normal release version by choosing "None"

    1. Wait for Open Brush to update.

    Opting in to the Meta beta (Quest or PC)

    In the headset (Quest)

    1. Find Open Brush in your Library, click the 3 dots menu and choose "Settings"

    1. Click "Release Channels"

    1. Choose "Beta"

    1. Wait for Open Brush to appear in your list of updates and choose "Update"

    Using the desktop app or website (Quest or PC)

    1. Or find Open Brush in the mobile app:

    1. Choose "Beta". (Or you can switch back to "LIVE" if you want to go back to the normal release version. Note: If LIVE has a lower release number than Beta, you'll need to uninstall Open Brush first before downloading the LIVE version again.)

    2. Wait for Open Brush to update.

    Download from Itch.io

    We also host some beta versions on our Itch.io page.

    Download Directly from Github

    If you can't find a version to suit your platform anywhere else then this page on Github has the latest beta build for all the platforms we support.

    Current Beta Release Notes
    https://uploadvr.com/sideloading-quest-how-to
    https://discord.openbrush.app
    Oculus Quest 1
    Oculus Quest 2 or 3
    Oculus PC VR
    SteamVR and other PC VR
    Other Builds
    Code
    https://docs.google.com/document/d/1tEGN6OjAI7DSIeqWwfdPOAH_APv-33cOEwz_gDdVVe8/edit
    https://github.com/TimAidley/open-brush/blob/features/simple-brushes/Docs/UserBrushes.md
    https://uploadvr.com/sideloading-quest-how-to/
    Open Brush Discord
    Creating a virtual costume in Tiltbrush

    Pre-release and Experimental Builds

    New features are usually developed on a separate branch of the project until they are ready to be merged into the current beta release. In most cases you can download builds of these branches and try them out yourself.

    In the sidebar to the left we list the major alternative versions that are currently available, explain their features and what state they are currently in.

    Some features are might spend months or years as separate builds. The person who started them might have got too busy to continue the work or they might just not be suitable in their current state. In most cases we will attempt to keep them up to date with the main release so they will have all the current beta release features as well as the extra things they bring to the table.

    Beta Release

    Whenever any new change is added to Open Brush, before it's released to the various stores and sites, there is an engineering "pre-release" version available. If you'd like to help beta test new versions, you can get these builds as soon as the new code is added (generally within 20 minutes!). Windows (SteamVR) and Quest/Quest 2 versions are built automatically which you can get from the . Versions of the form "vX.Y.0" are official releases, whereas versions that do not end in .0 are made available for testing purposes only, with no guarantees as to their quality.

    These builds share a save location with the official Open Brush release, but can be installed alongside the formal version. The Oculus build, like all sideloaded content, will be listed in "Unknown Sources", and will have the word "Github" appended to the name (with a different package name as well) to differentiate it from the official release).

    "Experimental Mode" Build

    Whilst Open Brush was still Tilt Brush, the original team had a bunch of features and brushes they felt weren't quite ready to be released in the official app. As soon as Tilt Brush was made open source, everyone immediately leapt on these features with great excitement.

    Feature Builds

    Generally - when someone is working on a new feature, they create a new build to work on until the features is ready to merge back into the main release.

    You can download these builds to try out new features. Sometimes the sketches you create with these builds won't open correctly in the main release (but not always) and like all pre-release versions these builds might contain bugs or incomplete features.

    Multibrush (Tilt Brush fork)

    Multibrush is mostly an with two extra features:

    1. Post-processing effects that change the appearance of your entire scene. 2. Multiuser support: multiple people can paint at the same time and use voice chat in realtime.

    Multibrush does not currently include most of the features that we have added to Open Brush since release.

    Silk Brush (Tilt Brush Fork)

    Tilt Brush. Running in a browser!

    TutoriVR

    A VR-embedded tutorial system that supplements video tutorials with 3D and contextual aids directly in the user's VR environment.

    Full list of known Work in Progress

    There's more features that are being worked on that listed above. We've omitted them because they are either too incomplete for users to try out or they have put on hold for some reason (usually that we're too busy to finish them at the moment!)

    Here's the complete list that contains many items above plus a few more!

    (If you can help out with any of these - please get in touch!)

    Feature: Multiplayer

    Status: Released in v2.10

    Download

    • (Rift, Quest via Link cable...)

    • (Vive, Index, Reverb...)

    • (Pico, Pimax etc)

    What does it do?

    Social painting. Create with others.

    What's it good for?

    Collaborate on a sketch or invite people to watch you create.

    How do I install it?

    Download a build for your headset from the link above and unzip it. You can run the Windows exe directly. To install the Quest apk use SideQuest:

    How do I use it?

    There's a new button on the main admin panel. You enter a room name of your choice (or accept the random one provided). Share that room name with anyone you want to join.

    Known Issues and current limitations

    • Undo is disabled when in multiplayer mode.

    • Loading sketches is disabled in multiplayer mode

    • You must switch to before joining a room. Currently only basic mode features are supported.

    • People that join the room will see the strokes you have made this session but they won't see any strokes that you loaded from saved sketch.

    Our next priority is to fix the last issue. After that we will probably release the multiplayer functionality into the main beta release so it's easier for people to try it out. However - the more testing and feedback we can get at this stage, the better the beta release will be so please try out this build.

    How do I get help

    Come over to the and chat to Riccardo ( @sbanca ) or me ( @andybak#5425 ). We're both on UK time.

    Can I see it in action?

    TODO

    Feature: Transform Panel and Snap Enhancements

    Status: Released in v2.4

    What does it do?

    A new panel allows for precise position/rotation/scale changes to brush strokes and imported objects.

    1. Enter an exact value to change the position, rotation or scale of the current selection

    2. Lock any axis so you can only move the selection along a line or in a plane

    3. Lock rotation axes in a similar fashion.

    4. Control which axes respond to the snap grid

    We've improved the Snap Settings panel:

    1. You can turn position and rotation snapping on or off for each axis independently

    2. You can also snap all the currently selected objects

    3. You can turn on or off the ability to snap the selected objects to guides

    What's it good for?

    Creating regular arrangements of strokes or precisely positioning/orientating parts of your sketch.

    How do I install it?

    Download a build for your headset from the link above and unzip it. You can run the Windows exe directly. To install the Quest apk use SideQuest:

    Where do I find the new Transform Panel?

    It should appear automatically.

    Known Issues

    (To do)

    How do I get help

    Come over to the Open Brush Discord: and chat to me ( andybak#5425 ).

    I'm on UK time but I check in fairly regularly.

    Can I see it in action?

    (To do)

    Differences between Open Brush and Tilt Brush

    Features Added to Open Brush

    This section only lists features currently in the main release. There is also a with new features. There's also plenty more stuff in .

    • Fly Tool

    Get started with Open Brush

    Paint in 3D with Open Brush, an app that runs on the , , , , and virtual reality systems. You can use different brushes, effects, and tools to paint your virtual creations.

    Requirements and Installation

    To paint in 3D with Open Brush, you’ll need to have a VR headset that supports SteamVR or any Oculus headset.

    HTC Vive / Valve Index

    Plugins

    Plugins are currently only in the

    You can open the Scripts Panel from a button on the

    We won't be using the buttons on the bottom row at the moment. These are related to the older which are are useful for controlling Open Brush remotely. However the new plugin scripts are much more powerful and can add new features and modify how Open Brush works interactively.

    The other four rows of buttons each relates to a different type of plugin. From the top down they are , , and .

    Multi Mirror

    What does it do?

    Big expansion to the mirror to support many different types of symmetry:

    Point symmetry: Symmetry around a point. 7 families of axial symmetry plus 7 unique polyhedral symmetries.

    Wallpaper symmetry: 17 types of tiling symmetry

    Duplicate selections using symmetry: Create multiple clones of a selection aligned in a pattern

    Writing Plugins

    Plugins are written in the scripting language which is designed to be simple to learn and easy to understand. There's plenty of tutorials online and Lua is widely used in games and applications such as , , , and many others.

    If you've written scripts in any other language then you'll find it easy to pick up.

    If you've never programmed at all then Lua is a great place to start. Copy an example script to your Open Brush folder (there's a button next to each Plugin type that does this for you), open it up in a text editor and try changing things.

    As soon as you save your changes, Open Brush will load the new version. If you've made a mistake then the console on the back of your brush hand will tell you what line the error is on.

    function Start()
        print (App.
    Oculus Quest 1
    Oculus Quest 2 or 3
    Oculus PC VR
    SteamVR and other PC VR
    Other Builds
    Code
    https://uploadvr.com/sideloading-quest-how-to/
    basic mode
    Open Brush Discord

    Plane Guide

  • Oculus MRC fixes

  • LIV Support

  • Icosa uploads

  • LATK export

  • Jitter

  • Repaint

  • Guide settings

  • Hiding Brushes with Brush Tags

  • Selection/Erase Filter

  • View Axis Unlocking

  • Lazy Input

  • Bimanual Input

  • The Revolver

  • Grid and Angle Snapping

  • Merging Sketches

  • Scripting API

  • Passthrough Mode

  • Layers

  • Snip/Join Strokes

  • Experimental mode

  • Advanced camera tool

  • WebM video import

  • Point cloud import

  • Switching hands

  • Reset to "First Time"

  • Support for more headsets

  • Bear in mind this gives a misleading impression of the amount of work that has been put in. There's been a ton of effort on things that don't result in user-visible features but will help ease future development. Special props to @mikeage for the amazing automated build system.

    beta version
    experimental and alternate builds

    Set up your HTC Vive or Valve Index.

  • If you haven't already, install Steam.

  • Download the Open Brush app.

  • To open Open Brush, open the Steam Library > select Games > Open Brush.

  • The system requirements for running Open Brush are the same system requirements for the HTC Vive and Valve Index.

    Oculus Rift

    Rift users can either use the SteamVR build as described above for the HTC Vive / Valve Index, or the Rift-specific build described here:

    1. Set up your Oculus Rift.

    2. Download the Open Brush app.

    3. To open Open Brush, open the Oculus Home Library > Open Brush.

    The system requirements for running Open Brush are the same system requirements for the Oculus Rift.

    Oculus Quest

    Oculus Quests can either be used standalone or tethered to a PC. For tethered ("PCVR" mode), see the instructions above for the SteamVR build for HTC Vive / Valve index. For standalone mode (which has some performance limitations compared to being connected to a PC), follow these instructions:

    1. Set up your Oculus Quest.

    2. Download the Open Brush app, currently on App Lab.

    3. To open Open Brush, open the Oculus Home Library > Open Brush.

    Windows Mixed Reality

    1. Set up your Windows Mixed Reality headset.

    2. If you haven't already, install Steam.

    3. Download the Open Brush app.

    4. To open Open Brush, open the Steam Library > select Games > Open Brush.

    The system requirements for running Open Brush are the same system requirements for the Windows Mixed Reality headsets.

    For a quick tutorial

    1. Make sure you are in Advanced Mode.

    2. On your palette, go to Tools > More > Tips ‘N Tricks.

    3. This will run you through an overview of your Open Brush controllers and where the various buttons are.

    Note that left handed users can switch the left and right controllers by tapping (gently!) the base of the two controllers together, so that the left hand controller will paint and the right hand controller will contain the various panels and settings. You can also swap left and right hands in the Settings Panel

    View sketches

    When you run Open Brush for the very first time, you'll be shown an introductory tutorial teaching you how to paint and use the palette.

    Every time the app is started after that initial run, your palette hand will by default open to the Sketchbook. In the Sketchbook, you can choose between viewing some featured sketches by the community and your own saved sketches. You can also choose to start a new sketch.

    HTC Vive
    Valve Index
    Oculus Rift
    Oculus Quest
    Windows Mixed Reality
    Labs Panel
    Settings Panel

    Align all the objects or brush strokes you've selected in various ways

  • Distribute all the objects or brush strokes you've selected so they are spaced evenly.

  • https://uploadvr.com/sideloading-quest-how-to/
    https://discord.openbrush.app
    Libraries

    In addition to the API commands you can use most of the Lua Standard Library. Another included library is Lume which you can use via require "lume"

    Built-in functions and properties

    The following realtime values from the sketch are examples of values that are available to use in your scripts. There are many more. Here is a full list of methods and properties for each type.

    • Brush.position: The current position of the brush pointer relative to the canvas

    • Brush.rotation: The current orientation of the brush pointer relative to the canvas

    • Brush.colorRgb: The current brush color

    • Brush.colorHsv: The current brush colour converted to HSV

    • Brush.size: The current brush size

    • Brush.pressure: The current pressure of the brush pointer (how hard the trigger is being pressed)

    • Brush.type: The current brush name

    • App.time: The time in seconds since Open Brush was launched

    • App.currentScale: The current scale of the canvas

    • Sketch.strokes A list of strokes in the current sketch

    Script Parameters

    Scripts can specify parameters that appear as UI widgets such as sliders. These appear in a popup when you click the "3 dots" button on the right of each row. For example you might want a script to have sliders to control "speed" or "wigglyness".

    You define the widgets for each parameter in your script. Here's an example:

    Here we have defined two widgets. Both are floats (rather than integers) and we have defined a minimum, a maximum and a default value. You can set the ltext abel that appears when you hover over each slider.

    The name of each widget (here "speed" and "radius") are then available to the script as variables.

    Coordinate Spaces

    By default each script type works relative to an origin and has a rotation that makes sense for each of the three types. Pointer and Tool Scripts are relative to the user's brush hand and Symmetry Scripts are relative to the Symmetry Widget.

    You can override this. For example, here's a PointerScript that is relative to the canvas. We can then position the pointer so it is always at y=0 (the floor) but still tracks the pointer in the x and z directions:

    Note that we have to manually specific pointer.position.x and pointer.position.y. If we were using space="pointer" (the default) then we wouldn't need to as coordinates are automatically relative to pointer.position

    Valid spaces are currently "pointer" or "canvas".

    Lua
    Factorio
    Garry's Mod
    Roblox
    LÖVR
    Parameters = {
        speed={label="Speed", type="float", min=0.01, max=32, default=16},
        radius={label="Radius", type="float", min=0.01, max=5, default=1},
    }
    
    function Main()
        angle = App.time * speed
        r = Brush.pressure * radius;
        pos = Vector3:New(Math.Sin(angle) * r, Math:Cos(angle) * r, 0)
        return Transform:New(pos)
    end
    Settings = {space="canvas"}
    
    function Main()
        return Transform:New(
            Vector3:New(Brush.position.x, 0, Brush.position.z)
        )
    end
    Understanding the different plugin types

    Pointer Plugin

    These are the simplest type of plugin. They can change how your brush works while you are painting brush strokes. They can't (currently) create new types of brush but they can change the motion, size, color of the stroke. And they can start and end strokes (for example to create dashed lines). They can even add extra strokes as you paint (for example to create a web of lines back to your starting point). Here are some of the included example Pointer Plugins.

    Symmetry Plugins

    Symmetry plugins supercharge the Mirror tool. Instead of simply adding a single extra stroke mirrored horizontally, Symmetry Plugins can create multiple copies of your brush stroke in any arrangement. The strokes can be mirrored, rotated, reflected or even scaled. They can be oriented around the mirror widget - or they can follow your brush like a flock of birds. Each stroke can have a different color, size or even use a different brush type. Here are some of the included example Symmetry Plugins.

    Tool Plugins

    The previous two types of plugin work in conjunction with the regular Brush Tool and simply change or add to the brush strokes you draw. Tool Plugins are are more powerful and can implement entirely new tools. They might create new objects in one go - or modify existing ones. Each plugin can behave in different ways so check each script's instructions to understand what it does. Here are some of the included example Tool Plugins.

    Background Plugins

    The final type of plugin takes the flexibility one step further. Background plugins can do almost anything. They are more complicated to write but they have less restrictions. For a start they run all the time and can listen in to button presses, track controller movement and react accordingly. They can create repeating animations by moving layers around, they can perform actions based on timers or external signals. And you can have multiple Background Plugins active at once (You can only activate one of each of the other plugin types at any one time). Here are some of the included example Background Plugins.

    Selecting and Activating a Plugin

    For Pointer, Symmetry and Tool plugins, you can only have one of each type active at any one time. The large button on the left of each row activates and deactivates that plugin type.

    The left and right arrow buttons cycle through each installed plugin.

    The cog button opens up a panel with controls specific to the currently active plugin. These usually have sliders to change various parameters.

    The final button will copy the currently selected plugin into your Plugins folder. You can then view the code, modify it or use it as a starting point for writing your own plugin.

    Background Plugins have an extra button and work slightly differently in terms of activating and deactivating. The reason for this is that you can have multiple Background Plugins active at once. The large button on the left will enable or disable all currently active Background Plugins. To turn individual plugins on or off you can click the button with the eye icon when that plugin has been selected with the arrow buttons.

    Plugin Parameters

    Plugins can define various parameters so you can easily change how they work without needing to edit the script. Each slider will show a tooltip when you hover over it.

    Drag the slider to change it's value. If you need more precision you can:

    While hovering you can

    • Move the thumbstick on your brush controller left and right to change the value

    • Click the small arrows at either end to apply a set increment to the value

    When you've finished you can click the tick button at the bottom or simply move your hand away from the panel to close it.

    Discovering New Plugins

    Eventually we hope to have an "App Store" for plugins so you can browse and install ones that the community have created. In the meantime you can check our Plugins Discord channel for info on any plugins.

    Installing Plugins

    Place plugins inside your Open Brush/Plugins folder. Some plugins might use extra libraries. These should be placed in Plugins/LuaModules

    beta release
    Labs Panel
    HTTP API Scripts
    Tool Plugins
    Symmetry Plugins
    Pointer Plugins
    Background Plugins
    Draw with multiple colours at the same time:
    The colour of each stroke can be varied in interesting new ways

    What's it good for?

    Creating symmetrical patterns. Drawing multiple strokes at the same time. Arranging models or images into grids or other regular patterns.

    How do I use it?

    Click the button on the Labs Panel to activate Multi Mirror mode:

    When it is active you can access multi mirror settings by clicking and holding the button down for a second or so. This will bring up a panel which contains three tabs:

    1. Point Symmetry

    Point symmetry creates copies arranged around the center of the mirror widget. Each icon selects one of the 14 different types of symmetry. This is the symmetry of molecules and polyhedra. It can create shapes such as stars, explosions, vases, octopi or plants and flowers.

    For the first 7 point symmetry types, the slider controls how many copies are arranged around the center axis. (The other 7 types are based on tetrahedra, cubes and icosohedron and have a fixed number of copies)

    2. Wallpaper Symmetry

    Wallpaper symmetry repeats your strokes in various types grid pattern - reflecting or rotating in specific ways. You can create wallpaper, floor tiles crystal lattices or any other repeating patterns.

    For all symmetry types you have control over the number of copies in x and y directions. For some you can also change the scale of the grid in both the x and y directions and skew the grid cells themselves in either direction.

    3. Options

    This screen allows you to vary the colour of each stroke based on waveforms of your choosing. Colors can cycle based on hue, saturation or brightness and the amount, frequency and type of the variance can be precisely controlled.

    Creating Patterns From Existing Brush Strokes

    You can also create symmetrical copies from existing strokes. Simple select the strokes you want to use and duplicate them in the same way you do without the mirror (Press the secondary button on the controller you paint with)

    This is buggy in the release version but fixed on the current beta

    Creating Symmetrical Patterns from Imported Objects

    As well as duplicating brush strokes, if you have imported some media such as images, video or 3D objects then you can select those and create copies that follow the current symmetry settings.

    Be aware that there are currently no limits in place. If you create copies of complex objects or even if you create lots and lots of copies of simple objects, then Open Brush can become unresponsive or even crash.

    Known Issues

    1. It's very easy to create so many strokes or duplicates of 3D models that Open Brush becomes unresponsive or even crashes. We plan to add limits and warnings once we figure out how best to calculate them.

    2. A few symmetry modes move the main pointer so your main stroke is rotated somewhere else. It takes a bit of getting used to but it doesn't actually prevent you painting in these modes.

    Can I see more?

    Other Builds
    Code
    List of changes in the current beta version
    Current Beta Release Notes
    Github releases page
    Installing the Beta Release
    "Experimental Mode" Builds
    Feature: 3D Shapes Tool
    Feature: Brush Editing
    Feature: New Monoscopic Mode
    Old or Completed Feature Builds
    experimental mode build

    Open Brush API

    What does it do?

    Allows you to control Open Brush using commands sent from your web browser or a script you write. You can use nearly any programming language or even just type commands into your browser address bar.

    It even works on computers that don't support VR. You can create Tilt Brush sketches on a Mac and export them to view in a web browser.

    Example of a script that uses a web form for input:

    Example output from the form shown above:

    Some output from other example scripts that are included:

    What's it good for?

    Almost anything! See the command list or the examples. These can be accessed via the help as described below.

    You can write scripts to modify existing sketches ("change the color of all strokes to a sequence of rainbow hues"), draw entirely new ones ("draw me a landscape based on this satellite data"), automate tasks ("sign my name and export this sketch"), automatically import a directory full of 3d models and distribute them around your scene, draw fractals or complicated geometry and whatever else you can think of.

    There are commands for features that are currently not exposed in the Open Brush UI such as resizing strokes and adding points to existing strokes. The example scripts should give you plenty of ideas.

    Can I run scripts automatically at startup?

    Yep. All you need to do is to create a text file called "startup.sketchscript"

    Make sure the file extension is .sketchscript and not .txt

    Place this file in your Open Brush folder inside your user documents folder. It should go into the "Scripts" subfolder in your Open Brush folder

    (Usually in C:\Users[your user name]\Documents\Open Brush - This folder is created automatically the first time you launch the API build but you can create it yourself as well)

    Each line in this file is a single command that Open Brush will run when you open it. For example:

    This will load a sketch from your Sketch folder called "startup.tilt", switch to fly tool and turn on "viewonly" mode which disables all the panels. If you want to try this you can either rename one of your sketches to "startup.tilt" or you can change the first line in the script above. As long as the first line matches the name of a file in your Sketches folder then it should work.

    If you want to distribute a sketch without people having access to the original .tilt file then you could change this slightly. Instead of loading a sketch, load an exported version of your sketch. For example, export your sketch and rename it to mysketch.glb. Place it in your Media Libary/Models folder and use this startup script:

    Voila - a way to let people fly around your sketches without being able to modify them.

    How do I configure it

    There are two new settings you can change in your main Open Brush.cfg Both belong in the "flags" section of the config file

    Defaults:

    These two settings are for security and default to "false" but you may want to set them both to "true" if you want to control Open Brush remotely.

    You should do this if you're on a private network. Disable it or configure a firewall to restrict access to known devices if you plan to use Open Brush on public Wifi such as at an event or show.

    EnableApiRemoteCalls - by default the API only accept commands from the same machine that is running Open Brush. Set this to true to allow API commands to be sent from other computers. In most cases this will only be machines on the same local network. You will need to configure your router to accept connections on port 40074 if you want to accept commands from remote devices as well. Apps such as ngrok or localtunnel can make this simpler to set up.

    EnableApiCorsHeaders: By default browsers are blocked from sending commands via javascript to another domain. Setting this to true will relax that restriction.

    How do I use Open Brush without a headset?

    See

    Monoscopic mode is a bit tricky to get the hang of but for using it as a quick way to experiment with the API then all you really need to know is how to pan the camera to look in different directions.

    Just hold down Alt (Cmd on a Mac) and drag your mouse in the viewport.

    Currently there's no controls to move the camera but we plan to add this in soon.

    A few other notes on monoscopic mode:

    • Left click and drag to draw on the drawing plane (the grid shown in front of you)

    • Dragging with the right button down will bring the drawing plane nearer or further.

    • Ctrl+mouse will rotate the drawing plane

    • Clicking in the game window will capture your mouse cursor.

    What's the simplest way to use the API?

    Just type a command into the address bar of your browser whilst running one of the builds you've downloaded from this page.

    You can also add html files to your Scripts folder. These can have standard form elements for input and some simple javascript to send commands based on those chosen values to Open Brush.

    Check out the simple form examples included:

    What commands are available?

    Visit while you've got the custom Open Brush running to access the help.

    A full list of commands can be viewed by going to

    Each command has a "try it" link that will open a new browser tab with an example of the command in the address bar.

    If you want to view commands when Open Brush isn't running: (not neccesarily as up to date as the list you get directly from the app)

    How do I use the API from javascript

    The has got some example scripts to look at.

    Here's a simple piece of code to send a single command:

    How about other languages?

    Any language that can send http requests should work.

    Known Issues with the API

    Currently the brush 'cursor' (or the 'turtle' if you want to think of this as a kind of LOGO system) doesn't store it's full rotation - only it's bearing.

    How to get help

    With a custom build running you can visit:

    and follow links to useful info such as a full list of commands, examples scripts etc

    Importing Images, Videos and 3D Models

    eIf you want to see an image or 3D model while you paint in Open Brush, you can add it to your scene. You can move, change, or delete reference images.

    1. Make sure you are in Advanced Mode.

    2. Below your palette, go to the Menu panel and select "More Options...".

    3. On your paint palette, swipe to the Tools panel and select More.

    4. Select Labs to open the

    Click this icon to open the Media Library:

    Add an image or video clip

    1. Copy a PNG or JPG file to Documents/Open Brush/Media Library/Images or a video file to Documents/Open Brush/Media Library/Videos

    2. In Open Brush, make sure you are in .

    3. Go to the Menu panel (below your palette) and select "More Options..." > Labs > Local Media Library > Local Images.

    Add a 3D model

    1. Copy any 3d file to Documents/Open Brush/Media Library/Models.

    2. In Open Brush, make sure you are in Advanced Mode. On the Quest you also need to switch Experimental Mode on in the settings.

    3. Go to the Menu panel (below your palette) and select "More Options..." > Labs > Local Media Library > Local Models.

    Supported File Formats

    Type
    Format
    Notes

    Video support varies across OS and hardware versions. See: for more detailed information.

    Interacting with Imported Objects

    Move an image or model: Position your controller on the image, press and hold a grip button on the side of your controller. Then, drag the image to the new location and release the grip button.

    Resize an image or model: With your controllers near the image or model, press and hold both grip buttons. Then, move the controllers farther apart or closer together.

    Pin an image or model: While holding your selection with the grip, pull the trigger to pin. Alternatively, you can use the Pin tool to pin images, models, or guides.

    Remove an image or model: With your controller near the reference image, press and hold a grip button. Then, flick the controller away from your body and release the grip button. You can also use the .

    Writing a Pointer Plugin

    Pointer Plugins can modify the pointer position and/or rotation every frame. You can get the current position and rotation so you can simply add an offset to those - or you could create an entirely new position or rotation based on any of the other context variables that are available to the script.

    Name a Pointer Script with the prefix "PointerScript". For example: PointerScript.MyPlugin.lua

    Assuming your script is valid (i.e. it has no syntax errors) then giving it a valid prefix is all you need for it to appear in the Scripts Panel.

    By default a Pointer Script returns a Transform which represents how the pointer moves relative to it's normal position (which in this case is wherever the user moves their brush hand)

    The simplest possible pointer plugin would be something like this:

    function Main()
        return Transform.identity
    end

    This does nothing at all. It returns a transform called "identity" which means "no change at all". There are several other ways to express the same thing:

    There's no difference between these - it's just sometimes more convenient or clearer to write things in different ways.

    So - a plugin script that does nothing isn't much fun. Let's change it so it does something.

    Vector3.up is another shorthand - this time it's shorthand for Vector3:New(0, 1, 0) this is a vector with:

    x is 0 (no change in the left/right direction) y is 1 (a shift of 1 in the up direction) z is 0 (meaning "no change in the forward/back direction")

    So - this plugin tells Open Brush "the user's pointer should be moved up by 1 unit from whereever they are painting". If you try it you should see your pointer is about 10cm above wherever you move your brush hand.

    So this is not very useful - but we at least we can see we are changing something now.

    Let's try something slightly more interesting.

    App.time is a property of the class where you can access various properties of Open Brush app itself. As you might have guessed App.time measures time - specifically the number of seconds since you launched Open Brush.

    This plugin script will result in your strokes being painted somewhere way higher than the user's brush hand. How high depends on how long since they opened the app! Let's rein things in a bit.

    That single return line is getting a bit complicated. Let's split things over two lines to make it easier to read:

    If you've done any programming or scripting before, you should recognise what we've done here. "y" is a variable. We chose "y" as the variable name but we could call it anything we want.

    We've assigned a value to "y" which is the result of calculating a

    The output of the Waveform:Triangle method takes two parameters as input time and frequency. It returns a value that varies between -1 and +1. If you've configured your editor as explained in then you should have seen a hint pop up when you typed the first open bracket:

    So we now have a plugin that moves the pointer up and down over time. You can change the second parameter to control the speed.

    Let's go one step further - allow the user the control the speed without needing to edit the plugin script:

    We've now told Open Brush that this plugin should show a slider in it's which changes the frequency that the pointer moves.

    Configuring Export

    We've changed how export in general is configured. Previously all supported formats were exported whether you needed them or not. Some were pretty slow for large scenes (STL - looking at you) and you probably only needed a couple of them. Now you can choose which are available using the config file:

    • ExportBinaryFbx: This setting specifies the version of the FBX file format to be used when exporting 3D models. Users can choose from FBX201600, FBX201400, FBX201300, FBX2012, or FBX201100. If not specified in the config file, the default version is FBX201400. If users experience issues importing the FBX file into older software, they may need to select an older version.

    • ExportFbxVersion: Controls whether exported FBX files will be in binary format. When set to true, binary FBX files will be exported; when set to false, ASCII FBX files will be exported.

    Example Tool Plugins

    Circle

    Draws a circle centered on the position you first press the trigger with the radius and orientation controlled by where you release the trigger.

    Writing a Symmetry Plugin

    Symmetry Plugins are similar to Pointer plugins with a few differences:

    1. They can return a list of transforms that represent multiple pointers.

    2. They can modify the color, size and brush type for each of the strokes separately.

    3. They have access to the Symmetry Widget which can be used as a point of origin for each pointer. If you've used the Mirror or features in Open Brush then the Symmetry Widget is like the Mirror Widget that controls the reflection plane and center for those mirrors.

    XR Framework Beta

    The future of Open Brush begins here!

    Status: Released in

    We have been hard at work updating Open Brush to the latest version of Unity and it's new XR Framework. This will enable us to keep up to date with new features that are only available with modern VR SDKs such as hand tracking and passthrough. In addition it will make it much easier to support new platforms and devices moving forward.

    As this is a big fundamental change in how Open Brush interacts with devices, we need your help testing our new builds before we release it generally.

    I want to help test! Where do I get the new build?

    Writing a Tool Plugin

    Tool Plugins can do many different things but they are often used for drawing a lot of brush strokes all in one go. For example you could draw an entire spiral shape whenever the user clicks the trigger. Or you could use the positions: where they first pressed the trigger in and where their brush controller was when they released the trigger - to get the size of a region and create a shape that filled that space.

    To create a Tool Plugin name your script with the prefix "ToolScript". For example: ToolScript.Circle.lua

    Tool Scripts should usually return a list of transforms. If they do then this defines an entire brush stroke that is then created for you.

    We previously started by showing the simplest possible plugin script - one that does nothing. Because a tool plugin does nothing by default that would be an empty file! But let's put a bit of scaffolding in so you have a starting point for a plugin that actually does something.

    It checks to see if the user pressed the trigger and if so it returns an empty list. So this plugin does nothing and it does it every time the user presses the trigger. Great, huh?

    Let's make it do something:

    Tools Panel

    1. Eraser Tool. You can use the eraser tool to erase entire brush strokes. To select the tool:

      1. Point your painting controller towards the palette and select the eraser .

      2. Position the tool anywhere on the brush stroke and press the trigger to erase.

    -- Explicitly returns zero for position, rotation and scale.
    return Transform:New(Vector3.zero, Rotation.zero, 0)
    
    -- If you miss out rotation and/or scale they are assumed to be zero
    return Transform:New(Vector3.zero)
    
    -- Vector3.zero is itself shorthand for this:
    return Transform:New(Vector3:New(0,0,0))
    
    -- You can create a transform with only a position in a slightly shorter way:
    return Transform:Position(0,0,0)
    Switch between selecting images and models using the icons in the top left.
    Switch between selecting images and models using the icons in the top left.
  • See "Supported Formats" below to see which file types you can use.

  • Video

    MP4

    See notes below.

    MKV

    See notes below.

    MOV

    See notes below.

    WEBM

    See notes below. Must use VP8 codec. Supports transparency on Windows only.

    3d Models

    GLTF/GLB

    OBJ

    (Quest support is beta version only as of November 2025)

    FBX

    PC/Mac only.

    USD

    PC/Mac only. Support is rather outdated and experimental

    PLY

    Point clouds only. Binary little-endian format.

    Images

    PNG

    JPEG

    SVG

    SVGs are rasterized on import.

    HDR

    Labs Panel
    Advanced Mode
    supported
    https://learn.microsoft.com/en-us/windows/win32/medfound/supported-media-formats-in-media-foundation#video-codecs
    https://learn.microsoft.com/en-us/windows/win32/medfound/supported-media-formats-in-media-foundation#video-codecs
    eraser tool
    https://code.visualstudio.com/downloadcode.visualstudio.com
    Monoscopic mode
    http://localhost:40074/examplescripts
    http://localhost:40074/help
    http://localhost:40074/help/commands
    API Commands List
    help
    App
    waveform shaped like a triangle
    Getting Started
    Parameters popup

    Bear in mind - the number of pointers you generate cannot change once a brush stroke has begun, but can change between each brush stroke.

    Make sure you name your symmetry plugin scripts with the prefix "SymmetryScript". For example SymmetryScript.MyMirror.lua

    Let's start with the simplest possible Symmetry Plugin:

    In lua you can define a list of items by enclosing them in curly braces. This example is almost identical to the simplest possible Pointer plugin except that we wrap the transform in curly braces.

    You might expect that it behaves the same - i.e. nothing changes and you paint as normal. However if you try it, you'll find that's not the case. In fact - you can't paint at all - your pointer remains stubbornly stuck to the center of the Symmetry Widget.

    Why is this? By default Pointer Plugins and Symmetry Plugins use a different coordinate space. This is how we describe how where the origin is and how translations and rotations are interpreted. Pointer plugins default to using the current brush controller position as the origin so all coordinates are relative to that. Symmetry plugins on the other hand default to using the Symmetry Widget as the origin. So returning a transform that does nothing means that the pointer is stuck at the widget's center.

    You can change the default coordinate space by adding a value to the script settings:

    This plugin will now behave the same as the "do nothing" pointer plugin example. Using space="pointer" in a Symmetry Plugin is useful if you want to ignore the widget and have all the pointers move relative to the brush controller.

    Let's do something more interesting in our Symmetry Plugin:

    Here we are returning a list of 4 transforms so we will have four separate pointers all creating a stroke at the same time.

    Transform.Lerp is a method that takes two transforms as input and blends them by an amount given by the third number. So Transform.Lerp(a, b, 0.5) will return a transform that is exactly half-way between a and b. It's position will be at the midpoint of a and b and will have a rotation and scale exactly halfway between those of a and b.

    What are we passing into Transform.Lerp? origin is set to Transform.identity which is our do-nothing transform. As mentioned before - in this case it will be the center point of the symmetry widget.

    brushOffset is a Transform with it's position set to the value ofSymmetry.brushOffset. This is a Vector3 which represents the position of the user's brush controller relative to the symmetry widget. It is a special value that only makes sense in the context of a Symmetry plugin and you won't use it in other types of plugin script.

    Usually the value of the user's brush controller is given byBrush.position. This is because by default, symmetry scripts use coordinates centered on the symmetry widget and you'd have to do a some complicated calculations to get from there to the current brush position. If you use symmetry.brushOffset this is done for you.

    So this script will create 4 pointers that are spaced evenly between the symmetry widget and the user's brush controller as they paint. Give it a try!

    Finally - let's look at one last symmetry script.

    Some things to note here:

    1. Instead of creating a list of transforms using curly braces we are creating a Pathobject and then using Insert to add pointers to it one at a time. Path is just a class that stores a list of transforms. It has some useful methods for transforming and modifying itself so is often more useful than just a simple list.

    2. We are using a loop: for i = 1, copies do You should have come across similar constructs in other scripting languages. Any lua tutorial will explain some small differences with lua loops but in general they should behave as you would expect.

    3. angleStepis always 36 in this case but if you wanted to,copies could be a slider that the user sets so we calculate how many degrees to add to the angle for each copy of the pointer.

    4. You don't have to calculate the position of each pointer around the circle. This is done automatically for you. The final position is calculated based on the symmetry widget's transform and the rotation value you return for each pointer. This saves you from having to do some pretty gnarly maths yourself in symmetry plugins.

    MultiMirror
    This returns a path with 5 points forming a square. A square has 4 corners so why 5 points? The last point is the same as the first so that the square closes on itself.

    If you try this, you'll notice the square isn't very square. This is because Open Brush tries to smooth brush strokes. It expects you to be hand-drawing smooth curvy lines in space - not carefully placing precise geometric paths.

    We can fix this by adding extra points:

    This time we create a Path object instead of just using a list of transforms. This allows us to use any of the handy methods that are provided by Path - in this case it's the SubdivideSegments method. This modifies the path by inserting as many new points as we ask for in each path segment. In this case we ask for 5 new points so the square that previously had 5 points (and thus 4 segments) will now have 4 x 5 = 20 points. (I'll let you work out how many segments!)

    Next let's draw a circle:

    There's a few new things here:

    1. a loop that begins for...do, this is a standard lua construct and works similarly to loops in other languages.

    2. we first calculate a 2d vector using Vector2:PointOnCircle(angle). A Vector2 is very similar to the Vector3 that we used previously for specifying a position. The difference is that it only has two coordinates: x and y.

    3. We convert the Vector2 into a Vector3 on the next line by using the OnZ() method. This creates a Vector3 where x and y are taken from the Vector2 the z value is set to 0. Therefore it lies on the plane perpendicular to the z axis (it could probably have been named on OnXY() but this sounded better to me)

    4. We are using triggerReleasedThisFrame instead of triggerPressedThisFrame. In this example we wait for the user to release the trigger before we do anything. This means we know both the start point (where they pressed the trigger) and the end point (where they released it). These two points are used to determine how the path we return is scaled and rotated. You don't need to do this scaling and rotating yourself - it happens automatically if you return a value representing a brush stroke.

    load.named=startup.tilt
    tool.fly
    viewonly.toggle
    import.model=mysketch.glb
    tool.fly
    viewonly.toggle
    "Flags": {
      "EnableApiRemoteCalls": false,
      "EnableApiCorsHeaders": false
    },
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.open('GET',  '/api/v1?brush.type=ink', false);
    xmlHttp.send(null);
    http://localhost:40074/help
    function Main()
        return Transform:New(0,1,0)
    end
    
    -- or
    
    function Main()
        return Transform:Vector3.up
    end
    function Main()
        return Transform:Position(0, App.time, 0)
    end
    function Main()
        return Transform:Position(0, Waveform:Triangle(App.time, 1), 0)
    end
    function Main()
        y = Waveform:Triangle(App.time, 1)
        return Transform:Position(0, y, 0)
    end
    Parameters = {
        frequency={label="Frequency", type="float", min=0.01, max=10, default=2}
    }
    
    function Main()
        y = Waveform:Triangle(App.time, Parameters.frequency)
        return Transform:Position(0, y, 0)
    end
    function Main()
        return {Transform.identity}
    end
    Settings = {space="pointer"}
    
    function Main()
        return {Transform.identity}
    end
    function Main()
        origin = Transform.identity
        brushOffset = Transform:New(Symmetry.brushOffset)
        return {
            Transform:Lerp(origin, brushOffset, 0.2),
            Transform:Lerp(origin, brushOffset, 0.4),
            Transform:Lerp(origin, brushOffset, 0.6),
            Transform:Lerp(origin, brushOffset, 0.8)
        }
    end
    function Main()
        copies = 10
        pointers = Path:New()
        angleStep = 360 / copies 
        for i = 1, copies do
            angle = i * angleStep
            pointer = Transform:New(Symmetry.brushOffset, Rotation:New(0, angle, 0))
            pointers:Insert(pointer)
        end
        return pointers
    end
    function Main()
        if Brush.triggerPressedThisFrame then
            return {}
        end
    end
    function Main()
        if Brush.triggerPressedThisFrame then
            return {
                Transform:Position(-1, -1, 0),
                Transform:Position(1, -1, 0),
                Transform:Position(1, 1, 0),
                Transform:Position(-1, 1, 0),
                Transform:Position(-1, -1, 0)
            }
        end
    end
    function Main()
        if Brush.triggerPressedThisFrame then
            myPath = Path:New({
                Transform:Position(-1, -1, 0),
                Transform:Position(1, -1, 0),
                Transform:Position(1, 1, 0),
                Transform:Position(-1, 1, 0),
                Transform:Position(-1, -1, 0)
            })
            return myPath:SubdivideSegments(5)
        end
    end
    function Main()
        if Brush.triggerReleasedThisFrame then
            points = Path:New()
            for angle = 0, 360, 10 do
                position2d = Vector2:PointOnCircle(angle)
                points:Insert(Transform:Position(position2d:OnZ()))
            end
            return points
        end
    end

    ExportStrokeTimestamp: (true | false) This will put timing information into texcoord2 for all GLB exports. Timestamps are a vec3: x,y = the earliest/latest timestamp in the stroke which contains that vertex. z = the timestamp for that vertex. This setting defaults to true but can be disabled to reduce file size.

  • ExportStrokeMetadata: includes extra information with each stroke that might be useful to developers writing their own importers

  • KeepStrokes: Each stroke will be exported as a separate mesh rather than grouped by brush type (export will take longer and may fail on complex scenes)

  • KeepGroups: Maintains groups on export (export will take longer and may fail on complex scenes)

  • Formats: Each item in here corresponds to an existing export format except for "newglb". This is also a glb file but we use the new export code to generate it.

  • Note that formats not supported on your platform will be ignored. See below for platform support.

    Import Differences between GLTFast (old) and UnityGLTF (new) formats

    Extensions supported by GLTFast but not UnityGLTF:

    • EXT_mesh_gpu_instancing

    • KHR_materials_pbrSpecularGlossiness (legacy extension - superseded by KHR_materials_specular which is only supported by UnityGLTF)

    Extensions supported by UnityGLTF but not GLTFast:

    • KHR_materials_clearcoat

    • KHR_materials_emissive_strength

    • KHR_materials_ior

    • KHR_materials_iridescence

    • KHR_materials_specular

    • KHR_materials_transmission (soon)

    • KHR_materials_volume (soon)

    • MSFT_lod

    Extensions supported by both:

    • KHR_draco_mesh_compression

    • KHR_lights_punctual

    • KHR_materials_unlit

    • KHR_mesh_quantization

    • KHR_texture_basisu

    • KHR_texture_transform

    (The above list may change as we implement missing features in UnityGLTF. GLTFast also has announced plans to support KHR_materials_variants, EXT_lights_image_based and KHR_materials_transmission)

    UnityGLTF has some other differences:

    • Model hierarchy should be faithfully preserved. GLTFast on the other hand doesn't support sub-meshes so any mesh that contains multiple materials will be split into separate objects. (this might be desirable in some cases)

    • In general 3d models should be more robustly handled if you round-trip between Open Brush and other 3D apps

    Please report any other differences you find. The reason we are keeping both importers around is to gather feedback on their strengths and weaknesses.

    Choosing between the new and old GLTF formats

    The use of the new exporter is currently optional and we will continue to support the old exporter until the new one is a full replacement.

    • If you're using the existing Open Brush Unity Toolkit/SDK then use the older GLB format

    • If you're manually uploading to Icosa Gallery then use the older GLB format

    • If you're use the Icosa three.js loader this also works best with the older exporter.

    • The new GLB export format should work better in Blender and other 3D animation apps although we still have work to do to fix support for particle brushes, transparent brushes and other features.

    • Imported 3D models will export much better with the new GLB exporter

    • In general new features in the or from other will work better using the new exporter.

    Platform Support

    Format
    Android/iOS (Standalone VR)
    PC (Tethered VR)

    FBX

    ✘

    ✔

    GLB

    ✔

    ✔

    NEWGLB

    ✔

    ✔

    JSON

    ✔

    Breaking Apart Imported Models

    This build supports a new feature - The existing "group/ungroup" button on the pop-out tray that appears when you activate the Selection Tool now works on imported models - if they consist of multiple parts. Just select a single imported model and if it does have sub-parts the button will show "ungroup" as an option - the same as if you select a normal grouped set of objects.

    Importing Lights

    If your imported model contains lights then these will appear in the scene and will act upon other objects the same as the Environment Lights. Furthermore imported lights support point lights and spot lights - whereas the existing environment lights only support directional lights.

    Known Issues

    If you break apart a model containing lights, the lights themselves can't be selected or moved.

    CircularPath

    Similar to Circle except it creates a camera path instead of a brush stroke

    Parameters

    • Sides: The circle is approximated by a polygon. This controls the number of sides.

    Cube

    Draws a cube centered on the position you first press the trigger with the size and orientation controlled by where you release the trigger.

    Parameters

    • Point Spacing: The distance between control points for the strokes that make up the cube

    • Inset Amount: How much to inset each face towards it's center

    LowPolyLandscape

    Draws tiles that follow a hilly landscape as you hold the trigger.

    Parameters

    • Scale: The scale of the landscape. Smaller values make hills and valleys closer together

    • Height: The height of the landscape (Controls the vertical scaling)

    • Offset: The distance from the floor to position the landscape

    • Grid Size: The size of the grid used. Bigger values are more "low poly"

    RandomAvatar

    Calls an API to generate a random SVG icon using the MultiAvatar library

    RandomIcon

    Calls an API to generate a random SVG icon using the Iconify library

    Rays

    Draws lines from the position you start drawing to your current position.

    Parameters

    • Spacing: How often to draw a new stroke

    ReplayStroke

    (Currently removed while I fix a bug)

    Instantly draws a brush stroke based on the path of the last brush stroke you drew

    ScatterCubes

    Switches to the Hull Brush and draws cubes of random size and color as you move your brush",

    Parameters

    • Maximum Size: Controls how big the cubes can be

    • Spread: Larger values allow cubes to be placed further from your brush position

    • Amount: 0.5 gives a random 50/50 chance of creating a new cube each frame. Smaller values produce less cubes, larger values more.

    Spiral

    Draws a conical spiral.

    Parameters

    • Number of turns:

    • Number of steps per turn:

    SpiralSphere

    Draws a spherical spiral.

    Parameters

    • Steps:

    • Turns:

    SuperFormula

    Draws a supershape using the Super Formula

    Parameters

    • Symmetry:

    • n1:

    • n2:

    • n3:

    SvgHeart

    Draws a heart shape using an SVG Path

    Parameters

    • Point Spacing:

    VoxelLandscape

    Draws a blocky landscape (best used with a hull brush).

    Parameters

    • Horizontal Spacing:

    • Verticle Spacing:

    Voxels

    Draws regular blocks in space as you draw (best used with the hull brush)

    Parameters

    • Grid Size:

    Words

    Draws words that follows your brush. Tries to access the clipboard so try copying in some text.

    Parameters

    • Size:

    • Spacing:

    Thank you very much! Please join our Discord and give yourself the 'Beta Testers' role from our #welcome-rules channel (click the button!) to receive important updates about new builds. We're discussing this huge change in a dedicated channel, called #unity-xr. Come and say hi!\

    ⚠️ Remember that this is a beta release, so if you do any important work with Open Brush, please back up your files! ⚠️

    This section is very detailed per platform, so here's some quick links to your preferred version: Windows via SteamVR (OpenXR) Oculus Quest Oculus Desktop Already set up? Jump to: What should I be testing? How do I report bugs?

    Windows via SteamVR (OpenXR)

    Our desktop build is now powered by OpenXR! To make it easy to access, we have added a new beta channel on Steam.

    Accessing Open Brush properties via Steam.

    First, grab Open Brush from the Steam store. Once you have added it to your library, right click on the listing and choose 'Properties...'

    The beta unlocks!

    Select 'Betas' from the sidebar. In the text box, add the access code: openbrushxrbeta and click 'Check Code'. A blue banner will appear below, confirming your access!

    Selecting the beta branch after opting in.

    You can now access the openxr and openxr-experimental betas. select your desired beta from the dropdown and Steam will automatically install that version! The name of the game in your Steam library will be appended with [openxr].

    Selecting the OpenXR Mode when launching Open Brush.

    When you click Launch from within Steam, make sure to select 'Launch Open Brush in OpenXR Mode'!

    Oculus Quest

    We have created a special SideQuest page for installation of the Quest beta. If you are already know what you're doing with SideQuest, proceed onwards! If you haven't used SideQuest before, please take some time to follow their excellent guide on setting up your Quest for development builds.

    Easy Installer (Beta)

    SideQuest have just released a new in-headset installer which you can find on the guide above! If you're using this method, simply search for 'Open Brush Beta' from within the SideQuest app to install the beta. From your app drawer, in the top right, there is a dropdown to filter types of apps. Select it, scroll to the bottom, and select 'Unknown Sources'. You will see an app called 'Open Brush (feature_xr_v2). Click it to begin testing!

    Open Brush (feature-xr-v2) in the Unknown sources section of the Quest app drawer.

    Advanced Installer

    Make sure your Quest is connected to your device. In the SideQuest app on your computer, search for 'Open Brush Beta'. On the app page, click 'DOWNLOAD APP (SIDELOAD)'. The app will install!

    Searching for Open Brush Beta in SideQuest
    Open Brush Beta page, highlighting the download app button.

    In your headset, open the app drawer. In the top right, there is a dropdown to filter types of apps. Select it, scroll to the bottom, and select 'Unknown Sources'. You will see an app called 'Open Brush (feature_xr_v2). Click it to begin testing!

    Oculus Desktop

    Due to the way the Oculus Desktop store versioning works, we can't automate builds without disrupting the main build! Instead, you can access a manual build from Nightly Link.

    nightly.link showing the various builds for xr_v2

    Click the long link beside the name of the build you wish to use (i.e. Windows Rift). A quick reminder that Windows Rift is the build you want if you're using Quest linked to your PC!

    Rift (Oculus Desktop)

    Setting Oculus as active XR Runtime

    Note: before you begin, you may need to set Oculus as your active XR Runtime. this may appear as a banner on the Oculus Desktop app. Go to Settings, General and under 'OpenXR Runtime', click 'Set Oculus as Active'. You may need to restart your PC afterwards. Double click the downloaded zip file. Press the Extract all button, and unzip the folder to a known location. You may want to use your Desktop or Documents folder. Once unzipped, open the StandaloneWindows64-Oculus folder, and double click 'OpenBrush-featurexrvr2.exe' to run the program! Windows may scan the folder for viruses as it's an unknown folder, which will prevent the program launching until complete. This is perfectly normal, and the program will launch by itself once finished.

    What should I be testing?

    In short, everything you can! The previous SDKs were woven throughout the fabric of the app, so our changes impacted a lot of features. We have prepared a list over on our GitHub with suggestions of things to test (anything already ticked is assumed to be working).

    How do I report bugs?

    If you are a GitHub user, please feel free to add a comment to our Issue #249 where we are keeping track of validation. Otherwise, please join our Discord if you haven't already and post a message in the #unity-xr channel, we'll log it on your behalf!

    v2.0
  • To disable the eraser, select the icon again.

  • Note: To erase your last brush stroke quickly, you can also use Undo. To use Undo, press the left side of the palette controller’s disk. You can also use Undo if you accidentally erase a brush stroke.

  • Dropper Tool. To select the brush and color used for a stroke or the color in a reference image:

    1. Position your controller on the brush stroke or the color in an image you want.

    2. Press the trigger to confirm. Your brush type, color and size will be copied.

    3. To disable the dropper, click the icon again

  • Repaint Tool

  • Camera Tool. Use Cameras to save your creation in various formats.

    1. Point your painting controller towards the palette and select Cameras.

    2. On your painting controller, swipe the thumbpad (HTC Vive) or thumbstick (Oculus Rift and Windows Mixed Reality) right or left to access the Camera options.

    3. After selecting your option, your image file will save to the "Open Brush" folder inside "Documents" on your computer.

    4. You can then share photos, videos, and GIFs or your artwork online.

    5. PC users can record still images, animated GIFs or video. The Quest only supports still images and GIFs.

    For better quality you can record . Long-press the camera tool to access the camera settings:

    \

  • Teleport Tool. To virtually hop to a different spot in your environment, use Teleport.

    1. Point your painting controller towards the palette and select Teleport.

    2. On your painting hand, press the thumbpad or trigger to move around the x and y axis.

    3. You will see footprints on the ground, which represent your landing spot.

    4. To disable Teleport, select the icon again.

    Note: The distance which you can teleport varies in each environment.

  • Selection Tool. Use Selection to select and duplicate strokes and models in your scene.

    1. Select strokes using the trigger. You can also flip into deselect mode by tapping the thumbpad (HTC Vive and Windows Mixed Reality) or “A/X” button (Oculus Rift).

    2. If you want to move your selection, grab it as you would any other model in your scene. To delete a selected group of strokes, just throw it away.

    3. Duplicate selections by either: a) holding the thumbpad (HTC Vive and Windows Mixed Reality) or “A/X” button (Oculus Rift) while intersecting your controller with selected strokes or... b) using the same button but whilst moving a selection The first method creates a duplicate slightly offset from the original whilst the second leaves a copy behind at the exact spot where you pressed the button.

    Selection Tray Buttons: Select All

    To select everything in a scene, long press on the Select button on the Tools panel and the Select All button will appear.

    Invert Selection

    To invert a selection that you have just made, long press on the Select button on the Tools panel and the Invert Selection button will appear.

    Toggle Grouping for Selection

    Combines the currently selected strokes into a single group. They will move and scale as one. You can ungroup them easily by clicking again.\

  • Mirror Tool. Use the mirror mode tool to paint symmetrically. To use the tool:

    1. Point your painting controller towards the palette and select Mirror Mode.

    2. To grab and move the mirror, use the Grip button on the sides of your controllers.

    3. To adjust the mirror back to default, grab and move the mirror onto the snapback widget.

    4. To spin the mirror, grab the mirror using the Grip button on the right side of your painting controller. Throw the mirror to spin it in an infinite loop. You can then paint within this loop.

    If you long-press the mirror tool you get the following options:

    The second button is the Mirror Recall button. This will recall a Mirror that is out of reach. (If you like the mirror - you might want to check out the multi-mirror )

  • Straight Edge Tool. Use the straight edge tool to paint in straight lines between two points.

  • Fly Tool

  • Snip Tool (currently beta only)

  • Join Tool (currently beta only)

  • Differences in Beginners vs Advanced modes

    The following tools only appear in Advanced Mode

    1. Dropper

    2. Repaint

    3. Selection

    4. Fly

    5. Snip

    6. Join

    Additionally in Advanced Mode the Environment Panel button moves to the Extras Panel

    Feature: 3D Shapes Tool

    Status: Mostly working. Some improvements to the UI are needed. Ready for beta testing

    Downloads

    • (Rift, Quest via Link cable...)

    • (Vive, Index, Reverb...)

    • (Pico, Pimax etc)

    What does it do?

    The core feature is support for low-poly 3d models that can be modified directly inside Open Brush. Currently the focus is on procedural shapes based on symmetry and repeating patterns.

    What's it good for?

    Creating symmetrical patterns, geometric forms and complex 3d shapes.

    How do I install it?

    Download a build for your headset from the link above and unzip it. You can run the Windows exe directly. To install the Quest apk use SideQuest:

    How do I use the 3D Shapes tool?

    1. (Make sure you've switch off beginner mode) Find the "Experimental Tools" panel which is usually attached to your wand.

    2. There will be a new icon at the bottom that looks like a wireframe cube. Click that to activate the 3D shape tool.

    3. A tray will appear on the right of the panel with some new buttons. You can pick from a range of shapes by clicking the top button "Shape Gallery".

    WARNING! There are currently no limits in place preventing you creating very complex shapes. It's quite easy to make everything super slow and potentially even cause Open Brush to crash.

    The main "3D Shape Tool" buttons

    There are four buttons on the tray that appears when the Polyhedra tool is active:

    1. Shape Gallery

    This opens a popup with a selection of built-in shapes to get you started.

    2. "Create" action

    Clicking this button cycles through the options for what kind of object you create when you click and drag the trigger on your drawing hand:

    • Create a 3D Shape: This will create a 3D shape in the scene based on your current choice of shape. A 3D shape is similar to an imported 3D model except it is generated on the fly based on settings that you choose.

    • Create brush strokes based on shape faces: Instead of creating a 3D shape this uses your current chosen shape as a template to draw brush strokes around the edges of each face.

    • Create brush strokes based on shape edges: This is similar to the above except it creates shorter brush strokes (but more of them). One for each edge in the shape. Experiment with these two different modes. Some will work better for one combination of brush and shape than the other.

    3. "Modify" action

    Clicking this button cycles through the options for what the secondary button on your drawing hand does (the "A" button on the Oculus controller or trackpad click on the Vive controller). In all cases you hold down the secondary button whilst moving your controller over existing editable models in your scene:

    1. Apply settings: picks up the Shape Designer settings from the model and loads those settings into the Shape Designer panel.

    2. Grab settings: Applies the current Shape Designer Settings to the model.

    3. Apply color: Changes all faces on the model to the current selected brush color.

    4. Shape Designer

    This opens a new panel that gives you access to the powerful underlying procedural generation engine. See the section below for detailed information on the Shape Designer

    Known Issues

    1. There's nothing to stop you creating extremely complex shapes that can slow everything down and even cause Open Brush to crash.

    2. Exported scenes work best in the gltf/glb format. Face colours will appear correctly. Currently the various materials don't export. Other formats don't support exporting face colours. (FBX actually does but you'll need to edit the material in your 3d app and set it to use "Vertex colours")

    3. Duplicating models using the selection tool sometimes produces changes in scale.

    The Custom Guide

    (docs coming soon)

    The Custom Mirror

    1. The symmetry mode only affects normal paint strokes. You can't currently use symmetry to create multiple copies of the polyhedra tool.

    2. You can grab the symmetry widget and change it's position and orientation.

    Using the Shape Designer

    (docs coming soon)

    How do I get help

    Come over to the Open Brush Discord: and chat to me ( andybak#5425 ).

    I'm on UK time but I check in fairly regularly.

    Can I see it in action?

    (docs coming soon)

    Feature: Polyhedra

    Status: OUTDATED

    THIS BRANCH HAS BEEN SUPERCEDED BY A NEW COMPLETELY WRITTEN VERSION WITH MANY MORE FEATURES

    See the new 3D Shapes feature instead!

    Downloads

    • (Rift, Quest via Link cable...)

    • (Vive, Index, Reverb...)

    • (Non-VR, Linux, Mac...)

    What does it do?

    Mainly two related things:

    1. Adds a polyhedra tool that can create a wide variety of polyhedra and grid patterns using brush strokes

    2. Adds a custom symmetry tool similar to the existing mirror except it creates multiple strokes for each face of your selected polyhedra or grid

    What's it good for?

    Creating regular patterns and geometry forms.

    How do I install it?

    Download a build for your headset from the link above and unzip it. You can run the Windows exe directly. To install the Quest apk use SideQuest:

    How do I use the Polyhedra tool?

    1. Switch out of beginner mode and you'll see the "Experimental Tools" panel on your wand.

    2. There is a new icon at the bottom that looks like a wireframe cube. Click that to activate the polyhedra tool.

    3. Draw a cube with your brush hand. Click once to start and release when you're happy with the size and rotation.

    4. The "A" button or trackpad left click will cycle through various snapping angles. Try setting it to 90 to draw shapes level with the ground plane

    Known Issues with the polyhedra tool

    1. There's nothing to stop you creating extremely complex shapes that might slow everything down

    2. There's currently no colour controls but you can use the standard recolor tool on your shapes.

    3. Snapping is a bit unpredictable sometimesree paint mode. You need to select the polyhedra tool every time you change brushes.

    4. Scene scale and brush size interact in a slightly confusing way.

    How do I use the new symmetry mode?

    1. The button is on the bottom right of the Experimental tools panel. Use the same panel you used with the polyhedra tool to change the shape that controls the symmetry strokes.

    2. The symmetry mode only affects normal paint strokes. You can't currently use symmetry to create multiple copies of the polyhedra tool.

    3. You can grab the symmetry widget and change it's position and orientation.

    Known Issues with the custom symmetry mode

    1. It's possible to create very complex sketches very quickly.

    2. There's no control over the color variation of the symmetry strokes.

    3. You can't scale the grids. Instead scale your scene

    4. I haven't added any way to control the colours of the additional strokes yet.

    How do I get help

    Come over to the Open Brush Discord: and chat to me ( andybak#5425 ).

    I'm on UK time (currently UTC+1) but I check in fairly regularly.

    Can I see it in action?

    Here's an earlier version of the polyhedra tool:

    Here's a video with terrible audio showing the symmetry tool:

    and another without any audio:

    Yeah. I really need to do better videos. Please share anything you make that I can use to show off the features.

    Feature: Multi-Mirror

    Status: Released in v2.4

    What does it do?

    Big expansion to the mirror to support many different types of symmetry:

    Point symmetry: Symmetry around a point. 7 familiies of axial symmetry plus 3 (soon to be 7) unique polyhedral symmetries.

    Wallpaper symmetry: 17 types of tiling symmetry

    Duplicate selections using symmetry: Create multiple clones of a selection aligned in a pattern

    Draw with multiple colours at the same time: The colour of each stroke can be varied in interesting new ways

    What's it good for?

    Creating symmetrical patterns. Drawing multiple strokes at the same time. Arranging models or images into grids or other regular patterns.

    How do I install it?

    Download a build for your headset from the link above and unzip it. You can run the Windows exe directly. To install the Quest apk use SideQuest:

    How do I use it?

    Hold down the mirror button on the Experimental Panel for a second or two:

    This will bring up the Symmetry settings panel which contains three tabs:

    Point Symmetry

    Point symmetry creates copies arranged around the center of the mirror widget. Each icon selects one of the 14 different types of symmetry. This is the symmetry of molecules and polyhedra. It can create shapes such as stars, explosions, vases, octopi or plants and flowers.

    For the first 7 point symmetry types, the slider controls how many copies are arranged around the center axis. (The other 7 types are based on tetrahedra, cubes and icosohedron and have a fixed number of copies)

    Wallpaper Symmetry

    Wallpaper symmetry repeats your strokes in various types grid pattern - reflecting or rotating in specific ways. You can create wallpaper, floor tiles crystal lattices or any other repeating patterns.

    For all symmetry types you have control over the number of copies in x and y directions. For some you can also change the scale of the grid in both the x and y directions and skew the grid cells themselves in either direction.

    Options

    This screen allows you to vary the colour of each stroke based on waveforms of your choosing. Colors can cycle based on hue, saturation or brightness and the amount, frequency and type of the variance can be precisely controlled.

    Creating Patterns From Existing Brush Strokes

    (This feature currently has some bugs. See )

    You can also create symmetrical copies from existing strokes. Simple select the strokes you want to use and duplicate them in the same way you do without the mirror (Press the secondary button on the controller you paint with)

    Currently disabled while I iron out the bugs

    Creating Symmetrical Patterns from Imported Objects

    As well as duplicating brush strokes, if you have such as images, video or 3D objects then you can select those and create copies that follow the current symmetry settings.

    Be aware that there are currently no limits in place. If you create copies of complex objects or even if you create lots and lots of copies of simple objects, then Open Brush can become unresponsive or even crash.

    Currently disabled while I iron out the bugs

    Known Issues

    1. It's very easy to create so many strokes or duplicates of 3D models that Open Brush becomes unresponsive or even crashes. We plan to add limits and warnings once we figure out how best to calculate them.

    2. Duplicating brush strokes currently positions copies incorrectly if you've transformed the selection since selecting it. A workaround is to deselect and reselect first.

    3. Duplicating brush strokes can position things incorrectly if you've scaled the world or moved the symmetry widget.

    How do I get help

    Come over to the Open Brush Discord: and chat to me ( andybak#5425 ).

    I'm on UK time but I check in fairly regularly.

    Can I see it in action?

    Enzyme Communicationsenzymecomms.com
    (Tilt Brush – advanced applications for healthcare comms)
    https://link.springer.com/article/10.1007/s10055-022-00711-wlink.springer.com
    Virtual Vogueing: How Tilt Brush is Transforming the Design ProcessThe Manor
    https://old.reddit.com/r/TiltBrush/comments/q0bazy/on_tuesday_a_film_i_shot_using_tilt_brush_will_be/old.reddit.com
    'Tilt Brush' Is Being Used to Prototype Levels in This Superhero VR Game by Dream On VRUploadVR
    https://www.sciencedirect.com/science/article/pii/S0197455621001003www.sciencedirect.com
    Tilt Brush: Not Just for Fun and Doodles | LBBOnlineLittle Black Book

    Open Brush Unity SDK

    Using Open Brush with Unity

    About

    The Open Brush Unity SDK allows you to import your Open Brush sketches into Unity. The SDK includes:

    • All of Open Brush’s brush materials

    Exporting to Unreal Engine 5

    How to Import OpenBrush FBX files & edit Materials to appear correctly

    This example uses models that are best viewed without lighting. In UE5's scene view, change the scene lighting to "UNLIT" (top left of window).

    • Drag the FBX from Windows Explorer into the UE5 scene

    • An FBX Import Option menu will come up:\

    Exporting Open Brush sketches to other apps

    Open Brush sketches can be exported by clicking the ‘Export’ button found on the Labs panel. The Labs panel can be found under ‘More…’ on the Tools panel.

    Each sketch exported from Open Brush creates a separate folder in Documents/Open Brush/Exports which contains the geometry in the following formats:

    Format
    PC Only?
    Experimental Mode Only?

    Example Symmetry Plugins

    AlongStroke

    The previous stroke you drew is used as a template and multiple copies of the pointer are spread along it as you draw

    Releases · icosa-foundation/open-brushGitHub
    Open Brushitch.io
      "Export": {
        "ExportBinaryFbx": true,
        "ExportFbxVersion": "FBX201400",
        "ExportStrokeMetadata": true,
        "KeepStrokes": true,
        "KeepGroups": false,
        "Formats": {
          "fbx": true,
          "glb": true,
          "newglb": true,
          "json": true,
          "latk": true,
          "obj": true,
          "stl": false,
          "usd": true,
          "wrl": false
        }
    re-render videos offline

    OBJ

    USD

    JSON

    LATK

    WRL

    STL

    (.glb is closely related to .gltf and most software will support both. We output binary glTF version 2)

    .latk is an interchange format for 3d brush strokes: https://lightningartist.org/

    The .json is a “raw” format which you can use if you need a different file format. See the Open Brush Toolkit for sample Python 2.7 scripts that convert the raw .json to .obj.

    python convert_to_fbx.py "c:\Users\username\Documents\Open Brush\Exports\Untitled_1.json"

    Each script has a set of command-line options that fine-tune the generated file.

    The USD contains both geometry and curve information. If your DCC tool doesn’t support USD, the Open Brush Toolkit contains a Python 2.7 script that can convert the .tilt file to a Collada .dae containing the curves.

    Flipside XR

    1. Follow the instructions for installing and configuring Flipside Creator Tools

    2. Download the .unitypackage for the latest release of the Open Brush Unity SDK

    3. You'll also need the Json.Net.for.open.brush.toolkit.unitypackage from the same page

    4. Add both to your Flipside Unity project

    5. Export your Open Brush sketch and import the .glb file into the Flipside project

    6. Follow the Flipside instructions for uploading a Unity scene as a Flipside Set

    Maya

    After importing the FBX file into Maya you will need to turn off the Alpha is Luminance attribute in the Color Balance section for each texture node. To see the brush colors in the viewport turn on the Display Colors attribute and set Material Blend to Multiply in the Mesh Component Display section on each mesh shape node.

    To render with the vertex colors you can use the mentalrayVertexColors shader node to access the stroke color in your material.

    Mozilla Hubs

    Mozilla Spoke (the Hubs editor) gives an error when you try to import our .glb file directly. However importing first into Blender and then re-exporting will fix this. Not all brushes work correctly but the simpler brushes should import fairly well.

    Sketchfab

    To post to Sketchfab you will need to upload the FBX file and the textures.

    We are working with Sketchfab to have Open Brush import correctly, but if the strokes look wrong you can try opening the 3D Settings Editor in Sketchfab and under the Materials tab set the material properties manually.

    Snapchat Lens Studio🔗

    See this page

    Styly

    To upload your work to Styly, you'll need to remove all traces of the audio-reactivity scripts in the Open Brush toolkit.

    1. Follow the instructions for setting up Styly in Unity here: https://styly.cc/manual/unity-asset-uploader/ but stop when you get to the section about half-way through headed "Upload from Unity to STYLY"

    2. Download the Open Brush Unity SDK unitypackage as described here: https://docs.openbrush.app/user-guide/open-brush-unity-sdk

    3. Delete the following folders from your Unity project window:

      1. ThirdParty/CSCore

      2. ThirdParty/Reaktion

    4. Delete the following files from you Unity project window:

      1. TiltBrush/Scripts:/VisualizerAudioInput

      2. TiltBrush/Scripts:/VisualizerManager

      3. TiltBrush/Scripts/Editor/VisualizerManagerEditor

    5. Also in the project window, drag the entire TiltBrush/Scripts/Gltf folder so it's inside TiltBrush/Scripts/Editor

    6. Carry on where you left off with the Styly docs.

    Unity

    We recommend using the Open Brush Toolkit and the .glb format. Open Brush Toolkit also understands the .fbx format. More info

    Unity WebGL

    You'll need to delete the following 2 scripts if you want to build for Unity WebGL targets: GenericAudioInputEditor.cs and GenericAudioInput.cs

    Unreal Engine🔗

    See this page

    Command-line Exporting

    To export sketches from the command line, use the --export option to specify a file or set of files to export. --export supports wildcards, and multiple files can be specified with a single --export flag. Filenames without a path are assumed to be found in the Open Brush Sketches directory.

    You can override the destination folder of exports using the --exportPath flag.

    We suggest you also specify the -batchmode option if you don’t want the Open Brush window to appear.

    GLTF/GLB

    FBX

    OpenBrush.exe --export Untitled_15.tilt Untitled_2*.tilt C:\Downloads\downloaded.tilt --exportPath C:\Temp -batchmode
    Draw your chosen shape using the trigger on your drawing hand. Click once to start and release when you're happy with the size.

    Create a new custom guide: This creates a new guide based on your current chosen shape. It has the limitation that only convex shapes are allowed so if you have a concave shape the the "convex hull" of it will be used to make the guide.

  • Create a custom mirror: This creates a custom mirror that works in a similar way to the normal mirror tool. However instead of two copies of your brush strokes, the custom mirror can create multiple strokes - one for every face of your chosen shape.

  • Draw brush strokes on faces: Create brush strokes on the model. One brush stroke for every face.
  • Draw brush strokes on edges: Create brush strokes on the model. One brush stroke for every edge.

  • You can't scale the custom mirror. Instead scale your scene.
  • Custom mirror stroke colours are sometimes unpredictable.

  • Oculus Quest 1
    Oculus Quest 2 or 3
    Oculus PC VR
    SteamVR and other PC VR
    Other Builds
    Code
    https://uploadvr.com/sideloading-quest-how-to/
    https://discord.openbrush.app
    The "Generate" panel showing the main shape categories
    The "Modify" panel showing 3 modifiers applied to the shape.
    The "Appearance" panel showing color and material options.
    The "Presets" popup where you can save the shapes you've created.
  • The panel that opens when you first clicked the button let's you select various shape.

  • If you want to change the default colours simply add some custom colours at the bottom of the standard colour picker panel.

  • Oculus Quest
    Oculus PC VR
    SteamVR
    Other Builds
    https://uploadvr.com/sideloading-quest-how-to/
    https://discord.openbrush.app
    Polyhedra Tool
    Custom Symmetry
    A few symmetry modes move the main pointer so your main stroke is rotated somewhere else. It takes a bit of getting used to but it doesn't actually prevent you painting in these modes.
  • The slider on the settings panel can glitch the Open Brush UI if you drag it past it's limits.

  • https://uploadvr.com/sideloading-quest-how-to/
    known issues
    imported some media
    https://discord.openbrush.app
    Some early experiments with spinning mirrors

    An importer script that automatically assigns Open Brush materials to imported .glb files

  • Open Brush’s audio reactivity functionality that make brushes react to music

  • Requirements

    The SDK has these requirements:

    • Your project must use Unity 2019.4 or higher

    • Macs running on Apple Silicon (i.e. M1 or M2) need to remove Audio Reactivity to fix errors related to "CSCore".

    Getting the code

    Download the latest version of the toolkit from: https://github.com/icosa-foundation/open-brush-toolkit/releases

    The SDK comes in the form of a Unity Package. To import:

    1. Open Unity

    2. Create a project or open an existing one

    3. Double click the downloaded .unitypackage file, or go to Assets > Import Package > Custom Package.

    4. Import the package

    Importing a sketch

    To use a Tilt Brush sketch inside of Unity, you need to export it and copy the exported .gltf file into your project. You do _not _need any of the .png files that come with the export. The SDK will use its own, Tilt Brush materials instead.

    The SDK will process .glb files on import and assign the correct materials.

    To export a sketch:

    1. Open Tilt Brush, load your sketch

    2. Click the [...] icon in the settings area of your hand menu

    3. Click the **Labs **icon

    4. Hit Export in the floating window that pops up

    To import a sketch into your scene:

    1. Find the exported files:

      1. On a PC or Mac look in Documents/Open Brush/Exports

      2. If you created the sketch on a standalone Quest thenconnect it to your PC/Mac by following these instructions and then browse to the Quest in Explorer/Finder and look in Internal Shared Storage/Open Brush/Exports

    2. Copy the .glb file into your Unity project

    3. Drag the file from the Project window into the Hierarchy

    Notes:

    • The Open Brush Unity SDK doesn’t load .tilt files.

    • You don’t need to copy the textures included with the .glb into your project

    Tips

    Fixing CSCore errors (or other errors related to Audio Reactivity)

    At the moment the plugin used for Audio Reactivity doesn't work on some platforms. If you see errors related to "CSCore" or anything that looks audio related deleting the following files from your project:

    1. The folder ThirdParty\CSCore

    2. The folder ThirdParty\Reaktion

    3. These files:

      1. TiltBrush\Scripts\VisualizerManager

      2. TiltBrush\Scripts\VisualizerAudioInput

      3. TiltBrush\Scripts\Editor\VisualizerManagerEditor

    "My brushes look different to Open Brush" (Linear vs Gamma)

    For historical reasons Open Brush uses gamma mode for color blending. We may offer the option to switch to linear in the future but it will change the appearance of sketches so gamma will always be an option when the hardware allows it.

    If your Unity project is set to linear mode (Projects > Player Settings) then imported sketches may look different. For example here's some smoke brush strokes in Open Brush:

    And here's the same sketch in Unity set to linear mode:

    The v11 toolkit shaders support both sRGB (Gamma) and Linear color spaces. The shaders are set to Gamma mode by default. If you wish to use Linear, add this call somewhere in your program.

    Note: while this improves the colour accuracy, due to fundamental differences between linear and gamma rendering, brushes may still not exactly replicate the look of their gamma counterparts.

    Audio Reactivity

    You can make the brushes wiggle to the audio in your scene:

    1. Drag the** [Tilt Brush Audio Reactivity] prefab** into your scene

    2. Add an audio source to your scene, if there’s none

    If the brushes aren’t moving, you can select the prefab in Play mode to visualize the audio data the shaders are receiving:

    Bloom

    You can achieve_ an Open Brush look_ by adding Bloom, using Unity’s built-in shaders:

    1. Import the Standard Assets “Effects” package (Assets menu / Import Package / Effects)

    2. **Important: **Enable your camera’s HDR checkbox

    3. Add the Bloom post-processing effect, these are recommended settings:

    Internally, Open Brush uses a modified version of Sonic Ether bloom, which has been released as open source.

    Make sure to select:
    Advanced > Vertex Color Import Option [REPLACE]

    Organize Materials, Textures, Mesh Files

    • Upon importing the FBX, the Content Drawer will include the meshes and materials

    • Create a subfolder for MATERIALS and TEXTURES

    • Select the imported materials, drag and drop them into the newly created MATERIALS folder\

    • The materials are pretty terribly named. I highly recommend renaming them. The brush material names are at the end of the filename:\

    • From Windows Explorer, drag optimized PNG brush textures into the UE5 TEXTURES folder:\

    • From the CONTENT DRAWER, drag and drop the meshes into the scene. I recommend creating a folder in the OUTLINER window and drag all the mesh objects into there:\

      Selecting all the model mesh objects, it may help to update these DETAILS:

      Location: 0,0,0 Scale: 0.5,0.5,0.5

    • I also recommend turning off visibility of all the other non-mesh objects in the OUTLINER tab (e.g. Atmospheric Fog, Floor, etc.)\

    Associate Vertex Colors, Textures, Opacity to Materials

    Edit Vertex Colors to Materials that only need Vertex Colors:

    Material Name
    NODE: Vertex Color
    NODE: Texture Sample
    Material Details

    Flat

    ✓

    No

    Blend Mode: MASKED ☑ Two Sided

    MatteHull

    ✓

    No

    Blend Mode: MASKED ☑ Two Sided

    UnlitHull

    ✓

    • In CONTENT DRAWER > MATERIALS, double click the "Flat" material file. The Material Graph window will popup

    • Right click on the empty grid, type in VERTEX COLOR to add the node

    Connect the top white dot to BASE COLOR in the "FLAT" window.

    • Click on "FLAT" so you can see its DETAILS on the left menu

    • Update: BLEND MODE - MASKED Two Sided - [checked]​

    That's it! Be sure to save these edits or CTRL + S. The edits won't show up on the main scene window until these Material changes are saved.

    • Repeat for the other three materials listed above that only need Vertex Colors associated to the materials.

    Edit Materials that need Vertex Colors and Texture Sample:

    Material Name
    NODE: Vertex Color
    NODE: Texture Sample
    Material Details

    DiamondHull

    ✓

    ✓ RGBA connects to Opacity Mask

    Blend Mode: MASKED ☑ Two Sided

    Dots

    ✓

    ✓ RGBA connects to Opacity Mask

    Blend Mode: MASKED ☑ Two Sided

    DoubleTaperedMarker

    ✓

    • Do the same steps above to add VERTEX COLOR to the BASE COLOR

    • Do the same steps above to update the Material Details to (same as before): BLEND MODE - MASKED Two Sided - [checked]

    • Right click the empty grid space and type in TEXTURE SAMPLE to bring up a node where you'll associate the texture png files

      • Click on the TEXTURE SAMPLE node window so you can edit the DETAILS

      • In the section for "Material Expression Texture Base" click on the dropdown to select the texture name that matches with the material name.

        • NOTE: The DoubleTaperedMarker material can use the "Marker" texture

      • Connect the TEXTURE SAMPLE node's "RGBA" dot to the Material's "Opacity Mask" dot

    • REPEAT for the other materials with same properties

    Edit Materials that need Vertex Colors, Texture Sample, and Transparency:

    Material Name
    NODE: Vertex Color
    NODE: Texture Sample
    Material Details

    Highlighter

    ✓

    ✓ RGBA connects to Opacity

    Blend Mode: ADDITIVE ☑ Two Sided

    Smoke

    ✓

    ✓ RGBA connects to Opacity

    Blend Mode: ADDITIVE ☑ Two Sided

    SoftHighlighter

    ✓

    • Do the same steps above to add VERTEX COLOR to the BASE COLOR

    • Update the Material Details: BLEND MODE - ADDITIVE Two Sided - [checked] "Additive" will allow these brushes to appear semi-transparent, foggy, smokey.

    • Do the same steps as above to associate textures to TEXTURE SAMPLE node

    • Connect the TEXTURE SAMPLE node's "RGBA" dot to the Material's "Opacity" [not Opacity Mask as previous materials]

    • REPEAT for the other materials with same properties

    Make sure to save all of your Material window edits!

    Make sure to view this in "unlit" mode.

    Also hide the Light Source, etc to prevent any shadows from showing up in the scene.

    Reward yourself with ice cream.

    Docs contributed by Estella Tse. Additional thanks to Steve Bowler

    Parameters
    • Point Spacing: The distance to space out the copies along the stroke

    AutoLathe

    Like spinning the mirror by hand but with precise control

    Parameters

    • Speed: How fast to spin

    • Angle X: The axis tilt in the X direction

    • Angle Y: The axis tilt in the Y direction

    Boids

    A flock of pointers follows your hand using simple rules to control how they fly

    Parameters

    • Number of copies: How many boids in the flock

    • Separation Amount: How strongly each boid tries to stay away from others

    • Alignment Amount: How closely the boids try and follow the flocks path

    • Pointer Attraction: How strongly each boid is attracted to your brush position

    Ducklings

    The pointers follow your brush position but each one moves towards a point where your hand was further back in time

    Parameters

    • Copies: The number of strokes to draw at once

    • Delay per copy: How far back in time (in frames) for each copy

    • Amount: How far between the current and past position to move towards. 0.5 is the midpoint between past and current

    EllipseAround

    Copies of your stroke forming an ellipse - with optional color shifts

    Parameters

    • Copies: The number of strokes to draw at once

    • Eccentricity: How elliptical the shape is

    • Axis Consistency: Controls how much the elliptical axis follows your brush position

    Frame

    A simple frame of points following your brush position

    HoldFirstClick

    Like Many Around except the widget always moves to where you start drawing

    Parameters

    • Copies: The number of strokes to draw at once

    ManyAlong

    Linear copies of your stroke with optional color shifts

    Parameters

    • Copies: The number of strokes to draw at once

    • Distance: How far each copy is from the next

    ManyAround

    Radial copies of your stroke with optional color shifts

    Parameters

    • Copies: The number of strokes to draw at once

    Pole

    Multiple copies of your brush spaced between your left and right hand positions

    Parameters

    • Copies: The number of strokes to draw at once

    PolygonAround

    Copies of your stroke forming an polygon

    Parameters

    • Copies: The number of strokes to draw at once

    • Sides: The number of sides of the polygon

    RectangleAround

    Copies of your stroke forming an rectangle

    Parameters

    • Number of points along width: How many points along the sides

    • Number of points along height: How many points along the top and bottom

    • Spacing: The distance between each point

    • Exterior Only: Whether to create copies just around the perimeter or also fill in the middle

    Spin

    Multiple copies of your brush spinning around your actual brush position

    Parameters

    • Copies: The number of strokes to draw at once

    • Speed: How fast the extra pointers are rotating

    • Radius: The radius of the circle they are rotating around

    SuperEllipseAround

    Copies of your stroke forming a superellipse

    Parameters

    • Copies: The number of strokes to draw at once

    • n: The parameter that controls the overall shape of the superellipse

    • Eccentricity: How elliptical to make the shape

    • Axis Consistency: Controls how much the elliptical axis follows your brush position

    Svg

    An example of using an SVG file as a template for symmetry patterns

    SvgAround

    Similar to SVG but centered around the Symmetry Widget

    Parameters

    • Point Spacing: The distance between each pointer around the shape

    ✔

    LATK

    ✔

    ✔

    OBJ

    ✘

    ✔

    STL

    ✔

    ✔

    USD

    ✘

    ✔

    WRL

    ✔

    ✔

    beta
    experimental branches
    http://wearcam.org/ece516/lab2.htmwearcam.org
    Silk Brushmsub2.github.io
    NEWS: MultiBrush by Rendever Now Available on SideQuest, Providing Artists with a Collaborative Tool in Virtual Realityblog.rendever.com
    https://www.tkbala.com/tutorivrwww.tkbala.com
    Some early experiments with spinning mirrors

    Feature: Improved Import/Export

    Status: Released in

    What does it do?

    Adds new optional GLTF import and export workflows. Allow import of lights, breaking apart of imported models and other new features that the updated libraries enable.

    Experimental Brushes

    This is a list of the brushes that are only available in any "Experimental Mode" Builds:

    Brush Name
    Notes

    Exporting to Snapchat Lens Studio

    Tilt Brush → Blender → Snap Lens Studio

    NOTE: Not all Tilt Brush brushes will export (e.g. particle brushes) The most reliable are the flat brushes and the Wire brush. Also, this process might not be compatible with Tilt Brush on the Quest as the export function works differently than the Rift.

    Shader.EnableKeyword("TBT_LINEAR_TARGET");
    Another early test of the feature
    Another early test of the feature
    How do I install it?

    Download a build for your headset from the link above and unzip it. You can run the Windows exe directly. To install the Quest apk use SideQuest: https://uploadvr.com/sideloading-quest-how-to/

    How do I use it?

    To switch to the new importer (which replaces GLTFast that we added in v2.4 with UnityGLTF you need to edit your Open Brush config file and add this entry after "Flags":

    We've changed how export in general is configured. Previously all supported formats were exported whether you needed them or not. Some were pretty slow for large scenes (STL - looking at you) and you probably only needed a couple of them. Now you can choose which are available using the config file:

    ExportBinaryFbx and ExportFbxVersion are existing options - but the rest of the entries here are new.

    • ExportStrokeMetadata: todo

    • KeepStrokes: todo

    • KeepGroups: todo

    • Formats: Each item in here corresponds to an existing export format except for "newglb" which is a glb file but we use the new export code to generate it. Note that formats not supported on your platform will be ignored. See below for platform support.

    Import Differences between GLTFast (existing) and UnityGLTF (new)

    Extensions supported by GLTFast but not UnityGLTF:

    • EXT_mesh_gpu_instancing

    • KHR_materials_pbrSpecularGlossiness (legacy extension - superseded by KHR_materials_specular which is only supported by UnityGLTF)

    Extensions supported by UnityGLTF but not GLTFast:

    • KHR_materials_clearcoat

    • KHR_materials_emissive_strength

    • KHR_materials_ior

    • KHR_materials_iridescence

    • KHR_materials_specular

    • KHR_materials_transmission (soon)

    • KHR_materials_volume (soon)

    • MSFT_lod

    Extensions supported by both:

    • KHR_draco_mesh_compression

    • KHR_lights_punctual

    • KHR_materials_unlit

    • KHR_mesh_quantization

    • KHR_texture_basisu

    • KHR_texture_transform

    (The above list may change as we implement missing features in UnityGLTF. GLTFast also has announced plans to support KHR_materials_variants, EXT_lights_image_based and KHR_materials_transmission)

    UnityGLTF has some other differences:

    • Model hierarchy should be faithfully preserved. GLTFast on the other hand doesn't support sub-meshes so any mesh that contains multiple materials will be split into separate objects. (this might be desirable in some cases)

    • In general 3d models should be more robustly handled if you round-trip between Open Brush and other 3D apps

    Please report any other differences you find. The reason we are keeping both importers around is to gather feedback on their strengths and weaknesses.

    Differences with the new UnityGLTF export

    The use of the new exporter is currently optional and we will continue to support the old exporter until the new one is a full replacement.

    • Currently - if you use the Open Brush Toolkit Unity SDK then use the existing exported GLB file

    • Use the existing exporter for uploads to Icosa.

    • Similarly - if you use the Icosa three.js loader this works best with the existing exporter

    • The new GLB export should work better in Blender and other 3D animation apps although we still have work to do to fix support for particle brushes, transparent brushes and other features.

    • Imported 3D models will export much better with the new GLB exporter

    • In general new features in the or from other will work better using the new exporter.

    Platform Support

    Format
    Android/iOS (Standalone VR)
    PC (Tethered VR)

    FBX

    ✘

    ✔

    GLB

    ✔

    ✔

    NEWGLB

    ✔

    ✔

    JSON

    ✔

    Breaking Apart Imported Models

    This build supports a new feature - The existing "group/ungroup" button on the pop-out tray that appears when you activate the Selection Tool now works on imported models - if they consist of multiple parts. Just select a single imported model and if it does have sub-parts the button will show "ungroup" as an option - the same as if you select a normal grouped set of objects.

    Importing Lights

    If your imported model contains lights then these will appear in the scene and will act upon other objects the same as the Environment Lights. Furthermore imported lights support point lights and spot lights - whereas the existing environment lights only support directional lights.

    Known Issues

    If you break apart a model containing lights, the lights themselves can't be selected or moved.

    How do I get help

    Come over to the Open Brush Discord: https://discord.openbrush.app and chat to me @andybak).

    I'm on UK time but I check in fairly regularly.

    Can I see it in action?

    v2.8

    3D Printing Brush

    Tube Toon Inverted

    Waveform FFT

    Waveform Particles

    Waveform Tube

    Wireframe

    Bubble Wand

    Candy Cane

    Buggy. Breaks "Undo"

    Charcoal

    Digital

    Double Flat

    Drafting

    Use with the "" button

    Dry Brush

    Duct Tape (Geometry)

    Fairy

    Feather

    Fire2

    Gouache

    Guts

    Tree

    Buggy. Breaks "Undo"

    Ink (Geometry)

    Keijiro Tube

    Lacewing

    Leaky Pen

    Wire (Lit)

    Lofted (Hue Shift)

    Marbled Rainbow

    Muscle

    Mylar Tube

    Braid

    Buggy. Breaks "Undo"

    Race

    Rain

    Rising Bubbles

    Single Sided

    Smooth Hull

    Snowflake

    Buggy. Breaks "Undo"

    Space

    Sparks

    Square Flat

    TaperedHueShift

    Tapered Wire

    Leaves2

    Geom/Thick (Duct Tape)

    Tube (Highlighter)

    Wind

    Concave Hull

    Dance Floor

    Dot Marker

    Faceted Tube

    Plasma

    Tilt Brush to Blender:
    • NOTE: Tilt Brush’s settings exports the FBX as an ASCII model. Blender won’t accept it, and you’ll receive an error message in Blender: "ASCII FBX files are not supported"\

    • To change the Tilt Brush FBX configuration from ASCII to Binary, follow these instructions to set up your Tilt Brush.cfg file: https://docs.google.com/document/d/11ZsHozYn9FnWG7y3s3WAyKIACfbfwb4PbaS8cZ_xjvo/preview#heading=h.g9ac8b39hgn0\

    • Add this CFG setting if it's not already there:

    • Within Tilt Brush (in VR):

      • Swipe to the Tools panel

      • Select "More Options..." > Labs > Export.

      • An .fbx file, brush texture, and geometry will be saved to your desktop computer’s Documents/Tilt Brush/Exports folder.\

    • For most optimization, consider taking the exported .PNGs and processing them thru to compress them even more.

    In Blender

    This helps merge vertices that are close together, and saves on polys

    • On the MESH subtab, go to Clean-up > Decimate Geometry\

    • In the pop-up menu for Decimate, enter the ratio of how much to decimate. I entered 0.25. (https://drive.google.com/file/d/1qSM1ss9mMXxbh689WwgDVJP8ZIxPjGkE/view?usp=sharing) \

    • Export the FBX

    Blender to Snap Lens Studio:

    • Import the decimated FBX model from Blender\

    • Rename Materials, (ex: from “13981290382_Marker” to “Marker”)\

    • Drag and drop the TinyPNG optimized imgs into the Lens Studio > Resources > Textures folder\

    • In the Resources > [ 3D Model Name ] folder > Materials, select the Material.\

    • In the Inspector for the Material:

      • For the Blend Mode, select anything other than “Disabled” — I preferred Normal or Alpha to Coverage\

      • For the Vertex Color dropdown, select “Base Color”\

      • For the Base Texture, check to enable, add the Tilt Brush texture here

    No

    Blend Mode: MASKED ☑ Two Sided

    Wire

    ✓

    No

    Blend Mode: MASKED ☑ Two Sided

    ✓ RGBA connects to Opacity Mask

    Blend Mode: MASKED ☑ Two Sided

    Embers

    ✓

    ✓ RGBA connects to Opacity Mask

    Blend Mode: MASKED ☑ Two Sided

    Marker

    ✓

    ✓ RGBA connects to Opacity Mask

    Blend Mode: MASKED ☑ Two Sided

    ✓ RGBA connects to Opacity

    Blend Mode: ADDITIVE ☑ Two Sided

    Logo
    Logo
    Logo
    Logo

    Using Open Brush without a VR headset

    This page has been update to reflect changes in the current beta version. Sketch Viewer mode is a new feature and Monoscopic Mode was previously only available as a separate download.

    Desktop Mode

    If you launch Open Brush without a headset attached (platforms where we don't currently have VR support), the app will start in "Sketch Viewer Mode" where you can load any of the available sketches and navigate around with the keyboard and mouse or the touchscreen.

    • Use the mouse or touch to look around

    • Press I to invert up/down

    • W,A,S,D: move forward/back/left/right

    • Q,E: move up/down

    On touchscreen devices there are onscreen buttons to emulate W, A, S and D.

    If you do have a VR headset attached you can still access Sketch Viewer Mode by adding a "DisableXrMode" entry to your in the "Flags" section and setting it to true. For example:

    You can return to normal either by removing the entry or by setting it to false.

    Plugins and Scripting in Desktop Mode

    Another great use case for Desktop Mode is in conjunction with either or both the and

    In fact - we've included a script designed to show how you can control and configure Open Brush and trigger plugins from your browser. Just open while Open Brush is running. (this also works in VR but is especially useful in desktop mode)

    Monoscopic Mode

    Open Brush has got a secret mode where it can be used without a VR headset - and even works on Mac! This mode was never released to the public and is clunky in places.

    It also works very nicely when using Open Brush via the allowing you to control Open Brush from a web browser.

    Activating Monoscopic mode

    You can access Monoscopic mode by adding a "EnableMonoscopicMode" entry to your in the "Flags" section and setting it to true. For example:

    You can return to normal either by removing the entry or by setting it to false.

    Controlling Monoscopic mode

    1. Alt+mousing will rotate your viewpoint.

    2. Panels become focused when roughly centered in your view. Your cursor is then locked to the panel boundary making it easier to click the buttons.

    3. Dragging with the right button down will bring the drawing plane nearer or further.

    4. Ctrl+mouse drag will rotate the drawing plane

    Other Keyboard Shortcuts

    The file Scripts/InputManager.cs lists all the keyboard controls. Also see However many aren’t relevant, aren’t implemented or only apply in particular modes. The more useful ones are listed below.

    Logo

    Other Resources

    This page lists various useful sources of information for using or tinkering with Icosa Gallery and Open Brush and about the community around them both.

    If you’re mainly interested in getting into the actual Open Brush codebase then you probably want to look at the as well.

    There’s some really useful info in the last that isn’t included here.

    Discussions and Questions

    Get Involved!

    Artists, Bloggers, Content Creators and anyone

    • Post your work on social media and make sure to name check us to spread awareness.

    https://nightly.link/icosa-foundation/open-brush/workflows/build/feature%2Fxr_v2nightly.link
    SideQuest VR apps and games for Meta Quest headsets, PCVR, Early Access, and sideload appsSideQuest - Oculus Quest Games & Apps including AppLab Games ( Oculus App Lab )
    SideQuest page link for those that know what to do!
     "Import": {
        "UseUnityGltf": true
      }
      "Export": {
        "ExportBinaryFbx": true,
        "ExportFbxVersion": "FBX201400",
        "ExportStrokeMetadata": true,
        "KeepStrokes": true,
        "KeepGroups": false,
        "Formats": {
          "fbx": true,
          "glb": true,
          "newglb": true,
          "json": true,
          "latk": true,
          "obj": true,
          "stl": false,
          "usd": true,
          "wrl": false
        }
    "Export": {
       "ExportBinaryFbx": true,
       "ExportFbxVersion": "FBX201400"
    }

    ✔

    LATK

    ✔

    ✔

    OBJ

    ✘

    ✔

    STL

    ✔

    ✔

    USD

    ✘

    ✔

    WRL

    ✔

    ✔

    beta
    experimental branches
    Toggle Drafting Mode
    Docs contributed by Estella Tse. Additional thanks to Jose Andres Rosero
    https://tinypng.com/
    Logo
    Join the
    or other Open Brush related groups. Give feedback to help us prioritize. support other users who need help.
  • Tell people about Open Brush in places where digital artists already hang-out and let them know what we're up to.

  • Contribute to the docs - send in corrections or improvements or fill in any gaps you find. (We have a TODO list just for the docs)

  • Create tutorials or guides. Show people the techniques you've developed or tricks you've discovered.

  • Help us improve and document workflows to other content creation apps. Share your experiences and pain points.

  • Try out the beta version or one of the experimental builds and share bugs you find or any other feedback.

  • Unity/C# Developers

    • Download the repo and read the developer notes and start tinkering.

    • Create your own fork, add a feature, fix a bug and send us a pull request.

    • Help improve to developer docs or create a developer tutorial

    Other Devs: Javascript/Processing/Python/anything

    • Check out the API and make something cool with it

    • Create a wrapper library or other integration to automate or add features via the API

    • Tell people about our API or suggest new use-cases or features

    • Create tutorials or live stream yourself using the API to do stuff nobody else is doing.

    UX/UI Designers

    • Suggest improvements to the app itself or help us plan new features.

    • Help out on the main website or the docs

    • If you know a little scripting then prototype something using the API. Or partner with a dev to make an innovative add-on tool.

    Teachers, Academics, Researchers in any field

    • Open Brush is fully open source. That makes us unique among creative VR apps - you can change how Open Brush works and tailor it to fit specific niche purposes.

    • Open Brush is also a brilliant place for students to learn what it's like to contribute to a real-world open source project. Any of the roles mentioned elsewhere on this page could be valuable experience for students across a range of disciplines

    • Use Open Brush as part of your teaching or research and then share/publish your findings.

    • Come and talk to us. Either email or via the Discord. Let us know your ideas about using Open Brush in new ways.

    Media, PR or Marketing people

    • We suck at marketing. We need help telling the world how great we are. Write about us or help us write about us!

    • Can you believe there's people who don't know we're completely open source and volunteer-run?

    • And they don't know about all the cool stuff we've been doing. Help us get the word out.

    Billionaires

    Enough funding for a couple of full-time staff would make a vast difference. That's small change to you, right? :-)

    Discord
    Logo
    Hold shift to move faster

    Clicking in the game window will capture your mouse cursor. Escape will return full control (so you can interact with Unity etc)

  • In most cases you can alt+mouse to left or right to view the tool panels and choose tools/brushes with the mouse.

  • Rotating with “Alt” whilst pressing shift will allow you to move the panel you were currently focused on.

  • Sometimes panels appear in weird places. Try looking behind you or down at your feet.

  • Space

    Resets the UI not the sketch

    Undo

    Z

    Redo

    X

    SaveNew

    S

    ExportAll

    A

    ViewOnly

    H

    Doesn't disable drawing. Just hidesUI

    PreviousTool

    LeftArrow

    5 tools are available: sketch surface, brush selection, color selection, BrushNColor, Erase

    NextTool

    RightArrow

    CycleSymmetryMode

    F2

    Export

    E

    StoreHeadTransform

    O

    Use with Right Shift

    RecallHeadTransform

    O

    (without Right Shift)

    ResetScene

    Return

    Doesn't delete sketch

    StraightEdge

    CapsLock

    Buggy

    Save

    S

    PositionMonoCamera

    Alt

    Action

    Shortcut

    Notes

    LockToHead

    LeftShift

    Use with Alt. Can move panels with this.

    PivotRotation

    LeftControl

    Use with Alt

    Scale

    Tab

    Only when not drawing. Hold tab and move mouse up or down to scale tool

    Open Brush config file
    HTTP API
    Plugins
    http://localhost:40074/examplescripts/remotecontrol.html
    API
    Open Brush config file
    Open Brush: Keyboard Controls and VR Input

    Reset

    {
      "Flags": {
        "DisableXrMode": true
      }
    }
    {
      "Flags": {
        "EnableMonoscopicMode": true
      }
    }

    Join our Discord

  • Threads and forum posts from Discord are mirrored here: Open Brush on AnswerOverflow

  • We are mods on the Tiltbrush subreddit It's pretty quiet but we check in occasionally.

  • Same for Open Brush Discussions on Steam

  • Social media:

    • https://twitter.com/openbrushapp

    • https://www.threads.net/@openbrushapp

    • https://www.instagram.com/openbrushapp/

  • Developer Resources:

    • Developer Notes

    • Open Brush Feature Tracking (known forks and features)

    Other Resources

    • A good explanation for non technical people about “Open Source and Tilt Brush”: Shameless Mayhem - Teaching Tilt Brush: Going Open Source

    • Unity Downloads:

      • Download Unity - Personal Use

    • Our Discord Bots: Bot

    • (big list of tutorials, tweets, videos, ideas etc)

    Community Creations:

    Custom brushes, new features and multiplayer interaction social posts.

    Date Posted
    Name
    Platform
    Link
    Subject

    1-28-2021

    PunktVR

    Twitter

    Dandelion Brush

    1-28-2021

    PunktVR

    Twitter

    Lacey Leaf Brush

    A big list of random stuff here: https://docs.google.com/spreadsheets/d/1exi7irQ35e8A9LZ6-ujVpLCF_vwBRclM1-iHBYenwBs/edit#gid=0

    Usage & Policy Guidelines

    _Open Brush.._In progress

    Public Assets Folder

    Google - Tilt Brush

    Tilt Brush Brand - Open Source Code Guidelines

    Tilt Brush Open Source Code

    Tilt Brush Brand Guidelines under (EULA License)

    Tilt Brush Media Kit

    Apache 2.0 License

    Contribute by Supporting Us or Getting Involved

    Make a donation

    https://opencollective.com/icosa

    Developer Notes
    TIlt Brush release notes

    Example Pointer Plugins

    Dashes

    Stops and restarts the stroke at regular intervals as you draw resulting in a dashed line.

    1-29-2021

    Open Brush

    Youtube

    https://www.youtube.com/watch?v=Y_9-cof7js4&feature=emb_logo

    Experimental Brushes display

    1-28-2021

    Andybak / Cabbibo

    Twitter / itch.io

    https://twitter.com/andybak/status/1354865232871632896

    Using https://cabbibo.itch.io/fantasy-crystals

    Crystal shaders

    1-29-2021

    M2

    Twitter

    https://twitter.com/msub2official/status/1355069506230636548

    WebXR version called - Silk Brush

    1-29-2021

    PatrickHackett

    Twitter

    https://twitter.com/phacktweets/status/1355206906441129992

    Youtube Brush

    2-1-2021

    SabbyLife

    Youtube

    https://www.youtube.com/watch?v=fMRLZS5cMRc https://youtu.be/xgv88VY6-1s

    Hearts, Jelly Brush, & Seed Brushes

    Download Unity - Business Use
    Time Zone Conversion
    Open Tilt Brush Documentation
    Open Brush Trello
    @andybak's personal open brush trello
    https://twitter.com/punktvr/status/1354842220361297920
    https://twitter.com/punktvr/status/1354900422503362561
    Logo
    Logo
    Parameters
    • Frequency: How many dashes there are in a given distance. Shorter values gives a result closer to a dotted line.

    • Spacing: Controls the spacing between dashes

    Tips

    If you use this in conjunction with Lazy Input Mode then you'll need to draw very slowly on the default settings Dashes.

    How it works

    The script callsBrush:ForcePaintingOn and Brush:ForcePaintingOn based on the value of Brush:DistanceDrawn

    GridFollow

    Locks movement of the pointer to either the x, y or z axis depending on which direction your hand is mostly moving.

    Parameters

    • Speed: How fast the pointer can move as it tries to keep up with your hand movements

    • Frames Between Changes: To avoid creating weird unintended artifacts, the plugin ignores changes of direction that happen too soon after the last one. You can control how many frames a direction is "locked in" here.

    Tips

    Draw slowly and deliberately. It can be tricky to get the hang of initially.

    LaserBeam

    The pointer continues moving in the direction you were pointing when you initially pressed the trigger. Pew pew...

    Parameters

    • Speed: The speed of the beam

    Tips

    You definitely want to try this in conjunction with Symmetry Plugins - especially if you also spin the mirror widget.

    Loops

    The pointer moves around a circlular path with your current hand position as it's center.

    Parameters

    • Speed: The speed of the pointer

    • Radius: The size of the circle it moves around

    Missile

    Similar to [LaserBeam](example-pointer-plugins.md#laserbeam) except that you can steer the brush stroke as it moves.

    Parameters

    • Speed: The speed of the missile

    Oscilloscope

    Control your pointer with multiple waveforms to create patterns

    Parameters

    • X Waveform Type: The waveform used along the x axis

    • X Frequency: The frequency for the x axis waveform

    • Y Waveform Type: The waveform used along the y axis

    • Y Frequency: The frequency for the y axis waveform

    • Y Phase: The phase of the y waveform relative to x

    • Radius: A scaling factor applied to both axes

    Tips

    The values for waveform type are as follows:

    • 0=Linear

    • 1=Cosine

    • 2=Triangle

    • 3=Sawtooth

    • 4=Square

    • 5=Pulse(0.8)

    • 6=Pulse(0.2)

    • 7=Exponent

    • 8=Power(2)

    • 9=Power(0.5)

    • 10=Parabolic

    • 11=Exponential Sawtooth

    • 12=Perlin Noise

    • 13=White Noise

    • 14=Brown Noise

    • 15=Blue Noise

    PolygonBrush

    The brush draws a path around your current hand position similar to [Loops](example-pointer-plugins.md#loops) - except the path is a polygon instead of a circle.

    Parameters

    • Points: How many sides the polygon has

    • Size: The outer radius of the polygon

    RainbowStrokes

    At regular intervals, ends a stroke and starts a new one with a different color. The effect is similar to dashes but with the smallest possible gap between sections of the stroke.

    Parameters

    • Rate: The number of frames between color changes.

    • Hue Shift Frequency: How fast to cycle the hue

    • Hue Shift Amount: How much the hue changes

    SineWave

    Moves the pointer in a simple wave pattern as you draw.

    Parameters

    • Frequency: How close together the peaks of the waveform are

    • Amplitude: The height of the waveform

    Spherograph

    Creates spherical patterns around the initial point you start drawing. The distance you move affects the patterns progress but the position is always centered around the initial point.

    Parameters

    • U Scaling: The rate of change of the pattern horizontally around the sphere

    • V Scaling: The rate of change vertically around the sphere

    • Radius: The size of the sphere

    Spirals

    The brush stroke moves in a circle but the radius increases the longer you keep the trigger pressed.

    Parameters

    • Speed: Controls the tightness of the spiral via changing the rate at which the pointer rotates around the brush position

    • Radius: The overall size of the spiral

    StringArt

    Additional lines are drawn from the initial point you started drawing to your current brush position.

    Parameters

    • Rate: How many frames to wait before drawing another connecting line

    Terrain

    As you draw you only control the x and z position of the stroke. The y position (the height) is determined by a noise function that maps out hills and valleys.

    Parameters

    • Scale: The scale of the terrain. Larger values spread out hills and valleys more, smaller values make them smaller

    • Height: The height of the terrain. (Scales everything in the vertical direction)

    • Offset: The starting distance of the terrain off the floor

    Tips

    If you want to use a hull brush then draw small patches or else any valleys will be filled in. For hull style results you will probably be better off using the low poly landscape Tool Plugin

    Twist

    As you draw the position is controlled by your hand as normal. However the orientation of the stroke spins around by itself

    Parameters

    • Speed: How fast to spin around the axis

    Tips

    • Try this with a broad flat brush like Paper or a brush that has an interesting profile shape such as Faceted Tube

    • This spins around the z-axis. i.e. the direction your brush is pointing. You will only see an effect of you draw strokes forwards or backwards along this axis.

    WandLerp

    The brush position cycles back and forth between your brush hand and your other hand. Paint with both hands for a change...

    Parameters

    • Frequency: The speed to oscillate between the brush and the wand

    • Amplitude: Controls how much to move. 0 is just the midpoint between both hands, 1 will reach both hands, 2 will overshoot both hands

    Tips

    Move your hands close together or further apart to see different effects

    Wander

    The brush stroke wanders off in random directions while you hold the trigger

    Parameters

    • Speed: How fast the pointer should move

    • Frames Per Path: After this many frames, the stroke is restarted from the current brush position

    Wiggle

    Randomizes the brush position

    Parameters

    • Wiggle Amount: The amount of randomness to add to the brush position

    Wobble

    Like Wiggle but uses a smooth noise function

    Parameters

    • Position Amount: The amount the noise affects the brush position

    • Rotation Amount: The amount the noise affects the brush orientation

    • Frequency: The scale of the noise function (higher = more jagged)

    Cameras and Exporting Video

    Quest and other Standalone Headset Users - exporting video directly from within Open Brush is currently only supported for PC VR only. See the section below

    If you are using Open Brush on PC VR / SteamVR, there are three types of cameras available to you. If you are using a version of the software that is run directly on a stand-alone headset such as the Oculus Quest 2 or 3 headsets, then there are limitations on some video functions because standalone headsets cannot process the video without being tethered to a PC. Steam VR allows the PC’s processors to handle the heavy lifting that is required to record Video in VR. This can be done with either a wired or wireless connection between the PC and the headset.

    The types of cameras available are:

    · Cameras Tools

    · Spectator Camera

    ·

    The Cameras Tool(s)

    The Cameras Tool is a set of camera tools options that are available in both the Beginners and Advanced Palates.

    In the Beginner’s mode, the camera icon is a single function tool, opening the Cameras tool on your brush controller. The Cameras tool has these options:

    1. Auto-Gif

    2. 5 Second Gif

    3. Snapshot

    4. Video (not present in some versions of Open Brush)

    The Cameras tools are all handheld and controlled with the brush controller where you will find the viewfinder and the record function. Using the thumbpad left and right shuffles through the four camera options. Clicking with the trigger initiates the process of recording in all options.

    The 5 Second Gif requires you to hold down the trigger for the 5 seconds. You can release the trigger and repull it to stop and start from the same place in the 5 second timeline. The video function begins when you pull the trigger and continues until you pull it again to stop the recording.

    The video function allows for a lot of control because you can move with 6 Degrees of Freedom through the scene limited only by your ability to control the direction, speed and orientation of the camera with your brush controller. This results in a handheld video, and the strengths and weaknesses of that approach are the same as real world handheld videography. It is hard to steady a camera being supported by your body.

    Any videos created with any of the Cameras options will show up in the /Documents/Open Brush/Videos folder.

    When switching to the Advanced Palate, the Cameras icon changes to be a multi-function button. This is visually shown by a triangle on the lower right corner of the icon.

    To access the Cameras sub-menu do a click and hold.

    In the sub menu you have the option to go into a Camera Options menu.

    Within the Camera Options menu you can:

    · Turn the Open Brush Watermark on or off,

    · Adjust field of view and smoothing variables, and

    · Toggle Post Effects.

    The series of images below demonstrates the differences in the captures with Field of View set to 140, 70 and 10. The first image shows the capture with the Watermark turned on, in the rest it has been toggle off. Understanding how this affects the image the camera captures allows you to better control the way you capture the scene.

    The video below is a demonstration of the tools mentioned above. It was recorded as a screen capture utilizing the Spectator Camera.

    The Spectator Camera

    The Spectator Camera does not record images or videos. Instead, it is used to send an image to a monitor. To capture images or videos, a screen capture function is required to record the video that is sent to the monitor. But the Spectator Camera is the only camera that shows the whole environment, including tools and camera paths.

    There are four options with the spectator Camera:

    Headset: Sends the video from the view of the headset. This is a view that moves along with your head, focusing on what is directly in front of your face as you wear the headset. This is a relatively jerky method of video capture because it moves every time your head moves.

    Stationary: This allows you to place a camera inside the scene and it captures either the stationary image in front of the camera, or you can use this as a handheld camera by grabbing and using the tool as you would a tangible camera.

    Figure 8: This is the same camera as the stationary, but it makes a continuous figure 8 moving around a fixed point which is established by where you place the spectator camera.

    Circle: Again, this is the same camera, but it revolves around the scene in a horizontal circle on a fixed path through or around the scene.

    Because the Spectator Camera does not record, recording of video lies outside of the scope of this document in that it becomes a discussion of a hundred separate toolboxes. You will need screen capture software that allows system audio to be captured along with the video (if you want to include audio in the recording).

    Note: You may not be able to capture audio from some sources because of DMCA rules in place that allow listening but not recording. Recording of your microphone does not have this limitation. Recording a music video in Spectator Mode can present some challenges that were intentionally put in place to protect copyright. Understanding that there are protections in place to prevent recording of some audio sources is an important part of the planning and production process. You will not be able to record audio from platforms such as Spotify. You can feed the audio into a scene and the audio responsive brushes will react, but there are digital blocks that prevent you from recording.

    A strength of the spectator camera is that it is easy to establish your camera path because it is limited to the preprogrammed options (Stationary, Figure 8, and Circle). You can also use the stationary option as a handheld option and move the camera around the scene.

    Another strength of the spectator camera is that it shows the environment including tools, controls, headset and controllers. It can also provide the opportunity to record the scene as it is rendered, providing a stroke-by-stroke perspective of how the scene is created.

    The weakness of the Spectator Camera is that it is limited to the preprogrammed options, and because recording with the Spectator Camera Option requires screen capture software that is not part of Open Brush.

    The Field of View setting in the /Cameras/Camera Options tool does not affect the Spectator Camera. Rather, when establishing the Spectator Camera shot, you can visibly see lines that illustrate the capture field for all of the spectator Camera settings except headset.

    Camera Paths Tools

    Camera Paths is an extremely important set of tools for Recording Video, or Virtual Cinematography in Open Brush. The tools are pretty basic, but learning to use them effectively and efficiently is the key to turning out high quality videos where you are in total control of how you capture the scene.

    Camera Paths is a set of tools that allow you to control the way that a camera captures the scene as the camera travels along a path you create through the scene. This method gives you a great deal of control and flexibility in your approach to filming the scene. But, once you click the record button, all other functions are locked until it has completed filming the path. There is an option to stop the recording while it is in process, but you will lose the video that was in process if it does not complete the defined path.

    The tools you can use to manipulate the path include:

    Add New Path Tool

    This is the only option when you enter the Camera Paths Tools if there are not already established camera paths. To establish a path, you need to click the Add Anchor Point tool and then create a path consisting of 2 or more points. Once you have a path, additional tools become available to you.\

    · Select Path: allows you to choose which of the existing paths you want to work with.

    · Show Paths: Makes Paths Visible in the Sketch so they can be manipulated.

    · Delete Path: Allows you to delete an entire path.

    · Record Path: After you have created and edited your path, this tool will launch the video recorder that will go through the entire path making a video record. Videos will show up in the /Documents/Open Brush/Videos folder. Recording cannot be paused. Recording can be cancelled by clicking the X on the bush controller while it is in the recording process.

    · New Anchor Point: Adds an additional anchor point to the path. If the anchor point is added at either end of a path, it will stay activated allowing you to add additional points to the path.

    · Delete Anchor Point: Deletes any controls form the timeline. This includes anchor, direction, speed, and zoom points.

    · Camera Direction Point: Controls the Direction the camera is pointed at the point in the timeline where it is placed. This type of point interacts with previous direction pointsand the path to determine the transition between camera direction points creating a flowing camera direction instead of a jumping camera direction.

    · Camera Speed Point: Provides values from .1 to 100 to control the speed the camera moves down the path at a given point. This type of point interacts with previous speed points and the path to determine the transitional speed between points.

    · Camera Zoom Point: Provides values from 10 to 140 to control the Field of View as the camera moves down the path at a given point. This type of point interacts with previous zoom points and the path to determine the transitional zoom between points.

    The strength of the Camera Path is its flexibility. The weakness is that you are locked into the defined path once recording has started. The camera paths tool is not accessible until a sketch is fully rendered, and once the recording has started, all other tools are locked until the recording has completed. That means it cannot capture the rendering of a scene, so all videos start with a fully rendered scene.

    Creating a camera path can be quite time consuming. In addition to the various tools, you need to work with the way that adding a point to the timeline can affect the elements ahead of and behind it on the path. Effective use of the Camera Paths requires the use of a lot of control points (each tool creates a control point when it is attached to a location on the camera path). The flexibility you can achieve comes at the cost of spending time learning each of the tools and how they interact with other points on the timeline.

    Settings that affect video render

    There are several useful settings you can change in the .

    Below is a sample Open Brush.cfg file showing the fields related to Video that can be used to control the video capture / render.

    {

    "User": {

    "Author":"Kevin W. Tharp, LLC"

    },

    "Video": {

    "Resolution":1920,

    "OfflineResolution":1920,

    "FPS":30,

    "OfflineFPS":30,

    "ContainerType":"mp4",

    "CameraSmoothing":0.98,

    "Encoder":"h.264",

    "SaveCameraPath":true,

    "FOV":129

    },

    "Flags": {

    "PostEffectsOnCapture":true,

    "ShowWatermark":false,

    "ShowHeadset":false,

    "ShowControllers":true,

    "DisableAudio":false

    },

    One of the Key variables is the number of frames you see per second (FPS). In virtual reality itself, this is the refresh rate. The refresh rate is important to the Virtual Reality experience but does not affect the virtual cinematography because videos of the scene are rendered at a fixed FPS rate. The number of frames per second affects the memory as each frame is processed in the memory. Using a lower FPS for recording impacts the memory by requiring less memory.

    When you are recording live, this can be a significant impact because the system renders the scene twice, once for each eye, so that you can see it in VR. Then you add the recording on top of that and you are really taxing the memory available for your display/recording function. If you run out of memory, the VR experience gets glitchy or fails completely. A glitchy VR experience is a bad thing, because it can lead rapidly to VR sickness and poor quality or failed recording.

    To minimize this impact, allows your system to redirect some of those memory resources to the function of recording the video. It does this by running a batch process. While the batch process requires the sketch to load in the headset, it disables all the interaction and dedicates all the memory to rendering and recording the scene. As such, it is recommended that you not wear the headset while batch rendering is going on, as the display may be glitchy or inconsistent as it is not prioritized during the offline recording process.

    Rendering ‘Offline’ videos

    When you create a video from inside Open Brush using the Camera tool and you've set "SaveCameraPath" to True in the - Open Brush will create a Windows batch file alongside the video (In Documents\Open Brush\Videos) that you can run to re-render the video at a higher resolution. For example:

    Untitled_13_00.mp4

    Untitled_13_00.HQ_Render.bat

    Double-clicking the ".bat" batch file will give you several options for re-rendering your video:

    Press the number corresponding to the format you prefer. It will then launch Open Brush, which will reload your sketch and render the video. Once it is done, Open Brush will exit. As rendering at higher quality tends to affect the framerate, it is suggested that you do not wear your headset until this process completes.

    “No Quick Load” option (#6) will forego quick loading of the sketch and will force it to load at normal speed. It is recommended that the time spent recording should exceed the normal loading time of the sketch or else the video may end before the sketch completes loading.

    Video Camera Paths

    Note: Video Camera Paths is not the same thing as the . Video Camera Paths track a camera through a scene and save the spatial data for offline rendering, whereas the Camera Paths Tools create a path that a video will take through a scene while recording.

    Rendering offline videos is achieved by saving off the path the camera took when the video was taken, and then re-using that to recreate the video. The camera path is saved off in ASCII USD () format, so if you have an application that can read and write USD, you may be able to use it to edit camera paths. Camera paths can also be combined with USD exports from Open Brush, to exactly recreate how the camera moved through the scene.

    If you want to render a camera path from the command line directly, rather than using the batch file detailed above, you can use the following:

    Changing Eye Scale on ODS 360 videos

    When you render an ODS video, you may find things like the floor is missing, or parts of your objects get clipped off.

    The reason this happens is that it’s often easier to scale down your sketch to make it easy to move the camera when you take your original video, but when you render out an ODS file, the objects are too close to the camera.

    To fix this, you can change a value in the .usda file. Open it up in your favorite text editor and look at around line 30 for:

    If you reduce this value, the render will feel bigger, and the camera is less likely to clip with parts of your sketch. A good value to try out is:

    Then you can just try re-rendering with the batch file.

    If you're rendering stereoscopic video then reducing eyeScale will reduce the strength of the stereo effect as well. It's often better to scale your scene in this case.

    Exporting 360 videos / Offline Video Rendering

    Videos can be rendered ‘offline’ faster and at a much higher resolution and framerate than using the internal Multicam tool

    1. Editing Open Brush cfg file

    2. Go to C:\Documents\Open Brush\Open Brush.cfg

    3. Under "Video" add the flag "SaveCameraPath": true,

    4. Save Open Brush.cfg

    Quest and Other Non-PC Devices

    Currently Open Brush doesn't support recording video directly on the headset. There are two main ways to work around this limitation.

    Option 1: Draw a Camera Path in the headset and render on a computer

    Standalone headsets like the Quest have the same Camera Path Tool as PC VR - the difference is that the record button is currently disabled. However any paths you create are saved with your sketch and can be copied to a PC or Mac and rendered there. The PC doesn't need to be a VR-capable PC - you can run Open Brush in a mode that doesn't require a VR headset.

    There is an example script you can use to help you generate the video.

    1. Launch Open Brush at least once to ensure the correct folders are created in your Documents folder.

    2. Copy the sketch from your headset to the Open Brush/Sketches folder on your PC or Mac

    3. If your sketch contains any images, videos or 3d models that appear in your video then copy those from the Quest's Media Library folder to the equivalent location on your PC or Mac.

    4. Ensure you have got Open Brush running on the PC or Mac. Switch to your web browser and enter this address:

    1. Click on the Example Scripts link and then click on /examplescripts/record_camera_path.html\

    2. Click browse and select the sketch you copied from the Quest earlier

    3. Click "Go"

    Option 2: Use native Quest video recording feature

    This allows you to record what you can see and record by moving through the scene. The quality will be lower than the above method and you may need to ensure that UI elements are hidden (The can help with this)

    Camera Setup

  • Load the sketch you would like to render

  • Find a good spot from which you would like to capture your 360 video

  • Be sure to look around in all directions to make sure no objects are too close to the point of capture

  • Save your sketch

  • Record your video by moving camera or keeping camera stationary

  • After saving, exit Open Brush

  • Rendering ****Note: When you create a video from inside Open Brush using the Camera tool with configuration "SaveCameraPath" flag set to true, Tilt Brush will create a Windows batch file alongside the video (In Documents\Open Brush\Videos) that you can run to re-render the video at a higher resolution

  • Go to C:\Documents\Open Brush\Videos . There should be .usda, .bat and video file which corresponds to the .tilt file

  • Double click on .bat file

  • If you run that batch file a command window will appear giving you several options for re-rendering your video: Press a number to get whichever format you prefer. It will then launch Open Brush, which will reload your sketch, and re-render the video. Once it is done, Open Brush will exit. As rendering at higher quality tends to affect the framerate, it is suggested that you do not wear your headset while this process completes.

  • Once the render is complete, it will pop open the “VRVideos” folder which should contain an video file with your stereo render.

  • Converting into 360 video 1. Download the 360° Video Metadata app for Mac or Windows. The dialog should look like this: 2. Un-zip the file, then open the 360 Video Metadata app. If you're on a Mac, you may need to right-click the app and then click Open. 3. Select the video file. 4. Select the checkbox for My Video is stereoscopic 3D (top/bottom layout) 5. Click Inject Metadata 6. Enter a name for the file that will be created. 7. Save the file. A new file will be created automatically in the same location as the original file.

  • Uploading to Youtube

    1. Upload the new “injected” video file to YouTube

    2. Note that it takes YouTube some additional time to process 360 videos, until this process is finished, you may see the raw over/under and the “View in Cardboard” option will not be available.

    3. Once processing is done, you should see an icon when viewing the video on your phone, indicating that it’s ready to be viewed in VR.

  • This will generate the video as if you'd recorded the path inside the headset
    Camera Paths
    config file
    offline rendering
    Open Brush config file
    Camera Paths Tools
    Universal Scene Description
    Spectator script
    The Cameras tool as seen from Beginner's Mode
    The Cameras Icon in the Advanced mode also has a sub-menu as indicated by the triangle in the lower right corner of the icon.
    The Camera Options tool is available in the Cameras Sub-menu
    Field of View set to 140 (wide angle), Watermark Toggled On
    Field of view set to 140, Watermark Off.
    Field of View 70
    Field of View 10
    The Camera Paths Tool opens a separate Panel that contains the tools
    You Must First Create a New Path before you can access the other Camera Paths Tools.
    The Camera Paths Panel and tools once a path has been established.
    Select Path Tool
    Show Paths Tool
    Delete Path Tool
    Record Path Tool
    New Anchor Point Tool
    Delete Point Tool
    Camera Direction Point Tool
    Camera Speed Point Tool
    Camera Zoom Point Tool
    http://localhost:40074/help/
    Openbrush.exe --renderCameraPath <path/to/camerpath.usda> <path/to/sketchfile.tilt>
    uniform float eyeScale = 1
    uniform float eyeScale = 0.1

    API Commands List

    API Docs

    This page was generated from the output directly from Open Brush API server. It's not always totally up to date. When you're running Open Brush then use the live commands list you get from http://localhost:40074/help/commands as that will always be current.

    The "Try It" links assume that a version of Open Brush with API support is currently running on this computer. They won't work if Open Brush isn't running. You can run a version if you don't have a VR headset attached.

    To run commands just send a request to this url with

    Commands are query string parameters. Like this: command.name=parameters

    Separate multiple commands with: &

    Example:

    If you want to send a lot of commands or especially long commands (complex paths etc) then you can just http POST instead of GET. The commands should be form-encoded in the body of the request (exactly as if you submitted a html form with the form name as the command name and the form value as the command parameters)

    You can also send multiple requests although because of the nature of http, these can sometimes arrive in a different order to how yousent them. We will soon support websockets which should be a better way to send realtime streams of commands.

    Command List

    Correct for beta version as of Oct 21 2025)

    listenfor.strokes (string url)

    Adds the url of an app that wants to receive the data for a stroke as each one is finished

    showfolder.scripts

    Opens the user's Scripts folder on the desktop

    showfolder.exports

    Opens the user's Exports folder on the desktop

    spectator.move.to (Vector3 position)

    Moves the spectator camera to the given position

    spectator.move.by (Vector3 amount)

    Moves the spectator camera by the given amount

    user.move.to (Vector3 position)

    Moves the user to the given position

    user.move.by (Vector3 amount)

    Moves the user by the given amount

    spectator.turn.y (float angle)

    Rotates the spectator camera left or right.

    spectator.turn.x (float angle)

    Rotates the spectator camera up or down.

    spectator.turn.z (float angle)

    Tilts the angle of the spectator camera clockwise or anticlockwise.

    user.turn.y (float angle)

    Rotates the user camera left or right.

    user.turn.x (float angle)

    Rotates the user camera up or down. (monoscopic mode only)

    user.turn.z (float angle)

    Tilts the angle of the user camera clockwise or anticlockwise. (monoscopic mode only)

    scene.scale.to (float scale)

    Sets the scene scale to the given value

    scene.scale.by (float amount)

    Scales the scene by the given amount

    spectator.direction (Vector3 direction)

    Points the spectator camera to look in the specified direction. Angles are given in x,y,z degrees

    user.direction (Vector3 direction)

    Points the user camera to look in the specified direction. Angles are given in x,y,z degrees. (Monoscopic mode only)

    spectator.look.at (Vector3 position)

    Points the spectator camera towards a specific point

    user.look.at (Vector3 direction)

    Points the user camera towards a specific point (In VR this only changes the y axis. In monoscopic mode it changes all 3 axes)

    spectator.mode (string mode)

    Sets the spectator camera mode to one of stationary, slowFollow, wobble, circular

    spectator.hide (string thing)

    Hides the chosen type of elements from the spectator camera (widgets, strokes, selection, headset, panels, ui

    brush.move.to (Vector3 position)

    Moves the brush to the given coordinates

    brush.move.to.hand (string hand, Boolean alsoRotate)

    Moves the brush to the given hand (l or r

    brush.move.by (Vector3 offset)

    Moves the brush by the given amount

    brush.move (float distance)

    Moves the brush forward by 'distance' without drawing a line

    brush.draw (float distance)

    Moves the brush forward by 'distance' and draws a line

    brush.turn.y (float angle)

    Changes the brush direction to the left or right. Angle is measured in degrees

    brush.turn.x (float angle)

    Changes the brush direction up or down. Angle is measured in degrees

    brush.turn.z (float angle)

    Rotates the brush clockwise or anticlockwise. Angle is measured in degrees

    brush.look.at (Vector3 direction)

    Changes the brush direction to look at the specified point

    brush.look.forwards

    Changes the brush direction to look forwards

    brush.look.up

    Changes the brush direction to look upwards

    brush.look.down

    Changes the brush direction to look downwards

    brush.look.left

    Changes the brush direction to look to the left

    brush.look.right

    Changes the brush direction to look to the right

    brush.look.backwards

    Changes the brush direction to look backwards

    brush.home.reset

    Resets the brush position and direction

    brush.home.set

    Sets the current brush position and direction as the new home. This persists in new sketches

    brush.transform.push

    Stores the current brush position and direction on to a stack

    brush.transform.pop

    Pops the most recent current brush position and direction from the stack

    debug.brush

    Logs some info about the brush

    text.add (string text)

    Adds a text widget to the sketch

    video.import (string location)

    Imports a video given a url or a filename in Media Library\Videos

    skybox.import (string location)

    Sets the skybox from either a url or a filename in Media Library\BackgroundImages (Images loaded from a url are saved locally first)

    image.import (string location)

    Imports an image given a url or a filename in Media Library\Images (Images loaded from a url are saved locally first)

    environment.type (string name)

    Sets the current environment

    panel.open (string name, float x, float y, float z)

    Opens a given panel at the given position

    panel.close (string name)

    Closes a given panel

    panel.position (string name, Vector3 position)

    Sets position of a given panel

    panel.rotation (string name, Vector3 rotation)

    Sets rotation of a given panel

    strokes.debug

    Logs some debug info about the strokes

    panel.attach (string name)

    Attaches the given panel to the user's wand

    panel.detach (string name, Vector3 position)

    Detaches the given panel from the user's wand

    layer.add

    Adds a new layer

    layer.clear (int layer)

    Clears the contents of a layer

    debug.ram (Boolean active)

    Enable/Disable logging of RAM usage to the in-app console (Android only)

    layer.delete (int layer)

    Deletes a layer

    layer.squash (int squashedLayer, int destinationLayer)

    Move everything from one layer to another then removes the empty layer

    layer.activate (int layer)

    Make a layer the active layer

    layer.show (int layer)

    Make a layer visible

    layer.hide (int layer)

    Hide a layer

    layer.toggle (int layer)

    Toggles a layer between visible and hidden

    model.select (int index)

    Selects a 3d model by index.

    model.position (int index, Vector3 position)

    Move a 3d model to the given coordinates

    model.rotation (int index, Vector3 rotation)

    Set a model's rotation to the given angles

    model.scale (int index, float scale)

    Set a model's scale to the amount

    symmetry.position (Vector3 position)

    Move the symmetry widget to the given coordinates

    symmetry.set.rotation (Vector3 rotation)

    Sets the symmetry widget rotation

    symmetry.set.transform (Vector3 position, Vector3 rotation)

    Sets the position and rotation of the symmetry widget

    brush.force.painting.on (Boolean active)

    Turns on or off an override that paints even if the trigger is not pressed.

    brush.force.painting.off (Boolean active)

    Turns on or off an override that stops the user painting even if the trigger is pressed.

    brush.new.stroke

    Ends the current stroke and starts a new one next frame

    image.select (int index)

    Selects an image by index.

    image.delete (int index)

    Deletes an image by index.

    video.delete (int index)

    Deletes a video by index.

    model.delete (int index)

    Deletes a 3d model by index.

    guide.delete (int index)

    Deletes a guide by index.

    image.position (int index, Vector3 position)

    Move an image to the given coordinates

    image.rotation (int index, Vector3 rotation)

    Set a images rotation to the given angles

    image.scale (int index, float scale)

    Set a images scale to the amount

    light.position (int index, Vector3 position)

    Move a light to the given coordinates

    light.rotation (int index, Vector3 rotation)

    Set a light's rotation to the given angles

    image.formEncode (int index)

    Converts an image to a string suitable for use in a form

    image.base64Decode (string base64, string filename)

    Saves an image based on a base64 encoded string

    scripts.initPluginScripting

    Call this before using any HTTP endpoint that accesses plugins (including html pages that list plugins)

    scripts.toolscript.activate (string scriptName)

    Activate the given tool script

    scripts.toolscript.deactivate

    Dectivate the tool script

    scripts.symmetryscript.activate (string scriptName)

    Activate the given symmetry script

    scripts.symmetryscript.deactivate

    Dectivate the symmetry script

    scripts.pointerscript.activate (string scriptName)

    Activate the given pointer script

    scripts.pointerscript.deactivate

    Dectivate the pointer script

    scripts.backgroundscript.activate (string scriptName)

    Activate the given background script

    scripts.backgroundscript.deactivate (string scriptName)

    Dectivate the given background script

    scripts.backgroundscript.activateall

    Dectivate all background scripts

    scripts.backgroundscript.deactivateall

    Dectivate all background scripts

    guide.add (string type)

    Adds a guide to the scene (cube, sphere, capsule, cone, ellipsoid)

    guide.select (int index)

    Selects a guide by index.

    guide.position (int index, Vector3 position)

    Move a guide to the given coordinates

    guide.scale (int index, Vector3 scale)

    Sets the (non-uniform) scale of a guide

    draw.paths (string jsonString)

    Draws a series of paths at the current brush position [[[x1,y1,z1],[x2,y2,z2], etc...]]. Does not move the brush position

    brush.pathsmoothing (float amount)

    Sets the amount of smoothing applied to brush paths at corners. Default is 0.10 turns off smoothing and you'll have to ensure you create enough points or else the path may end up smoothed to nothing.

    draw.path (string jsonString)

    Draws a path at the current brush position [x1,y1,z1],[x2,y2,z2], etc.... Does not move the brush position

    draw.stroke (string jsonString)

    Draws an exact brush stroke including orientation and pressure

    draw.polygon (int sides, float radius, float angle)

    Draws a polygon at the current brush position. Does not move the brush position

    draw.text (string text)

    Draws the characters supplied at the current brush position

    draw.opentypetext (string text, string fontPath)

    Same as draw text but uses an opentype font (the font should be in a Fonts folder in your Open Brush folder)

    draw.svg (string svg)

    Draws an entire SVG document

    draw.svg.path (string svgPath)

    Draws the path supplied as an SVG Path string at the current brush position

    brush.type (string brushType)

    Changes the brush. brushType can either be the brush name or it's guid. brushes are listed in the /help screen

    color.add.hsv (Vector3 hsv)

    Adds the supplied values to the current color. Values are hue, saturation and value

    color.add.rgb (Vector3 rgb)

    Adds the supplied values to the current color. Values are red green and blue

    color.set.rgb (Vector3 rgb)

    Sets the current color. Values are red, green and blue

    color.set.hsv (Vector3 hsv)

    Sets the current color. Values are hue, saturation and value

    color.set.html (string color)

    Sets the current color. colorString can either be a hex value or a css color name.

    brush.size.set (float size)

    Sets the current brush size

    brush.size.add (float amount)

    Changes the current brush size by the given amount

    draw.camerapath (int index, float step)

    Draws along a camera path with the current brush settings

    model.webimport (string url)

    Imports a model given a url or a filename in Media Library\Models (Models loaded from a url are saved locally first)

    import.webmodel (string url)

    Same as model.webimport (backwards compatibility for poly.pizza)

    model.icosaimport (string modelId)

    Imports a model from the Icosa Gallery given a model id

    model.import (string location)

    Imports a model given a filename in Media Library\Models (Models loaded from a url are saved locally first)

    model.breakapart (int index)

    Breaks apart a model

    save.overwrite

    Save the current scene overwriting the last save if it exists

    save.as (string filename)

    Saves the current scene under a new name. (No need to include the .tilt suffix)

    save.new

    Saves the current scene in a new slot

    save.selected

    Saves the current selected strokes in a new slot

    icosa.devicelogin (string code)

    Login to the Icosa Gallery using a device code

    icosa.logout

    Logout of the Icosa Gallery

    icosa.upload

    Uploads it to the Icosa Gallery

    export.all

    Exports all the scenes in the users's sketch folder

    drafting.visible

    Shows all strokes made with the drafting brush fully opaque

    drafting.transparent

    Shows all strokes made with the drafting brush semi-transparent

    drafting.hidden

    Hides all strokes made with the drafting brush

    load.user (int slot)

    Loads the sketch from the user's sketch folder given an index (0 being most recent)

    load.featured (int slot)

    Loads the sketch in the given slot number from the featured sketch list

    load.liked (int slot)

    Loads the sketch in the given slot number from the user's liked sketches

    load.drive (int slot)

    Loads the sketch in the given slot number from the user's Google Drive

    load.named (string filename)

    Loads the sketch with the given name from the user's sketch folder

    merge.named (string filename)

    Loads the sketch with the given name from the user's sketch folder

    new

    Clears the current sketch

    symmetry.mirror

    Sets the symmetry mode to 'mirror'

    symmetry.multimirror

    Sets the symmetry mode to 'multimirror'

    twohandeded.toggle

    Toggles painting with both hands at once

    straightedge.toggle

    Toggles the straight edge tool on or off

    autoorient.toggle

    Toggles autoorientate on or off

    undo

    Undoes the last action

    redo

    Redo the last action

    panels.reset

    Reset the position of all panels

    sketch.origin

    Enables the sketch origin tool

    viewonly.toggle

    Toggles 'view only' mode on or off

    spectator.toggle

    Toggles the spectator camera

    spectator.on

    Turns the spectator camera on

    spectator.off

    Turns the spectator camera off

    autosimplify.toggle

    Toggles 'auto-simplify' mode on or off

    export.current

    Exports the current sketch to the user's Exports folder

    showfolder.sketch (int index)

    Opens the user's Sketches folder on the desktop

    guides.disable

    Toggles guides on and off

    disco

    Starts a party

    selection.duplicate

    Create a duplicate of the current selection (uses symmetry mirrors if active

    selection.delete

    Deletes the current selection

    selection.group

    Groups (or ungroups) the current selection

    export.selected

    Exports the selected strokes to the user's Media Library

    camerapath.render

    Renders the current camera path to a video

    profiling.toggle

    Toggles profiling mode on or off

    settings.toggle

    Toggles the settings panel on or off

    mirror.summon

    Summons the mirror origin to the user's position

    selection.invert

    Inverts the current selection

    select.all

    Selects all strokes and widgets on the current layer

    select.none

    Deselects all strokes and widgets on the current layer

    selection.flip

    Mirrors the current selection

    postprocessing.toggle

    Toggles post-processing effects on or off

    watermark.toggle

    Toggles the watermark on or off

    camerapath.togglevisuals

    Toggles the camera path visuals on or off

    camerapath.togglepreview

    Toggles the camera path preview on or off

    camerapath.delete

    Deletes the current camera path

    camerapath.record

    Starts recording a camera path

    camerapath.setactive (int index)

    Sets the active camera path

    stroke.delete (int index)

    Delete a stroke by index

    stroke.select (int index)

    Select a stroke by index.

    strokes.select (int from, int to)

    Select multiple strokes by index.

    selection.recolor (Boolean jitter)

    Recolors the currently selected strokes

    strokes.move.to (int start, int end, Vector3 position)

    Moves several strokes to the given position

    strokes.move.by (int start, int end, Vector3 translation)

    Moves several strokes to the given coordinates

    strokes.rotate.by (int start, int end, float angle)

    Rotates multiple brushstrokes around the current brush position

    strokes.scale.by (int start, int end, float scale)

    Scales multiple brushstrokes around the current brush position

    selection.rebrush (Boolean jitter)

    Rebrushes the currently selected strokes

    selection.resize (Boolean jitter)

    Changes the brush size the currently selected strokes

    selection.trim (int count)

    Removes a number of points from the currently selected strokes

    selection.points.perlin (string axis, Vector3 scale)

    Moves the position of all control points in the selection using a noise function

    stroke.points.quantize (Vector3 grid)

    Snaps all the points in selected strokes to a grid (buggy)

    stroke.join

    Joins a stroke with the previous one

    strokes.join (int from, int to)

    Joins all strokes between the two indices (inclusive)

    stroke.add (int index)

    Adds a point at the current brush position to the specified stroke

    symmetry.type (string type)

    Sets the custom symmetry type (Currently either 'point' or 'wallpaper'

    symmetry.pointfamily (string family)

    Sets the custom point symmetry family (Any of Cn, Cnv, Cnh, Sn, Dn, Dnh, Dnd, T, Th, Td, O, Oh, I, Ih) Replace n with a number to also set the order.

    symmetry.wallpapergroup (string group)

    Sets the custom wallpaper symmetry group (Any of p1, pg, cm, pm, p6, p6m, p3, p3m1, p31m, p4, p4m, p4g, p2, pgg, pmg, pmm, cmm)

    symmetry.pointorder (int order)

    Sets the custom point symmetry order

    symmetry.wallpaperrepeats (int x, int y)

    Sets the custom wallpaper symmetry repeats

    symmetry.wallpaperscale (float x, float y)

    Sets the custom wallpaper symmetry scale

    symmetry.wallpaperskew (float x, float y)

    Sets the custom wallpaper symmetry skew

    symmetry.colorshift.hue (string mode, float amplitude, float frequency)

    Sets the custom wallpaper color shift hue (mode is one of SineWave, SquareWave, SawtoothWave, TriangleWave, Noise)

    symmetry.colorshift.saturation (string mode, float amplitude, float frequency)

    Sets the custom wallpaper color shift saturation (mode is one of SineWave, SquareWave, SawtoothWave, TriangleWave, Noise)

    symmetry.colorshift.brightness (string mode, float amplitude, float frequency)

    Sets the custom wallpaper color shift brightness (mode is one of SineWave, SquareWave, SawtoothWave, TriangleWave, Noise)

    multiplayer.join (string nickname, string roomName, Boolean isPrivate, int maxPlayers, Boolean silentRoom, Boolean viewOnlyRoom)

    Joins a multiplayer room

    multiplayer.leave

    Leaves a multiplayer room

    tool.sketchsurface

    Activates the SketchSurface

    tool.selection

    Activates the Selection Tool

    tool.colorpicker

    Activates the Color Picker

    tool.brushpicker

    Activates the Brush Picker

    tool.brushandcolorpicker

    Activates the Brush And Color Picker

    tool.sketchorigin

    Activates the SketchOrigin Tool

    tool.autogif

    Activates the AutoGif Tool

    tool.canvas

    Activates the Canvas Tool

    tool.transform

    Activates the Transform Tool

    tool.stamp

    Activates the Stamp Tool

    tool.freepaint

    Activates the FreePaint Tool

    tool.eraser

    Activates the Eraser Tool

    tool.screenshot

    Activates the Screenshot Tool

    tool.dropper

    Activates the Dropper Tool

    tool.saveicon

    Activates the SaveIcon Tool

    tool.threedofviewing

    Activates the ThreeDofViewing Tool

    tool.multicam

    Activates the MultiCam Tool

    tool.teleport

    Activates the Teleport Tool

    tool.repaint

    Activates the Repaint Tool

    tool.recolor

    Activates the Recolor Tool

    tool.rebrush

    Activates the Rebrush Tool

    tool.pin

    Activates the Pin Tool

    tool.camerapath

    Activates the CameraPath Tool

    tool.fly

    Activates the Fly Tool

    snap.angle (string angle)

    Sets the current snapping angle. Angle must be a supported value (15, 30, 45, 60, 75 or 90)

    snap.grid (string size)

    Sets the current snapping grid. Size must be a supported value (0.1, 0.25, 0.5 ,1, 2, 3, 5

    selection.snap.angles

    Applies the current snap angle to all selected objects

    selection.snap.positions

    Applies the current snap grid to all selected objects

    selection.align (string axis, string alignBy)

    Aligns all selected objects to the given axis using their minimum, center or maximum points

    monoscopic
    http://localhost:40074/api/v1?
    http://localhost:40074/api/v1?brush.turn.y=45&brush.draw=1
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it
    Try it

    Brush List

    • Type: Most brushes fall into one of three categories: Flat (ribbon shaped), Tube (a cylinder or other shape with thickness) or Particle (the brush stroke generates multiple small objects that only roughly follow the path of the stroke)

    • Animated?: Does the brush stroke have any automatic movement either to it's shape or texture?

    • Self-lit?: A self-lit brush doesn't react to lighting and will still be visible even without any lights in the scene. It appears to give off it's own light (although brush strokes don't actually illuminate other objects nearby)

    • Audio Reactive?: Does the brush respond to audio when you turn on

    Standard Brushes

    Brush Name
    Type
    Animated?
    Self-lit?
    Audio Reactive?

    Experimental Brushes

    Brush Name
    Type
    Animated?
    Self-lit?
    Audio Reactive?

    Developer Notes

    Developer Resources

    Tutorials and Write ups for Modifying Tilt Brush:

    • Customizing Tilt Brush - Part One: Introduction and Custom Brushes

    • (nb the "Flight" feature itself is now included in the main release but the tutorial is still useful as a guide for adding your own features)

    Open Brush Developer Documentation

    Spreadsheets with some useful info:

    Developing and Testing Without a VR Headset

    It’s often quicker while developing to avoid jumping in and out of VR. is very useful for this.

    1. Under "Flags" set EnableMonoscopicMode to true in your

    2. Sometimes panels are placed over other panels. To move a panel hold shift at the same time as holding Alt to rotate the viewpoint (see below)

    Entering play mode should now allow you to draw and control the app using the mouse and keyboard.

    You can learn more about using

    Enums

    How to safely add new items to existing enums

    Important note: Unity serializes enums as ints. Therefore if you change the order of enums then any scene or asset with a reference to them will suddenly point at the wrong entry.

    This is especially a problem when merging branches. If you’re working on a feature that you will eventually want to merge with another branch you want to ensure that your enum values don’t change when the files are merged.

    The best way to do this is to explicitly number your enums

    Now the only problem is to ensure you use numbers that other branches haven’t already used. We’ve settled on a simple low tech solution for now. Just go to this Google Sheet and reserve a block of 1000****

    Important Enums

    • SketchControlsScript.GlobalCommands: Commands are actions that (usually) record Undo state.

    • BasePanel.PanelType: Panels are the persistent UI elements (as opposed to popups which tend to be transitory)

    • BaseTool.ToolType: “Tools” are usually modal states that determine what actions happen when you use the controls on your main controller (the “brush” controller)

    Adding a New Panel

    1. Add an entry to BasePanel.PanelType (see the note above about enums clashing)

    2. If you think you’ll need custom functionality in the Panel class itself then create a new class inheriting from BasePanel:

    Otherwise you can just use BasePanel directly in the next step.

    1. It's easiest to copy an existing panel prefab (from Prefabs\Panels). If it's using a subclass of BasePanel different to yours, then change the script type for the panel (neat trick to swap scripts on existing components here: )

    2. Ensure your component’s PanelType is set to the value you added to BasePanel.PanelType

    3. Change the Panel Description field for your new panel to something relevant.

    Opening the new Panel:

    Either:

    1. Add a button to an existing panel. The button should use the PanelButton component (or copy an existing one) or...

    2. Tick “Begin Fixed” on the new panel component itself.

    Question - what controls how close a panel is allowed to get to another panel on the wand?

    Answer - BasePanel.m_WandAttachHalfHeight

    Popups

    Panels script components have a m_PanelPopUpMap property which connects a GlobalCommand to a popup prefab. Having to add a GlobalCommand for every popup type is a bit tedious. I need to figure out how to open a popup without needing a GlobalCommand

    1. Create a subclass of PopUpWindow if you need one (or just use OptionsPopUpWindow)

    2. Copy the structure of an existing popup prefab substituting your popupwindow class

    3. Add a button to a panel to open your popup. It should be an OptionButton or a subclass thereof.

    4. Add a command to the GlobalCommand enum to handle opening your popup

    Passing Parameters to Popups

    CreatePopup calls SetPopupCommandParameters on the popup and passes in iCommandParam and iCommandParam2 (usually from the OptionButton used to open the popup). So override this method to handle the parameters how you want.

    See the MenuPopUpWindow subclass for an example.

    Sliders

    1. Create a class that inherits from BaseSlider

    2. Go to BackdropPanel prefab and copy FogDensitySlider

    3. Paste into the panel prefab you want to use it in

    4. Change FogDensitySlider to use the class you created in #1(use method found at minute 18 here Found here ()

    Guides

    These are typically known as "stencils" in code but prefab names may still use the term "guide".

    Key Classes involved

    • StencilWidget -> GrabWidget

    • WidgetManager

    • SketchControlScript

    Creating a new Stencil / Guide

    1. Make a copy of one of the stencil prefabs and rename it for your shape. The sphere is the easiest to work with in many cases.

    2. Add your shape name to the end of the StencilType Enum in WidgetManager.cs. You may need to follow the recommendations about .

    3. Add your prefab and shape type (Enum) to the WidgetManager Stencil Map in the inspector.

    Question: What determines the distance at which the pointer will snap to the guide?

    Answer: WidgetManager.m_StencilAttractDist. The code does this in WidgetManager.MagnetizeToStencils.

    Question: How do you enable a stencil to be scaled non-uniformly (i.e. along a particular axis)?

    Answer: See SketchControlScript.UpdateGrab_ContinuesTwoHands and implement GetScaleAxis and RecordAndApplyScaleToAxis.

    Button Scripts

    (Also see )

    • ActionButton : BaseButton Triggers a UnityEvent assigned in the inspector.

    • ActionToggleButton : ActionButton

      Triggers a UnityEvent and maintains on/off state

    • ConfirmationButton : BaseButton

      Used in popups. Calls ResolveDelayedButtonCommand on the parent panel and sends true/false depending on the property set in the inspector

    Pointers and the Input System

    By @moat

    For the input system there's this one scene Gameobject called a SketchControls:

    This whole chungus of a gameobject sits in the scene and it's got like, nearly every bit of UI and management and widgety stuff.

    It's like the player is already instantiated within the game to start with when you load the Main scene. There's a gameobject called the PointerManager:

    This thing manages up to 10 cursors at once (although it can be set to handle more):

    Brushes are attached to cursors, and when you do anything with your controllers, it drives the Main Pointer Prefab.

    The reason they have multiple cursors is for things like multibrushes that make multiple brushstrokes appear simultaneously when you drag out a stroke

    Pretty much every tool you switch between is sitting on a script within one of these gameobjects parented to SketchSurface:

    When you switch tools, it activates one of these objects and deactivates the others

    Much of the magic occurs within the FreePaintTool

    It's the star of the show, being the thing that makes happy little trees appear and happy little clouds.

    What most tools have in common is UpdateTool()

    This is like their main interaction loop. At the start, the inputmanager states are captured into variables to be used throughout the rest of the update loop:

    (rather than re-calling the same inputmanager functions again and again and again)

    The Wand is your non-dominant hand, the Brush is your dominant hand controller and performing the controller-tap gesture (lightly tapping the handles together) will swap these controllers.

    This BrushTrigger bit handles the actual trigger press:

    m_brushTrigger is just a boolean that becomes TRUE when the trigger is pressed beyond the threshold while the BrushTriggerDown variable becomes true only during the update tic when the trigger has been pressed and brushTriggerRatio is a value mapped from 0->1 depending on how far that analog trigger has been pulled.

    The Model Import UI

    ReferencePanel.cs is the media library script.

    LocalModelButton has got a method RequestModelPreloadInternal but it isn’t called on the local media panel - only on the Poly panel. If we want to make local media behave more like the the Poly panel then we should go through PolyPanel RefreshPage to understand what it's doing and take the relevant parts and add them to ModelPanel RefreshPage.

    Importing 3d models

    The code that does the actual work is in models.cs. A typical call stack goes:

    This presupposes you’ve instantiated model class. An example instantiation might look something like:

    Once you have a valid model you need to spawn it into the scene. Look at SpawnValidModel in ModelButton.cs

    Example code to synchronously load a model:

    Note - only tested on local models. The filename is appended to Media Library/models

    Export formats

    Currently several formats are hidden behind ifdefs for various platform flags and the experimental flag. The logic is a bit tortuous so here’s a pseudocode version:

    If you want to add a new export format then add your script to Scripts/Export and modify the big set of if statements in ExportScene in Exports.cs. You’ll also want to add a pair of progress.SetWork and progress.CompleteWork calls to update the progress UI.

    How Exports Group Strokes

    Currently strokes are grouped by brush type when exported to other formats. People have asked in the past to also group by color AND brush type. @1pld offered the following solution:

    You need to convince Open Brush to split things out by color as well as by brush. It's not that tricky a change if you can modify the code (or can get someone to modify it for you). This compiles but I haven't tested it

    And also

    Taken from the following comment:

    Procedural Strokes

    By @andybak

    I've written code to procedurally generate strokes in two places with some subtle differences that prevents me from combining them into a single utility method just yet.

    The gist of it all is basically:

    1. Create an array of control points

    2. Create a Stroke using those points

    3. Call stroke.Recreate and pass in App.Scene.ActiveCanvas or similar

    4. MemoryListAdd

    That whole shebang seems necessary to ensure that undo and saving work correctly.

    I think MemoryListAdd was needed for save/loading to work and PerformAndRecordCommand was needed for Undo… The sketch memory list is what gets saved into .tilt files for brush strokes. The undo stuff handles more than just brush strokes. The undo log knows about (most) user actions and what code to call to reverse/redo them.

    Stroke.Recreate seems to create the batch object and mesh - but that's not enough for "real" brush strokes.

    Recreate (eventually) calls FinalizeBatchedBrush on the correct BrushScript. These overridden methods are what actually does the mesh creation.

    Adding a New Tool

    In Open Brush, almost everything we do is done with the help of tools. A tool can be something like the Straight Line tool, which applies a modifier to any new brushes created with the Free Paint tool, or it can be something like the Teleport tool, which moves the player. At the end of the day, a tool is simply a way for us to run some code in a nice compartmentalized way.

    In essence they are usually modal states that determine what actions happen when you use the controls on your main controller (the “brush” controller).

    (based on )

    1. Open Assets/Prefabs/Panels folder. Find “AdvancedToolsPanel” and open it

    2. (If you want to build for Quest, you’ll also need to perform the following operations on the “AdvancedToolsPanel_Mobile” prefab)

    3. Duplicate one of the other Tool buttons to create a new button. (Note that the mirror and straight edge buttons are not tool buttons)

    4. Name your new button object “Button_Foo”

    1. Go back to our component and select “Foo Tool” as the tool type for our button. Save the prefab.

    2. In the main scene find the object SketchSurface which is a child of SketchControls.

    3. Add a new empty child to this object

    4. Give it a scale of (0.5, 0.5, 0.5) and call it FooTool placing it just above the EmptyTool object.

    Controller UI for Tools

    (this section of the docs is a work in progress)

    Places to look:

    1. Controller Material Catalog component on the App object in the main scene (contains all the materials used for adding custom buttons to the controller model)

    2. AssignControllerMaterials method on BaseTool subclasses. This often calls methods on ControllerGeometry.cs which in turn typically does something like:

    Custom Stroke Data

    by @1pld

    For stroke/control point extension data, I'd propose adding a level of indirection (the solution for everything). If a .tilt appends data to strokes or points, it should come with some extra self-describing data in the .tilt. So rather than this:

    you'd have something like "the stroke sets extension bit 16; the client looks in the sketch metadata to find out what stroke extension 16 is. It has a mime type / guid / whatever. The client determines it doesn't know what to do with that data so it throws it away, which it can because that data chunk is in length+data format" or "all stroke extensions 16 and above are now defined to be length + guid + <length - sizeof(guid)> bytes. The client determines whether it understands the data based on the guid etc".

    The coordinate system

    by @1pld

    Re some comments I've seen elsewhere, it would be good to document the coordinate systems Tilt Brush uses and how they're reflected in the scene graph. Super quick notes on this:

    • "room space" = the user's physical environment. some people call this "tracking space"

    • "scene space" = the user's virtual environment -- the square panel on the ground, the mountains in the distance, etc.

    • "canvas space" = the user's artwork. Typically there's just a single Canvas whose pose is the same as the Scene pose (it's a direct child of the scene, with identity localTransform). But when you have a selection or groups, those are additional Canvas instances

    the root of unity's scene graph we call "global space" (we try to avoid the term "world space" in the code because "world" is ambiguous). "global space" == "room space". The Scene is a child in global space, and canvas is a child of scene

    That is backwards from what some people expect, which is for "room space" to be a child of "virtual space".

    _CS, _SS, _GS, _RS suffixes all denote those spaces.

    Paul Du Bois’s Thoughts on Procedural Strokes

    I would look at the rebrush tool (the one that's like recolor, but changes brushes). That takes an existing set of control points and regenerates the geometry.

    More specifically, take a look at Stroke.cs and the various functions in there like Recreate. The general idea is you should be able to dump a bunch of control points into a Stroke, call Recreate, and you've got geometry. The API hasn't gotten as simple as I'd like, you still have to worry a bit about the various intrusive linked lists that strokes get put into when you draw "normally" (or on load), but it shouldn't be too bad

    The guts of that are how I'd do it if you want something up and running quickly -- it's a good demonstration of how to generate knot information, pipe it to the right place, get a proper stroke back out. See ParametricStrokeCreator.cs

    ParentBrush might also be interesting to you... but it violates some assumptions and doesn't play nicely with save/load, undo/redo etc. There's some notes about how to move forward from that in the file

    The playback code might be another entry point, if you want to make more than one stroke (i.e. fill a volume with strokes). You could boot up the playback system pretend you're loading a file (but instead, you're generating the control points programmatically) The playback system has a mode that is more "real time", where stroke timestamps are allowed to overlap, multiple strokes can draw in at once and will draw in at the speed they were painted, etc. Might have bitrotted a bit, but might be a useful entry point for understanding the drawing system

    One kind of annoying thing that we never fixed is that there are only 4 (or maybe 8) global pointers, and everyone just kind of hardcodes the index of the one they want to use. So the 4-way mirror will use pointers 0-3, the load code assumes it can use any of them, etc. That's as opposed to people instantiating as many pointers as they need concurrent lines, doing stuff with them, throwing them away

    Ideally you wouldn't need a "pointer" at all in order to draw lines. Anyway, something to watch out for if you want procedural stuff happening at the same time the user's painting.

    The guide system could use a SDF based mode so guides could interact with each other, have smooth joins, etc; rather than you getting stuck to one at a time. Man, that would be great.

    (Another time Paul said “Look at basebrushscript.cs and the method Stroke.Recreate” - the latter is mentioned above.)

    Open Questions

    1. How to programmatically generate a mesh in such a way that it will correctly save and load back in a .tilt file?

    TB files only save references to meshes (eg, Poly asset ids, paths to imported fbx or obj files, etc). Currently the only way to put geometry in a tilt file is to add brush strokes to it.

    1. How to modify meshes from either Blocks or Poly that are embedded in a sketch?

    Poly assets are immutable, so if a .tilt has a reference to a poly object, a tilt file that references it can guarantee that it will always look the same.

    1. How to fix the undo/save behaviour of experimental brushes using “ParentBrush”?

    See the giant comment at the top of ParentBrush :) Consider ParentBrush proof-of-concept that needs a week-ish of design thinking and implementation work to turn into something ready for prime time

    1. How to add parameters to brushes. The sheer number of brushes might become too many and many brushes are simple variants of each other. A UI to allow brush parameters to define variants would help address this.

    2. How to visualize/manipulate stroke knots?

    For the most part the knots aren’t that interesting; but in a pinch you could try taking a stroke, switching its brush to a spray brush (which lays down one quad per control point) and calling stroke.Recreate(). For bonus points you could create a SprayBrush variant that drops down little coordinate axes instead of quads.

    1. How to see the console log in a live VR session?

    Global Transform Helper

    By @1pld

    If you have a global transform we have a helper: App.ActiveCanvas.AsCanvas[your transform component] = your canvas-relative transform This works no matter where the transform component is in the hierarchy

    Other Discord Brain Dumps by @1pld

    (various nuggets extracted from drive-by comments that Paul made on the Discord)

    Knot is a control point with some more data glommed on; it's a term that geometrybrush invented

    Do you need to manually record strokes to memory after using DetachStroke?

    You do. The intent is that Recreate doesn't interact at all with "memory" (the two linked lists of strokes, ordered by time of first and time of last control poin t). Recreate, uncreate, etc only affect the stroke geometry. They take it from the state "no geo" to "with geo", or from "with geo" to "with different geo", but shouldn't interact with any higher-level considerations like memory

    There may be assumptions that you're calling it on a stroke that's in the linked lists already, so maybe that explains some of the strange behavior you're seeing.. but if you want to memorize a stroke I'm almost certain you should do it yourself; don't count on recreate to do it for you

    1pld

    Historically, things started with QuadStripBrush, with a couple variants based on how UVs were generated. It just generates strips, 6 unique verts per tri (3 for top, 3 for bottom, backface culled). Then there was a variant that produced isolated quads (for brushes like "leaves") instead of strips. QuadStripBrush uses a class called MasterBrush to temporarily store and work on the geometry before it's finalized into a mesh / batch. Then I wrote GeometryBrush to "reboot" geometry generation and enable other kinds of topology. The intent was that QuadStripBrush-based brushes would migrate to FlatGeometryBrush, but the way that QuadStripBrush did its smoothing was not easy to replicate (the details aren't important but the incremental algorithm QSB uses means that each knot doesn't have "local support" in the technical sense, and GeometryBrush in part was written to force people to use knots with local or at least bounded support for efficiency reasons). So FlatGeometryBrush isn't used much. Most other brushes are derived from GeometryBrush. GeometryBrush is notable for using a different storage scheme for intermediate geometry called "GeometryPool". This is used all over the place, wherever we want to process mesh data in C# (eg: geometry generation, multiplying geometry by a TrTransform, export). Some of these manipulations have native-code versions that MachWerx wrote in C++; I think we ship that DLL in the repo. The GeometryBrush variant of the old "isolated quad" brushes is SprayBrush, and I think the old version of that doesn't exist in the code any more. GeniusParticlesBrush is I think Xap's very first work on the project and replaced an older less genius way of particle brushes. TubeBrush was our first volumetric brush; it's also slightly notable for using a different method of curve framing. Instead of BaseBrushScript.ComputeSurfaceFrameNew, it uses parallel transport Dark Jeremy wrote HullBrush and that made the concept of "Knot" kind of weird.

    ParentBrush was an experiment That's the major ones

    I don't work for Google any more, but I don't think any kind of wholesale export of the bug db would be allowed. Happy to expand on any TODOs that I still understand though

    Backwards compatibility is a very real issue in the code; we took a very hard line and very seldom swapped in completely new implementations for a brush guid. Mostly when we wanted to fix or upgrade the behavior of brushes, we'd create an entirely new guid and leave the old one around for compat.

    I think monoscopic mode is a prime area for improvement! A lot of people would benefit

    Anything is possible, but the main reason I wrote abstractions like Stroke.Recreate and so on is because I found it hard to keep track of all the contortions with pointers, pointer managers, input, and so on :). I know I traced through the whole path from input to geometry many many times over the course of the project; it's useful to do. From memory I can sketch it out at a very high level: input comes in from a user, makes its way to a pointer. The pointer deals with creating/finalizing BaseBrushScript instances. The pointer also deals with remembering which control points were used. This is a little gross though; see UpdateLineFromObject. The pointer assumes that the BBS will use a piece of input, and it's up to the BBS to tell it "I used new input to over-write the last quad/whatever" or "I used your input to create an all-new quad", which has implications for which control points the pointer keeps around. Lots of potential for off-by-one errors and so on. Eventually the user lets go of the trigger, the PointerScript terminates the line, deals with off-by-one issues in its control point array, arranges for the geometry in the brush to be finalized into a GameObject/batch, for the control points to be finalized into a stroke, puts the stroke into the memory, and so on

    Or we could be loading from a file, in which case the work is substantially similar. We reuse PointerScript to load from files and kind of trick it into thinking that it's being driven from a user; but there are hacks to ensure that the BaseBrushScript doesn't reject any control points coming in. And there are some other hacks to allow brushes to try to process a whole batch of control point input at once instead of one-at-a-time. This was one of the main motivations for GeometryBrush; a brush should 1. not do O(n) work for each new control point, and 2. be able to process a group of control points at once instead of doing O(n) updates

    Updating "stretch" UVs is obviously always going to be O(n) so there are some other hacks to defer that generation until "update visuals" gets called. Maybe some other things. Anyway, there are mechanisms to prevent O(n^2) behavior on load. Similarly, you wouldn't want your hull brush to compute a hull N times when loading. Something to think about when writing a geometry generator.

    The batch manager was written because "1 gameobject per stroke" is obvs not scalable. So it's a way of taking a bunch of tiny meshes, all of the same material, and grouping them into larger meshes. The tiny meshes become a "BatchSubset" within a larger mesh "Batch", and a single material ("BatchPool") will have multiple meshes ("Batches") and the whole thing is orchestrated by BatchManager

    Some thoughts on @andybak 's comment about "let a thousand brushes bloom". Tilt Brush didn't have a well-defined notion of what should happen when loading a .tilt containing an unknown brush guid. It would warn about it, and end up ignoring the strokes using that brush (see: SaveLoadScript.GetForceSupersededBy which ignores the problem when loading from disk, and StrokePlayback.BaseInit for where that warning is eventually surfaced quite late in the load process, after a stroke creation has already failed). It got away with that because by construction (and by control of the ecosystem) that error was prevented for the most part. In this new ecosystem where "unknown brush" is going to be much more likely, regardless of the strategy chosen for blooming 1000 brushes, I think it's worthwhile replacing the current behavior with something a little more friendly to both producers and consumers of .tilt files. So a sketch of a proposal: - At a minimum, guarantee that loading then saving a .tilt containing an unknown brush preserves strokes using that brush - Embed some "fallback brush" data in the .tilt's brush index, so clients can at least show something reasonable. eg, if a client knows that the missing brush is a quadstrip, tube, spray (ie, disconnected quads), volume (ie, some kind of hull), particles, or "other", that's enough info to substitute in some generic-looking placeholder brush.

    There could be a similar discussion around the forward-compatible extension points built into the per-stroke and per-control-point data. Currently there can only be 32 kinds of extension data (as opposed to basically infinite brushes), which doesn't seem like enough for an ecosystem. Plus, you'd need someone to control a registry to dole out pieces of that very tiny namespace. On the other hand, it's not like people are clamoring to add new kinds of data to strokes or control points (... yet)

    andybakToday at 9:03 PM

    So we do need some taxonomy for brush behaviour that can be relied on universally. i guess that could be based on historic baseline of brushes released before we went brush crazy.

    1pldToday at 9:04 PM

    Yeah, I think we have enough data to have a rough taxonomy; and if some .tilt used an unknown taxonomy for an unknown brush, a client could then choose to ignore it, or substitute in whatever they chose

    My initial taxonomy would be: ribbon, tube, hull, spray, particles, and "do not substitute"

    andybakToday at 9:11 PM

    why not have the entire original brushset as potential fallbacks?

    we could have the smaller taxonomy to help partial implementations - but any proper client app should at least support the original set of brushes that are already out there.

    1pldToday at 9:17 PM

    Totally; the fallback could be specified as a guid too. I thought that a higher-level approach might be easier for brush authors -- it's the difference between an extra kind-of-inscrutable guid field in the brush descriptor, vs a dropdown saying "brush type"

    Tube

    Yes

    Yes

    Yes

    Coarse Bristles

    Spray

    No

    No

    No

    Comet

    Tube

    Yes

    Yes

    Yes

    Concave Hull

    No

    No

    No

    Dance Floor

    Yes

    Yes

    Yes

    Diamond

    Hull

    No

    No

    No

    Disco

    Tube

    Yes

    Yes

    Yes

    Dot Marker

    Spray

    No

    Yes

    No

    Dots

    No

    Yes

    Yes

    Pinched Flat

    Flat

    No

    No

    No

    Pinched Marker

    Flat

    No

    Yes

    No

    Duct Tape

    Flat

    No

    No

    No

    Electricity

    Flat

    Yes

    Yes

    Yes

    Embers

    Particle

    Yes

    Yes

    Yes

    Faceted Tube

    Tube

    No

    Yes

    No

    Felt

    Flat

    No

    No

    No

    Fire

    Flat

    Yes

    Yes

    Yes

    Flat

    Flat

    No

    No

    No

    Highlighter

    Flat

    No

    Yes

    No

    Hypercolor

    Flat

    Yes

    Yes

    Yes

    Hyper Grid

    No

    Yes

    Yes

    Icing

    Tube

    No

    No

    No

    Ink

    Flat

    No

    No

    No

    Leaves

    Spray

    No

    No

    No

    Light

    Flat

    No

    Yes

    Yes

    Light Wire

    Tube

    Yes

    Yes

    Yes

    Lofted

    Tube

    No

    No

    No

    Marker

    Flat

    No

    Yes

    No

    Matte Hull

    Hull

    No

    No

    No

    Oil Paint

    Flat

    No

    No

    No

    Paper

    Flat

    No

    No

    No

    Petal

    Tube

    No

    No

    No

    Plasma

    Flat

    Yes

    Yes

    Yes

    Rainbow

    Flat

    Yes

    Yes

    Yes

    Shiny Hull

    Hull

    No

    No

    No

    Smoke

    Particle

    Yes

    Yes

    No

    Snow

    Particle

    Yes

    Yes

    Yes

    Soft Highlighter

    Flat

    No

    Yes

    Yes

    Spikes

    Tube

    No

    No

    No

    Splatter

    Spray

    No

    No

    No

    3D Printing Brush

    No

    No

    No

    Stars

    Particle

    Yes

    Yes

    Yes

    Streamers

    Flat

    Yes

    Yes

    Yes

    Taffy

    Flat

    Yes

    No

    Tapered Flat

    Flat

    No

    No

    No

    Tapered Highlighter

    Flat

    No

    Yes

    No

    Tapered Marker

    Flat

    No

    Yes

    No

    Thick Paint

    Flat

    No

    No

    No

    Toon

    Tube

    No

    Yes

    Yes

    Tube Toon Inverted

    Tube

    No

    Yes

    No

    Unlit Hull

    Hull

    No

    Yes

    No

    Velvet Ink

    Flat

    No

    Yes

    Yes

    Waveform

    Flat

    Yes

    Yes

    Yes

    Waveform FFT

    Flat

    Yes

    Yes

    Yes

    Waveform Particles

    Yes

    Yes

    Yes

    Neon Pulse

    Tube

    Yes

    Yes

    Yes

    Waveform Tube

    Tube

    Yes

    Yes

    Yes

    Wet Paint

    Flat

    No

    No

    No

    Dr. Wigglez

    Flat

    Yes

    No

    Yes

    Wire

    Tube

    No

    Yes

    No

    Wireframe

    No

    Yes

    Yes

    Flat

    Yes

    Double Flat

    Flat

    No

    No

    Drafting

    Flat

    No

    Dry Brush

    Flat

    No

    No

    Duct Tape (Geometry)

    Flat

    No

    No

    Fairy

    Flat

    Yes

    Feather

    Flat

    Yes

    Fire2

    Flat

    Yes

    Yes

    Flat Geometry

    Flat

    No

    No

    Gouache

    Flat

    No

    No

    Guts

    Tube

    No

    No

    Diffuse

    No

    No

    Ink (Geometry)

    Flat

    No

    No

    Keijiro Tube

    Tube

    Yes

    No

    Lacewing

    Flat

    No

    Leaky Pen

    Flat

    No

    Wire (Lit)

    Tube

    No

    No

    Lofted (Hue Shift)

    Tube

    Yes

    Marbled Rainbow

    Flat

    Yes

    Marker (Geometry)

    Flat

    Yes

    No

    Muscle

    Tube

    No

    No

    Mylar Tube

    Tube

    No

    Oil Paint (Geometry)

    Flat

    No

    No

    Paper (Geometry)

    Flat

    No

    No

    Race

    Flat

    Yes

    Yes

    Rain

    Tube

    No

    Rising Bubbles

    Particle

    Yes

    No

    Single Sided

    Flat

    No

    No

    Smooth Hull

    Hull

    No

    No

    Space

    Flat

    Yes

    Sparks

    Tube

    No

    Square Flat

    No

    No

    TaperedHueShift

    Flat

    Yes

    TaperedMarkerGeo

    Flat

    Yes

    No

    Tapered Wire

    Tube

    No

    No

    Leaves2

    Spray

    No

    No

    Geom/Thick (Duct Tape)

    No

    No

    Tube (Highlighter)

    Tube

    Yes

    No

    Tube (Flat)

    Tube

    No

    No

    Tube (Marker)

    Tube

    Yes

    No

    Watercolor Paper

    Flat

    No

    No

    Watercolor Paper (Geometry)

    Flat

    No

    No

    Wet Paint (Geometry)

    Flat

    No

    No

    Wind

    Flat

    Yes

    No

    Bubbles

    Particle

    Yes

    Yes

    No

    Cel Vinyl

    Flat

    No

    Yes

    No

    Bubble Wand

    Tube

    No

    No

    Charcoal

    Flat

    No

    No

    audio reactivity

    Chromatic Wave

    Digital

    PointerManager.SymmetryMode: The only symmetry mode enabled by default is the normal mirror. But there is a double mirror hidden behind the experimental flag and a “debug” symmetry mode that can only be enabled via code.
    In the main scene under SketchControls add an entry to the Panel Map (on the Panel Manager component). Choose the same PanelType as before. (note that the list item will have the wrong panel - or just a number - next to it if you used your own explicit enum value. This doesn’t seem to matter)

    The OptionButton should have it’s command set to the new command

  • Tick “requires popup” on the buttonscript

  • Edit the m_PanelPopUpMap property on the panel prefab root that references the command and the popup prefab

  • Create a custom command for editing the value the slider represents. See ModifyFogCommand for an example.

  • Use your new command to change the underlying value that the slider represents. This is typically done in OnPositionSliderNobUpdate and EndModifyCommand.

  • Test and make sure your slider correctly changes the underlying value

  • Register for events that get triggered if some other piece of code modifies your underlying value. In this case, we need to know about it so that we can update where the slider tick is located. If the event does not already exist, you may have to create a new event. One possible appropriate place is in Switchboard.cs

  • Make a duplicate of the stencil script you used in #1 and rename it myNameStencil.cs
  • Replace the stencil script on your prefab to use the one you just created.

  • Open the GuideToolsPanel in Assets/Prefabs/Panels, duplicate one of the buttons and position it appropriately in the panel.

  • In the StencilButton component change the Description Text and Button Texture to something appropriate for your shape and change the type to your stencil type.

  • LongPressButton : OptionButton

    OptionButton that opens a popup when long pressed.

  • LongPressToolButton : LongPressButton

    (not used) Extends LongPressButton and adds tool activation

  • ModeButton : BaseButton

    Not used directly but is the base class for Gallery PolySet and Reference buttons

  • MultistateButton : BaseButton

    Cycle through multiple states on each click. Calls a GlobalCommand with the index of the current option

  • NavButton : BaseButton

    Navigates between pages in paged panels and popups.

  • OptionButton : BaseButton

    Optionally calls a GlobalCommands and passes in two parameters assigned in the inspector. Optionally opens a popup set via the PopupMap on the parent Panel script. Optionally toggles between two states.

  • PanelButton : BaseButton

    Toggles visibility of a panel (BasePanel.PanelType)

  • PropertyToggleButton : BaseButton

    Allows the button to be connected to a bool property on a component, and automatically reflect its value as well as toggling its value when the button in pressed.

  • Layers.ToggleButton : BaseButton

    Performs no action but maintains on/off state

  • ToggleButton : OptionButton

    Invokes a UnityAction and also maintains on/off state.

  • ToolAndPanelButton : BaseButton

    Combines ToolButton and PanelButton functionality

  • ToolButton : BaseButton

    Activates a tool (BaseTool.ToolType)

  • PerformAndRecordCommand BrushStrokeCommand

  • Make sure that it’s right underneath the “Button_Straightedge” object at the same level in the hierarchy.

  • Change the Description Text to read “Fly”

  • Make a 128x128 black and white image to use as the button texture. Place this image in the Assets/Resources/Icons folder and name it “foo.png”.

  • Drag it on to the “Button Texture” property of your new button object.

  • In Assets/Scripts/Tools/BaseTool.cs find the ToolType enum and add a new line to the bottom:

  • Place all the visual content as children of an empty ‘DirectionIndicator’ object which is a child of our tool.

  • Deactivate the new tool

  • Create a new script in Assets/Scripts/Tools and call it FooTool.cs. Use the template script [link]

  • Add this new component to our FlyTool object in the scene, ensure that that tool type is set to FooTool

  • In Assets/Scripts/InputManager.cs look for the SketchCommands enum. Add “Fly” at the bottom

  • Scroll down in InputManager to the GetCommand function. We need to pass the command through to the Brush

  • Update the function to look like this (note lines 37 and 38):

  • Find the Brush.GetCommand function in the file Assets/Scripts/Input/ControllerInfo.cs and update it (note lines 27 and 28)

  • Press play.

  • Customising Tilt Brush - Part Two: Adding Flight
    Scobot - How I change the look of Tilt Brush brushes in Unity3D
    Open Brush: Brushes, Materials and Shaders
    Open Brush: Panels, Popups and UI Classes
    Open Brush: Keyboard Controls and VR Input
    Monoscopic mode
    Open Brush Config file
    Open Brush without a headset
    : Open Brush enum reservations
    https://answers.unity.com/questions/1125244/what-happened-to-conveniently-replacing-component.html
    https://youtu.be/HjsLzyNNxuM
    Enums
    Open Brush: Panels, Popups and UI Classes
    https://discord.com/channels/783806589991780412/806934697237938216/820958273032683520
    Here in my API branch
    Here in my symmetry branch
    Lachan's Tutorial
    "Flags": {
        "EnableMonoscopicMode": true
    }
    public enum FoobarType
    {
       ExistingValueA,
       ExistingValueB,
       ...
       MyNewValueA = 5000
       MyNewValueB = 5001
    }
    public class MyNewPanel : BasePanel
    {
    }
    RequestModelPreloadInternal (LocalModelButton.cs)
      LoadFullyCoroutine (models.cs)
        LoadModel (models.cs) 
          CreatePrefab (models.cs)
    var model= new Model(Model.Location.File(path));
    public void TestImport(string filename, Vector3 position, Quaternion rotation)
    {
        path = Path.Combine(App.MediaLibraryPath(), "Models", path);
        var model = new Model(Model.Location.File(path));
        model.LoadModel();
    
        var tr = new TrTransform();
        tr.translation = position;
        tr.rotation = rotation;
        CreateWidgetCommand createCommand = new CreateWidgetCommand(
        WidgetManager.m_Instance.ModelWidgetPrefab, tr);
        SketchMemoryScript.m_Instance.PerformAndRecordCommand(createCommand);
        ModelWidget modelWidget = createCommand.Widget as ModelWidget;
        modelWidget.Model = model;
        modelWidget.Show(true);
        createCommand.SetWidgetCost(modelWidget.GetTiltMeterCost());
    
        WidgetManager.m_Instance.WidgetsDormant = false;
        SketchControlsScript.m_Instance.EatGazeObjectInput();
        SelectionManager.m_Instance.RemoveFromSelection(false);
    }
    if App.PlatformConfig.EnableExportJson:
        "json"
    
    #if FBX_SUPPORTED:
        if App.PlatformConfig.EnableExportFbx:
            "fbx"
    
    #if USD_SUPPORTED:
        if App.PlatformConfig.EnableExportUsd:
            "usd"
    
    #if (UNITY_EDITOR || EXPERIMENTAL_ENABLED):
        if Config.IsExperimental:
            "wrl"
            "stl"
            #if FBX_SUPPORTED:
                "obj"
    
    if App.PlatformConfig.EnableExportGlb:
        "glb"
    diff --git a/Assets/Scripts/Export/ExportCollector.cs b/Assets/Scripts/Export/ExportCollector.cs
    index c9df745..5b1e27f 100644
    --- a/Assets/Scripts/Export/ExportCollector.cs
    +++ b/Assets/Scripts/Export/ExportCollector.cs
    @@ -251,6 +251,13 @@ class ExportCollector {
     
             string legacyUniqueName = $"{desc.m_DurableName}_{desc.m_Guid}_{group.id}_i{batchIndex}";
             string friendlyGeometryName = $"brush_{desc.m_DurableName}_g{group.id}_b{batchIndex}";
    +        // If it's split by color then we have to append some kind of thing to keep the unique name unique
    +        if (brush.m_color is Color c) {
    +          Color32 c32 = (Color32)c;
    +          string cstr = $"_c{c.r:2X}{c.g:2X}{c.b:2X}";
    +          legacyUniqueName += cstr;
    +          friendlyGeometryName += cstr;
    +        }
     
             UnityEngine.Profiling.Profiler.BeginSample("ConvertToMetersAndChangeBasis");
             ExportUtils.ConvertUnitsAndChangeBasis(geometry, payload);
    diff --git a/Assets/Scripts/Export/ExportUtils.cs b/Assets/Scripts/Export/ExportUtils.cs
    index 935411f..486a3a2 100644
    --- a/Assets/Scripts/Export/ExportUtils.cs
    +++ b/Assets/Scripts/Export/ExportUtils.cs
    @@ -76,7 +76,7 @@ public static class ExportUtils {
         }
     
         public IEnumerable<ExportBrush> SplitByBrush() {
    -      return m_strokes.GroupBy(stroke => stroke.m_BrushGuid)
    +      return m_strokes.GroupBy(stroke => (stroke.m_BrushGuid, stroke.m_Color))
               .Select(g => new ExportBrush(g));
         }
       }
    @@ -85,6 +85,7 @@ public static class ExportUtils {
       /// This is the only grouping that can be converted to geometry
       public class ExportBrush {
         public BrushDescriptor m_desc;
    +    public Color? m_color;
         private List<Stroke> m_strokes;
     
         public ExportBrush(IGrouping<Guid, Stroke> group) {
    @@ -92,6 +93,12 @@ public static class ExportUtils {
           m_strokes = group.ToList();
         }
     
    +    public ExportBrush(IGrouping<(Guid guid, Color color), Stroke> group) {
    +      m_desc = BrushCatalog.m_Instance.GetBrush(group.Key.guid);
    +      m_color = group.Key.color;
    +      m_strokes = group.ToList();
    +    }
    +
         public struct PoolAndStrokes {
           public GeometryPool pool;
           public List<Stroke> strokes;
    public class BaseTool : MonoBehaviour
    {
     public enum ToolType
     {
       [...],
       FooTool
     }
    Materials.Assign(PadMesh, SelectPadTouched(active, Materials.ShareYt));
     // Data blocks for StrokeExtension IDs in [0,15] are 4 bytes.
     // Data blocks for StrokeExtension IDs in [16,31] are uint32 length + <length> bytes.
    
      [Flags]
      public enum StrokeExtension : uint
      {
        MaskSingleWord = 0xffff,
        None = 0,
        Flags = 1 << 0,     // uint32, bitfield
        Scale = 1 << 1,     // float, 1.0 is nominal
        Group = 1 << 2,     // uint32, a value of 0 corresponds to SketchGroupTag.None so in that case,
                            // we don't save out the group.
        Seed = 1 << 3,      // int32; if not found then you get a random int.
    
        AudioStream = 1<<16, // wav-format audio to be piped into the shader for this stroke while it's playing back  <--- new
      }

    Tilt Brush Version 23 Release Notes

    These were the last release notes that were put out by Google and contain some useful information not found elsewhere.

    Version 23

    • Added Google Drive Backup (in Beta for now!).

      • Requires signing-in with a Google account.

      • Enable Google Drive Backup on Accounts popup or Sketchbook.

      • Can optionally configure Google Drive Backup to backup Sketches, Snapshots, Media Library, Exports, and Videos.

      • Backup is disabled if Google Drive has less than 0.5 Gb of storage free.

    • Added upload to Sketchfab.

      • Requires a Sketchfab account.

    • Added Camera Path.

      • Open Camera Paths Panel from More Panel.

      • Allows defining a spline to record a video. Spline is defined by various points.

    • Added support for .glb / .gltf files in the Media Library.

    • Added Ellipsoid guide.

    • Changed max snapshot dimensions from 8192 to 16000. Note that very large snapshots may crash your computer.

    • Changed Profile popup to Accounts popup, to support multiple accounts.

    • Modified Upload popup to support multiple accounts.

    • Info cards (like, “Sketch loaded!”) don’t fall away immediately, allowing you a little more time to read them. Tap them to dismiss.

    • Removed h265 support.

    Accessing Autosave Files

    Tilt Brush regularly saves your work into your Documents/Tilt Brush/Sketches/Autosave folder. Each sketch you make has a separate autosave file, and Tilt Brush keeps autosaves from your last five sketches. If you need to access an autosave, move it into your Documents/Tilt Brush/Sketches folder using Windows Explorer—it will have a Tilt Brush logo as its thumbnail in the Sketchbook.

    Tilt Brush Config File

    Outdated See

    Exporting Tilt Brush Sketches

    Tilt Brush sketches can be exported by clicking the ‘Export’ button found on the Labs panel. The Labs panel can be found under ‘More…’ on the Tools panel.

    Each sketch exported from Tilt Brush creates a separate folder in Documents/Tilt Brush/Exports which contains the geometry in the following formats:

    • .glb (binary glTF version 2)

    • .fbx (Desktop only)

    • .usd (Desktop only)

    • .json (Desktop only)

    The .json is a “raw” format which you can use if you need a different file format. See the for sample scripts that convert the raw .json to .obj.

    python convert_to_fbx.py "c:\Users\username\Documents\Tilt Brush\Exports\Untitled_1.json"

    Each script has a set of command-line options that fine-tune the generated file.

    The USD contains both geometry and curve information. If your DCC tool doesn’t support USD, the contains a Python 2.7 script that can convert the .tilt file to a Collada .dae containing the curves.

    Maya

    After importing the FBX file into Maya you will need to turn off the Alpha is Luminance attribute in the Color Balance section for each texture node. To see the brush colors in the viewport turn on the Display Colors attribute and set Material Blend to Multiply in the Mesh Component Display section on each mesh shape node.

    To render with the vertex colors you can use the mentalrayVertexColors shader node to access the stroke color in your material.

    Sketchfab

    To post to Sketchfab you will need to upload the FBX file and the textures.

    We are working with Sketchfab to have Tilt Brush import correctly, but if the strokes look wrong you can try opening the 3D Settings Editor in Sketchfab and under the Materials tab set the material properties manually.

    Unity

    We recommend using the Tilt Brush Toolkit and the .glb format. Tilt Brush Toolkit also understands the .fbx format.

    Command-line Exporting

    To export sketches from the command line, use the --export option to specify a file or set of files to export. --export supports wildcards, and multiple files can be specified with a single --export flag. Filenames without a path are assumed to be found in the Tilt Brush Sketches directory.

    You can override the destination folder of exports using the --exportPath flag.

    We suggest you also specify the -batchmode option if you don’t want the Tilt Brush window to appear.

    Exporting Video

    Rendering ‘Offline’ videos

    When you create a video from inside Tilt Brush using the Camera tool, Tilt Brush will create a Windows batch file alongside the video (In Documents\Tilt Brush\Videos) that you can run to re-render the video at a higher resolution. For example:

    Untitled_13_00.mp4

    Untitled_13_00.HQ_Render.bat

    Double-clicking the ".bat" batch file will give you several options for re-rendering your video:

    Press the number corresponding to the format you prefer. It will then launch Tilt Brush, which will reload your sketch and render the video. Once it is done, Tilt Brush will exit. As rendering at higher quality tends to affect the framerate, it is suggested that you do not wear your headset until this process completes.

    “No Quick Load” option (#6) will forego quick loading of the sketch and will force it to load at normal speed. It is recommended that the time spent recording should exceed the normal loading time of the sketch or else the video may end before the sketch completes loading.

    Video Camera Paths

    Rendering offline videos is achieved by saving off the path the camera took when the video was taken, and then re-using that to recreate the video. The camera path is saved off in ASCII USD () format, so if you have an application that can read and write USD, you may be able to use it to edit camera paths. Camera paths can also be combined with USD exports from Tilt Brush, to exactly recreate how the camera moved through the scene.

    If you want to render a camera path from the command line directly, rather than using the batch file detailed above, you can use the following:

    Changing Eye Scale on ODS 360 videos

    When you render an ODS video, you may find things like the floor is missing, or parts of your objects get clipped off.

    The reason this happens is that it’s often easier to scale down your sketch to make it easy to move the camera when you take your original video, but when you render out an ODS file, the objects are too close to the camera.

    To fix this, you can change a value in the .usda file. Open it up in your favorite text editor and look at around line 30 for:

    If you reduce this value, the render will feel bigger, and the camera is less likely to clip with parts of your sketch. A good value to try out is:

    Then you can just try re-rendering with the batch file.

    Exporting 360 videos / Offline Video Rendering

    Videos can be rendered ‘offline’ faster and at a much higher resolution and framerate than using the internal Multicam tool

    1. Editing Tilt Brush cfg file

    2. Go to C:\Documents\Tilt Brush\Tilt Brush cfg

    3. Under "Video" add the flag "SaveCameraPath": true,

    4. Save Tilt Brush cfg

    Tilt Brush Unity Shader Examples

    Use these with geometry you export from Tilt Brush and import into Unity. However, you should prefer to use the , which comes with Tilt Brush shaders.

    Opaque shader

    Additive shader

    Tilt Brush File Format

    The .tilt file format can also be parsed by the .

    A .tilt is a zip-format file with a prepended header:

    Inside the zip, the strokes are stored in a custom binary format in a file, "data.sketch":

    The orientation is that of the controller. Curve and surface frames must be reconstructed.

    Stroke extensions:

    Control point extensions:

    0
    float pressure, in [0,1]

    Also inside the zip is "metadata.json", the metadata for the sketch in json format. Here are some of the fields that can be found there:

    • "Authors": an array of author names.

    • "SceneTransformInRoomSpace": the transform of the scene relative to the room.

    • "ThumbnailCameraTransformInRoomSpace": the transform used to generate the sketch as an array of:

    Previous Releases

    Version 22

    • Added Groups to Selection tool.

      • Grouping allows brush strokes and widgets to share selection state. Select part of a group and the whole group is selected with it.

      • Grouping status data is saved with the sketch.

    Version 21

    • Quest release only.

    • Added Labs Panel.

      • Contains Reference Image Panel, Pin Tool, Export, and experimental Cameras.

    • Added Reference Image support.

    Version 20

    • PC release only.

    • Add Valve Index support.

      • Update to latest SteamVR plugin to support custom input bindings.

    • Added Logitech VR Ink Pilot Edition.

    Version 19

    • Oculus Quest release only.

    • Deviations from PC.

      • Labs Panel has been removed.

    Version 18

    • New audio for all brushes.

      • Each brush sound is now unique, and subtly reacts to the way you are painting.

    • Flip Selection.

    • Added a button in the Settings to link to the .

    Version 17

    • Added controller support for Windows Mixed Reality headsets on SteamVR

    Version 16

    • NEW BRUSHES! 12 brand new brushes for your enjoyment:

      • Wet Paint - Glossy, high shine paint

      • Dr Wigglez - Animated sketchy charcoal

      • Cel Vinyl - A flat cartoon brush with a black outline

    Version 15

    • Support for importing any object uploaded to Poly (w/ CC-BY license)

      • The “Poly” panel is located inside Tilt Brush: "Tools" panel -> “More Tools...” -> “Poly”.

      • Any CC-BY Blocks model or .obj you like on Poly will appear on that panel (assuming you’re signed-in with the same account).

    Version 14

    • Blocks Library:

      • Accessible on the “Tools” panel, the Blocks Library allows you to add remixable featured and liked objects to your Tilt Brush sketches.

      • Tilt Brush sketches using Blocks objects can now be published to vr.google.com/sketches.

    Version 13

    • Internal version that was either too good to release, or the dev team suffered from triskaidekaphobia.

    Version 12

    • Ability to “repaint” stroke colors

      • Allows you to change the color of any strokes in your scene

      • Accessible through the “Labs” panel

    • “Featured” sketches in Tilt Brush pull from tiltbrush.com/sketches

    Version 11

    • UI polish

      • Refreshed panel form factor (rounded edges, same sizes, all elements aligned to a grid)

      • Refreshed the visual style of the icons

    • Added lights/backdrop to the undo/redo stack

    Version 10

    • Sharing

      • Share sketches to the !

      • Use the Share button on the Save/Trash Panel to upload the active sketch. Requires logging in with a Google account.

    Version 9

    • Oculus Rift support on Oculus Home

    • Oculus Rift support on SteamVR

    • Added customizable Color Palette to Color Picker.

    • Color Palette is saved with sketch.

    Version 8

    • Sharing directly from Tilt Brush to YouTube

      • When you record a video, you now have the option to upload to YouTube.

      • Hold down the thumbpad after a video has finished recording to go into Preview mode.

    Version 7.5

    • Media Library Improvements

      • Support for importing multiple models and images.

      • Added ability to pin models and images, disabling movement.

    Version 7

    • Rotate and Resize

      • Hold both grip buttons at the same time to move, turn, or resize yourself.

      • While resizing, click the trackpad to reset yourself to original size.

    • Controller Swapping

      • Point the controllers away from each other and tap the bottoms to swap the palette and paint brush.

    • High resolution snapshot mode

    Version 6

    • Audio reactive brushes

      • Added new “Audio Reactive” mode for brushes.

        • Toggle Audio Reactive mode on the Brushes panel.

    Version 5

    • Switch versioning numbers to be more open-ended.

    • Added 5-Second Gif mode to MultiCam.

    • Export button now auto-generates .fbx, along with old .json intermediate file.

    • Color picker works on reference images.

    Version 1.4

    • Added Teleport Tool.

    • Added ability to view YouTube Live chat while streaming. (see notes below)

    • Replaced IRC support with dedicated Twitch Chat support. (see notes below)

    • Labs Panel can be dismissed by tossing.

    Labs Panel

    • YouTube Chat

      • Requires “Tilt Brush.cfg”, stored in: Documents/Tilt Brush

      • Format:

      • Note:

      • Use Grip button to move chat widget.

      • Note:

      • Use Grip button to move chat widget.

    Version 1.3

    • Improved guide for Spectator Camera in Circle Mode.

    • Added Mirror snap functionality.

    • Added basic Export support.

    • Added ability to view .jpgs and .pngs as Reference Images.

    Labs Panel

    • Reference Images

      • Used for viewing external images while inside Tilt Brush.

      • Loads .png and .jpg images stored in Documents/Tilt Brush/Reference Images.

    }

    Note:

      • Use Grip button to move chat widget.

      • Use both Grip buttons to scale chat widget.

    Anchor Points define spline position. Use tangent controls to modify curves.
  • Direction Points define camera facing at that point on the path. While manipulating, use trigger to preview camera.

  • Speed Points define camera speed at that point on the path. Use cone control to adjust speed value.

  • Zoom Points define camera zoom at that point on the path. Use frustum control to adjust zoom value. While manipulating, use trigger to preview camera.

  • Camera Setup

  • Load the sketch you would like to render

  • Find a good spot from which you would like to capture your 360 video

  • Be sure to look around in all directions to make sure no objects are too close to the point of capture

  • Save your sketch

  • Record your video by moving camera or keeping camera stationary

  • After saving, exit Tilt Brush

  • Rendering ****Note: When you create a video from inside Tilt Brush using the Camera tool with configuration "SaveCameraPath" flag set to true, Tilt Brush will create a Windows batch file alongside the video (In Documents\Tilt Brush\Videos) that you can run to re-render the video at a higher resolution

  • Go to C:\Documents\Tilt Brush\Videos . There should be .usda, .bat and video file which corresponds to the .tilt file

  • Double click on .bat file

  • If you run that batch file a command window will appear giving you several options for re-rendering your video: Press a number to get whichever format you prefer. It will then launch Tilt Brush, which will reload your sketch, and re-render the video. Once it is done, Tilt Brush will exit. As rendering at higher quality tends to affect the framerate, it is suggested that you do not wear your headset while this process completes.

  • Once the render is complete, it will pop open the “VRVideos” folder which should contain an video file with your stereo render.

  • Converting into 360 video 1. Download the 360° Video Metadata app for Mac or Windows. The dialog should look like this: 2. Unzip the file, then open the 360 Video Metadata app. If you're on a Mac, you may need to right-click the app and then click Open. 3. Select the video file. 4. Select the checkbox for My Video is stereoscopic 3D (top/bottom layout) 5. Click Inject Metadata 6. Enter a name for the file that will be created. 7. Save the file. A new file will be created automatically in the same location as the original file.

  • Uploading to Youtube

    1. Upload the new “injected” video file to YouTube

    2. Note that it takes YouTube some additional time to process 360 videos, until this process is finished, you may see the raw over/under and the “View in Cardboard” option will not be available.

    3. Once processing is done, you should see this icon when viewing the video on your phone, indicating that it’s ready to be viewed in VR:

  • translation (array of 3 floats)
  • rotation quaternion (array of 4 floats)

  • scale (single float)

  • "ModelIndex": an array of models imported into the sketch. Each model can have the following:

    • "FilePath": location of the model

    • "PinStates": an array to indicate whether each instance of the model should initially be pinned.

    • "RawTransforms": an array of transforms for each instance of the model.

  • When a sketch is exported, each group is written to a separate node in the exported file. This allows easier sketch manipulation in editing tools, post-export.
  • “Group Selection” is one of the buttons available on the new selection tray that pops out next to the selection button when the selection tool is on.

  • Added Reference Videos support.

    • New tab added to Media Library Panel for videos.

    • Videos are taken from the Tilt Brush\Media Library\Videos directory.

    • Videos, like reference images, are not stored in the .tilt file and are not uploaded to Poly.

    • You can link to an online video by putting its URL into a .txt file inside the videos directory.

    • Audio from videos is supported, but is ‘2D’ only.

    • Known bugs:

      • Reference Videos do not currently work in offline renders.

  • Export Improvements.

    • Tilt Brush exports .glb (glTF 2.0) instead of .glb1 (glTF 1.1). glTF 2.0 is supported by more tools and is slightly more efficient.

    • Export now works on Oculus Quest (.glb only)

    • Tilt Brush Toolkit supports both .glb and .glb1.

    • glb: Added timing information to .glb exports.

      • Tilt Brush Toolkit will put timing information into texcoord2.

      • Timestamps are a vec3.

    • glb, fbx: Media Library models are now included in exports.

    • glb, fbx: Various quality of life improvements in the exported file.

  • New tool tip descriptions.

    • Tool tips have a new cleaner and consistent look.

  • Deterministic Geometry Generation.

    • Some stroke behavior is randomized—for example, brush textures and Light Wire light colors. This behavior is now saved into the .tilt, so when you re-load a sketch you will see the same thing as when you drew it.

    • Requires connecting your Quest to a PC and side loading images into a Tilt Brush folder. Some restrictions apply.

    • See the Help Center for a more detailed explanation of how to use Reference Images.

  • Added Export to .glb1 (binary glTF).

    • Updated Tilt Brush Toolkit to support .glb1 import.

    • Previously, Reference Images would appear in the export as as empty transform nodes. They are now included in the export.

  • Added Cameras.

    • Experimental version of Snapshot and Gif Capture cameras.

  • Tilt Brush files moved to “/sdcard/Tilt Brush” on Quest.

    • This prevents work from being lost when Tilt Brush is uninstalled.

  • Drastically decreased the amount of memory allocated during sketch quick-loading.

  • Variety of performance optimizations pulled from the Oculus Quest version.

  • Export not supported.
  • Spectator Camera not supported.

  • Twitch Chat not supported.

  • YouTube Chat not supported.

  • Local Media Library not supported.

  • Tiltasaurus game not supported.

  • MultiCam has been removed.

    • Photo capture, video capture, and streaming are all supported by the Oculus Dash platform.

  • Select All has been disabled.

  • Invert Selection has been disabled.

  • Flip Selection has been disabled.

  • Autosave has been disabled. Be careful!

  • Added Memory Warning Mode.

    • Memory allocation can be viewed in the Settings Panel.

    • After crossing a memory threshold, the app will enter a ‘Memory Warning’ state.

    • Deleting a Sketch will reset allocated memory.

    • Sketches above a certain triangle limit will display a warning in the Showcase and Liked Sketches section of the Sketchbook.

    • Sketches above a certain larger triangle limit will display a more severe warning in the Liked Sketches section of the Sketchbook.

  • Long press on Selection Tool icon in Advanced mode.
  • Allow tuning of MultiCam field of view.

    • Requires “Tilt Brush.cfg”, stored in: Documents/Tilt Brush

    • Format:

  • Import and apply normal maps for .fbx models in Media Library.
  • Fix screen tearing bugs with video recording.

  • Added a frame counter for offline rendering.

  • Fix some Poly models not loading.

    • Visible error was, “No usable geometry found!”.

  • Petal - 3d flower-like brush, also great for hair

  • Icing - A lit tube brush with a light texture

  • Spikes - 3d spikes

  • Lofted - 3d calligraphic brush

  • Comet - A new spin on a 3D animated fire brush

  • Hull brushes - create volumes by sweeping out the brush with a few different shading options:

    • Shiny

    • Matte

    • Unlit

    • Diamond

  • Beginner & Advanced modes.

    • New “Beginner” mode with a more limited set of tools, well suited for new users, and when giving demos.

    • Panel layout saved session to session in Advanced mode.

    • New Main Menu Panel design.

  • New Pin tool.

    • New dedicated tool for quickly pinning and unpinning models, guides and images.

    • Located on the Labs Panel.

  • Select All and Invert Selection.

    • Long press on Select Tool icon in Advanced mode.

  • Recall Mirror.

    • Long press on Mirror Tool icon in Advanced mode.

    • Useful for retrieving the mirror when it is out of arm's reach.

  • Rapid Undo / Redo.

  • Press & hold the Undo or Redo button on the controller to repeat the action repeatedly.

  • New UI audio.

  • Stroke Simplification Slider.

    • Allows vertex reduction on sketches. Useful for low performance PCs and simplifying geometry before export.

    • Located on the Settings Panel.

  • Pixar's Universal Scene Description (USD) is now exported when pressing ‘Export’ on the Labs Panel.

    • This new export includes geometry, models, brush curves, and stroke timing.

  • Support for changing eye scale when rendering ODS 360 videos.

    • You can now create a camera path with everything scaled down, and then scale the camera back up when doing an offline render.

  • General performance improvements.

    • Sped up rendering of UI.

    • Sped up rendering of several brushes.

  • You can remix Blocks models and uploaded .objs in your Tilt Brush sketches, and share remixed sketches back to Poly!
  • Note: you cannot import published Tilt Brush sketches into Tilt Brush sketches at this time.

  • New intro flow and updated Sketchbook panel

    • Starting with the second time users open Tilt Brush, we now show a more illustrative “intro” screen.

    • The controllers also default to having the Sketchbook open, highlighting sketches featured from Poly.

  • Selection improvements

    • Stamp mode: when gripping a selection with your painting controller, you can now stamp duplicates of your selection in your scene

  • New contextual tooltips for actions and features

    • We’ve added contextual tooltips to instruct users how to use certain features.

    • Specifically: grip to grab, toss to dismiss, selection, and sharing sketches to Poly.

  • Video Recording

    • 360 videos now render 5x as fast.

    • Added the option to use “h.264” encoder, see user config for details.

    • Videos can now be rendered ‘offline’ at a higher resolution and framerate than feasible from inside Tilt Brush. See Rendering ‘Offline’ Videos.

  • *Only* remixable Blocks objects will appear in the Blocks Library.
  • Selection Tool:

    • With the new “Selection Tool”, you can select and duplicate strokes and models in your scene.

    • “Selection” is found next to the “Eraser” button on the Tools panel.

    • Select strokes using the trigger. You can also flip into deselect mode by tapping the thumbpad (Vive) or “A/X” button (Rift).

    • If you want to move your selection, grab it as you would any other model in your scene. To delete a selected group of strokes, just throw it away.

    • Duplicate selections by holding the thumbpad (Vive) or “A/X” button (Rift) while intersecting your controller with selected strokes.

  • Quick Tool:

    • Holding the “menu” button (Vive) or “Y/B” (Rift) on the controller now triggers a “Quick Tool” menu, letting you quickly swap tools without reaching back to the palette.

  • Palette icon reorganization:

    • Reshuffled icons on the palette, based on common usage patterns

    • Moved the user profile button to the Menu Panel

    • Introduced a new “More…” menu where we’re moving more advanced tools and features.

    • We did not remove any Tools - if you’re looking for something and can’t find it, it is probably either in a “More…” menu or under “Labs.”

  • Relaxed limit on model scale:

    • Imported models can be scaled to much smaller and larger sizes.

    • At certain large scales you may find performance hitches -- your fate is in your hands.

  • Fixed duplicate upload bug:

    • Now when you upload sketches to vr.google.com/sketches, new drafts of a sketch will overwrite the last draft (instead of creating a new one).

    • Doesn’t affect published sketches.

  • Tiltasaurus tweaks:

    • Now sketches are saved automatically when a new word is chosen.

    • Share your sketches to the web for a chance to be featured in Tilt Brush!

    • Featured sketches are found in the “Sketchbook” panel in the app

  • Ability to view rights reserved sketches liked on tiltbrush.com/sketches

  • Added a parameter in "Tilt Brush.cfg" to control camera smoothing for video captures

    • Changes to lights’ color and orientation are on undo stack

    • Changes to skybox (unlocking, changing color and orientation) are on undo stack

    • Changes to fog color and density are on undo stack

    • Changing environments is on undo stack

  • Camera movement for 360 stereo video export (example)

    • Two sketches can now be specified when rendering with --captureOds

    • Save the same sketch twice: the first with your starting camera angle, and the second with the camera where you want the path to end

    • The camera will move on a path from the first camera location to the second in a single 360 video

    • See “Exporting 360 Videos” below for details

  • Faster video encoding

    • The video camera now encodes faster, which enables higher resolution videos and higher frame rates. See “Using the Tilt Brush.cfg file” below for details on how to adjust resolution and frame rate.

  • Integrated Google VR spatial audio

  • Sketches exported to FBX include transforms for Media Library assets. This means you can easily rebuild your scenes (including those Media Library assets) in another 3D package. Formal support is in place for Unity and Maya.

  • 100% Brush Parity in the Tilt Brush Toolkit (including all particles)

  • Linear lighting support in The Tilt Brush Toolkit

    • Previously, there were issues with color disparity between Linear & Gamma lighting modes.

    • If you export with Version 10 or above, you should use the new Toolkit. Otherwise, your colors will look incorrect.

  • Unsaved sketches shared to the online gallery are automatically saved to your Sketchbook.
  • Imported models, images, and guides currently do not upload to the online gallery.

  • Environment models, like the Snowman and Moon, currently do not upload to the online gallery.

  • Added ‘Likes’ tab to Sketchbook

    • Sketches ‘Liked’ on the online gallery show up in this tab. Browse here!

    • Sketches flagged as ‘Don’t Allow Remixing’ on the online gallery will not show up in the Likes section of your Sketchbook (for now).

  • Added Profile to Sketchbook

    • Log in with your Google account to Share sketches to the online gallery and to view Liked sketches from the gallery.

    • Logging in must be done through a web browser, which will open when clicking the Profile button or Share button.

  • Lighting Panel

    • Control the color of the ambient lighting.

    • Control the colors, intensities, and directions of one shadow-casting and one non shadow-casting light.

    • Custom lighting is saved with the sketch.

  • Backdrop Panel

    • Change the sky to a two-colored gradient.

      • Each of the two colors can be customized.

      • The orientation of the gradient can be customized.

    • Change the color and density of the fog.

    • Custom sky and fog is saved with the sketch.

  • Detachable and Customizable UI Panes

    • Grab any Panel with the grip button to adjust its position on the Pane, or to remove it from the Pane.

    • The Save/Trash Panel cannot be removed from the Pane.

    • Panels opened in the ••• Panel selection popup can be attached to a Pane.

    • Panel configuration can be reset by clicking the Refresh button in the ••• Panel selection popup.

  • Changed save flow to allow Save and Save New

    • An unsaved sketch must have a thumbnail captured before saving.

    • A previously saved sketch can be saved over with Save, or copied to a new file with Save New.

    • Honestly, it works like every application ever and exactly as you’d expect.

  • Added Disaster Recovery functionality

    • Active sketch is periodically backed up to C:\Users\<username>\Documents\Tilt Brush\Sketches\Autosave folder. More info.

  • Increased performance of particle brushes.

  • Greatly increased performance of Eraser and Brush Picker.

  • Fix material leaking bug which caused large hitches after long periods of usage.

  • Colors in .fbx exports are now in linear space.

  • Fixes to add more compatible brushes in the Unity SDK.

  • Color Picker type saved between sessions.

  • Custom Color Palette is shared across all color pickers.

  • Updated SteamVR plugin to v1.2.0.

  • Fixed bug allowing false positives when Eraser was at the origin.

  • Revised loading overlay to be consistent across multiple platforms.

  • Added 'ShowControllers' flag to config for toggling controller visibility. Intended use for performances, galleries, and mixed reality.

  • Disabled saving videos under a second in length, as they were confusing YouTube upload.

  • If you like the video you’ve captured, hold down the checkmark to upload.
  • YouTube sharing requires that you sign-into your YouTube account in your default desktop browser.

  • If your video includes audio you may be affected by YouTube’s copyright policies. Read about them here.

  • Hint: Want to record audio from your microphone? Go to the Recording tab in Windows Sound properties, select Properties for your microphone then check Listen to this device. Make sure the Video Recorder has found audio before beginning a recording!

  • Guides for easily constraining strokes to cubes, spheres, and other shapes.

    • Access through Tools -> More… -> Guides.

    • Use the sphere, cube, and pill guides to create perfect shapes.

    • Guides are moved and scaled similar to other widgets, using the Grip buttons.

  • Straightedge now shows the final stroke you’re painting.

  • Increased size range for a couple dozen brushes.

  • “DisableAudio” field added to the Tilt Brush.cfg.

    • How to use the Tilt Brush config file.

  • Change to save file naming.

  • Fixed bug where Tilt Brush would be unplayable when the Documents folder was moved or inaccessible due to virus detection software.

  • Minor improvements to models.

    • Models can now be grabbed while inside them.

    • Model materials support alpha cut-out and transparency.

    • FBX format models are now supported.

  • Minor placement fixes to the Mirror tool.

  • Added in-app reminder instructions for skipping the intro tutorial.

  • While holding a model or image, pull Trigger to pin and unpin.
  • Models and images save with sketch.

  • Models and images contribute to Tilt Meter.

  • Model and image interactions added to the undo stack.

  • Images support binary alpha.

  • Updated visuals for highlighting objects that can be grabbed with Grip button.

  • Improved Snapping

    • While holding a snappable object, hold Trackpad to snap.

      • Snappable objects include: models, images, mirror, Tips ‘N Tricks, and brush strokes, when Straightedge is selected.

      • Removed auto-snap on Mirror and Straightedge.

    • Model, image, and Tips ‘N Tricks snap to cardinal orientations.

    • Mirror snaps to flat horizontal, as well as 15 degree increments where n=(x, 0, z).

    • Straightedge snaps to up, down, 45 degrees, and 0 degrees.

    • Models and images can snap to center of environment.

      • In the Pedestal environment, models and images snap to the pedestal.

  • Video Recorder Improvements

    • Video capture now records with audio.

    • Ability to customize video resolution, FPS, container type in the Tilt Brush.cfg. How to use the Tilt Brush config file.

  • Misc. improvements

    • "Animal Ruler" shows relative size when using the scale feature.

    • Mirror position saved with sketch.

    • Mirror position added to undo stack.

    • Added unsaved work warning before loading a sketch.

    • Added clock to Controller Console.

    • Animate grip and trigger buttons on controller meshes.

    • Added new tips to the Tips ‘N Tricks.

    • Updated SteamVR plugin to v1.1.1.

    • “Author” field added to the Tilt Brush.cfg.

      • When the Author field is set, all sketches created will have the author name embedded in saved .tilt files.

    • Support scripts have moved to the .

  • Any changes to size or rotation are saved with sketches.
  • Media Library

    • Added ability for users to import an .obj model into their sketch.

    • Moved reference images and models to “Media Library” panel accessed through the “More…” menu on the Tools panel.

    • Models are pulled from the Documents/Tilt Brush/Media Library/Models folder, images are pulled from the Documents/Tilt Brush/Media Library/Images folder.

    • See Tilt Brush/Media Library/MediaLibraryReadme.txt for details on how to use Media Library.

  • Tiltasaurus

    • Added new game to the Labs panel.

    • See the Help Center for instructions how to play.

    • Adding Tiltasaurus.json to the Documents/Tilt Brush folder will let you add your own list of words.

    • Format:

  • Added flag “HighResolutionSnapshots” to the Tilt Brush.cfg. How to use the Tilt Brush config file.
  • Setting the flag to true causes the Camera tool to take snapshots at 6x the default resolution (11,880 x 6,588px).

  • Exporting to Sketchfab

    • Many important material properties are now preserved when exporting .fbx files and then uploading to Sketchfab. Posting to Sketchfab.

  • Misc. improvements

    • More aggressive video camera stabilization.

    • Fire brush bloom effect fixed on “Future Desktop” settings.

    • Cleaned up the progress bar images, added info text during loading.

    • Added new tips to the Tips ‘N Tricks.

    • Changed video file extension to .mp4.

    • Exports binary FBX by default, configurable in Tilt Brush.cfg.

    • Pressing the pad no longer activates teleport with Teleport Tool. Trigger only.

    • Teleport Tool boundaries are extended when the sketch has been resized.

    • Changed selection icon for Sketchbook to trash can.

    • References to models are saved with sketches, but the file data is not embedded within the .tilt file. If a sketch is loaded without the referenced model in the Media Library, a missing model icon will be displayed.

    • Added ‘About’ button to Settings for viewing really exciting third party notices.

  • Audio Reactive mode scans the computer’s audio out signals and connects to the first found active signal.
  • Audio Reactive mode will respond to any computer audio.

  • Added 15 new brushes and deprecated 3 (Taffy, Leaves, and Plasma)

  • Updated many brushes to add audio-reactive behaviour.

  • Cameras

    • Renamed from “MultiCam”.

    • Added Video mode to “Cameras”.

    • Added vignetting and depth of field effects to snapshots and videos.

  • Interface improvements

    • Streamlined the UI down to 3 panels.

    • Added dedicated Sketchbook panel, below Tools panel.

    • Added toggleable measurements to Straightedge tool.

      • Enable this feature on the Settings panel.

    • Undo/Redo can be used when a panel has focus.

    • Swiping on the brush controller thumbpad scrolls through the pages of the Brushes panel.

    • Added new “More” menu.

    • Changed Teleport tool icon visual from “Pin” to “Feet”.

    • Application button on the brush controller now toggles the last tool.

    • New visual design for the Color and Brush Picker tool.

  • Grabbable object improvements

    • Moveable UI panels now move out of each other’s way.

    • Mirror can be reset by dragging it to the target above the center of the floor.

    • Mirror now snaps to vertical and horizontal planes.

  • Added Tips ‘N Tricks tutorial section, under “More” menu.

  • Export button now generates textured .fbx files. See the Exporting Tilt Brush Sketches section below for more details.

  • Improved visual quality at all performance levels.

  • Unlit brushes made more efficient by using single-sided geometry.

  • Added progress bar when exporting or loading sketches.

  • Revised controller pad visuals for MultiCam.

  • Fix help text on Twitch Chat window.

  • Allow controller pad click to teleport.

  • Improved Undo/Redo trackpad click functionality.

  • Reference Image widget resets position when a new image is selected.

  • Moved Quick-Load tip to Palette controller so user can teleport during sketch load.

  • Use both Grip buttons to scale chat widget.

  • Toss the widget to dismiss it.

  • Twitch Chat

    • Requires “Tilt Brush.cfg”, stored in: Documents/Tilt Brush

    • Format:

  • Use both Grip buttons to scale chat widget.

  • Toss the widget to dismiss it.

  • Added visual notification when an important message is on the Controller Console.

  • Added a button to Sketch Gallery for easy viewing Sketches on disk.

  • Added ability to connect to an IRC channel for assisting live streamers.

  • Added a ‘Labs’ button on the Settings panel for advanced and experimental features.

  • Skip the intro tutorial by holding down both trigger buttons.

  • Use Grip button to move image widget.
  • Use both Grip buttons to scale image widget.

  • Toss the widget to dismiss it.

  • Caution! Extra large images, such as 4k, may cause performance hitches in Tilt Brush.

  • Export

    • Exports current scene's metadata and 3D geometry to a json file in Documents/Tilt Brush/Exports.

    • Tilt Brush ships with sample Python 2.7 scripts to convert the .json to .obj and .fbx formats. These scripts are in the Support/bin folder, which is next to TiltBrush.exe. The fbx conversion also requires the Autodesk FBX Python SDK. To find TiltBrush.exe from Steam, right-click "Tilt Brush" → Properties → Local Files → Browse Local Files...

    • Example script usage:

      python convert_to_fbx.py "c:\Users\username\Documents\Tilt Brush\Exports\Untitled_1.json"

      Each script has a set of command-line options that fine-tune the generated file.

    • Note that this initial preview does not export textures or materials. In addition, the .obj file format does not support vertex colors. We’re looking into solutions to provide users with more of this data, but didn’t want to delay sharing what we have now. The .fbx does support vertex colors, but to see them you will need to apply a shader that uses vertex color information like the two example Unity shaders below.

    • Please how you use this functionality!

  • IRC

    • Requires “Tilt Brush.cfg”, stored in: Documents/Tilt Brush

    • Format:

  • Toss the widget to dismiss it.

  • Watermark

    • The Tilt Brush logo watermark can be disabled. This also requires a "Tilt Brush.cfg" file, stored in Documents/Tilt Brush. The format is

  • 0

    uint32 bitfield. Bit 0: IsGroupContinue

    1

    uint32 timestamp, in milliseconds

    Open Brush Config File
    Tilt Brush Toolkit
    Python 2.7
    Tilt Brush Toolkit
    Universal Scene Description
    Tilt Brush Toolkit
    Tilt Brush Toolkit
    How to use the Tilt Brush config file.
    Help Center
    Blocks
    online gallery
    How to find your YouTube Channel ID.
    How to use the Tilt Brush config file.
    How to get an OAuth key for Twitch.
    How to use the Tilt Brush config file.
    How to get an OAuth key for Twitch.
    How to use the Tilt Brush config file.
    How to use the Tilt Brush config file.
    TiltBrush.exe --export Untitled_15.tilt Untitled_2*.tilt C:\Downloads\downloaded.tilt --exportPath C:\Temp -batchmode
    Tiltbrush.exe --renderCameraPath <path/to/camerpath.usda> <path/to/sketchfile.tilt>
    uniform float eyeScale = 1
    uniform float eyeScale = 0.1
    Shader "Brush/Standard"
    {
        Properties
        {
            _Color ("Main Color", Color) = (1,1,1,1)
            _SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 0)
            _Shininess ("Shininess", Range (0.01, 1)) = 0.078125
            _MainTex ("Base (RGBA)", 2D) = "white" {}
            _BumpMap ("Normalmap", 2D) = "bump" {}
            _Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
        }
        SubShader
        {
            Tags
            {
                "Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"
            }
            LOD 400
            CGPROGRAM
            #pragma target 3.0
            #pragma surface surf StandardSpecular vertex:vert alphatest:_Cutoff addshadow
            struct Input
            {
                float2 uv_MainTex;
                float2 uv_BumpMap;
                float4 color : Color;
            };
    
            sampler2D _MainTex;
            sampler2D _BumpMap;
            fixed4 _Color;
            half _Shininess;
    
            void vert(inout appdata_full i)
            {
            }
    
            void surf(Input IN, inout SurfaceOutputStandardSpecular o)
            {
                fixed4 tex = tex2D(_MainTex, IN.uv_MainTex);
                o.Albedo = tex.rgb * _Color.rgb * IN.color.rgb;
                o.Smoothness = _Shininess;
                o.Specular = _SpecColor;
                o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
                o.Alpha = tex.a * IN.color.a;
            }
            ENDCG
        }
        FallBack "Transparent/Cutout/VertexLit"
    }
    Shader "Brush/Additive"
    {
        Properties
        {
            _MainTex ("Texture", 2D) = "white" {}
        }
        Category
        {
            Tags
            {
                "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"
            }
            Blend SrcAlpha One
            AlphaTest Greater .01
            ColorMask RGB
            Cull Off Lighting Off ZWrite Off Fog
            {
                Color (0,0,0,0)
            }
            SubShader
            {
                Pass
                {
                    CGPROGRAM
                    #pragma vertex vert
                    #pragma fragment frag
                    #include "UnityCG.cginc"
                    sampler2D _MainTex;
    
                    struct appdata_t
                    {
                        float4 vertex : POSITION;
                        fixed4 color : COLOR;
                        float3 normal : NORMAL;
                        float2 texcoord : TEXCOORD0;
                    };
    
                    struct v2f
                    {
                        float4 vertex : POSITION;
                        fixed4 color : COLOR;
                        float2 texcoord : TEXCOORD0;
                    };
    
                    float4 _MainTex_ST;
    
                    v2f vert(appdata_t v)
                    {
                        v2f o;
                        o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                        o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
                        o.color = v.color;
                        return o;
                    }
    
                    fixed4 frag(v2f i) : COLOR
                    {
                        half4 c = tex2D(_MainTex, i.texcoord);
                        return i.color * c;
                    }
                    ENDCG
                }
            }
        }
    }
    uint32 sentinel ('tilT')
    uint16 header_size (currently 16)
    uint16 header_version (currently 1)
    uint32 reserved
    uint32 reserved
    uint32 sentinel
    uint32 version
    uint32 reserved (must be 0)
    [ uint32 size + <size> bytes of additional header data ]
    int32 num_strokes
    num_strokes * {
        int32 brush_index
        float32x4 brush_color
        float32 brush_size
        uint32 stroke_extension_mask
        uint32 controlpoint_extension_mask
        [ int32/float32 for each set bit in stroke_extension_mask & ffff ]
        [ uint32 size + <size> bytes for each set bit in stroke_extension_mask & ~ffff ]
        int32 num_control_points
        num_control_points * {
            float32x3 position
            float32x4 orientation (quat)
            [ int32/float32 for each set bit in controlpoint_extension_mask ]
        }
    }
    {
      "Video": {
        "FOV": 90
      },
      "Flags": {
        "FOV": 100
      }
    }
    {
       "Categories":[
          {
             "Name":"Action",
             "Words":[
                "Applause",
                "Arguing",
                "Ballet"
             ]
          },
          {
             "Name":"Animal",
             "Words":[
                "Butterfly ",
                "Cat",
                "Chicken"
             ]
          }
       ]
    }
    {
     "YouTube": {
     "ChannelID": "UCabcdefghijklmnopqrstuv",
     },
    }
    {
     "Twitch": {
     "Username": "TiltBrushStreamer",
     "OAuth": "oauth:abcdefghijklmnopqrstuvwxyz0123",
     "Channel": "#tiltbrushchannel",
     },
    }
    {
       "IRC":{
          "ServerName":"irc.twitch.tv",
          "ServerPort":6667,
          "Username":"TiltBrushStreamer",
          "OAuth":"oauth:abcdefghijklmnopqrstuvwxyz0123",
          "Channel":"#tiltbrushchannel"
       }
    }
    {
     "Flags": {
     "ShowWatermark": false,
     },
    }
    x,y = the earliest/latest timestamp in the stroke which contains that vertex.
  • z = the timestamp for that vertex.

  • This can be disabled in the Tilt Brush config Export section with “ExportStrokeTimestamp”: false

  • How to use the Tilt Brush config file.

  • How to use the Tilt Brush config file.
    Tilt Brush Toolkit
    How to use the Tilt Brush config file.
    let us know