Paint in 3D


DOCUMENTATION

Thank you for using Paint in 3D ❤️

If you haven't already, please consider writing a review. They really help me out!



How do I upgrade?

First, make sure you back up your project files.

Next, install the latest version.

If for some reason the latest updates breaks your project (e.g. errors in the console), then try deleting the root folder for this asset, and reinstalling it.

If it still doesn't work then go back to your previous version, and let me know what the errors are, so I can fix it.



Is LWRP/URP supported?

Yes, LWRP/URP is fully supported.

After you've set a scriptable rendering pipeline in your Graphics settings:

STEP 1 Go to to the PaintIn3D folder.
STEP 2 Select the PIPELINE asset.
STEP 3 Click the Switch To Scriptable Pipeline button.
DONE Paint in 3D has now been converted to use SRP.

If you decide to go back to the standard rendering pipeline, then you can click the Switch To Standard Pipeline button.

NOTE  If you update this asset, then you will have to follow these steps again to switch render pipelines. This is because I submit the package with the standard pipeline, and updating the asset will revert the materials you previously switched.


Is HDRP supported?

Yes, just follow the same steps as the above tutorial.

The biggest difference between HDRP and all other rendering pipelines is how the lighting is handled. To make most demo scenes render correctly, you must:

STEP 1  Make a new GameObject.
STEP 2  Add the Volume component to it.
STEP 3  Add a profile by clicking the New button.
STEP 4  Click the Add Override button, and select Exposure.
STEP 5  Enable the Mode setting, and set it to Fixed.
STEP 6  Enable the Fixed Exposure setting, and set it to 7.

If the scene contains a light (e.g. a star), then you can:

STEP 1  Find the Light component.
STEP 2  Set its Emission / Intensity setting to 500 or 1000.

These modifications should more or less fix the lighting in all the demo scenes. Keep in mind these are just example settings for demo purposes, you can then tweak these to get the exact look you desire.

If you encounter any issues with this then let me know so I can improve them.



Are custom shaders/materials supported?

Yes, Paint in 3D is compatible with almost all custom shaders/materials.

The only requirement is that the texture you want to paint must be rendered to your mesh using the mesh UV data (e.g. uv, uv2, texcoord, texcoord2), which should be true for most shaders.

Keep in mind that shaders that perform minor modifications to the UV should still work, but the paint may appear slightly offset, depending on the level of UV modification performed. Minor modifications would include parallax mapping shaders, tessellated displacement, heat distortion, etc. If you want to paint these kinds of shaders/materials, then I recommend adding some kind of effect to your object while painting (e.g. particle effects) to disguise the offset.

The reason for this requirement is that Paint in 3D applies paint to your mesh using the mesh UV data. Paint in 3D doesn't know how your shader is modifying the UV data, so any shader modifications to the UV will be ignored and there will be a discrepancy between where the texture is painted, and where it actually maps to when rendered with your custom shader.

NOTE  By default the P3dPaintableTexture targets the "_MainTex" texture slot, which is usually the albedo texture. Some custom shaders/materials use a different texture slot like "_BaseMap", "_Albedo", etc. You may have to experiment with different texture slots depending on the shader (you can click the texture slot dropdown to see a list of available textures).


Is VR supported?

Yes, this asset has been developed and tested in VR, and supports both multi-pass & single-pass rendering modes.

Demo scenes like VR HVLP and VR Pen show you how to implement painting using Unity's XR system. While these demo scenes don't have integrations for third party VR systems (e.g. VRTK), integrating them yourself should be easy enough, as the components are designed to work using any system that support inspector events, and thus they shouldn't require any code changes.

Most of the example components and scenes that come with Paint in 3D are designed for mouse/touch inputs. For example the P3dHitScreen component uses mouse and touch data to paint, so it will not work in VR.

To paint in VR, you can use the P3dHitBetween component, which allows you to paint between two Transform points. The Paint Between demo scene shows you how to use it, and you can apply the same approach to your VR tool. Most of the example scenes can be modified to work in VR with this change alone.

Alternatively, the P3dHitNearby component can be used, which will paint anything near the current GameObject. The Asteroid Holes demo scene shows you how this can be used.

Keep in mind that by default both of these components paint continuously with the same pressure/strength. If you want to be able to toggle painting on and off, or associate your VR trigger pressure with paint pressure, then you will have to write a simple script to connect the two together. If you want to be able to preview the painting without applying it (e.g. when not pulling the trigger), then you will have to control the Preview setting yourself.



Can I save my in-game paint to my project?

Yes, while in play mode open the Window/Paint in 3D from the top menu bar.

On the Scene tab you can see a list of paintable objects in your scene, with a list of their materials, and a list of their textures. Next to the texture name you want to save, you can click the Export button, and save it to your project as a .png file.

This can be done at runtime too from the P3dPaintableTexture component, using the GetPngData() method.



Is the new InputSystem supported?

Yes, all of the non-VR comonents should work automatically in either input system.

If you're using the VR components then you must manually create a PlayerInput component, bind some VR controls to an input, and use the events to send the CallbackContext information to the P3dVrManager component.

The VR examples use the P3dInputAxis component to send (legacy) input axis data to functions like P3dVrManager.SetLeftTrigger, and you can replace these using the new system.



Getting Started (In-Game)


Step 1 - Make Your Object Paintable

Any GameObject that has a MeshFilter + MeshRenderer or SkinnedMeshRenderer can be painted.

METHOD 1 Add the P3dPaintable component to your GameObject.
METHOD 2 Click the context menu (gear icon at the top right) of your MeshRenderer, or SkinnedMeshRenderer component, and select the Make Paintable (Paint in 3D) option.
METHOD 3 Open the Window/Paint in 3D to the Scene tab, and click the Make Paintable button.


Step 2 - Make a Texture Paintable

Next, you need to mark which textures you want to paint. Your MeshRenderer or SkinnedMeshRenderer component has the Materials array, and each texture used by these materials can be painted.

METHOD 1 Click the Add Paintable Texture button from the P3dPaintable inspector.
METHOD 2 Add the P3dPaintableTexture component to your GameObject, alongside the P3dPaintable component.
METHOD 3 Open the Window/Paint in 3D to the Scene tab, and click the Preset button next to the material you want to paint, and select the texture preset to paint.

You should now see the P3dPaintableTexture component added to your GameObject.

Inside this component, you can click the dropdown to the right of the Slot setting, allowing you to pick from a list of materials and texture slots.

For most objects, the default 0, _MainTex setting is all you need. But if you have multiple materials or need to do advanced painting you may need to change this. For example, to paint normal maps you may need to choose 0, _BumpMap or similar, the exact texture name depends on the shader/material.

The rest of the settings should be OK at their default values for now.



Step 3 - Make Your Material Clone Itself

The P3dPaintableTexture component takes over the texture slot of the material you specify, which means all other objects using this material will see the same paint. To fix this you must make sure the material is turned into a unique clone before your paintable textures are applied.

METHOD 1 Click the Add Material Cloner button from the P3dPaintable inspector.
METHOD 2 Add the P3dMaterialCloner component to your GameObject, alongside the P3dPaintable component.
NOTE  If your P3dPaintableTexture was added using a Window / Paint in 3D preset, then it should automatically have been given a P3dMaterialCloner component.

You should now see the P3dMaterialCloner component added to your GameObject.

Finally, make sure the P3dMaterialCloner.Index setting matches your P3dPaintableTexture.Slot index. For example, if your slot is 0, _MainTex, then your Index should also be set to 0.

NOTE  The first material is index 0, the second is index 1, etc.
NOTE  You only need to clone each material once, even if you have multiple paintable textures targeting the same material.


Step 4 - Paint It!

Paint in 3D comes with many ways to paint objects.

One simple method is to make a new GameObject, and add the P3dHitScreen and P3dPaintDecal components. These components will automatically work together, allowing you to paint using the mouse (or your finger if you run it on a mobile device).

NOTE  The P3dHitScreen component uses raycasts, so your mesh must have colliders (e.g. MeshCollider) for it to know where to paint.

You can now adjust the P3dPaintDecal settings to your liking. I recommend you at least change the Color or Texture, because the default paint color is white, and if you paint on a white texture then it may look like nothing is happening!

Once done, press play. You should now be able to click on your object in the Game window, and have the decal you paint on your object under the mouse.

For more advanced ways to paint I recommend you go through the demo scenes in the PaintIn3D/InGame/Examples folder and see how they're put together!




Getting Started (In-Editor)


Step 1 - Open Paint in 3D

To open the main Paint in 3D window, click on Window > Paint in 3D from the top menu bar.



Step 2 [Optional] - Make a New Scene

If you only want to paint objects in-editor, then I recommend you make a new scene. This is because painting data is stored in the scene, and you may not want to modify your main scene to include this. You can then copy+paste or drag+drop the objects you want to paint in this new scene.

If you want to remove paint data from your scene then look at the Scene tab, and click the X next to each paintable object.



Step 3 - Add Objects

Make sure you're on the Scene tab inside the Paint in 3D window.

Any GameObjects eligible for painting will appear here. If you don't see any, then you must select some in either the Scene or Hierarchy windows.

For a GameObject to be eligible for painting it must have the Skinned Mesh Renderer or MeshFilter + MeshRenderer components.

To add it to your painting scene, simply click the Make Paintable button next to it.



Step 4 - Add Materials

After you make a paintable object, you can see a list of its materials in the Scene tab. On the right side you can click the Preset button to open a list of preset configurations available for this material, which allows you to pick how you want to paint it.

If you don't see any presets, then you can make your own in the PaintIn3D/InEditor/Presets folder. You can add your material or shader to an existing preset, duplicate one and modify it, or right click and select Create/Paint in 3D/Preset to create one from scratch. To understand how to set up a preset, I recommend you read the Getting Started - In Game tutorial, as the steps are the same.

If you don't want to use a preset, then you can double click your paintable object to select it in the scene, and you can manually add the P3dMaterialCloner and P3dPaintableTexture components.



Step 5 - Export Textures

After you add a material preset, you will see a list of textures that will be painted. If you want to save these textures in your project then you can click the Export button to the right, and choose a place to save them. The saved textures will be in .png format.



Step 6 - Painting

Make sure you're on the Paint tab.

At the top you can see 3 boxes: Tool, Material, and Shape.

If you click the Tool box, then you can choose a paint tool. These control how the paint is applied in the scene (e.g. dots, line, triangles).

If you click the Material box, then you can choose a paint material. These define a set of textures that allow you to paint a type of surface (e.g. brick, dirt, chrome).

If you click the Shape box, then you can choose the paint shape. These change the shape of the material as you paint, giving more interesting edges.

NOTE  You must enter play mode to be able to paint.

If you enable the Override Camera setting, then you can control the game view camera using:

Rotate Right Click + Drag.
Zoom Mouse Wheel.
Pan Middle Click + Drag.
Orbit Point Double Right/Middle Click.
Move WASD (Config tab to change).


Step 7 - Save

After you've painted your textures, you can click the Export All button at the bottom of the Paint in 3D window. This will automatically save all previously exported textures with the current paint state.

NOTE  If you exit play mode before pressing this, then your paint progress will be lost.
NOTE  If you don't want to save all painted textures, then you can manually click Export next to each texture like in step 5.



UV Data Requirements

For Paint in 3D to work, the mesh you want to paint must have UV data. Not only that, but for best results the UV data shouldn't have overlapping areas (e.g. no mirroring), or exceed the 0..1 range (e.g. no texture tiling).

If your mesh fails any of these requirements, then I recommend you modify the UV data in your favorite 3d modelling program (e.g. Blender).

NOTE  The default Cube mesh that comes with Unity has overlapping UV data. I recommend you use the Separated Cube mesh that comes with Paint in 3D instead.
NOTE  The default Cylinder mesh that comes with Unity has overlapping UV data. I recommend you use the Separated Cylinder mesh that comes with Paint in 3D instead.

What if I don't know how to UV map?

Unity can automatically do it for you. Just keep in mind that doing it manually will allow you to achieve better results.

To automatically generate UV data, you can enable the Generate Lightmap UVs setting in your mesh import settings. This will generate UV data suitable for painting, and they will be stored in the second UV channel.

NOTE  Most shaders (including all default Unity shaders) only read data from the first UV channel, so this new UV data won't be used. To use it, you must either use a shader that reads from the second UV channel instead of the first, or copy the new UV data from the second UV channel to the first.
NOTE  If you want to remove UV seams from this newly generated UV data, then you will have to run the second UV channel through the Seam Fixer tool.


Does Paint in 3D come with shaders that use the second UV channel?

Yes, Paint in 3D comes with several shaders designed to solve this issue.

If you want to keep your original shader/material that uses the first UV channel, then you can use the P3D Overlay shader on top of your base material. Paint in 3D already comes with a pre-configured material called Overlay (Second UV Coord), which you can add on top of your base material. Keep in mind you will now be painting the second material (index 1), so you must update your P3dMaterialCloner and P3dPaintableTexture component settings to target the second material slot index (1).

This technique is demonstrated in the UV Requirements / Automatic Overlay demo scene.

NOTE  If your mesh has multiple sub-meshes, then this technique won't work.

If you don't mind replacing your original shader/material, then the P3D Solid shader can be used instead. This shader uses the first UV channel for base textures, and then allows you to override the albedo/opacity/smoothness/etc using secondary textures that use the second UV channel.

This technique is demonstrated in the UV Requirements / Automatic Secondary demo scene.

NOTE  The secondary/override textures in this shader use premultiplied alpha blending, so you should change your paint brushes to use the Premultiplied blending mode.
NOTE  You should expand the P3dPaintableTexture component's Advanced menu, and change the Conversion setting to Premultiply.


How do I copy UV data from the second UV channel to the first?

Paint in 3D comes with the Coord Copier tool, which allows you to do this.

To use this tool, select your mesh in the Project window, and click the context menu (gear) icon at the top right of the inspector, and select the Coord Copier (Paint in 3D) option.

Your Project window should now contain a Coord Copier (YOUR_MESH_NAME) prefab, and you can click Generate to copy the coords over.

The generated mesh with the copied coords is now placed as a child of the Coord Copier prefab, and you can drag and drop it into your Mesh Filter or Skinned Mesh Renderers.

NOTE  This tool will overwrite the UV data in the first UV channel. If you still need this data, then this solution isn't suitable for you.


Can I use the second UV channel with the Standard shader?

Kind of. Using the following steps you can get it working using the detail texture. Just keep in mind this isn't the best solution, because it doesn't replace the albedo exactly.

Step 1 Select your material that uses the Standard shader, and change the Secondary Maps > UV Set setting to UV1.
Step 2 Select your P3dPaintableTexture component, and change the the Slot setting from _MainTex to _DetailAlbedoMap.
Step 3 Change the Channel setting to Second.
Step 4 Change the Shader Keyword setting to _DETAIL_MULX2.


How can I use the second UV channel with a different shader?

Most shaders only the first UV channel, so you will need to make an alternative shader that uses the second.

For example, instead of using uv_MainTex you use uv2_MainTex, or instead of using texcoord0 : TEXCOORD0, you use texcoord1 : TEXCOORD1.

NOTE  When painting using the second channel, you must set the P3dPaintableTexture > Channel setting to Second.

Paint in 3D comes with a range of shaders that allow you to specify the UV channel used (e.g. P3d Opaque).




Undo & Redo

Paint in 3D supports runtime undo & redo, but to save memory it's disabled by default.

To enable it, you need to follow these steps:


UndoRedo Setting

The first step is to select your P3dPaintableTexture components, and enable the UndoRedo setting.

If you're painting animated objects then you should set this to FullTextureCopy, but for most scenarios you can use LocalCommandCopy.

If you use the FullTextureCopy state mode then you must also set the State Limit setting. A value of 10 means you can undo paint operations 10 times, and then redo them 10 times. If you paint 11 times with this setting then your initial paint state will be deleted, and you will only be able to undo 10 times to your first paint operation.

You can read the P3dPaintableTexture documentation for more details.



Store States

The next step is to find your painting components, and enable the Store States setting.

This setting will automatically call the StoreState method on each P3dPaintableTexture in your scene, letting Paint in 3D know that you're about to paint on them.

For example, the P3dHitScreen component has the StoreStates setting, as well as P3dToggleParticles, and P3dTapThrow.



Buttons

Finally, you can add the P3dUndoAll and P3dRedoAll components to your UI elements, and they will automatically be set up so when you click them they perform an undo or redo operation.

And that's it, your game should now have Undo & Redo paint functionality!



Memory Usage

Keep in mind that when using the FullTextureCopy mode, each undo/redo state is stored as a full texture state. This means that if your texture is 1024x1024 using the RGBA32 format, then each undo/redo state will consume 1024x1024x4 bytes of memory, or 4 megabytes.

If your game requires a lot of undo states and you want to reduce memory usage, then you should use the LocalCommandCopy mode instead, which will store a list of all paint commands (e.g. decal texture + paint orientation). This approach can reduce memory usage a lot, and it allows unlimited undo levels, but performing an undo requires rebuilding the texture from scratch, which can be slow if you have a lot of undo states. It also may not work correctly if your mesh is animated, because the paint will apply to different areas if your mesh has changed.



Manual Undo & Redo

The undo & redo functionality listed above works well for most games, but it's not suitable for all scenarios. To get full control you can manage it yourself using the following methods in the P3dPaintableTexture class:

Call StoreState before you apply paint to your objects.

Call Undo/Redo after, when you want to undo or redo.

These methods can also be accessed from the P3dPaintableTexture inspector context menu (gear icon at top right), so you can test it from the editor.




Fixing UV Seams

When you make complex 3d models it's inevitable your mesh will have UV seams, where one part of the texture is disconnected from another.

This normally isn't a problem with clever texturing, but when painting it can result in visual seams between these disconnected UV islands (see the seams around the shoulders on the zombie image).

The blue lines in this image show you the UV seams:


How do we fix them?

To fix these UV seams, Paint in 3D comes with a tool that can convert a normal mesh with UV seams into a fixed mesh without UV seams.

To access the tool, select any mesh in your project, click the context menu icon (gear) at the top right, and select Fix Seams (Paint in 3D).

This creates a seam fixer in your project, and automatically sets the Source mesh to the one you picked.

If you want to see the result of the seam fixing, set the Debug Scale setting to 10 or so.

You can now press the Generate button to generate the fixed mesh.

If it was successful, you should see something like this in your Scene window:

Where the green lines are the original seams, and the blue lines are the new fixed seams. The blue lines should be outside of your original green lines. If your blue lines are overlapping then try reducing the Border setting a little, or the Threshold setting.

NOTE  Fixing seams adds vertices to your mesh. If your mesh was already close to the mesh vertex limit then this tool may not work for you.
NOTE  This tool isn't magic. If your original UV map is laid out poorly then this will won't fix it.


How do we use the fixed mesh?

The generated mesh will be placed as a child of the seam fixer in your Project window.

To use it, just drag and drop it from here into your MeshFilter or SkinnedMeshRenderer that uses this mesh.




Blend Modes

Blend modes allow you to change the way your painted pixels are applied to your textures.

If you're using in-editor painting, then you can right click a material to select it, and change the Blend Mode of the P3dPaintDecal components you wish to modify.

If you're using in-game painting, then you can change the Blend Mode in the painting components (e.g. P3dPaintSphere, P3dPaintDecal).


Alpha Blend

This blend mode increases the alpha channel of your texture, and blends the RGB channels of your texture toward the color of your paint, based on the opacity of your paint.



Alpha Blend Inverse

This blend mode works similar to Alpha Blend, but it applies the blending in reverse.

This allows you to paint 'behind' the current painted areas, or fill them in.



Alpha Blend RGB

This blend mode works similar to Alpha Blend, but the alpha channel is not modified. This is ideal when you want to paint on only the solid parts of an already transparent texture.



Additive