If you haven't already, please consider writing a review. They really help me out!
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.
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.
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.
If you want to use the SgtBlackHole feature, then you must enable the Opaque Texture setting in your pipeline settings asset.
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.
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.
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.
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.
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.
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.
Any GameObject that has a MeshFilter + MeshRenderer or SkinnedMeshRenderer can be painted.
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.
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.
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.
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.
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).
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!
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).
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.
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.
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.
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.
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.
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.
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.
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).
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.
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.
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.
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.
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.
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.
Paint in 3D comes with a range of shaders that allow you to specify the UV channel used (e.g. P3d Opaque).
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).
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.
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.
If the above steps seem too tedious for you, then you can let Paint in 3D automatically do the seam fixing for you.
Your mesh will now be auto seam fixed just before you paint it for the first time.
If either of these caveats is an issue, then I recommend you follow the previous section and manually seam fix the mesh.
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.
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'.
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.
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.
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:
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.
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!
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.
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 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).
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.
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.
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.
This blend mode works by increasing the RGBA values of your texture based on the paint color.
This blend mode works similar to Additive, but the strength of the blending fades based on how bright the texture already is.
This works by decreasing the RGBA values of your texture based on the paint color.
This blend mode works similar to Subtractive, but the strength of the blending fades based on how dark the texture already is.
This blending mode works like Alpha Blend, but the alpha channel of the texture will transition toward the paint alpha channel value, rather than just increase. In effect, this blends all channels toward the paint color at the same rate.
This is useful for painting advanced textures (e.g PBR), where you want to paint a specific alpha channel value.
This blending mode works similar to Replace, but instead of transitioning to the paint color, the paint color will be based on the original color of the texture.
This color is defined by the P3dPaintableTexture component's Texture and Color settings.
This blending mode works similar to Replace Original, but instead of transitioning to the original texture color, you can specify a custom texture and color to transition to.
This blend mode allows you to darken your texture based on the paint color.
To make it easier to use, the blending is inversed. This means your decal should be white where you want the color to be multiplied, and black where you want no change.
This blend mode allows you to blur your texture based on the paint opacity.
This blend mode allows you to paint a normal map with another, and both normal maps will combine together.
This blend mode allows you to paint a normal map on top of another, and the original normal map will be replaced by the new one.
This blend mode allows you to move the pixels in the texture you're painting. The direction and distance the pixels will move is based on the normal map you specify.
Paint in 3D allows you to paint skinned meshes. The set up is almost the same, where you add the P3dPaintable component alongside the SkinnedMeshRenderer component. However, there are some things to keep in mind.
To paint objects in your scene you need to use a hit component like P3dHitScreen, P3dHitParticles, etc. Some of these components like P3dHitNearby will apply in 3D without the need for colliders, but components like P3dHitScreen use Physics.Raycast, which means your paintable objects need colliders.
Normal non-skinned meshes are usually static, so you can just add a MeshCollider. However, skinned meshes usually bend and deform such that you cannot use a MeshCollider, because as soon as it animates, the collider surface will not match the visual mesh, which causes the paint to apply to the wrong area.
While the collider doesn't have to match the visual mesh, it needs to be close enough relative to the size/radius of your paint tool (e.g. P3dPaintDecal's Radius & Scale settings). If you have a complex skinned mesh, this usually means you must add many colliders to your object (e.g. BoxColliders and CapsuleColliders, perhaps one per bone).
However, if your game doesn't require precise painting (e.g. bullet wounds only), then there is one alternative strategy that is simpler to configure that is shown in the "PaintIn3D/Examples/Zombie Blood" demo scene. In this scene, the skinned zombie mesh is given one large BoxCollider, that encapsulates the whole zombie animation cycle. The P3dHitScreen component's RotateTo setting is set to Normal, and RotateTo/Direction is set to RayDirection. The P3dPaintDecal component's Scale.z setting is then set to 15 (the exact value depends on the size of the skinned mesh). With this configuration, the paint is aligned to and stretched along the hit direction, so it goes through the skinned mesh.
Inside the P3dPaintable component is the IncludeScale setting. Depending on your skinned mesh, you may need to enable this setting for the painting to work.
I wasn't able to identify exactly when this setting needs to be enabled or disabled, so it can't be automatically set. I think it has something to do with the software used to export the mesh, or the export settings, so for now you must manually try toggling this if you find your mesh can't be painted even if every other setting looks correct.
When painting using components like P3dHitScreen, you may notice your paint can appear as separate dots. This can easily happen if the object you're painting is far away, your paint brush radius is low, or the surface you're painting is at a sharp angle relative to your camera.
This happens because the paint is actually applied as a dot, and to make a continuous line the dots are simply placed close enough together that they no longer appear as dots. However, under certain circumstances this illusion can be broken.
To improve this, the easiest way to is to just lower the P3dHitScreen component's Interval setting. This will increase the amount of dots drawn by reducing the pixel distance between them. However, this carries a performance penalty, and it only makes the issue less apparent, it doesn't solve it.
To solve this issue you want to have each separate dot connect together to form a continuous line, and this can be done by enabling the Advanced / Connect Hits setting. This setting appears on components like P3dHitScreen, P3dHitNearby, and P3dHitBetween. Instead of sending hit point information to paint components, it will instead connect the hits points, and send out hit lines.
When using connected hits, the connected lines are drawn separately, which causes the overlapping corners to receive double the paint. This is an issue with semi-transparent painting, because they will appear stronger than the main line body.
To fix this, you must enable the Advanced / Clip Connected setting, which eliminates this issue in most scenarios.
Paint in 3D allows you to paint multiple textures at the same time (e.g. Albedo + Normal).
To set this up you must first add multiple P3dPaintableTexture / Paintable Texture components to your object, and make them target different texture slots in your current material/shader. For example, the first texture could be for the _MainTex slot, and the second texture could be for the _BumpMap slot.
Next, you must choose a different paint Group for each component. By default all textures are assigned to group "0: Albedo (RGB) Alpha(A)". If your first texture is albedo then you can keep this value. If your second texture is a normal map then you can change it to group "10: Normal (RGBA)".
Next, you must make multiple paint components (e.g. P3dPaintDecal / Paint Decal), and change their Group setting to match the texture groups you previously set.
You can now paint two textures at the same time! These same steps can be repeated for any number of textures.
Although paint in 3D is very optimized, it's still easy to make it run slow, especially on mobile devices. Here are some tips and tricks on how to optimize your scene and maximize performance.
The easiest way to optimize painting performance is to reduce the size of your P3dPaintableTexture. If you halve the width & height of your texture, then there are now only 1/4 of the pixels being painted, which means your paint will apply up to 4x faster.
I recommend you reduce the texture resolution as much as possible, until you find the perfect balance between performance and visual quality.
Another easy way to optimize your painting is to paint less often.
For example, the P3dHitScreen component has the Interval setting, which allows you to choose the pixel distance between each paint hit. If you set this to 3 pixels and move your mouse/finger 300 pixels in one frame, then this will result in your scene being painted 100 times. If you increase this to 6 pixels, then it will result in the scene being painted 50 times, or a 2x optimization. You can also set the Frequency to OnceEveryFrame, which will paint the scene no more than once per frame.
For example, the P3dHitParticles component by default paints every time a particle hits something. This can be optimized using the Advanced / Skip setting, which allows you to paint once every n times.
If your object has a large texture and you cannot reduce its resolution, then you can still optimize the painting without a loss in detail. This is done by splitting your mesh up into smaller parts, and setting them up as separate objects. If done correctly, when you paint your object only a small area of it will be painted, and thus less pixels will be processed overall.
The easiest example of this is painting a large wall. Instead of having one wall mesh, you can split it up into a grid of smaller sections. If done correctly you will still have the same overall texture resolution, but when painting you will only every paint a small number of meshes in this grid, and thus your painting performance will be greatly improved.
If you're using URP or HDRP, then you may notice painting _MainTex (Albedo) doesn't work, even though it shows up in the inspector list.
This is because these shaders seem to have a 'fake' _MainTex slot that doesn't do anything.
To fix this, you must instead paint the _BaseMap, which is the 'real' albedo texture.
This device can incorrectly paint on Android 7 with the OpenGL ES3 graphics API. Previously painted pixels are observed to randomly become transparent and otherwise change.
If you need to support this device:
This should allow you to paint properly again.
While the painting features can work with any VR asset/toolkit, the Paint in 3D VR examples are only configured to work with Unity's legacy XR system.
Yes, you can find the existing presets in the PaintCore/Extras/Presets folder.
To make a new one I recommend you duplicate one of the existing ones, and change its settings to your liking.
Each preset has one or many P3dPaintableTexture components.
Each paintable texture's Slot setting is automatically set when using the Paint in 3D window, so you can leave it empty.
Each paintable texture must have its own Group setting, which defines the kind of texture it will paint. For example, if you have one paintable texture that targets the "Occlusion (G)" group, then this preset will allow you to paint occlusion textures.
For a preset to show in the Paint in 3D window, the shader you want to paint must have textures that match all paintable textures in the preset.
Since shaders can arbitrarily define texture names, you must manually associate a paint group with a shader and its texture slot.
You can find the existing paint groups in the PaintCore/Extras/Groups folder.
The way this works is each paint group defines a list of shaders and texture names associated with the group. In the example image you can see the "Albedo (RGB) Alpha (A)" group, which among others has the "_MainTex@Standard" line. This means the "Standard" shader has the "_MainTex" texture, which is an albedo and alpha texture.
Paint in 3D comes pre-configured with paint groups and associations for most built-in Unity shaders.
Yes, you can find the existing tools in the PaintCore/Extras/Tools folder.
You can duplicate one of the existing ones, and change its settings to your liking.
Yes, you can find the existing materials in the PaintCore/Extras/Materials folder.
Your material should now have its textures replaced, and it should be ready to paint.
To make an icon for your material:
Your paint material should now have an icon. You may want to play with the scene light brightness to achieve best results.
Yes, there are two general techniques to do this depending on your requirements.
Paint hits are the high-level data used to paint your scene (e.g. the P3dHitScreen component sends hit data to components like P3dPaintDecal). Depending on the paint hit type, this just stores the world space position, rotation, seed, and other basic data.
This is the easiest data to send, but since the data is handled in world space and applied to everything in the scene, it's not suitable for moving objects.
To listen for paint hits you can create a new component and add it to the GameObject that has your P3dHit___ component. You can then implement any of the IHit___ interfaces, to get specific hit data. For example, the P3dHitScreen component can send point and line hit data, so you can implement the IHitPoint and IHitLine interfaces.
When a hit occurs, the HandleHitPoint and HandleHitLine and methods from these interfaces will be invoked. You can then store the given parameters to a file, or send it over the network.
Once this data is loaded/received, you can then broadcast it again using code like this:
// Loop through all components that implement IHitPointforeach (var hitPoint in GetComponentsInChildren
()) {
// Ignore this one so we don't recursively paint
if ((Object)hitPoint != this)
{
// Submit the hit point
hitPoint.HandleHitPoint(preview, priority, pressure, seed, position, rotation);
}
}
You can see the P3dPaintMultiplayer.cs code for an example of this.
Paint commands are the low-level data used to paint each individual paintable texture. These store everything about the paint that was applied (e.g. texture references), so it's not as simple to serialize it all.
To allow for de/serialization of this data, you must first provide unique hash codes to the P3dModel, P3dPaintable, and P3dPaintableTexture components. This is done via the Advanced / Hash setting.
In addition to these hashes, you must provide hashes for all textures used by your paint commands. For example, if you use decal painting then the decal texture must have a hash.
Since the Texture class is made by Unity and can't be modified, you must assign a hash to a texture using the P3dTextureHash component. You can add this component to your scene, assign the texture, and assign a hash code.
You can now listen for paint commands using the static P3dPaintableTexture.OnAddCommandGlobal event, or the instance OnAddCommand event. These events will give you every paint command for a specific paintable texture.
The paint command can then be stored or sent over the network using JsonUtility serialization, or similar.
Once this data is loaded/received, you can apply it using your paintable texture component's AddCommand() method.
You can see the P3dCommandSerialization.cs code for an example of this.
This is a list of the in-game example scenes and a description of what it shows.
This shows you how the Spaceship GameObject can be made paintable. This is done by adding the P3dPaintable, P3dMaterialCloner, and P3dPaintableTexture components. You can then paint the spaceship using the mouse/finger with the Paint GameObject, which has the P3dHitScreen and P3dPaintSphere components. Keep in mind that P3dHitScreen uses raycasts, so your mesh must have a collider to work.
This shows you how to remove painting seams from your mesh using the Seam Fixer tool. Seams are caused by gaps/islands in the mesh UV data, which are usually present at the edges of complex meshes. To use the seam fixer, simply click the context menu button (⋮ icon) at the top right of your mesh inspector window. You can then select Fix Seams (Paint in 3D), adjust the settings, and click Generate. You can double click the Spaceship GameObject's MeshFilter.Mesh setting to see it in action.
This shows you how to automatically fix seams in your mesh without using the Seam Fixer tool. This is done by changing the P3dPaintable component''s Advanced / UseMesh setting to AutoSeamFix. Keep in mind this mode doesn''t give you control over the seam fix settings (the defaults should be suitable for most meshes). Also keep in mind there will be a small performance hit the first time you paint your object when its seam fixed mesh is generated.
This shows you what happens when you paint a mesh that isn''t suitable for painting. For a mesh to be paintable, it shouldn''t have overlapping UV, or UV areas that exceed the 0..1 range (e.g. tiling). Notice the paint appears in unexpected areas on this mesh, because it contains both tiling UV, and overlapping areas.
This shows you how painting meshes with overlapping UV data can cause unexpected results. The left shows you what painting the standard Unity Cube mesh looks like, and the right shows what painting the Separated Cube mesh that comes with Paint in 3D looks like.
This shows you how painting the standard Unity Cylinder mesh can give unexpected results, and how the Separated Cylinder mesh that comes with Paint in 3D can avoid these issues.
This shows you how a mesh with UV data unsuitable for painting can still be painted. This is done by enabling the Generate Lightmap UVs setting in the mesh import settings. This setting will generate new UV data in the second UV channel/coord, which can be used by custom shaders. The Paint in 3D / Solid shader has this feature if you enable the Use Second UV setting. If you use this configuration then make sure the P3dPaintableTexture.Coord is set to the Second UV channel.
This shows you how the Unsuitable UV demo scene can be modified to allow correct painting on top. This is done by generating mesh data for the second UV channel/coord as seen in the Auto UV demo scene, and using a second transparent material layer on top of the base material. This second material uses the Paint in 3D / Overlay shader, which allows you to paint on top of the base material using the second UV channel. If you use this configuration then make sure the P3dPaintableTexture.Coord is set to the Second UV channel.
This shows you an alternative way to paint objects using secondary UV data. The overlay approach requires multiple materials, which may not be suitable for your project. In this scenario, you can use a shader that is specifically designed to allow you to paint on both the first and second UV channels. The P3D Solid shader has the basic albedo/metallic/etc textures that use the first UV channel, but you can also override these using secondary albedo/metallic/etc textures that use the second UV channel. This is done by painting the _AlbedoTex/_MetallicTex/etc, which will override the base texture based on the opacity of the secondary paint. Keep in mind this shader requires you to paint the override textures using the Premultiplied blending mode.
This shows you what happens when you paint objects that have materials with different color settings (top row). Notice how the color tint also applies to the paint, because the material color is multiplied with the painted texture color. To make the painted color apply without tinting you can set the material color to white, and instead change the P3dPaintableTexture.Color setting to the base color you want (middle row). You can also set the material color to white, and instead change the default texture (e.g. Albedo texture) to the color you want (bottom row).
This shows you how decreasing the P3dPaintSphere.Radius setting and/or increasing the P3dHitScreen.Interval setting allows you to draw dotted lines.
This shows you how the P3dHitScreen component''s Advanced / ConnectHits setting can be enabled, allowing paint dots to be joined together. A similar result can also be achieved using a lower Interval setting, but that has a performance penalty.
This shows you how the P3dButtonClearAll component can be added to a UI element, which makes it clear the paint of all textures in your scene. This also shows you how you can clear the texture of a specific texture by connecting the OnClick event to the P3dPaintableTexture.Clear method.
This shows you how the P3dButtonIsolate component can be added to UI elements. This turns them into buttons that can enable a GameObject, and disable its siblings. This allows you to switch between different painting tools.
This shows you how the P3dPaintSphere component''s Advanced / Tile settings can be used to paint seamless textures across your objects. This is done using triplanar mapping.
This shows you how the paint component''s BlendMode setting can be changed to Blur. This blending mode blurs the pixels of the paintable texture.
This shows you how to prevent the Blur blending mode from causing the pixels outside the edges of your mesh UV islands from ''bleeding'' into your main texture. This is done by setting the P3dPaintableTexture component''s Advanced / LocalMask texture. This texture can be created using Paint in 3D if you begin with a black paintable texture, paint it white, and then export the painted texture via the main Paint in 3D window.
This shows you how the P3dPaintableTexture component''s Advanced / LocalMask texture can be automatically generated with a mask suitable for use with the Blur blending mode. This is done by adding the P3dGenerateMask component alongside your P3dPaintableTexture component, and setting its Mesh setting to be the non-seam-fixed (original) version of your mesh. Automatically generating the mask like this means your build size doesn''t increase.
This shows you how the P3dHitScreen and P3dPaintDecal components can be combined to paint decals. Decals allow you to paint a custom texture on an object at a specific location. The P3dPaintDecal settings give you control over the angle, size, opacity, etc.
This shows you how the P3dPaintDecal component''s Wrapping setting can be used to control how the decal is applied to curved surfaces. When set to 0, the decal is applied using planar projection without any wrapping. When set to 1 the decal is wrapped around curved surfaces.
This shows you how the P3dHitScreen component''s Emit setting can be set to PointsOnUV, allowing you to apply decals directly to your paintable texture in UV space. This is useful when painting complex curved surfaces, because the texture can apply without distortion if your mesh is suitably UV mapped. Keep in mind this mode requires a non-convex MeshCollider for UV data, and for your objects to all have consistent texel sizes. Keep in mind this mode does not support painting between UV seams, and you may get paint bleeding if your UV islands are too close together. This scene also makes use of the Group setting (works like Layers) to avoid cross painting.
This shows you how the P3dHitScreen component''s Advanced / Normal settings can be used to control the visibility of the decal based on to the the angle between the decal and the surface being painted. This allows you to enable or disable painting of steep angles, behind surfaces, etc.
This shows you how the P3dPaintDecal component''s Advanced / NormalFront setting can be used to force paint to only appear on surfaces that have a surface normal (direction) similar to the surface normal of the hit point (mouse point).
This shows you how the P3dPaintDecal component''s Advanced / NormalFade setting can be used to control the sharpness of the normal cut-off transition.
This shows you how the P3dPaintDecal settings can be modified from UI buttons by calling the various functions like IncrementAngle, FlipVertical, etc.
This shows you how the Mirror GameObject has the P3dCloneMirror component attached. This automatically mirrors all paint across a 3D plane defined by its Transform position and rotation. If you select the Mirror GameObject then you can see a preview of the mirror plane in the Scene view.
This shows you how the Mirrored Painting demo scene can be modified to prevent decals from appearing backwards when mirrored. This is done by enabling the P3dCloneMirror.Flip setting, which makes the decals appear the same on both sides.
This shows you how mirrors can combine together, creating interesting symmetries.
This shows you how to apply paint when a Rigidbody collides with something. The P3dTapThrow component can be used to spawn and throw the Ball prefab when you click or tap the screen. The ball then paints the spaceship on impact using the P3dHitCollisions and P3dPaintDecal components.
This shows you how to automatically destroy a GameObject itself when it hits something. This is done by adding the P3dDestroyer component alongside the P3dHitCollisions component.
This shows you how to spawn an explosion effect when a Rigidbody hits something. This is done by adding the P3dSpawner component alongside the P3dHitCollisions component. The spawned prefab contains a ParticleSystem, and uses the P3dDestroyAfterTime component to destroy itself.
This shows you how the P3dHitBetween component can be used to paint between two Transform points. The P3dHitBetween.Line can be used to visualize the current beam, and the P3dHitBetween.Point setting can be used to vislize the hit point with particles.
This shows you how to paint everything at the center of the screen directly in front of the camera, like a laser eye beam. This is done using the P3dHitBetween component, which is set to hit between the Main Camera Transform, and the In Front Of Camera Transform, which is a child GameObject placed in front. This will then automatically call P3dPaintSphere on the first hit point it finds between these two points, and paint them red. The camera can then be rotated using the P3dPitchYaw component.
This shows you how the P3dHitThrough component can be used to paint trhough two Transform points. The P3dHitThrough.Line setting can be used to visualize the current beam. Unlike P3dHitBetween, this component paints all surfaces between the two points.
This shows you how the P3dHitParticles component can be added to your ParticleSystem GameObjects. This allows you to paint with components like P3dPaintSphere when particles hit objects in the scene. Keep in mind you must enable collision in your particle system for this to work.
This shows you how particle painting can be greatly optimized. By default, the P3dHitParticles component paints once per particle collision. However, this can be incredibly slow if you emit too many particles. To optimize this, you can use the P3dHitParticles component's Advanced / Skip setting, which allows you to paint once every 'Skip' particles. In this scene Skip = 10, which means for every particle collision that would result in a call to P3dPaintSphere, 9 calls are skipped.
This shows you how the P3dHitNearby and P3dPaintSphere components can be combined to paint any surfaces within the specified sphere shape.
This shows you how the P3dTapThrow component can spawn and throw the Ball prefab. This prefab has the P3dHitNearby component, which can paint surfaces near the current Transform position. This effect can be used to create fireballs that pass through objects, and paint them on the way.
This shows you how the P3dPaintableTexture.SaveName setting can be used to enable automatic save/load. Paint something, then run the scene again to see it in action. Keep in mind these save names should be unique, so using the same name with multiple prefabs may not work as expected.
This shows you how the P3dPaintableTexture.UndoRedo setting can be used to store undo and redo states. You can then add the P3dButtonUndoAll and P3dButtonRedoAll components to UI elements to cycle through them. Keep in mind storing of states requires the StoreStates setting to be enabled, this is on components like P3dHitScreen.
This shows you how the paint settings can be randomly adjusted before the paint is applied. This is done by clicking the Add Modifier button inside the paint component (e.g. P3dPaintDecal), and selecting a value to modify (e.g. Angle), and then the type of modification (e.g. Random). Keep in mind these modifiers can be combined together to make even more interesting results.
This shows you how to gradually fade a texture back to its original state after you paint it. This is done using the P3dGraduallyFade component, and dragging and dropping the texture you want to have fade into the PaintableTexture setting. You can then set the BlendMode setting to ReplaceOriginal, and it will gradually fade to its original state as defined by the P3dPaintableTexture component''s Texture and Color settings.
This shows you how the Gradually Fade demo scene can be modified to blur the texture over time.
This shows you how the Gradually Fade demo scene can be modified to fade a normal map to its original state. This is done by using the Normal Replace blending mode and the DefaultNormal texture. Keep in mind the ReplaceOriginal blending mode can''t be used with normal maps, because the original texture and color are converted into normal maps, and this would cause them to be replaced by their non-converted state.
This shows you how to paint holes in your paintable objects. This is done using the Subtractive blending mode, which allows you to reduce the alpha/opacity of the pixels in your texture. Keep in mind this requires you to use a shader/material that supports transparency, like the P3d Solid one used here. Keep in mind the underlying mesh still remains, so you can''t paint through the holes you create.
This shows you how the P3dPaintReplace component can be used to replace every pixel in the currently painting texture. Keep in mind the GameObject with the P3dPaintableTexture must have a collider for this to work, and P3dHitScreen.Emit must be set to PointsOnUV.
This shows you how the P3dPaintFill component can be used to blend every pixel in the painted texture. This allows you to gradually change it, rather than instantly like P3dPaintReplace does. Keep in mind the GameObject with the P3dPaintableTexture must have a collider for this to work, and P3dHitScreen.Emit must be set to PointsOnUV.
This shows you how to paint an object in from an invisible state. This is done by changing the P3dPaintableTexture.Color setting''s alpha/opacity value to 0, which causes the texture to initialize as invisible. You can then reveal the object by painting the alpha/opacity back in, which is automatically done when using the Alpha Blend blending mode. Keep in mind this requires you to use a transparent material/shader like the Paint in 3D / Solid one used here.
This shows you how a textured mesh can be hidden, and then revealed by painting on it. This is done by changing the P3dPaintableTexture.Color alpha/opacity value to 0. The texture can then be revealed by painting with the Additive blending mode, with a color of RGBA 0,0,0,1. Keep in mind this requires your mesh to use a transparent (e.g. cutout) shader/material.
This shows you how to paint on top of a transparent material. This is done using the Alpha Blend blending mode. Notice how the erase tool erases both the paint, and the original dirt.
This shows you how the Glass Painting demo scene can be modified so the paint is applied to secondary albedo and opacity textures that override the base values. Notice how the erase tool only erases the new paint, and keeps the original dirt. This technique also allows you to paint at a lower resolution, but keep the original higher resolution texture, allowing you to optimize performance. Keep in mind this configuration requires you to use a special mater/shader designed to override the base texture values (the Paint in 3D / Alpha shader is used here). Keep in mind the override textures use premultiplied alpha, so you must set your paint tools to use the Premultiplied blending mode (though erasing can use the subtractive blending mode).
This shows you how the P3dChannelCounter component can be used to count the total pixels in the specified P3dPaintableTexture that exceed the threshold value in each R/G/B/A channel. The P3dChannelCounterText component can then be used to display these in the UI.
This shows you how the Channel Counter demo scene can be modified to accurately display how much of a mesh you have painted. This is done by setting the Spaceship GameObject\u2019s P3dChannelCounter.Mesh setting to the original non-seam-fixed mesh. The paint percentage can then be displayed using the P3dChannelCounterText and P3dChannelCounterFill components. To make the paint work with any color this spaceship paint uses a second layer on top, similar to the Paint On Top demo scene.
This shows you how the P3dColorCounter component can be used to count the total pixels in the specified P3dPaintableTexture that are within the threshold color of a P3dColor. The P3dColorCounterText component can then be used to display these in the UI.
This shows you how the P3dChangeCounter component can be used to count how many pixels in the specified texture are different to a reference state. The reference state can be set using the P3dChangeCounter component''s Texture and Color settings.
This shows you how the Alpha Blend Inverse blending mode can be used to paint transparent areas of your texture. This gives the effect of painting undernearth your existing paint.
This shows you how the Replace Original blending mode can be used to paint your object back to its original state based on the P3dPaintableTexture component''s Texture and Color settings.
This shows you how the Replace Custom blending mode can be used. This works similar to Replace Revert, but you can specify custom Texture and Color values per paint tool.
This shows you how to paint decals with dynamically changing content. This is done using a RenderTexture, making a second camera, and changing its TargetTexture setting to the RenderTexture. Keep in mind you must correctly set up your layers and Camera.CullingMask values to keep each camera isolated. Also keep in mind dynamic decals can''t be undone using the P3dPaintabeTexture.State = LocalCommandCopy setting.
This shows you how to create live paint that can be repositioned in game. This is done using the P3dHitNearby component with the Preview setting enabled. You can control the draw order of these decals using the Priority setting.
This shows you how live paint can be applied to your objects when you press a button. This is done by linking the button's OnClick event to the P3dHitNearby component's ManuallyHitNow function.
This shows you how the P3dTranslate component can be used to move a live decal around the scene using UI button events that call the P3dTranslate.TranslateX/Y/Z functions.
This shows you how to optimize painting speed using different LOD meshes for visuals and painting. The Knot_High GameObject is used to render the high poly visual mesh. The Knot_Low GameObject is used for the low poly MeshCollider, and for painting. To make the paint apply on the high poly mesh, the P3dPaintable.OtherRenderers list contains the Knot_High MeshRenderer.
This shows you how to paint multiple separate objects that share the same texture. This is done by setting up one paintable object normally, and then dragging and dropping the other objects into the P3dPaintable component's Advanced / OtherRenderers list. You must then add the P3dModel component to the other objects, and drag and drop the first object into the P3dModel.Paintable setting.
This shows you how to paint filled in polygon shapes. This is done by replacing the P3dHitScreen component with the P3dHitScreenFill component. This causes the polygon shape you draw to be filled in with a grid of points. Keep in mind the points are drawn in screen space, so the resolution depends on the camera distance to the paint surface.
This shows you how the P3dMask component can be added to the scene. This allows you to define an area where paint will be blocked, allowing you to paint within a specific shape. You can see the location of the mask in the Scene window after you select the mask.
This shows you how the P3dMask component''s Stretch setting can be used to extend the edges of the mask without modifying the mask texture. This allows you to more easily block painting across a large area without requiring a high resolution mask texture.
This shows you how normal maps can be painted. This is done by opening the advanced settings for the P3dPaintableTexture component, and changing the Conversion setting to Normal, as well as changing the Slot to _BumpMap. You can then paint using the Normal Blend blending mode. Keep in mind the normal maps use all four RGBA channels to store data, so you must set the shape of the decal separately with the Shape setting.
This shows you how to read the paint pixel color under the mouse/finger. This is done using the P3dReadColor component, which can be added alongside any P3dHit___ component that works using raycasts like P3dHitScreen and P3dHitBetween. Keep in mind the hit component must be set to emit PointsOnUV. The OnColor event is then used to change the UI Image color to the read color.
This shows you how to detect when a specific color has been read, and trigger an action from it. This is done using the P3dReadColorEvent component, which can be added alongside the P3dReadColor component. When you read a color within the Threshold distance of your specified Color, it will trigger the OnColor event, which can be used to perform any action.
This shows you how the P3dReadColor and P3dPaintBetween components can be combined, allowing you to read the color under a specific GameObject, and display that color in the UI.
This shows you how the P3dPaintMultiplayer component can be added to your paint tool to simulate painting over a network. To make this work using actual multiplayer, the SimulateNetworkTransmission coroutine must be replaced with actual network transmission code, which will differ depending on the network solution you''re using.
This shows you how to set up a GameObject to be paintable from scratch using C# code. See the P3dProceduralSetup script in the PaintIn3D/Examples/Scripts folder for more details.
This shows you how to paint the underlying triangles of your mesh. This is done by changing the P3dHitScreen component's Emit setting to TrianglesIn3D.
This shows you how basic painting can be used to reveal a complex design. This is done using the ReplaceOriginal blending mode on your paint tool, which will revert a P3dPaintableTexture to its current Texture and Color settings. The texture that will be revealed is first hidden using the P3dPaintableTexture.Color setting with 0 alpha. The P3dPaintable.OnActivated event is then used to reset this back to full alpha using the P3dPaintable.SetColor event, with a hex color of #FFFF.
This shows you how the Graffiti scene can be modified to count the % of the design you have painted. This is done using the P3dChangeCounter component, which monitors the graffiti texture. This component''s MaskTexture is set to read the final graffiti design''s alpha channel so it ignores pixels outside of the design. The Texture setting is then set to the final design, so the currently painted/revealed graffiti texture is compared against the final design.
This shows you how to make painted decals change direction based on the angle of your mouse/finger as you paint. This is done by changing the P3dHitScreen component''s RelativeTo setting to DrawAngle when RotateTo = Normal. Keep in mind the draw angle isn''t known on the first frame your mouse/finger touches the screen, so the first paint hit is skipped.
This shows you how to mask specific areas of your texture using your mesh UV, rather than being in 3D like with P3dMask. This is done using the P3dPaintableTexture component''s LocalMask setting inside the Advanced settings.
This shows you how to paint decals under the mouse from code. Check out the PaintIn3D/Examples/Scripts/P3dPaintFromCode.cs code to see how it works!
This shows you how the Flow blend mode can be used to move the pixels in the texture you paint using a normal map that defines which direction and how far they should move. The maximum distance of the flow samples can be controlled from the Kernel setting.
This shows you how to make paint flow across the surface of your object over time. This is done using the P3dGraduallyFade component with BlendMode = Flow. This allows you to set a normal map in the Texture setting that allows you to control how the paint should flow.
This shows you how the Flow / Gradually demo scene can be modified so the paint begins at full speed, but gradually slows down until it stops. This is done by adding a second paintable ''Speed'' texture to your object. Since this speed texture isn''t applied to the material, you must enable the Advanced / IsDummy setting. Like the albedo texture, this speed texture uses P3dGraduallyFade to twist the texture around, but it also has a second P3dGraduallyFade to fade it to black to slow down the speed. The albedo texture''s P3dGraduallyFade.MaskPaintableTexture is then set to this speed texture, which will cause its flow speed to depend on the speed texture''s red channel. You can then paint both the albedo and speed textures at the same time to make the effect work. Keep in mind both of these textures must use a different P3dGraduallyFadeGroup setting.
This shows you how to make a liquefy paint effect, where the painted pixels will move based on the direction you move the mouse/finger when painting. This is done using the Flow blend mode with a normal map pointing up. The flow is rotated using the P3dHitScreen component''s RotateTo / Relative To = DrawAngle setting.
This shows you how to configure the four basic primitives to be paintable, so that any paintable pixels that enter them get painted. This is done using a combination of P3dHitNearby and P3dHitThrough components with the P3dPaintSphere and P3dPaintDecal components to continuously paint any pixels that enter the current volume. Keep in mind the P3dPaintDecal.NormalFront setting should be set to 2 to apply paint even if it's applying to steep or back faces.
This shows you how to paint points or lines between the mouse/finger start and end positions. This is done using the P3dHitScreenLine component, which can be combined with the P3dPaintSphere/Decal component. This component''s Frequency setting can be used to control how many and where the points/lines are drawn. The ConnectHits setting can also be used to switch between drawing points and lines. Keep in mind painting lines on complex geometry requires you to paint many points, otherwise they will go through the geometry.
This shows you how the P3dHitScreen and P3dHitScreenLine components can be used together to draw lines. This is using a combination of other settings, like Frequency, and setting Rotate To / Relative To to Draw Angle.
This shows you how the P3dPaintDebug component can be added alongside your other paint components. This will show you where Paint in 3D is applying the paint in the Scene view. This allows you to easily diagnose painting problems. Keep in mind this feature requires you to enable Gizmos.
This shows you how to make paint gradually appear after you paint it, rather than instantly. This is done by configuring two P3dPaintableTexture components as normal. However, the first should have its Group setting changed to an unused group (e.g. DUMMY), and the second should have its Advanced/IsDummy setting enabled to prevent it from applying to the object''s material. A P3dGraduallyFade component is then used on the first paintable texture with the Replace blend mode, and the BlendPaintableTexture set to the second paintable texture. In effect this means your paint will apply to the second paintable texture, and this paint will be gradually copied over to the first. The other settings are just to prevent paint from applying directly to the first paintable texture.
This shows you how to listen for and store paint commands that get added to any P3dPaintableTexture component in the scene. You can then click a button to reset all paintable textures, and randomly apply one of the recorded paint commands. See the PaintIn3D/Examples/Scripts/P3dCommandSerialization.cs code to see how this works. Keep in mind this is an advanced technique that requires good C# knowledge.
This shows you how to eliminate the overlap points from transparent painting when using the Advanced / Connect Hits setting. This is done by enabling the Advanced / Clip Connected setting, which blends connected lines together.
This shows you how to make a mask texture at runtime from a camera. This is done by making a new camera with its TargetTexture set to a RenderTexture in your project. A separate Screen Space - Camera UI is used to render to this camera (you could also render 3D objects). The RenderTexture is then added to a P3dMask in the scene. In this example only the Red channel of the mask is used, so the RenderTexture uses the R8 format to save memory.
This shows you how to initialize a paintable texture with texture tiling. This is done using the P3dHitNearby component with the PaintIn setting set to Start. The P3dPaintSphere component is then used to apply the paint. This component's Advanced/TileTransform can be set to any GameObject/Transform that has scaling, and you can set the Advanced/TileTexture to your desired texture. When you enter play mode, these components will activate and apply the paint to your scene. Make sure the P3dPaintSphere.Radius setting is large enough to encompass your object. To isolate painting to just one paintable texture you can drag and drop your object into the P3dPaintSphere component's Advanced/TargetModel setting.
This shows you how to mask paint behind foreground objects. This is done with the P3dRenderDepth component, which can render the scene depth from the perspective of a camera. You can then drag and drop this component into the P3dPaint___ component''s Advanced / DepthMask setting.
This shows you how to paint holes and dents on a transparent target object. The bullet mark ignores transparent areas using the Alpha Blend blending mode, with only the RGB channels (1, 1, 1, 0), skipping modifications to the alpha channel.
This shows you how the Undo Redo demo scene can be combined with Sphere and Decal painting so you can paint on a car.
This shows you how the Seamless Painting and Blur Painting demo scenes can be combined to create a chalkboard you can draw on and erase from in a realistic way.
This shows you how the Collision Painting and Flow / Time demo scenes can be combined to create a paint dripping effect that slows to a stop over time. Unlike the Flow / Time demo scene, this uses a downward facing flow texture, so the albedo and speed textures flow down the wall.
This shows you how the Nearby Painting / Throw demo scene can be modified to cut holes through an object.
This shows you how the Color Counter demo scene can be modified to paint splats of color.
This shows you how to paint the Albedo, Normal, and PBR (Metallic + AO + Smoothness) textures at the same time using the Group feature. You can assign a texture group using the P3dPaintableTexture.Group setting, and to paint these textures a matching P3dPaintSphere.Group/P3dPaintDecal.Group setting can be used.
This shows you how the albedo and normals can be painted at the same time, creating a rock engraving effect.
This shows you how two P3dPaintCollisions components can be used with different layer filtering and different Root settings, allowing you to apply different kinds of paint to different objects. The P3dPaintDecal component and P3dPaintableTexture''s GameObject must have matching layers for this to work.
This shows you how P3dHitCollisions and P3dPaintSphereTriplanar can be added to a Rigidbody GameObject. This allows them to paint the Spaceship_Shield GameObject with a special impact pattern. The P3dGraduallyFade component is then used to gradually fade the texture back to transparent black, simulating a spaceship shield effect.
This shows you how to paint a background skybox without seams or distortion. Notice the skybox mesh is a subdivided cube turned into a sphere with cube mapped UV coordinates. The mesh is then run through the Seam Fixer tool.
This shows you how to paint an RGBA splat map. This is done using the Splat (R, G, B, A) group, with the Replace blending mode. Each paint tool replaces the splat texture with a specific channel color (e.g. 0,1,0,0 for green). It''s also possible to use the Additive & Subtractive blending modes on each channel instead. Keep in mind splat maps require your object to have a special material/shader that implements splat maps.
This shows you how to paint an object using a spray can that emits paint particles. This is done using the P3dToggleParticles component.
This shows you how the albedo of a transparent object with overlapping UV data can be painted using auto generated UVs and secondary textures.
This shows you how PBR spray painting can be implemented in VR using Unity''s XR library. Make sure to enable Virtual Reality Supported in your project settings. Also, make sure to select the VR Manager GameObject, and check to see if each input axis is set up. If you''re using the new InputSystem, then please read the documentation for it.
This shows you how VR pen painting can be implemented in VR using Unity''s XR library. Make sure to enable Virtual Reality Supported in your project settings. Also, make sure to select the VR Manager GameObject, and check to see if each input axis is set up. If you''re using the new InputSystem, then please read the documentation for it.
This shows you how to particle collision painting can be used to apply dirt to a car as its wheel kick up dust.
This shows you how to paint dynamic blood decals on an animated SkinnedMeshRenderer GameObject. These decals are painted using the Multiply RGB blending mode, which causes them to stack and get darker. Keep in mind the zombie uses a big BoxCollider, so the decal must extend quite far into the zombie to paint it. This is done using a high P3dPaintDecal.Scale.z setting, and with the P3dHitScreen.Normal = RayDirection setting, to rotate the depth so it faces the paint direction.
Here's a list of all my other assets, please check them out!
You can also view this list on my Asset Store page.
Rapidly develop your game with consistent input across desktop & mobile using Lean Touch. This lightweight asset comes with many modular components, allowing you to customize them to your exact project needs!
Lean Touch+ is an extension to the popular Lean Touch asset, adding many more example scenes.
Lean Localization is a localization library that's designed to be as simple to use as possible for both designers, and programmers.
Quickly optimize the performance of your games using Lean Pool. Within minutes you can use this lightweight asset to preload, recycle, and limit the spawning of your prefabs.
Quickly polish your games using Lean Transition. This asset allows you to easily tween or animate almost anything in your game, making it transition smoothly.
Lean GUI is a colllection of components that extend Unity's GUI system, allowing you to rapidly enhance the user experience (UX) of your game's UI.
Lean GUI Shapes allows you to quickly add lines, rounded boxes, polygons, and much more to your GUI!
Lean Texture allows you quickly modify textures in your project with a range of filters, pack them together into channels, and much more!
Lean Texture+ is an extension to Lean Texture, adding many new types of texture modification tools!
Take your space game to the next level with this collection of 8K background planets. Just drag and drop them in, and enjoy orbiting around them.
Paint all your objects using Paint in 3D - both in game, and in editor. All features are optimized with GPU accelerated texture painting, so you can enjoy consistent performance, even if you paint your objects one million times!
FLOW allows you to add large scale interactive fluids to your scene - all highly optimized using GPU acceleration.
Unlock the full potential of your 2D games using Destructible 2D, this asset allows you to quickly convert all your boring solid sprites into fully destructible ones!
Quickly make the space scene of your dreams using Space Graphics Toolkit. This huge collection of space effects can be customized and combined in any way you like, allowing you to quickly make realistic or fantasy worlds. Each feature has been heavily optimized to run on almost any device and platform.
Enhance your space scenes using this large pack of high detail volumetric planets. These planets are finished using the powerful planet features from Space Graphics Toolkit (not required).
Unity sounds only emanate from a single point source. This is great for explosions and footsteps, but quite often you need something more advanced. Volumetric Audio is an easy to use package that allows you to define boxes, spheres, capsules, paths, or meshes that sounds can emanate from.
Fixed normal map painting when Normal Map Encoding is set to DXT5nm.
Fixed P3dHitScreen painting bug with connected preview hits.
Fixed P3dHitScreen not showing clip connected preview hits.
Renamed SlidingToolButton to ToolButton.
Adding the P3dHitScreen component will automatically add the P3dPointerMouse/Touch/Pen components.
Moved main build to Unity 2021.3.0f1.
Updated shaders to latest version.
Fixed P3dCloneMirror component when the Flip setting is enabled.
Fixed P3dCoordCopier index counts.
Fixed P3d___Counter components updating when not necessary.
Added P3dRenderDepth component.
Added Advanced/DepthMask setting to P3dPaintSphere component.
Added Advanced/DepthMask setting to P3dPaintDecal component.
Added Depth Mask demo scene.
Fixed P3dHitScreen component's GuiLayers setting.
Fixed P3dHitScreenLine component painting.
Fixed P3dHitScreenFill component painting.
WARNING: To update from an earlier version: back up your project, delete the old Plugins/CW/PaintIn3D folder, and then install the new version.
Moved main build to Unity 2020.3.0f1.
Moved in-editor painting features to Plugins/CW/PaintInEditor folder.
Fixed in-editor triangle painting.
Fixed manual disabling of P3dPaintable components.
Fixed in-editor painting not painting alpha.
Added P3dPointerMouse component.
Added P3dPointerTouch component.
Added P3dPointerPen component.
Added AlphaFromAlbedo setting to P3dMaterial component.
Added Min blending mode.
Added Max blending mode.
Added Initial Tiling demo scene.
Moved main build to Unity 2020.3.0f1.
Fixed in-editor triangle painting.
Fixed manual disabling of P3dPaintable components.
Fixed in-editor painting not painting alpha.
Added AlphaFromAlbedo setting to P3dMaterial component.
Fixed P3dHitBetween when Orientation = WorldUp.
Improved P3dMask component gizmo rendering.
Added NormalReplaceOriginal blending mode.
Added NormalReplaceCustom blending mode.
Fixed P3dGraduallyFade colors being incorrect during transition.
Added Default Format setting to Config tab of the Paint In 3D window.
Added unlit versions of the 4 main example shaders.
Removed global shader keywords.
Fixed P3dChannelCounter component setting changes not being reflected.
Fixed P3dChangeCounter component setting changes not being reflected.
Fixed P3dColorCounter component setting changes not being reflected.
Every P3dColorCounter now updates when a P3dColor is enabled or disabled.
Fixed P3dReadColor reading incorrect UV location on the Metal graphics API.
Changed Solid shader's Tiling setting to be a vector.
Changed Alpha shader's Tiling setting to be a vector.
Changed folder structure to be inside Plugins/CW/PaintIn3D.
Updated inspector code to support third party assets that implement nested inspectors.
Added P3dHitNearby.PaintIn = ManuallyOnly setting.
Added Splat Map Painting demo scene.
Added Clip Connected demo scene.
Added Advanced / ClipConnected to most P3dHit___ components to eliminate connected line overlap.
Fixed texture modifiers not saving textures.
Fixed undo/redo of local commands breaking if the paintable object is moved.
Fixed undo/redo of local commands if you paint while in an undo state.
Fixed undo/redo of local commands when using SaveLoad = Automatic.
Fixed seam fixer with multi submesh meshes that share UV coords between submeshes.
Fixed seam fixer with invertex mesh UV data.
Renamed P3dHitScreen.Offset to NormalOffset.
Added P3dHitScreen.MouseOffset setting.
Added warning to P3dModel if the mesh is non-readable.
Added warning to P3dPaintable if the mesh is non-readable.
Inverted P3dChangeCounter results to count differing pixels.
Added P3dPaintableTexture.OnAddCommandGlobal static event.
Added P3dPaintableTexture.OnInstanceAdded static event.
Added P3dPaintableTexture.OnInstanceRemoved static event.
Added Command Serialization demo scene.
Added Hash setting to P3dModel component.
Added Hash setting to P3dPaintable component.
Added Hash setting to P3dPaintableTexture component.
Added P3dTextureHash component.
Fixed DUMMY group having preset components.
Added Blur Painting / Mask demo scene.
Added Blur Painting / Mask / Generate demo scene.
Added LocalMask texture sampling to Blur blending mode.
Added LocalMask texture sampling to Flow blending mode.
Added P3dGenerateMask component.
Renamed shader includes to reduce possible clashes with other assets.
Fixed P3dHitScreen.TouchOffset setting.
Fixed P3dMask ordering when there are multiple in the scene.
Fixed P3dPaintableTexture inspector warning with clashing slots when IsDummy is set.
Improved P3dPaintableTexture inspector to make it clearer when IsDummy is set.
Added Delayed Appearance demo scene.
Added DUMMY = -1 paint group.
Fixed P3dHitScreen not working on mobile when using new InputSystem package.
Made P3dHitScreen.Key work without mouse click on desktop platforms.
Added P3dHitScreen.RequiredButtons setting.
Replaced P3dHitScreen.Key setting with RequiredKey.
Updated paint modifier code to no longer use custom serialization.
Added P3dHitBetween.Orientation = ThisRotation setting.
Added P3dHitBetween.Orientation = ThisLocalRotation setting.
Added P3dHitBetween.Orientation = CustomRotation setting.
Added P3dHitBetween.Orientation = CustomLocalRotation setting.
Added P3dHitBetween.CustomTransform setting.
Added ClearHitCache and ResetConnections to P3dHitThrough component.
Added ClearHitCache and ResetConnections to P3dHitScreen component.
Added ClearHitCache and ResetConnections to P3dHitScreenLine component.
Added ClearHitCache and ResetConnections to P3dHitNearby component.
Added ClearHitCache and ResetConnections to P3dHitBetween component.
Fixed P3dChannelCounter when Counters list contains null entries.
Fixed P3dColorCounter when Counters list contains null entries.
Fixed P3dChangeCounter when Counters list contains null entries.
Fixed P3dChannelCounter not updating when enabled.
Fixed P3dColorCounter not updating when enabled.
Fixed P3dChangeCounter not updating when enabled.
Combined P3dHitScreenLine.Frequency = Start/End into Once.
Fixed various demo scene UI and description issues.
Fixed in-editor paint point offset.
Fixed in-editor paint applying with left/middle click.
Fixed harmless in-editor painting errors when editing play mode.
Modified P3dColorCounterText to use OnString event rather than UI text.
Modified P3dChannelCounterText to use OnString event rather than UI text.
Modified P3dChangeCounterText to use OnString event rather than UI text.
Added in-editor painting warning when not over the Scene view.
Added in-editor painting warning when the scene contains painting components.
Moved in-editor painting tools back to scene window.
Made in-editor painting tools not require colliders.
Added P3dGraduallyFade.BlendPaintableTexture setting.
Added Scale / Random paint modifier to P3dPaintSphere and P3dPaintDecal.
Fixed P3D / Solid shader's Opacity Override not working.
Fixed P3dPaintableTexture.Resize not updating mips.
Fixed P3dReadColor giving incorrect values in OpenGL.
Fixed connected hits incorrectly joining together on mobile devices.
Renamed P3dGraduallyFade.Texture setting to BlendTexture.
Renamed P3dGraduallyFade.Color setting to BlendColor.
Added P3dSerialization class for easier low-level de/serialization of paint commands.
Modified P3dCommand data to allow for de/serialization.
Added more Paint in 3D window material presets.
Added PaintIn3D window material export button to speed up exporting.
Fixed P3D/Alpha shader error in URP.
Fixed Shield Impacts demo scene.
Updated shaders to use latest BetterShaders version.
Moved main build to Unity 2019.4.12f1.
Added Seam Fixer / Auto Seam Fix demo scene.
Added Auto UV demo scene.
Added Base Color demo scene.
Added Line Painting demo scene.
Added Line Painting / Arrows demo scene.
Added P3dHitScreen.Frequency setting.
Added P3dPaintable.OnActivating event.
Added P3dPaintable.UseMesh advanced setting.
Added P3dHitParticles.Emit setting.
Added P3dHitParticles.Layers setting.
Added P3dHitParticles.Root setting.
Added P3dHitCollisions.PressureMode setting.
In-Editor: Added Build Material As Decal button to materials.
P3dPaintableTexture now shows a warning when trying to paint a Slot with tiling or offset.
Improved inspector organization of all P3dHit___ components.
Improved inspector organization of all P3dDraw___ components.
Reduced Solid shader instruction count.
Reduced Alpha shader instruction count.
Improved VR Pen demo scene setup.
Simplified hierarchy of all demo scenes.
Moved fill painting to new P3dHitScreenFill component.
Fixed P3dBlendMode overlap with narrow inspector.
Replaced example shaders with Better Shaders.
Fixed Texture Pressure modifier errors.
Fixed Texture Random modifier errors.
Made in-editor painting only begin after you switch to the paint tab.
Added Unload Paint Brush button to in-editor paint tab.
Added Gradually Fade / Blur demo scene.
Added Gradually Fade / Normal demo scene.
Added Dip demo scene.
Added ability to bind in-game camera rotate.
Added ability to bind in-game camera pan.
Made in-game camera pan default to left command key on OSX.
Fixed P3dPaintableTexture inspector error when painting meshes with submeshes.
Fixed P3dHitScreen.TouchOffset DPI scaling being inverted.
Fixed P3dGroupData shader texture presets for URP and HDRP shaders.
Fixed P3dMirror in some scenarios.
Added Wheel Dirt demo scene.
Fixed P3dHitScreen values persisting through disable/enable.
In-Editor: Simplified P3dMaterial builder tools.
In-Editor: Added Override Angle setting to Paint tab.
In-Editor: Added Override Normal setting to Paint tab.
In-Editor: Added Override Modifiers setting to Paint tab.
In-Editor: Added Override Tiling setting to Paint tab.
In-Editor: Added Override State Limit setting to Scene tab.
In-Editor: Moved camera options to Camera tab.
In-Editor: Added Show Pivot camera option.
In-Editor: Simplified P3dPreset settings.
Added Dripping Paint demo scene.
Added Flow demo scene.
Added Flow / Gradually demo scene.
Added Flow / Time demo scene.
Added Emission to P3D Solid shader.
Added Shift blend mode.
Added P3dPaintableTexture.IsDummy setting to Advanced menu.
Added P3dPaintableTexture.Aniso setting to Advanced menu.
Allowed P3dPaintableTextures to be placed in child GameObjects.
Fixed painting when using per-texture anisotropic filtering above 0.
Fixed P3dHit.Root setting in some scenarios.
Added Local Mask demo scene.
Added Paint From Code demo scene.
Added P3dPaintableTexture.LocalMask setting to Advanced menu.
Renamed P3dMask.Shape setting to .Texture.
Fixed error when seam fixing mesh without UV coords.
Fixed P3dSpawner inspector not drawing.
Fixed P3dMask ignoring paint layers.
Fixed PPtr error when using texture modifiers.
Added P3dHitScreen.RelativeTo = DrawAngle setting.
Fixed painting of static meshes.
Added paint priority sorting for non-preview painting.
Added "Draw Angle" demo scene.
Added multi prefab support to P3dSpawner.
Added Radius setting to P3dSpawner.
Fixed P3dSeamFixer incorrectly upgrading.
Fixed P3dSeamFixer with unlimited bone meshes.
Fixed P3dSeamFixer bug with tiny triangles.
Fixed mesh analysis overlap test when using linear color space.
Fixed texture modifier de/serialization of texture references.
Fixed P3dReader error on devices that don't support async texture reads.
Fixed quick clicks making paint components behave incorrectly.
Disabled component activation context menu option when in edit mode.
Added warning to activated components when in edit mode.
Fixed P3dHitParticles error on first frame.
Fixed P3dHitBetween when using Interval of -1.
Fixed P3dHitThrough when using Interval of -1.
Textures now save and load in sRGB color space only.
Fixed P3dChangeCounterEvent menu entry.
Fixed P3dReadColor in linear color space.
Fixed color painting in linear color space.
Fixed simulated VR controls when interacting with UI.
Fixed P3dPaintableTextureMonitorMask with MaskMesh.
Fixed undo/reco when using P3dHitScreen.
Fixed console warning when using automatic save/load.
Moved main build to Unity 2018.4.13f1.
Added support for the new input system (see documentation).
Fixed Auto Save Load demo scene.
Fixed Bullet Dents demo scene.
Fixed Overlay material to use the P3D Overlay shader.
Fixed P3dHitCache bug with triangles, quads, and coords.
Added Procedural Setup demo scene.
Added Reveal Graffiti demo scene.
Added Reveal Graffiti / Counter demo scene.
Added P3dPaintable.OnActivated event.
Added Triangles draw mode to P3dHitScreen.
Added Triangle painting tool to in-editor painting.
Added material builder tool to in-editor P3dMaterial inspector.
Added icon builder tool to in-editor P3dMaterial inspector.
Added seam fixer option to the ModelImporter inspector.
Added multi mesh support to seam fixer.
Added MaskTexture setting to P3d___Counter components.
Added channel information to P3dGroupData instances.
Added OnCompleted event to all P3d___Counter components.
Fixed seam fixer bug with higher poly meshes.
Fixed console errors that can appear when finishing in-editor painting.
Fixed normal painting on platforms that don't support DXT5nm textures.
Fixed in-editor camera to not longer snap with double left click.
Fixed P3D Overlay shader in SRP.
Fixed P3D Overlay/Alpha opacity in SRP.
Improved Seam Fixer performance.
Simplified P3dPaintable inspector.
Changed default P3dPaintable.Activation to Start.
Renamed P3dHitScreen.Fill to Draw.
Renamed P3d___Counter.Mesh setting to MaskMesh.
Replaced IHitRaycast interface with IHitCoord.
Removed P3dPaintSphere.Paint setting.
Removed P3dPaintDecal.Paint setting.
Updated documentation.
Added Simulated Multiplayer demo scene.
Added Live Painting / Apply demo scene.
Added Live Painting / Translate demo scene.
Fixed PBR Painting demo scene.
Modified P3dHitNearby.ManuallyHitNow() to only use non-preview painting.
Modified P3dHitBetween.ManuallyHitNow() to only use non-preview painting.
Modified P3dHitThrough.ManuallyHitNow() to only use non-preview painting.
Added C# API to P3dModifierList class.
Unlocked P3dPaintableManager default execution order.
Removed P3dPaintableTexture.KeepUnpaintable setting.
Allowed painting of overlapping UV areas.
Fixed painting atlas meshes that are close together.
Added P3dChangeCounter component.
Added P3dChangeCounterEvent component.
Added P3dChangeCounterFill component.
Added P3dChangeCounterText component.
Added Change Counter demo scene.
Added Rock Engraving demo scene.
Added Transparent Object Painting demo scene.
Replaced P3D Opaque shader with P3D Solid.
Replaced P3D Cutout shader with P3D Solid.
Fixed P3dPaintableTexture error when using an invalid slot.
Fixed P3dVrTool.StoreStates setting.
Fixed Undo/Redo not updating mip maps.
Replaced Alpha Blend RGB blending mode with Premultiplied.
Added P3dBlendMode.Channels setting.
Removed splat map examples.
Removed parallax mapping from example shaders.
Added P3dPaintableTexture.Normal setting.
Improved Normal Blend blending mode.
Switch VR examples to left hand for mobile touch compatibility.
Removed VR recenter function.
Fixed bug when P3dPaintSphere would fail to paint on UV.
Fixed bug when P3dPaintDecal would fail to paint on UV.
Fixed bug where paint material overrides wouldn't apply to child paint components.
Added PBR presets for P3D and Standard shaders.
Added extra paint materials.
Added asmdef.
Moved main build to Unity 2018.4.0f1.
Fixed textures not saving on mobile when closing the app.
Fixed Atlas Painting demo scene materials.
Added P3dPaintableTexture.Filter setting.
Added P3dPaintableTexture.WrapU setting.
Added P3dPaintableTexture.WrapV setting.
Improved VR Pen demo scene performance.
Fixed paint drifting issue on some meshes.
Rewrote in-editor painting features.
Added material Preset settings to editor Scene tab.
Renamed P3dMaterialCloner.ResetActivation method to Deactivate.
Added P3dPaintableTexture.Deactivate method.
Tidied up P3dPaintableTexture inspector.
Renamed P3dPaintableTexture.State setting to UndoRedo.
Added P3dPaintableTexture.SaveLoad setting.
Added P3dPaintableTexture.UseExisting setting.
Renamed P3dChannelCounter.SolidR/G/B/A to CountR/G/B/A.
Added P3dColorCounterFill component.
Added P3dColorCounterEvent component.
Added P3dColorCounterEvent component.
Added Read Color demo scene.
Added Read Color / Event demo scene.
Added Read Color / Under demo scene.
Added Mirror / Multiple demo scene.
Fixed Color / Random modifier inspector error.
Removed P3dScatterSpawner component.
Removed P3dDrip component.
Removed P3dMover component.
Fixed P3dCoordCopier mesh not appearing.
Fixed P3dSeamFixer mesh not appearing.
Added coord selection to P3dCoordCopier.
Added Automatic UV demo scene.
Added missing components to documentation.
Moved render pipeline switching tool to root folder.
Added P3dPaintSphere.TileTransition setting.
Added P3dPaintDecal.TileTransition setting.
Added Normal Painting demo scene.
Added P3dHitScreen.Fill setting.
Added P3dHitScreen.FillSpacing setting.
Added P3dMask component.
Added Path Filling demo scene.
Added Mask demo scene.
Added Mask Stretch demo scene.
Removed P3dPaintSphere.RotateTo setting.
Added P3dHitScreen.RotateTo setting.
Added Normal Blend blending mode.
Added Normal Replace blending mode.
Improved P3dConnectablePoints.ConnectHits inspector order.
Fixed P3dHitScreen stopping when reaching HitLimit.
Fixed P3dPaintableTexture.State = LocalCommandCopy bug.
Fixed P3dGraduallyFade bug.
Fixed in-editor painting of skinned meshes.
Improved P3dHitScreen.Spacing behaviour.
Improved connected P3dPaintSphere painting when using scaling.
Improved connected P3dPaintDecal painting when using scaling.
Added P3dChannelCounter.Interval setting.
Added P3dColorCounter.Interval setting.
Added Atlas Painting demo scene.
P3dHitParticles.Pressure setting renamed to PressureMultiplier.
P3dHitParticles.PressureMinDistance setting renamed to PressureMin.
P3dHitParticles.PressureMaxDistance setting renamed to PressureMax.
P3dHitParticles.PressureMode setting added.
Fixed P3dPaintDecal when using Texture modifiers.
Fixed P3dPaintableTexture.State = LocalCommandCopy undo and redo.
Fixed P3dModel painting with different submesh and material indices.
Fixed painting when P3dPaintableTexture.State is set to LocalCommandCopy.
Painting on UV now accounts for P3dPaintableTexture aspect ratio.
Added P3dHitScreen.Normal = CameraDirection setting.
Added P3dPaintableTexture.KeepUnpaintable optimization setting.
Added Decal Hit Normal demo scene.
Added Decal Normal Front demo scene.
Added Decal Normal Fade demo scene.
Added Rock Throwing demo scene.
Improved Car Decals demo scene.
Added workaround for scenario where mip maps would turn off.
Added P3dHitCollisions.Root setting.
Added P3dHitCollisions.SpeedMin setting renamed to ImpactMin.
Added P3dHitCollisions.SpeedPressure setting renamed to ImpactPressure.
Replaced P3dPaintDecal.TileBlend setting with TileOpacity.
Replaced P3dPaintSphere.TileBlend setting with TileOpacity.
In-Game: Fixed shader errors when compiling for PS4.
In-Game: Fixed connected hits persisting even when disabling hit component.
In-Game: Integrated P3dModify___ components into P3dPaint___ components.
In-Game: Added Collision Destroyer demo scene.
In-Game: Added Collision Spawner demo scene.
In-Game: Removed P3dPaintDirectDecal component.
In-Game: Added P3dPaintDecal.Paint setting.
In-Game: Added P3dPaintSphere.Paint setting.
In-Game: Added scene gizmo to P3dPaintSphere.
In-Editor: Fixed error when painting objects with multiple materials.
In-Editor: Added modifiers to Paint tab.
In-Editor: Added opacity setting to Paint tab.
In-Editor: Added angle setting to Paint tab.
In-Editor: Added normal settings to Paint tab.
In-Editor: Added Point mode to Paint tab.
In-Editor: Added Airbrush mode to Paint tab.
In-Editor: Added Triangle mode to Paint tab.
In-Editor: Added texture toggle settings to Paint tab.
In-Editor: Added Camera Light Lock setting to Config tab.
All IHit___ interfaces implement this interface so they can all be easily found with GetComponent.
This interface allows you to make components that can paint points defined by UV coordinates.
This interface allows you to make components that can paint 3D points with a specified orientation.
This interface allows you to make components that can paint quads defined by a pair of two points.
This interface allows you to make components that can paint triangles defined by three points.
This defines the blending mode used by a painting operation.
This is the index of the currently selected blending mode.
When using the ReplaceCustom blending mode, this allows you to specify the replacement color.
When using the ReplaceCustom blending mode, this allows you to specify the replacement texture.
When using the Blur or Flow blending modes, this allows you to set the maximum pixel distance of samples.
This allows you to control which channels will be modified by this blending mode.
1,1,1,1 = All channels will be modified.
1,0,0,0 = Only red will be modified.
This component will check all pixels in the specified paintable texture, compare them to the reference state defined in this component, and tell you how many of them differ by more than the threshold value.
This stores all active and enabled instances.
The RGBA values must be within this range of a color for it to be counted.
The texture we want to compare change to.
None/null = white.
The color we want to compare change to.
The previously counted amount of pixels with a RGBA value difference above the threshold.
The Count / Total value.
The Total of the specified counters.
The Count of the specified counters.
The Ratio of the specified counters.
This component will total up all RGBA channels in the specified P3dPaintableTexture that exceed the threshold value.
This stores all active and enabled instances.
The RGBA value must be higher than this for it to be counted.
The previously counted amount of pixels with a red channel value above the threshold.
The previously counted amount of pixels with a green channel value above the threshold.
The previously counted amount of pixels with a blue channel value above the threshold.
The previously counted amount of pixels with a alpha channel value above the threshold.
The CountR/Total value, allowing you to easily see how much % of the red channel is above the threshold.
The CountG/Total value, allowing you to easily see how much % of the green channel is above the threshold.
The CountB/Total value, allowing you to easily see how much % of the blue channel is above the threshold.
The CountA/Total value, allowing you to easily see how much % of the alpha channel is above the threshold.
The RatioR/G/B/A values packed into a Vector4.
The Total of the specified counters.
The CountR of the specified counters.
The CountG of the specified counters.
The CountB of the specified counters.
The CountA of the specified counters.
The CountR / Total of the specified counters.
The CountG / Total of the specified counters.
The CountB / Total of the specified counters.
The CountA / Total of the specified counters.
The GetCountR/G/B/A / GetTotal of the specified counters stored in a Vector4.
This is the base class for all components that repeat paint commands (e.g. mirroring).
This stores all active and enabled instances in the open scenes.
This component grabs paint hits and connected hits, mirrors the data, then re-broadcasts it.
When a decal is mirrored it will appear backwards, should it be flipped back around?
This component allows you to define a color that can later be counted from the P3dColorCounter component.
The color associated with this component and GameObject name.
This stores all active and enabled instances in the open scenes.
This tells you how many pixels this color could be painted on.
This tells you how many pixels this color has been painted on.
This is Solid/Total, allowing you to quickly see the percentage of paintable pixels that have been painted by this color.
This component will search the specified paintable texture for pixel colors matching an active and enabled P3dColor.
This stores all active and enabled instances.
The RGBA values must be within this range of a color for it to be counted.
Each color contribution will be stored in this list.
The Total of the specified counters.
The Count of the specified counters.
The Ratio of the specified counters.
This tells you how many pixels of the specified color are in the current PaintableTexture.
This is the base class for all paint commands. These commands (e.g. paint decal) are added to the command list for each P3dPaintableTexture, and are executed at the end of the frame to optimize state changes.
This is the original array index, used to stable sort between two commands if they have the same priority.
Is this preview painting, or real painting?
The draw order priority of this command for this frame.
The hash of the Material used to apply this paint command.
The material pass that will be used.
The hash of the Model used to apply this paint command.
The mesh submesh that will be painted.
The LocalMask that will be used when painting.
The channel of the LocalMaskTexture that will be used.
This class contains some useful methods used by this asset.
This method allows you to save a byte array to PlayerPrefs, and is used by the texture saving system.
If you want to save to files instead then just modify this.
This method allows you to load a byte array from PlayerPrefs, and is used by the texture loading system.
If you want to save to files instead then just modify this.
This method tells if you if there exists save data at the specified save name.
This method allows you to clear save data at the specified save name.
This tool allows you to copy UV1 data into UV0. This is useful if you let Unity automatically generate lightmap UV data for you and you want to use them to paint normally.
The original mesh whose UV seams you want to fix.
The coord that will be copied into the first UV channel of the output mesh.
The coord that will be copied into the second UV channel of the output mesh.
The coord that will be copied into the third UV channel of the output mesh.
The coord that will be copied into the fourth UV channel of the output mesh.
This component allows you to fade the pixels of the specified P3dPaintableTexture.
This allows you to choose which paintable texture will be modified by this component.
Once this component has accumulated this amount of fade, it will be applied to the PaintableTexture. The lower this value, the smoother the fading will appear, but also the higher the performance cost.
The speed of the fading.
1 = 1 Second.
2 = 0.5 Seconds.
This component will paint using this blending mode.
The texture that will be faded toward.
The paintable texture that will be faded toward.
The color that will be faded toward.
If you want the gradually fade effect to be masked by a texture, then specify it here.
If you want the gradually fade effect to be masked by a paintable texture, then specify it here.
This allows you to specify the channel of the mask.
This object allows you to define information about a paint group like its name, which can then be selected using the P3dGroup setting on components like P3dPaintableTexture and P3dPaintDecal.
This allows you to set the ID of this group (e.g. 100).
This allows you to specify the way each channel of this group's pixels are mapped to textures. This is mainly used by the in-editor painting material builder tool.
This allows you to specify which shaders and their properties are associated with this group.
This static property returns a list of all cached P3dGroupData instances.
This method allows you to get the name of the current group, with an optional prefix of the Index (e.g. "100: Albedo").
This static method calls GetAlias on the P3dGroupData with the specified Index setting, or null.
This static method returns the P3dGroupData with the specified Index setting, or null.
This static method forces the cached instance list to update.
This struct can be used to reference a Material by instance or hash for de/serialization.
This struct can be used to reference a Material by instance or hash for de/serialization.
This struct can be used to reference a Texture by instance or hash for de/serialization.
This stores information about a scene point on a mesh. This is usually generated from a RaycastHit, but it can also be filled manually.
The world position that was hit.
The world normal that was hit.
The Transform that was hit.
The triangle index that was hit.
The world distance that was hit.
The Collider that was hit.
This class allows you to easily create components that can have their paint lines connected together to form quads.
The world space distance between each paint point.
0 = No spacing.
When using HitSpacing, this prevents scenarios where something goes wrong and you attempt to paint too many times per frame.
If you enable this then the hit lines generated by this component will be connected into quads, allowing you to paint continuously.
If you enable ConnectHits, then each connected quad will overlap with the next. When using semi-transparent painting, this causes the overlap to become double opacity and look obvious. If you enable this setting, then this overlapping area will be removed.
This component sends hit events to a cached list of components that can receive them. If this list changes then you must manually call this method.
If this GameObject has teleported and you have ConnectHits or HitSpacing enabled, then you can call this to prevent a quad being drawn between the previous and current lines.
This component allows you to block paint from being applied at the current position using the specified shape.
The mask will use this texture shape.
The mask will use pixels from this texture channel.
If you want the sides of the mask to extend farther out, then this allows you to set the scale of the boundary.
1 = Default.
2 = Double size.
This stores all active and enabled instances in the open scenes.
This component allows you to duplicate a material before you paint on it. This is useful if the material is shared between multiple GameObjects (e.g. prefabs).
The material index that will be cloned. This matches the Materials list in your MeshRenderer/SkinnedMeshRenderer, where 0 is the first material.
This lets you know if this component has already been activated and has executed.
This allows you to manually activate this component, cloning the specified material.
This reverses the material cloning.
This component marks the current GameObject as being paintable, as long as this GameObject has a MeshFilter + MeshRenderer, or a SkinnedMeshRenderer.
The paintable this separate paintable is associated with.
Transform the mesh with its position, rotation, and scale? Some skinned mesh setups require this to be disabled.
This allows you to choose how the Mesh attached to the current Renderer is used when painting.
AsIs = Use what is currently set in the renderer.
AutoSeamFix = Use (or automatically generate) a seam-fixed version of the mesh currently set in the renderer.
The hash code for this model used for de/serialization of this instance.
This stores all active and enabled instances in the open scenes.
Materials will give you a cached CachedRenderer.sharedMaterials array. If you have updated this array externally then call this to force the cache to update next them it's accessed.
This will return a list of all paintables that overlap the specified bounds
This is the base class for all paint modifiers. To make a paint modifier, simply inherit this class, and implement one of the virtual methods to modify its data.
Should this modifier apply to preview paint as well?
Should this modifier use a unique seed?
This class maintains a list of P3dModifier instances, and contains helper methods to apply them.
This is used instead of a normal list so the modifiers can be de/serialized with polymorphism.
The amount of modifiers in the list.
This stores all modifiers in this list.
This component marks the current GameObject as being paintable.
To actually paint your object, you must also add at least one P3dPaintableTexture component to specify which texture you want to paint.
This allows you to control when this component actually activates and becomes ready for painting. You probably don't need to change this.
If you want the paintable texture width/height to be multiplied by the scale of this GameObject, this allows you to set the scale where you want the multiplier to be 1.
If this material is used in multiple renderers, you can specify them here. This usually happens with different LOD levels.
This event will be invoked before this component is activated.
This event will be invoked after this component is activated.
This event will be invoked before this component is deactivated.
This event will be invoked after this component is deactivated.
This lets you know if this paintable has been activated.
Being activated means each associated P3dMaterialCloner and P3dPaintableTexture has been Activated.
This gives you all P3dPaintableTexture components that have been activated.
This method will remove all P3dPaintable, P3dMaterialCloner, and P3dPaintableTexture components from this GameObject.
This will scale the specified width and height values based on the current BaseScale setting.
This allows you to manually activate all attached P3dMaterialCloner and P3dPaintableTexture components.
This reverses the material cloning.
This allows you to clear the pixels of all activated P3dPaintableTexture components associated with this P3dPaintable with the specified color.
This allows you to clear the pixels of all activated P3dPaintableTexture components associated with this P3dPaintable with the specified color and texture.
This allows you to manually register a P3dPaintableTexture.
This allows you to manually unregister a P3dPaintableTexture.
This component automatically updates all P3dModel and P3dPaintableTexture instances at the end of the frame, batching all paint operations together.
This stores all active and enabled instances in the open scenes.
This class stores information about a particular paintable texture state. Either a full texture copy, or a list of commands used to draw it.
This component allows you to make one texture on the attached Renderer paintable.
The material index and shader texture slot name that this component will paint.
The UV channel this texture is mapped to.
The group you want to associate this texture with. Only painting components with a matching group can paint this texture. This allows you to paint multiple textures at the same time with different settings (e.g. Albedo + Normal).
This allows you to set how this texture's state is stored, allowing you to perform undo and redo operations.
FullTextureCopy = A full copy of your texture will be copied for each state. This allows you to quickly undo and redo, and works with animated skinned meshes, but it uses up a lot of texture memory.
LocalCommandCopy = Each paint command will be stored in local space for each state. This allows you to perform unlimited undo and redo states with minimal memory usage, because the object will be repainted from scratch. However, performance will depend on how many states must be redrawn, and it may not work well with skinned meshes.
The amount of times this texture can have its paint operations undone.
This allows you to control how this texture is loaded and saved.
Manual = You must manually call Save(SaveName) and Load(SaveName) from code.
Automatic = Save(SaveName) is called in Deactivate/OnDestroy, and Load(SaveName) is called in Activate.
SemiManual = You can manually call the Save() and Load() methods from code or editor event, and the current SaveName will be used.
If you want this texture to automatically save & load, then you can set the unique save name for it here.
The base width of the created texture.
The base height of the created texture.
When activated or cleared, this paintable texture will be given this texture, and then multiplied/tinted by the Color.
None = White.
When activated or cleared, this paintable texture will be given this color.
The format of the created texture.
The useMipMap mode of the created texture.
Auto = Copied from the Texture.
The filterMode of the created texture.
Auto = Copied from the Texture.
The anisoLevel of the created texture.
Auto = Copied from the Texture.
The wrapModeU mode of the created texture.
Auto = Copied from the Texture.
The wrapModeV of the created texture.
Auto = Copied from the Texture.
If this component's Texture setting is none/null but the Slot texture is not none/null when this component activates, what should happen?
Ignore = Nothing will happen.
Use = This paintable texture will activate with the Slot texture.
UseAndKeep = The same as Use, but the Slot texture will also be stored in the Texture setting.
If you're painting special textures then they may need to be converted before use.
Normal = Convert texture to be a normal map.
Premultiply = Premultiply the RGB values.
This allows you to restrict painting to specific areas.
This allows you to specify which channel from the LocalMaskTexture texture will be used.
Some shaders require specific shader keywords to be enabled when adding new textures. If there is no texture in your selected slot then you may need to set this keyword.
The hash code for this model used for de/serialization of this instance.
If you want to paint a texture but don't want it to be applied to the specified material texture slot, then enable this.
When you export this texture as a PNG asset from the in-editor painting window, the exported texture's GUID will be stored here so you can easily re-export it to the same file.
This event is called after a paint command has been added to this texture. These commands will be executed at the end of the frame.
This event is called after a paint command has been added to this texture. These commands will be executed at the end of the frame.
This is invoked every time a paintable texture component is enabled.
This is invoked every time a paintable texture component is disabled.
This event is called after this texture has been painted, allowing you to perform actions like counting the pixels after modification.
Bool = Preview painting.
This stores all active and enabled instances in the open scenes.
This lets you know if this texture is activated and ready for painting. Activation is controlled by the associated P3dPaintable component.
This lets you know if there is at least one undo state this texture can be undone into.
This lets you know if there is at least one redo state this texture can be redone into.
This property returns a list of all stored undo/redo states.
This tells you which undo/redo state is currently active inside the States list.
This tells you which material this paintable texture is currently stored in.
This quickly gives you the P3dPaintable component associated with this paintable texture.
This gives you the current state of this paintable texture.
This gives you the current state of this paintable texture including any preview painting information.
This lets you know if there are paint commands in this paintable texture's paint stack.
This allows you to get a list of all paintable textures on a P3dModel/P3dPaintable with the specified group.
This will clear all undo/redo texture states.
This will store a texture state so that it can later be undone. This should be called before you perform texture modifications.
This will revert the texture to a previous state, if you have an undo state stored.
This will restore a previously undone texture state, if you've performed an undo.
This allows you to set the Color based on an HTML style string (#FFF, #FF0055, yellow, red)
You should call this after painting this paintable texture.
This method returns a Texture2D copy of the current texture state, allowing you to read pixel values, etc.
This method returns the current texture state as a PNG byte array.
This method returns the current texture state as a TGA byte array.
This method will clear the current texture state with the current Texture and Color values.
This method will clear the current texture state with the specified texture and color.
This method will replace the current texture state with the current Texture and Color values, including size.
This method will resize the current texture state based on the specified texture, and then replace its contents with the specified texture and color.
This method will resize the current texture state with the specified width and height.
This method will save the current texture state to PlayerPrefs using the current SaveName.
This will save the current texture state with the specified save name.
This method will replace the current texture state with the data saved at SaveName.
This method will replace the current texture state with the data saved at the specified save name.
This method will replace the current texture state with the specified image data (e.g. png).
If you last painted using preview painting and you want to hide the preview painting, you can call this method to force the texture to go back to its current state.
This automatically calls HidePreview on all active and enabled paintable textures.
This will clear save data with the current SaveName.
This will clear save data with the specified save name.
If you modified the slot material index, then call this to update the cached material.
If the current slot has a texture, this allows you to copy the width and height from it.
This copies the texture from the current slot.
This allows you to manually activate this paintable texture.
This will add a paint command to this texture's paint stack. The paint stack will be executed at the end of the current frame.
This allows you to manually execute all commands in the paint stack.
This is useful if you need to modify the state of your object before the end of the frame.
This base class allows you to quickly create components that listen for changes to the specified P3dPaintableTexture.
This is the paintable texture whose pixels we will count.
This allows you to specify the minimum delay between each texture read in seconds.
0 = Instant.
1 = Once a second.
If you disable this, then the texture will be updated immediately, which may cause slowdown.
Testing all the pixels of a texture can be slow, so you can pick how many times the texture is downsampled. One downsample = half width & height or 1/4 of the pixels.
This event is invoked each time this texture monitor updates its pixel counts.
This will be true after Register is successfully called.
This forces the specified P3dPaintableTexture to be registered.
This forces the specified P3dPaintableTexture to be unregistered.
This base class allows you to quickly create components that listen for changes to the specified P3dPaintableTexture.
If you want this component to accurately count pixels relative to a mask mesh, then specify it here.
If you have a MaskMesh set, then this allows you to choose which submesh of it will be used for the mask.
If you want this component to accurately count pixels relative to a mask texture, then specify it here.
This allows you to specify which channel of the MaskTexture will be used to define the mask.
The previously counted total amount of pixels.
This class allows you to easily create components that can have their paint points connected together to form lines.
The world space distance between each paint point.
0 = No spacing.
When using HitSpacing, this prevents scenarios where something goes wrong and you attempt to paint too many times per frame.
If you enable this then the hit points generated by this component will be connected into lines, allowing you to paint continuously.
If you enable ConnectHits, then each connected line will overlap with the next. When using semi-transparent painting, this causes the overlap to become double opacity and look obvious. If you enable this setting, then this overlapping area will be removed.
This component sends hit events to a cached list of components that can receive them. If this list changes then you must manually call this method.
If this GameObject has teleported and you have ConnectHits or HitSpacing enabled, then you can call this to prevent a line being drawn between the previous and current points.
This component allows you to read the paint color at a hit point. A hit point can be found using a companion component like: P3dHitScreen, P3dHitBetween.
Only the P3dPaintableTexture components with a matching group will be painted by this component.
Should the color be read during preview painting too?
How should the texture be read?
Immediate = The reading method will block until the pixel is fetched from the GPU.
Async = The pixel value will be read after some time, giving you better performance.
The last read color value.
When a color is read, this event will be invoked.
Color = The color that was read.
This component renders scene depth to a RenderTexture. This scene depth can be set in a P3dPaint___ component's Advanced/DepthMask setting, which allows you to paint on the first surface in the view of the specified camera.
The camera whose depth information will be read.
The transformation matrix of the camera when the depth texture was generated.
The RenderTexture where the depth information will be stored.
If this is 0, the RenderTexture size will match the viewport. If it's above 0, then the RenderTexture size will be set to the viewport size divided by this value.
The rendered depth must be at least this mant units different from the painted surface for the paint to be masked out.
Should the scene depth be rendered in Start?
Should the scene depth be rendered every frame in Update?
This method will update the TargetTexture with what the SourceCamera currently sees.
This class handles the low level de/serialization of different paint in 3D objects to allow for things like networking.
This stores an association between a Material hash code and the Material instance, so it can be de/serialized.
This stores an association between a Material instance and the Material hash code, so it can be de/serialized.
This stores an association between a P3dModel hash code and the P3dModel instance, so it can be de/serialized.
This stores an association between a P3dModel instance and the P3dModel hash code, so it can be de/serialized.
This stores an association between a Texture hash code and the Texture instance, so it can be de/serialized.
This stores an association between a Texture instance and the Texture hash code, so it can be de/serialized.
This stores an association between a P3dModel hash code and the P3dModel instance, so it can be de/serialized.
This stores an association between a P3dModel instance and the P3dModel hash code, so it can be de/serialized.
This struct stores a reference to a texture on a GameObject.
The material index in the attached renderer.
The name of the texture in the specified material.
This component allows you to manage undo/redo states on all P3dPaintableTextures in your scene.
This method will call StoreState on all active and enabled P3dPaintableTextures.
This method will call StoreState on all active and enabled P3dPaintableTextures.
This method will call Undo on all active and enabled P3dPaintableTextures.
This method will call Redo on all active and enabled P3dPaintableTextures.
This component allows you to manually associate a Texture with a hash code so it can be de/serialized.
The texture that will be hashed.
The hash code for the texture.
This component raycasts between two points, and fires hit events when the ray hits something.
Where in the game loop should this component hit?
The time in seconds between each raycast.
0 = Every frame.
-1 = Manual only.
The start point of the raycast.
The end point of the raycast.
The end point of the raycast.
The layers you want the raycast to hit.
How should the hit point be oriented?
WorldUp = It will be rotated to the normal, where the up vector is world up.
CameraUp = It will be rotated to the normal, where the up vector is world up.
ThisRotation = The current Transform.rotation will be used.
ThisLocalRotation = The current Transform.localRotation will be used.
CustomRotation = The specified CustomTransform.rotation will be used.
CustomLocalRotation = The specified CustomTransform.localRotation will be used.
Orient to a specific camera?
None = MainCamera.
If you use Orientation = CustomRotation/CustomLocalRotation, this allows you to set the transform.
Which normal should the hit point rotation be based on?
If you want the raycast hit point to be offset from the surface a bit, this allows you to set by how much in world space.
Should the applied paint be applied as a preview?
This allows you to override the order this paint gets applied to the object during the current frame.
This allows you to control the pressure of the painting. This could be controlled by a VR trigger or similar for more advanced effects.
This allows you to control the hit data this component sends out.
PointsIn3D = Point drawing in 3D.
PointsOnUV = Point drawing on UV (requires non-convex MeshCollider).
TrianglesIn3D = Triangle drawing in 3D.
If you want to display something at the hit point (e.g. particles), you can specify the Transform here.
If you want to draw a line between the start point and the his point then you can set the line here.
This allows you to connect the hit points together to form lines.
This method will immediately submit a non-preview hit. This can be used to apply real paint to your objects.
This component sends hit events to a cached list of components that can receive them. If this list changes then you must manually call this method.
If this GameObject has teleported and you have ConnectHits or HitSpacing enabled, then you can call this to prevent a line being drawn between the previous and current points.
This class stores lists of IHit__ instances, allowing components like P3dHit__ to easily invoke hit events.
This component can be added to any Rigidbody, and it will fire hit events when it hits something.
This allows you to control the hit data this component sends out.
PointsIn3D = Point drawing in 3D.
PointsOnUV = Point drawing on UV (requires non-convex MeshCollider).
TrianglesIn3D = Triangle drawing in 3D.
When emitting PointsOnUV or TrianglesIn3D, this setting allows you to specify the world space distance from the hit point a raycast will be fired. This is necessary because collisions by themselves don't provide the necessary information.
This allows you to filter collisions to specific layers.
If there are multiple contact points, skip them?
If this component is generating too many hits, then you can use this setting to ignore hits for the specified amount of seconds.
0 = Unlimited.
How should the hit point be oriented?
WorldUp = It will be rotated to the normal, where the up vector is world up.
CameraUp = It will be rotated to the normal, where the up vector is world up.
Orient to a specific camera?
None = MainCamera.
Should the applied paint be applied as a preview?
If the collision impact speed is below this value, then the collision will be ignored.
This allows you to set how the pressure value will be calculated.
Constant = The PressureConstant value will be directly used.
ImpactSpeed = The pressure will be 0 when the collision impact speed is PressureMin, and 1 when the impact speed is or exceeds PressureMax.
The impact strength required for a hit to occur with a pressure of 0.
The impact strength required for a hit to occur with a pressure of 1.
The pressure value used when PressureMode is set to Constant.
The calculated pressure value will be multiplied by this.
If you want the raycast hit point to be offset from the surface a bit, this allows you to set by how much in world space.
This allows you to override the order this paint gets applied to the object during the current frame.
Hit events are normally sent to all components attached to the current GameObject, but this setting allows you to override that. This is useful if you want to use multiple P3dHitCollisions components with different settings and results.
This component sends hit events to a cached list of components that can receive them. If this list changes then you must manually call this method.
This component continuously fires hit events using the current Transform position.
Where in the game loop should this component hit?
The time in seconds between each hit.
0 = Every frame.
Should the applied paint be applied as a preview?
This allows you to override the order this paint gets applied to the object during the current frame.
This allows you to control the pressure of the painting. This could be controlled by a VR trigger or similar for more advanced effects.
This allows you to connect the hit points together to form lines.
This method will immediately submit a non-preview hit. This can be used to apply real paint to your objects.
This component sends hit events to a cached list of components that can receive them. If this list changes then you must manually call this method.
If this GameObject has teleported and you have ConnectHits or HitSpacing enabled, then you can call this to prevent a line being drawn between the previous and current points.
This component can be added to any ParticleSystem with collisions enabled, and it will fire hits when the particles collide with something.
This allows you to control the hit data this component sends out.
PointsIn3D = Point drawing in 3D.
PointsOnUV = Point drawing on UV (requires non-convex MeshCollider).
TrianglesIn3D = Triangle drawing in 3D.
When emitting PointsOnUV or TrianglesIn3D, this setting allows you to specify the world space distance from the hit point a raycast will be fired. This is necessary because particles by themselves don't provide the necessary information.
This allows you to filter collisions to specific layers.
How should the hit point be oriented?
WorldUp = It will be rotated to the normal, where the up vector is world up.
CameraUp = It will be rotated to the normal, where the up vector is world up.
Orient to a specific camera?
None = MainCamera.
Which normal should the hit point rotation be based on?
If you want the raycast hit point to be offset from the surface a bit, this allows you to set by how much in world space.
If you have too many particles, then painting can slow down. This setting allows you to reduce the amount of particles that actually cause hits.
0 = Every particle will hit.
5 = Skip 5 particles, then hit using the 6th.
Should the particles paint preview paint?
This allows you to override the order this paint gets applied to the object during the current frame.
This allows you to set how the pressure value will be calculated.
Constant = The PressureConstant value will be directly used.
Distance = A value will be calculated based on the distance between this emitter and the particle hit point.
Speed = A value will be calculated based on the hit speed of the particle.
This allows you to specify the distance/speed that gives 0.0 pressure.
This allows you to specify the distance/speed that gives 1.0 pressure.
The pressure value used when PressureMode is set to Constant.
The calculated pressure value will be multiplied by this.
Hit events are normally sent to all components attached to the current GameObject, but this setting allows you to override that. This is useful if you want to use multiple P3dHitParticles components with different settings and results.
This component sends hit events to a cached list of components that can receive them. If this list changes then you must manually call this method.
This component will perform a raycast under the mouse or finger as it moves across the screen. It will then send hit events to components like P3dPaintDecal, allowing you to paint the scene.
This allows you to control how often the screen is painted.
PixelInterval = Once every Interval pixels.
ScaledPixelInterval = Like PixelInterval, but scaled to the screen DPI.
TimeInterval = Once every Interval seconds.
OnceOnRelease = When the finger/mouse goes down a preview will be shown, and when it goes up the paint will apply.
OnceOnPress = When the finger/mouse goes down the paint will apply.
OnceEveryFrame = Every frame the paint will apply.
This allows you to set the pixels/seconds between each hit point based on the current Frequency setting.
This allows you to connect the hit points together to form lines.
This component sends hit events to a cached list of components that can receive them. If this list changes then you must manually call this method.
If this GameObject has teleported and you have ConnectHits or HitSpacing enabled, then you can call this to prevent a line being drawn between the previous and current points.
This class contains common code for screen based mouse/finger hit components.
Orient to a specific camera?
None = MainCamera.
The layers you want the raycast to hit.
Fingers that began touching the screen on top of these UI layers will be ignored.
This allows you to control the hit data this component sends out.
PointsIn3D = Point drawing in 3D.
PointsOnUV = Point drawing on UV (requires non-convex MeshCollider).
TrianglesIn3D = Triangle drawing in 3D (requires non-convex MeshCollider).
This allows you to control how the paint is rotated.
Normal = The rotation will be based on a normal direction, and rolled relative to an up axis.
World = The rotation will be aligned to the world, or given no rotation.
ThisRotation = The current Transform.rotation will be used.
ThisLocalRotation = The current Transform.localRotation will be used.
CustomRotation = The specified CustomTransform.rotation will be used.
CustomLocalRotation = The specified CustomTransform.localRotation will be used.
Which direction should the hit point rotation be based on?
Based on the normal direction, what should the rotation be rolled relative to?
WorldUp = It will be rolled so the up vector is world up.
CameraUp = It will be rolled so the up vector is camera up.
DrawAngle = It will be rolled according to the mouse/finger movement on screen.
This allows you to specify the Transform when using RotateTo = CustomRotation/CustomLocalRotation.
Should painting triggered from this component be eligible for being undone?
This allows you to override the order this paint gets applied to the object during the current frame.
This component works like P3dHitScreen, but it will fill in the shape you draw.
This allows you to set the pixel distance between each grid point.
This component will perform a raycast under the mouse or finger as it moves across the screen. It will then send hit events to components like P3dPaintDecal, allowing you to paint the scene.
This allows you to control how many hit points will be generated along the drawn line.
StartAndEnd = Once at the start, and once at the end.
PixelInterval = Once at the start, and then every Interval pixels.
ScaledPixelInterval = Once at the start, and then every Interval scaled pixels.
StretchedPixelInterval = Like ScaledPixelInterval, but the hits are stretched to reach the end.
StretchedScaledPixelInterval = Like ScaledPixelInterval, but the hits are stretched to reach the end.
Once = Once at the specified Position and PixelOffset along the line.
This allows you to set the pixels between each hit point based on the current Frequency setting.
When using Frequency = Once, this allows you to set the 0..1 position along the line.
When using Frequency = Once, this allows you to set the pixel offset along the line.
This allows you to connect the hit points together to form lines.
This component sends hit events to a cached list of components that can receive them. If this list changes then you must manually call this method.
If this GameObject has teleported and you have ConnectHits or HitSpacing enabled, then you can call this to prevent a line being drawn between the previous and current points.
This component constantly draws lines between the two specified points.
Where in the game loop should this component hit?
The time in seconds between each hit.
0 = Every frame.
-1 = Manual only.
The start point of the raycast.
The end point of the raycast.
How should the hit point be oriented?
WorldUp = It will be rotated to the normal, where the up vector is world up.
CameraUp = It will be rotated to the normal, where the up vector is world up.
Orient to a specific camera?
None = MainCamera.
This allows you to control the pressure of the painting. This could be controlled by a VR trigger or similar for more advanced effects.
Should the applied paint be applied as a preview?
This allows you to override the order this paint gets applied to the object during the current frame.
If you want to draw a line between the start point and the his point then you can set the line here.
This allows you to connect the hit points together to form lines.
This method will immediately submit a non-preview hit. This can be used to apply real paint to your objects.
This component sends hit events to a cached list of components that can receive them. If this list changes then you must manually call this method.
If this GameObject has teleported and you have ConnectHits or HitSpacing enabled, then you can call this to prevent a line being drawn between the previous and current points.
This window allows you to examine the UV data of a mesh. This can be accessed from the context menu (⋮ button at top right) of any mesh in the inspector.
This component allows you to define a set of P3dPaintableTexture and P3dMaterial components that are configured for a specific set of Materials.
This allows you to name this preset.
None/null = The GameObject name will be used.
Automatically add the P3dMaterialCloner.
This gives you a list of all presets in the project.
This method returns true if this preset is designed for the specified shader.
This method applies the preset components to the specified paintable.
This tool allows you to convert a normal mesh with UV seams to a fixed mesh without UV seams.
This tool can be accessed from the context menu (⋮ button at top right) of any mesh/model inspector.
The original mesh.
The mesh with fixed seams.
The meshes we will fix the seams of.
The UV channel whose seams will be fixed.
The threshold below which vertex UV coordinates will be snapped.
The thickness of the UV borders in the fixed mesh.
If this is above 0 then Debug.Lines will be output during generation.
This allows you to add a mesh to the seam fixer.
This static method allows you to fix the seams of the source mesh at runtime.
This class allows you to randomize the painting angle of the attached component (e.g. P3dPaintDecal).
This is the minimum random angle that will be picked.
This is the maximum random angle that will be picked.
The way the picked angle value will be blended with the current one.
This class allows you to randomize the painting color of the attached component (e.g. P3dPaintDecal).
This is the gradient containing all the possible colors. A color will be randomly picked from this.
The way the picked color value will be blended with the current one.
This class allows you to change the painting hardness based on the paint pressure.
The paint component's Hardness value will be modified using this value based on the current Blend setting.
This allows you to control how this new Hardness value will modify the old value in the paint component.
Replace = Transition between [old, new] based on pressure.
Multiply = Transition between [old, old*new] based on pressure.
Increment = Transition between [old, old+new] based on pressure.
This class allows you to randomize the painting hardness of the attached component (e.g. P3dPaintDecal).
This is the minimum random hardness that will be picked.
This is the maximum random hardness that will be picked.
The way the picked hardness value will be blended with the current one.
This class allows you to change the painting opacity based on the paint pressure.
The paint component's Opacity value will be modified using this value based on the current Blend setting.
This allows you to control how this new Opacity value will modify the old value in the paint component.
Replace = Transition between [old, new] based on pressure.
Multiply = Transition between [old, old*new] based on pressure.
Increment = Transition between [old, old+new] based on pressure.
This class allows you to randomize the painting opacity of the attached component (e.g. P3dPaintDecal).
This is the minimum random opacity that will be picked.
This is the maximum random opacity that will be picked.
The way the picked opacity value will be blended with the current one.
This class allows you to randomize the painting position of the attached component (e.g. P3dPaintDecal).
The position will be offset up to this radius away in world space.
This class allows you to change the painting radius based on the paint pressure.
The paint component's Radius value will be modified using this value based on the current Blend setting.
This allows you to control how this new Radius value will modify the old value in the paint component.
Replace = Transition between [old, new] based on pressure.
Multiply = Transition between [old, old*new] based on pressure.
Increment = Transition between [old, old+new] based on pressure.
This class allows you to randomize the painting radius of the attached component (e.g. P3dPaintDecal).
This is the minimum random radius that will be picked.
This is the maximum random radius that will be picked.
The way the picked radius value will be blended with the current one.
This class allows you to randomize the painting scale of the attached component (e.g. P3dPaintDecal).
This is the minimum random scale that will be picked.
This is the maximum random scale that will be picked.
The way the picked scale value will be blended with the current one.
If you disable this then each x, y, and z value will be scaled separately.
This class allows you to change the painting texture of the attached component (e.g. P3dPaintDecal) based on the paint pressure.
The painting texture will be changed to this.
The paint pressure must be at least this value.
The paint pressure must be at most this value.
This class allows you to randomize the painting texture of the attached component (e.g. P3dPaintDecal).
A random texture will be picked from this list.
This component implements the fill paint mode, which will modify all pixels in the specified texture in the same way.
This is useful if you want to gradually fade a texture to a specific color.
Only the P3dPaintableTexture components with a matching group will be painted by this component.
This allows you to choose how the paint from this component will combine with the existing pixels of the textures you paint.
The color of the paint.
The color of the paint.
The opacity of the brush.
The minimum RGBA value change. This is useful if you're doing very subtle color changes over time.
This stores a list of all modifiers used to change the way this component applies paint (e.g. P3dModifyColorRandom).
This method increments Opacity by the specified value.
This component implements the replace paint mode, which will replace all pixels in the specified texture.
Only the P3dPaintableTexture components with a matching group will be painted by this component.
The texture that will be painted.
The color of the paint.
This stores a list of all modifiers used to change the way this component applies paint (e.g. P3dModifyColorRandom).
This component implements the replace channels paint mode, which will replace all pixels in the specified textures and channel weights.
Only the P3dPaintableTexture components with a matching group will be painted by this component.
This this is the base class for any component that sends pointer information to any P3dHitScreen component.
This component sends pointer information to any P3dHitScreen component, allowing you to paint with the mouse.
If you enable this, then a paint preview will be shown under the mouse as long as the RequiredKey is not pressed.
This component will paint while any of the specified mouse buttons or keyboard keys are held.
This component sends pointer information to any P3dHitScreen component, allowing you to paint with a pen.
If you enable this, then a paint preview will be shown under the pen as long as the tip is not pressed.
If you want the paint to appear above the pen, then you can set this number to something positive.
This component sends pointer information to any P3dHitScreen component, allowing you to paint with a touchscreen.
If you want the paint to appear above the finger, then you can set this number to something positive.
This component allows you to perform the Clear action. This can be done by attaching it to a clickable object, or manually from the ClearAll method.
When clearing a texture, should its undo states be cleared too?
This component allows you to perform the Redo All action. This can be done by attaching it to a clickable object, or manually from the RedoAll method.
If you want to manually trigger RedoAll, then call this function.
This component allows you to perform the Undo All action. This can be done by attaching it to a clickable object, or manually from the RedoAll method.
If you want to manually trigger UndoAll, then call this function.
This component allows you to perform an event when the specified P3dChangeCounter instances are painted a specific amount.
This allows you to specify the counters that will be used.
None = All active and enabled counters in the scene.
This paint ratio must be inside this range to be considered inside.
This tells you if the paint ratio is within the current Range.
This event will be called on the first frame Inside becomes true.
This event will be called on the first frame Inside becomes false.
This tells you the current paint ratio of the specified Color, where 0 is no paint, and 1 is fully painted.
This component fills the attached UI Image based on the total amount of pixels that have been painted in the specified P3dChangeCounterFill components.
This allows you to specify the counters that will be used.
Zero = All active and enabled counters in the scene.
Inverse the fill?
This component will output the total pixels for the specified team to a UI Text component.
This allows you to specify the counters that will be used.
Zero = All active and enabled counters in the scene.
Inverse the Count and Percent values?
This allows you to set the amount of decimal places when using the percentage output.
This allows you to set the format of the team text. You can use the following tokens:
{TOTAL} = Total amount of pixels that can be painted.
{COUNT} = Total amount of pixel that have been painted.
{PERCENT} = Percentage of pixels that have been painted.
The color count will be output via this event.
This component allows you to perform an event when the specified P3dChannelCounter instances are painted a specific amount.
This allows you to specify the counters that will be used.
None = All active and enabled counters in the scene.
This allows you to choose which channel will be output to the UI Text.
This paint ratio must be inside this range to be considered inside.
This tells you if the paint ratio is within the current Range.
This event will be called on the first frame Inside becomes true.
This event will be called on the first frame Inside becomes false.
This tells you the current paint ratio of the specified Channel, where 0 is no paint, and 1 is fully painted.
This component fills the attached UI Image based on the total amount of opaque pixels that have been painted in all active and enabled P3dChannelCounter components in the scene.
This allows you to specify the counters that will be used.
Zero = All active and enabled counters in the scene.
This allows you to choose which channel will be output to the UI Image.
Inverse the fill?
This component allows you to output the totals of all the specified pixel counters to a UI Text component.
This allows you to specify the counters that will be used.
Zero = All active and enabled counters in the scene.
This allows you to choose which channel will be output to the UI Text.
Inverse the Count and Percent values?
This allows you to set the amount of decimal places when using the percentage output.
This allows you to set the format of the team text. You can use the following tokens:
{TOTAL} = Total amount of pixels that can be painted.
{COUNT} = Total amount of pixel that have been painted.
{PERCENT} = Percentage of pixels that have been painted.
The color count will be output via this event.
This component allows you to perform an event when the specified P3dColorCounter instances are painted a specific amount.
This allows you to specify the counters that will be used.
None = All active and enabled counters in the scene.
This allows you to set which color will be handled by this component.
This paint ratio must be inside this range to be considered inside.
This tells you if the paint ratio is within the current Range.
This event will be called on the first frame Inside becomes true.
This event will be called on the first frame Inside becomes false.
This tells you the current paint ratio of the specified Color, where 0 is no paint, and 1 is fully painted.
This component fills the attached UI Image based on the total amount of pixels that have been painted in the specified P3dColorCounter components.
This allows you to specify the counters that will be used.
Zero = All active and enabled counters in the scene.
This allows you to set which color will be handled by this component.
Inverse the fill?
This component will output the total pixels for the specified color to the OnString event.
This allows you to specify the counters that will be used.
Zero = All active and enabled counters in the scene.
This allows you to set which color will be handled by this component.
Inverse the Count and Percent values?
This allows you to set the amount of decimal places when using the percentage output.
This allows you to set the format of the team text. You can use the following tokens:
{TOTAL} = Total amount of pixels that can be painted.
{COUNT} = Total amount of pixel that have been painted.
{PERCENT} = Percentage of pixels that have been painted.
The color count will be output via this event.
This component allows you to debug hit points into the Scene tab. Hit points will automatically be sent by any P3dHit___ component on this GameObject, or its ancestors.
The color of the debug.
The duration of the debug.
The size of the debug.
This allows you to spawn a prefab at a hit point. Hit points will automatically be sent by any P3dHit___ component on this GameObject, or its ancestors.
A random prefab from this list will be spawned.
The spawned prefab will be randomly offset by a random point within this radius in world space.
If the prefab contains a Rigidbody, it will be given this velocity in local space.
The spawned prefab will be offset from the hit point based on the hit normal by this value in world space.
The spawned prefab will be offset from the hit point based on this value in world space.
Call this if you want to manually spawn the specified prefab.
This component invokes the Action event when this component is enabled.
The event that will be invoked.
This component shows you how to listen for and store paint commands added to any P3dPaintableTexture component in the scene.
This component can then reset each paintable texture, and randomly apply one of the recorded paint commands.
Should this component listen for added commands?
This method will pool and clear all commands.
This method will clear all paintable textures, and apply one random paint command that was recorded.
This component automatically destroys this GameObject after some time.
If this component has been active for this many seconds, the current GameObject will be destroyed.
-1 = DestroyNow must be manually called.
This component automatically destroys the specified GameObject when sent a hit point. Hit points will automatically be sent by any P3dHit___ component on this GameObject, or its ancestors.
This GameObject will be destroyed.
This component adds basic Pitch/Yaw controls to the current GameObject (e.g. camera) using mouse or touch controls.
Rotation will be active if all of these tools are deactivated.
The key that must be held for this component to activate on desktop platforms.
None = Any mouse button.
Fingers that began touching the screen on top of these UI layers will be ignored.
The target pitch angle in degrees.
The speed the pitch changed relative to the mouse/finger drag distance.
The minimum value of the pitch value.
The maximum value of the pitch value.
The target yaw angle in degrees.
The speed the yaw changed relative to the mouse/finger drag distance.
How quickly the rotation transitions from the current to the target value (-1 = instant).
This component allows you to convert input axis values to a boolean event. This can be used to map VR buttons to other components.
The name of the input axis in the Project Settings.
The index of the input axis in the Project Settings.
This component listens for point and line painting events. It then simulates transmitting them over a network with a delay, and then painting the received data.
This allows you to specify the simulated delay between painting across the network in seconds.
This component can be added to an empty GameObject, and it will set it up with a procedurally generated quad that is ready for painting.
The Material applied to the renderer.
The size of the generated quad in local space.
This component allows you to perform an event when the attached P3dReadColor component reads a specific color.
This color we want to detect.
The RGBA values must be within this range of a color for it to be counted.
When the expected color is read, this event will be invoked.
Color = The expected color.
This component allows you to rotate the current Transform.
This allows you to set the coordinate space the movement will use.
The position will be incremented by this each second.
This component will spawn and throw Rigidbody prefabs from the camera when you tap the mouse or a finger.
The key that must be held for this component to activate on desktop platforms.
None = Any mouse button.
Fingers that began touching the screen on top of these UI layers will be ignored.
The prefab that will be thrown.
The speed that the object will be thrown at.
Should painting triggered from this component be eligible for being undone?
This component enables or disables the specified ParticleSystem based on mouse or finger presses.
Fingers that began touching the screen on top of these UI layers will be ignored.
The key that must be held for this component to activate.
None = Any mouse button or finger.
The particle system that will be enabled/disabled based on mouse/touch.
Should painting triggered from this component be eligible for being undone?
This component allows you to enable/disable the target component while the specified key is held down.
The key that must be held for this component to activate.
None = Any mouse button or finger.
The component that will be enabled or disabled.
Should painting triggered from this component be eligible for being undone?
This component allows you to move the current Transform using editor events (e.g. UI buttons).
This allows you to set the coordinate space the movement will use.
The movement values will be multiplied by this before use.
If you want this component to change smoothly over time, then this allows you to control how quick the changes reach their target value.
-1 = Instantly change.
1 = Slowly change.
10 = Quickly change.
The position will be incremented by this each second.
This method allows you to translate along the X axis, with the specified value.
This method allows you to translate along the Y axis, with the specified value.
This method allows you to translate along the Z axis, with the specified value.
This method allows you to translate along the specified vector.
This method allows you to translate along the specified vector in world space.
This component attached the current GameObject to a tracked hand.
This key allows you to reset the VR orientation.
The default distance in world space a hand must be to grab a tool.
This key allows you to simulate a left hand VR trigger.
This key allows you to simulate a left hand VR grip.
This key allows you to simulate a right hand VR trigger.
This key allows you to simulate a right hand VR grip.
When simulating a VR tool, it will be offset by this Euler rotation.
When simulating a VR tool, it will be offset by this local position.
When simulating a VR tool, it will be moved away from the hit surface by this.
The simulated left VR eye will be offset this much.
When simulating a VR tool, this will control how much the hit surface normal influences the tool rotation.
This stores all active and enabled instances in the open scenes.
This component attached the current GameObject to a tracked hand.
The XR node this GameObject will follow.
Should painting triggered from this component be eligible for being undone?
This tool will be offset by this vector in local space.
When simulating a VR tool, it will be offset by this local position.
The SimulatedOffset value will be offset by this when the simulated key is held.
This allows you to control the speed of the simulated transform changes.
This will drop the current tool.
This will drop the current tool and grab the next in the scene.
This method allows you to find the tool currently on the specified node.
This method allows you to drop all tools on the specified node.
Thank you for using Paint in 3D ❤️
Are custom shaders/materials supported?
Can I save my in-game paint to my project?
Is the new InputSystem supported?
Can I Create New Paint Presets?
Can I Create New Paint Tools? (In-Editor)
Can I Create New Paint Materials? (In-Editor)
Can Each Individual Paint Be De/Serialized? (e.g. networking)
P3dPaintableTextureMonitorMask