Simple per-poly vertex painter for Unity. Written/tested on Unity 5.4.0b21. 5.3+ should be ok.
FacePaint paints triangles rather than individual vertices. This is mainly suited for materials and meshes using a low-poly / flat shaded / faceted look. Note that this may have strange effects for meshes with smoothing groups!
Editing is non-destructive; FacePaint stores its data in a FacePaintData component (automatically added to edited objects). This data is applied at runtime. Your mesh files aren’t altered, and each instance of a mesh can have its own vertex colours.
Installation and Use
Copy the FacePaint folder into the Assets folder of your project. Window > FacePaint will launch a dockable editor window. Select an object with a MeshRenderer and MeshFilter and press Edit in the FacePaint window.
FacePaint is designed to be minimal and extensible, not feature-complete. One person’s super-specialised tool is another’s bloated mess!
FacePaint features a plugin system to easily extend the tool without having to modify core code - quick guide below. A few are included both as examples and as potentially helpful tools. In general, I’ll add new features as plugins to avoid bloat, unless they should absolutely be core functionality.
- May interfere with unity-generated lightmapping UVs. This should be fixed soon.
- If your mesh isn’t totally flat shaded (i.e. each triangle must have completely unique vertices) you may see colours ‘bleed’ across triangles. I’ll add a custom mesh import script soon.
- To give multiple mesh instances the same colours, simply copy and paste the FacePaintData component. Press the “Force Re-apply Vertex Colours” button if nothing happens.
- To reset vertex colours entirely, make sure you’re out of edit mode and then delete the FacePaintData component.
This tool is inspired by the excellent Unity 5.0 Vertex Painter by Jason Booth (particularly the use of MeshRenderer.additionalVertexStreams to apply colours non-destructively).
Paint bucket icon by Yusuke Kamiyamane
Plugin Development Guide
Plugins implement the IFacePaintPlugin interface. All classes implementing this will be automatically found by FacePaint and added to the plugins list, using spooky reflection magic. Alternatively, just inherit from the FacePaintPluginBase “template” class to get a head start.
Plugins (when set active in the ‘Plugins’ panel of FacePaint) get callbacks at various points in OnGUI. These are after a panel has been drawn by FacePaint, allowing plugins to augment the existing panels. The OnSceneGUI callback allows plugins to act when the user interacts with the model being painted.
Most callbacks pass the FacePaint instance itself for access to the API, and the FacePaintData component currently being edited (this is the MonoBehaviour attached to a mesh which stores and applies vertex colours).
The OnPluginPanel callback should be used to implement any general UI that’s not appropriate for any of the existing panels.
The OnSceneGUI callback passes data on what kind of mouse event has occurred, which triangle on the mesh is affected if any, and the verts which comprise that triangle. This data can be used to manually paint on the mesh, for example. Currently it’s not possible to ‘eat’ the event and prevent the default FacePaint behaviour from happening.
If in doubt, Intellisense!
GUI helper functions FacePaint.DrawBtn(), FacePaint.ToggleButton(), FacePaint.DrawPluginTitle() are purely for convenience. Any standard IMGUI code can be used.
FacePaint.paintColor and FacePaint.writeX/SetChannels() control the paint colour and the channels paint will apply to. FacePaint.Paint() calculates the resulting colour when a given colour is painted over with a new colour, respecting the channel settings. It returns this colour without applying it to anything.
To apply colours, use FacePaintData.GetColors(), modify the resulting array, and then FacePaintData.SetColors(). Changes to FacePaintData made in plugins are automatically added to undo.
The “Assist Mode” shader can be overridden using FacePaint.OverrideAssistShader(), or reset by passing null. This is used, for instance, by the FacePaint_LUT built-in plugin.