Paint in 3D


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 URP/HDRP supported?

Paint in 3D supports all 3 render pipelines (Standard, URP, HDRP) in a seamless way that automatically detects your current project settings, and makes the required modifications to the scene so they look similar.

Better Shaders

This compatibility was made possible using the Better Shaders system (not required).

The Better Shaders asset generates multiple variants of each shader ahead of time, so even if you don't have this asset, you will still be able to have full render pipeline compatibility with Paint in 3D.

BetterShaders (and therefore this asset) currently supports:

Standard Rendering Pipeline from Unity 2019 on

URP7.x in Unity 2019.3LTS

URP10.x in Unity 2020.3LTS

URP12.x in Unity 2021.2

URP14.x in Unity 2022.2->2022.3LTS

HDRP7.x in Unity 2019.3LTS

HDRP10.x in Unity 2020.3LTS

HDRP12.x in Unity 2021.3LTS

HDRP14.x in Unity 2022.2->2022.3LTS

Support for newer versions will appear when it does in this asset.


Each rendering pipeline handles lighting differently. To make the scenes look consistent, each light has the P3dLight component attached to it, which overrides the light intensity for each pipeline.

If you don't like this behavior then you can set the values (for example IntensityInHDRP) to -1.

Opaque Texture (URP only)

If you want to use the SgtBlackHole feature, then you must enable the Opaque Texture setting in your pipeline settings asset.

Volume (HDRP only)

To make HDRP compatibility seamless, each demo scene contains the P3dSceneManager GameObject, which adds the Volume component in HDRP.

This volume will adjust the scene exposure, disable the visual environment, and disable fog. These are all done to make the scenes look consistent with the other rendering pipelines. If you want to adjust these settings yourself then delete this GameObject, and create your own volume.

However, for your own scenes you may want to remove this volume component and use your own exposure settings.

Are custom shaders/materials supported?

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

The only requirements are that:

1 - The texture you want to paint must be sampled in your shader using the mesh UV data (e.g. uv, uv2, texcoord, texcoord2).

2 - The mesh UV data shouldn't be modified in any significant way (e.g. no tiling or offset).

3 - The mesh positions shouldn't be modified in any significant way.

Keep in mind that shaders that perform minor modifications to the position or UV data will still work, but the paint may appear slightly offset (depending on the magnitude of modification performed). Minor modifications would include parallax mapping shaders, tessellated displacement, heat distortion, etc. If you want to paint these kinds of shaders/materials and notice this offset, then I recommend adding some kind of effect to your object when it gets painted to disguise the offset (e.g. particle effects).

The reason for these requirements is that Paint in 3D applies paint to your mesh using the mesh position and UV data. Paint in 3D doesn't know how your shader is modifying this data, so any modifications the shader performs will result in 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 component 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. Under each object you can see a list of its paintable materials, and under those you can see a lise of its paintable textures.

If you want to save each texture individually, then click the Export button next to the texture name, and you can choose where to save it in your project. It will then be saved there as a .png file.

If you want to save a copy of the material with all of its paintable textures, then click the Export button next to the material name, and you can choose where to save it in your project. It will then be saved as a material, and all its textures as .png files.

NOTE When saving a material with its textures, the textures will be named like this: %Material_Name%%Texture_Name%.png For example: MyCoolMaterial_MainTex.png

This can also be done in-game from code too, using the P3dPaintableTexture component's GetPngData() method, which you can then save to file, and later load back using the LoadData(byte[]) 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 (⋮ 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/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/Examples folder and see how they're put together!

Getting Started (In-Editor)

Step 0 [Optional] - Make a New Scene

Before you paint objects in-editor, I recommend you make a new scene (e.g. copy+paste your objects into a new scene). This is because configuring your objects for painting requires the scene to be modified (these modifications can easily be removed though).

Step 1 - Open Paint in 3D

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

Step 2 - Make Objects Paintable

Make sure you're on the Scene tab.

Select at least one GameObject in your scene that you want to paint, and it should appear in the list.

On the right of each object you should see the Make Paintable button, which you can click to configure the GameObject for painting.

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

Step 4 - Make Materials Paintable

After you make an object paintable, you must choose which of its materials you want to paint. Below the object you can see a list of its materials, and on the right side you can click the +Preset button to open a list of preset configurations available for this material.

NOTE  If you don't see any presets, then read the documentation HERE.

Step 5 - Export Material & Textures

After you add a material preset, you can see a new Export button next to it. If you click this, then you can save a copy of this material and all its textures to the location you specify.

Once you finish painting you can use this new material with painted textures in your scenes.

NOTE  If you don't want to save the material and all textures then you can click the Export button individually next to each texture.

Step 6 - Open Paint in Editor

To open the main Paint in Editor window, click on Window > Paint in 3D > Paint in Editor from the top menu bar, or select the Paint in Editor tool from the top left tool bar.

NOTE  You must enter play mode to be able to paint.
NOTE  You must paint in the Scene view.

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.

Step 7 - Save

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

After you've painted your textures, you can click the Re-Export All button at the bottom right. 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 individual texture.

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 Paint in 3D / 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 Paint in 3D / 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 (⋮icon) button 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).

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).

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 (⋮ button) 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.

Auto Seam Fixer

If the above steps seem too tedious for you, then you can let Paint in 3D automatically do the seam fixing for you.

STEP 1 Select your paintable GameObject.
STEP 2 Find the P3dPaintable component in the inspector window.
STEP 3 Expand the Advanced settings.
STEP 4 Change the UseMesh setting to AutoSeamFix.

Your mesh will now be auto seam fixed just before you paint it for the first time.

NOTE  This technique doesn't allow you to adjust the seam fix settings.
NOTE  This technique has some performance overhead when you first paint your object, because the mesh must be seam fixed before it can be painted.

If either of these caveats is an issue, then I recommend you follow the previous section and manually seam fix the mesh.

Examples Of UV Maps

Below are some examples of different kinds of UV maps.

To view these yourself for any mesh, simply open the cotext menu for a mesh (⋮ button), and select Analyze Mesh.

Example 1

This is an example of what a good UV map looks like.

As you can see, the whole mesh is unwrapped making good use of the texture space. All triangles are within the standard (0..1) boundary, none of the triangles overlap, and there is sufficient spacing/padding between each UV 'island'.

Example 2

This is an example of what a bad UV map looks like.

As you can see, most of the triangles have no UV data, so they cannot be painted. The remaining triangles have UV data, but it's all overlapping, which means painting one area will cause paint to appear in multiple areas, because they share the same pixels.

Example 3

This is another example of what a bad UV map looks like.

As you can see, most of the triangles are out of bounds. This means most of the mesh can't be directly painted. If you paint the remaining areas, the paint will appear on the out of bounds areas due to texture tiling.

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.


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 (⋮ button at top right), so you can test it from the editor.

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