Material Spray is a small addon for the Godot engine (version 3.1.1 only) that can be used to paint meshes.
- clone or download this repository and copy (or create a symbolic link to) the addons/material_spray directory into your Godot project
- enable the MaterialSpray extension in your project (using the Extensions tab in the Project->Parameters window)
- select a MeshInstance in any scene of the project and use the MaterialSpray button (see image below) above the 3D view. This will open the MaterialSpray window
- in the bottom right corner, the brush can be configured. The channels to be modified can be selected (albedo, metallic and roughness) as well as their color/values. A texture can be selected for albedo (click on the image to be prompted for it) as well as the way it will be used (no texture, stamp and pattern).
- select a tool in the top left corner (freehand painting, line, linestrip)
- adjust the brush size and hardness by holding the Shift key and moving the mouse (left-right for size, up-down for hardness). When in stamp mode, up-down rotates the texture. When in pattern mode, the pattern can be resized and rotated by holding the Control key
- and finally, start painting directly your mesh with the left mouse button. The mesh can be rotated with the right mouse button or the arrow keys. The mesh can also be moved by holding the Shift key and the right mouse button while moving the mouse. The mouse wheel can be used to zoom in and out (hold the shift key to zoom faster).
- Only the first surface of a mesh will be painted. Meshs with more than one surface are neither supported nor tested.
It is all @Bauxitedev's fault ! ;)
I really wanted his godot-texture-painter to be integrated in Godot, so I forked his repository, and tried and failed gave up. I then decided to start my own implementation, with a slightly different approach (although I "borrowed" lots of code from his shaders), and here it is!
This plugin is based on intermediate textures that are generated before painting and used by the paint shader.
When loading the mesh, the plugin generated the seams texture, that is used to paint "beyond" seams in texture space so seams cannot be seen. The texture just contains, for pixels that are close to painted areas, the UV offset to be applied to get to the closest painted point.
The seams texture is generated in 2 passes:
- the first pass is generated in a 3d view with an isometric camera, and a shader that uses the UV coordinates as vertex coordinates. The result is an UV map where useful parts of the texture are white and the rest is black
- the second pass is the result of a 2d shader that takes the UV map as input and finds the offset to the nearest "useful" pixel for "useless" pixels
This seams texture is only used in the final paint shader
This texture is a copy of the painting view shown to the user, but where the colors of the object are its UVs. It is generated in a 3d viewport containing a copy of the mesh and camera, and a very simple shader.
This texture is generated whenever the view angle is modified and only used in the following step.
This is basically the opposite of the view-to-texture texture, an UV map where the color is the position of the corresponding point in the user view (in the red and green channels). This texture is generated using the same setup as the first pass of the seams texture (isometric camera, UV as vertex coordinates) and calculate the position in the user view using a function I borrowed from @Bauxitedev's project.
The blue channel contains a multiplier that will be used when painting (only pixels whose blue channel is higher than 0 will be painted), and it is calculated from:
- the normal of the surface compared to the viewer's position
- the color of the corresponding pixel in the view-to-texture texture (if the pixel does not have the current UV coordinates as color, the corresponding part of the texture is hidden and should not be painted)
As a consequence, only blueish parts of the texture shown below will be painted (which correspond to the visible parts of the mesh on the user's view).
And since the user's view coordinates are too big to fit in an 8 bits per channel texture, another texture-to-view texture is generated to hold least significant bits of those values.
Both texture-to-view textures are only used when painting which is the final step.
This shader actually paints textures and is used in 4 viewports in parallel to modify 4 textures:
- Albedo
- Metallic and Roughness
- Emission
- Depth (the Normal texture is generated from this one)
This painting shader just paints the texture in 2D (it is generated in a 2d viewport that only contains a ColorRect with that shader), and uses the following inputs:
- the seams input is used to find the nearest useful pixel of the texture
- the texture-to-view inputs are used to find the corresponding coordinates in the user view
- the brush parameters are used to calculate the distance from the painted pixel to the brush, and then the color it should be painted and the corresponding alpha. The result then is applied to the current textures.
When using the tool, you can use the choice boxes in the bottom left corner of the window to show 2 of those generated textures (this was really handy when debugging :D).