Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice
  3. Dismiss Notice

Paint In 3D ✍️ Paint In Editor✏️ Paint In 2D

Discussion in 'Assets and Asset Store' started by Darkcoder, Jul 10, 2018.

  1. renman3000

    renman3000

    Joined:
    Nov 7, 2011
    Posts:
    6,702
    Ok thank,
    thank you! Will go over!
     
  2. xuanquang4968

    xuanquang4968

    Joined:
    May 19, 2021
    Posts:
    1
    Hi there! Thanks for your great asset. I want to create a effect just like the one that you replied here. Any idea about recreating the effect by tweaking into your paint assets. Thanks again
     
  3. dan99nik_unity

    dan99nik_unity

    Joined:
    Nov 22, 2018
    Posts:
    2
    Hi! How can I color objects in the desired color from the start of the game and return it to the default color using collision/raycast?
    Thank you!
     
  4. The11thAlchemist

    The11thAlchemist

    Joined:
    Aug 10, 2020
    Posts:
    30
    Hi Dan99nik, You can just change the CWPaintSphere Component in the paint gameobject from premultiplied to replace original.
     
    dan99nik_unity likes this.
  5. ddsinteractive

    ddsinteractive

    Joined:
    May 1, 2013
    Posts:
    28
    Is there a way to paint through and include the material behind as well? For example, I have a fish fin, but it blocks painting through to the fish body behind the fin so that always stays white and doesn't ever color in.

    Thanks!
     
  6. dan99nik_unity

    dan99nik_unity

    Joined:
    Nov 22, 2018
    Posts:
    2
    Thank you! But how can I color full mask in the desired color from playmode in Start() or Awake() or Editor? Mask must be colored for use CWPaintSphere with replace original.
     
    Last edited: Jan 25, 2024
  7. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,423
    I'll see if I can add this as a new demo scene in the next version.



    Assuming you're talking about Paint in Editor: You can go to the Config tab, and increase the Depth Bias value. Currently the max value is 1, but I think it makes more sense to unlock this to be any value.


    As The11thAlchemist says, using Replace Original is correct. This blending mode doesn't exactly paint them back to their original state, it actually paints all your paintable textures back to what you've currently set their Texture * Color settings to.

    Therefore, to achieve what you want you must change either the Texture or Color values to what you deem to be their 'original' states after the texture has activated. You can do this with a custom script, or using the CwPaintableMesh component's Advanced/OnActivated event. With this event you can call your CwPaintableMeshTexture component's SetColor function with a hex color like #FFFF for opaque white, or set the Texture.
     
    dan99nik_unity likes this.
  8. ddsinteractive

    ddsinteractive

    Joined:
    May 1, 2013
    Posts:
    28
    Actually I'm talking about PaintIn3D so this would be runtime. The fish fin blocks painting behind it. So when the fish is swimming, there is a white spot behind it. I'm trying to work with the Paint Through script but am totally lost with how to make that work with a finger touch and mouse click.
     
  9. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,423
    I see. By default, Paint in 3D doesn't block any paint from going through objects. What's likely happening is your paint sphere/decal has a low radius/size, and when the paint is applied to the fin, it's just not reaching the fish body.

    If you only want to change the depth/penetration of the paint, then you can increase the paint sphere/decal component's Scale.z setting. However, depending on how you want this to look it likely requires the paint to be oriented to match the camera or finger, which you can do by setting your CwHitScreen component's RotateTo/Direction setting to RayDirection or CameraDirection.

    Keep in mind that if you change the Scale.z a lot you are elongating the paint shape, so for decal painting you will likely want to set the Wrapping setting to 0 so the decal shape remains consistent at every depth it gets applied to.

    Something similar is shown in the "Zombie Blood" demo scene, where the blood decal has a depth of 15 units, and goes through the whole model even though it just uses a BoxCollider.

    The CwHitThrough component does something like this, but instead of being based on mouse/touch positions, it paints through two 3D points you specify so it's likely not so useful in this particular scenario.
     
  10. The11thAlchemist

    The11thAlchemist

    Joined:
    Aug 10, 2020
    Posts:
    30
    Hi Darkcoder. I've been going through your examples and it appears that the CWHitNearby and CWHitThrough components are the only ones that don't need a collider to paint on an object. Unfortunately, those components also don't allow for painting triangles. I'm working with low poly objects and I'd like to paint triangles at runtime, but I also don't want mesh colliders. Mesh colliders allowed for excellent painting coverage and are easy to implement on thousands of objects but are very performance intensive (even with low poly). Primitive colliders are less performant but the implementation would be a nightmare put on thousands of objects and the few objects I tested it on resulted in very inconsistent painting (which is expected since the colliders don't match the mesh perfectly). I tried to go through your code to determine why I can't do triangle painting with the CWHitNearby component but your scripts are pretty complicated and beyond my current capabilities. It would probably take me weeks to learn what I need in order to understand your code. Before I spend the time learning your code to see if I can modify it, I was wondering if there is anything inherently impossible about using CWHitNearby with painting triangles? I love learning, but I'm kind of on a time crunch at the moment.
    Thanks
     
  11. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,423
    Triangle painting requires knowing where the triangle is, which is why it's only supported by hit components that perform raycasts, because if a raycast hits a MeshCollider it tells you which triangle was hit.

    If you want to do triangle painting without a MeshCollider then you must manually calculate where the triangle is and call the HandleHitTriangle method on the paint components yourself.
     
  12. The11thAlchemist

    The11thAlchemist

    Joined:
    Aug 10, 2020
    Posts:
    30
    Ahh. That makes sense. I didn't realize that you could get specific triangles from a mesh collider. My guess was that you were using uv normals and somehow deriving the triangles from those maps. Thanks for the reply. I'll think about what I can possibly do.
     
    Darkcoder likes this.
  13. Funtyx

    Funtyx

    Joined:
    May 3, 2017
    Posts:
    39
    Is it possible not to use your shader? And to use my own, for example, I use URP Lit, but I am seeing problems with the color of the decal. If the default color on the decal is red, then the decal will not be colored, and if the material is white, then the decal will be colored. What should I do?

    upload_2024-1-30_13-14-57.png upload_2024-1-30_13-15-11.png upload_2024-1-30_13-15-42.png
     
  14. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,423
    You can paint any shader. If you set your material's color to red, then your texture will always be tinted red so it becomes impossible to paint/show white. Therefore, you must always keep the material's color white. If you want the texture to begin as red then either modify your material so it has a red texture to begin with, or change the CwPaintableMeshTexture component's Color setting to red.

    This is shown in the "10 Base Color" demo scene.
     
  15. Funtyx

    Funtyx

    Joined:
    May 3, 2017
    Posts:
    39
    Is it possible to change the color of CwPaintableMeshTexture in Play Mode? In our game, in addition to decals, we will change the color and also control the properties of the material. I see that in CwPaintableMeshTexture you can change the color and you can assign a texture next to it, but this does not work in Play Mode.
     
  16. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,423
    Once the texture has been created you can't change the background without resetting the whole thing. The fastest approach to change only the background color is to use 2 layers.

    For example, you can use an opaque material on the base, and then add a secondary transparent material on top, and paint that. They will then combine together when rendered.

    You can also achieve this effect using one shader, but it requires a custom shader. For example, the Paint in 3D/Solid shader allows you to set the base color/texture, and then override it with the override albedo texture (08 Overlay demo scene).
     
  17. Gssev7

    Gssev7

    Joined:
    Jul 9, 2014
    Posts:
    39
    Hi, I have Paint in 3d and am creating a 3d object paint app to basically paint objects in VR. I have a simple working scene for painting Albedo, Normal and Metallic on to an object. I use Playmaker as I'm not a coder and this can do a lot but my challenge is to save each texture to disk at runtime. I have seen the threads about using get png data but playmaker doesn't seem to be able to use this. I have got a texture 2d variable by using getreadablecopy which playmaker can get but I'm unable to convert it to a texture which playmaker can export at runtime.
    So any chance of a basic save to disk script that works with paintable textures. It just needs to be for one of the types as I could modify it to use for the other like normals or metallic etc. Ideally this would be great integrated into the Paint in 3d asset. Many thanks.
     
  18. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,423
    Paint in 3D comes with basic save/load functionality. If you set the SaveLoad setting to Automatic then you can just set a unique SaveName for each texture and it will auto save and load. You can also manually call the Save and Load functions on each texture with a specific name, which you should be able to do from PlayMaker.
     
  19. Gssev7

    Gssev7

    Joined:
    Jul 9, 2014
    Posts:
    39
    I was able to get it working and used a chat gpt solution which I was able to modify and called the method with playmaker
    this was the code which i added using paint core and system collections.

    using UnityEngine;
    using PaintCore;
    using System.Collections.Generic;
    public class SaveTexture : MonoBehaviour
    {
    public Texture2D paintableTexture; // Assign your paintable texture in the Unity Editor
    // Call this method to save the paintable texture to disk
    public void SaveTextureToDisk()
    {
    byte[] textureBytes = paintableTexture.EncodeToPNG();
    System.IO.File.WriteAllBytes("SavedTextures/paintedTexture.png", textureBytes);
    }
    }

    here is a screen in unity.
    upload_2024-2-13_17-41-38.png Thanks for the help
     
    Darkcoder likes this.
  20. Gssev7

    Gssev7

    Joined:
    Jul 9, 2014
    Posts:
    39
    Is it possible to change a paintable mesh texture slot via code or in my case using playmaker as I tried to set a property in the component but its not showing an option for slots or groups which Id like to change at runtime .
     
  21. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,423
    The slot is a struct containing the Index (int) and Name (string), so it's possible Play Maker can't set this directly.

    Similar to before, you can probably do this using a little script to call it for you like this (untested):

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using PaintCore;
    4. public class ChangeSlot : MonoBehaviour
    5. {
    6.     public CwPaintableTexture paintableTexture;
    7.  
    8.     public int slotIndex = 0;
    9.  
    10.     public string slotName = "_MainTex";
    11.  
    12.     public void ApplySettingsToSlot()
    13.     {
    14.         if (paintableTexture.Activated)
    15.         {
    16.             paintableTexture.Model.ApplyTexture(paintableTexture.Slot, paintableTexture.Texture); // Revert the old slot's texture?
    17.         }
    18.  
    19.         paintableTexture.Slot = new CwSlot(slotIndex, slotName);
    20.     }
    21. }
    The paintable texture isn't designed with slot changing in mind, so this may not work. For example, the previously applied slot texture isn't cleared when changing it, so I added a little code to try and revert the previous slot's texture, but there are scenarios where this won't revert as expected.
     
  22. abdullahriaz41

    abdullahriaz41

    Joined:
    Aug 12, 2020
    Posts:
    4
    Hey, I'm using Paint Sphere to paint a texture, everything is working fine.

    How can I create a visually appealing color spreading animation after painting is done. for example, default radius is 1, when painting starts the painted color should spread to maybe 1.2 radius.

    Paint modifiers are doing this before the painting.
     
  23. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,423
    Didn't I answer your email yesterday with the same question? In case it's a different person: "In the latest version (4.0.5), I added the "94 Expanding Paint" demo scene, which shows you how to make paint that can expand or rotate after painting."
     
  24. Gssev7

    Gssev7

    Joined:
    Jul 9, 2014
    Posts:
    39
    That did work for the slot, then I still had to change other settings so I tried another way by copying all components from a paintable object in code to my new imported object which worked but still not getting paint to appear on the texture all the time but I'm close. Thanks for the help.
     
  25. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,423
    Changing the slot won't immediately change the texture, you have to paint or preview paint for it to apply the next time.

    So perhaps adding this after the .Slot = change will work: paintableTexture.Model.ApplyTexture(paintableTexture.Current);

    You will likely want to put this inside a if (paintableTexture.Activated) check like the other bit.
     
  26. Gssev7

    Gssev7

    Joined:
    Jul 9, 2014
    Posts:
    39
    The imported at runtime mesh works good now, I set the paintable mesh that is the source of the copy to ' after first use ' and that worked. Also as its in vr I am using paint sphere but I had to use a playmaker raycast with it and sent its hit points to the paint sphere . The only issue I have left is when normal painting it shows the uv seams dark at one side of the seam and that's with fix seams set as. well. Any thing I should be doing to fix this.
     
  27. Krooq

    Krooq

    Joined:
    Jan 30, 2013
    Posts:
    196
    I'm getting an error when I build in Unity 2022.3.19, HDRP 14.0.10

    Code (CSharp):
    1. Error building Player: Shader error in 'Paint in 3D/Solid': "Undefined punctual shadow filter algorithm" at <project>/PackageCache/com.unity.render-pipelines.high-definition@14.0.10/Runtime/Lighting/Shadow/HDShadowAlgorithms.hlsl(47)
    2.  
    3. Compiling Subshader: 0, Pass: Forward, Fragment program with AREA_SHADOW_MEDIUM DECALS_3RT LOD_FADE_CROSSFADE PROBE_VOLUMES_OFF SCREEN_SPACE_SHADOWS_OFF SHADOW_VERY_HIGH USE_FPTL_LIGHTLIST _REFRACTION_OFF
    4. Platform defines: SHADER_API_DESKTOP UNITY_ENABLE_DETAIL_NORMALMAP UNITY_ENABLE_REFLECTION_BUFFERS UNITY_LIGHTMAP_FULL_HDR UNITY_LIGHT_PROBE_PROXY_VOLUME UNITY_PBS_USE_BRDF1 UNITY_SPECCUBE_BLENDING UNITY_SPECCUBE_BOX_PROJECTION UNITY_USE_DITHER_MASK_FOR_ALPHABLENDED_SHADOWS
    5. Disabled keywords: AREA_SHADOW_HIGH DEBUG_DISPLAY DECALS_4RT DECALS_OFF DECAL_SURFACE_GRADIENT DIRLIGHTMAP_COMBINED DISABLEFOG DOTS_INSTANCING_ON DYNAMICLIGHTMAP_ON INSTANCING_ON LIGHTMAP_ON PROBE_VOLUMES_L1 PROBE_VOLUMES_L2 SCREEN_SPACE_SHADOWS_ON SHADER_API_GLES30 SHADOWS_SHADOWMASK SHADOW_HIGH SHADOW_LOW SHADOW_MEDIUM UNITY_ASTC_NORMALMAP_ENCODING UNITY_COLORSPACE_GAMMA UNITY_FRAMEBUFFER_FETCH_AVAILABLE UNITY_HALF_PRECISION_FRAGMENT_SHADER_REGISTERS UNITY_HARDWARE_TIER1 UNITY_HARDWARE_TIER2 UNITY_HARDWARE_TIER3 UNITY_LIGHTMAP_DLDR_ENCODING UNITY_LIGHTMAP_RGBM_ENCODING UNITY_METAL_SHADOWS_USE_POINT_FILTERING UNITY_NO_DXT5nm UNITY_NO_FULL_STANDARD_SHADER UNITY_NO_SCREENSPACE_SHADOWS UNITY_PBS_USE_BRDF2 UNITY_PBS_USE_BRDF3 UNITY_PRETRANSFORM_TO_DISPLAY_ORIENTATION UNITY_UNIFIED_SHADER_PRECISION_MODEL UNITY_VIRTUAL_TEXTURING USE_CLUSTERED_LIGHTLIST _ADD_PRECOMPUTED_VELOCITY _DISABLE_DECALS _DISABLE_SSR _DISABLE_SSR_TRANSPARENT _ENABLE_FOG_ON_TRANSPARENT _OVERRIDE_EMISSION _OVERRIDE_MOS _OVERRIDE_NORMAL _OVERRIDE_OPACITY _REFRACTION_PLANE _REFRACTION_SPHERE _REFRACTION_THIN _TRANSPARENT_WRITES_MOTION_VEC
     
  28. Gssev7

    Gssev7

    Joined:
    Jul 9, 2014
    Posts:
    39

    Its better now . it was just the settings and the object I'm using to test uv map is not great. Also using the "hit between" component now as the docs recommend for vr.
     
    Darkcoder likes this.
  29. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,423
    Thanks for pointing this out. I've just released a new version that updates the shaders to the latest version.



    Great!
     
    Krooq likes this.
  30. Kp0LiK

    Kp0LiK

    Joined:
    May 2, 2022
    Posts:
    4
    Hello, have a great day.

    Can you please help us? We are drawing a decal (Cw PaintDecal) on a board. The decal is only drawn when our object is set to IsKinematic. However, the issue is that the board can also act as a physics object (it can be moved, it can fall, etc.), and when we disable kinematic, our decal disappears immediately. Is there a way to apply a decal to a non-kinematic object?
     
  31. MichealChiNguyen

    MichealChiNguyen

    Joined:
    Nov 16, 2020
    Posts:
    5
    Hi, i am using Color Book - Paint in 2d and having a huge performance issue, whenever i use the big brush and drag it quickly the fps drop below 10, It's like there is a problem with drawing to fill in between 2 distant points
     
  32. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,423
    Does this issue only occur when the physics object is moving? Since the paint is applied at the end of the frame, it's possible the object moves between when the paint command is sent, and when it's applied.



    Oops, you can open the "Bucket Spread (Slide From Bottom)" prefab, and change the Tool GameObject's CwHitScreen2D component's Frequency setting to OnceOnPress to fix this. I'll release an update shortly. [Edit] Update is now out.
     
    Last edited: Feb 22, 2024
    MichealChiNguyen likes this.
  33. Kp0LiK

    Kp0LiK

    Joined:
    May 2, 2022
    Posts:
    4
    Yes, this issue occurs on any object that has a Rigidbody with the non-kinematic property. I tried checking this on your marker board (in the Example scene VR Pen) as well. When I added the Rigidbody component to the board, the decal stopped being drawn on it. However, as soon as I set it to Kinematic, the marker started drawing on the board again.[/QUOTE]

     
  34. lclemens

    lclemens

    Joined:
    Feb 15, 2020
    Posts:
    765
    I just bought this asset last night, but I am considering requesting a refund today.

    The reason is that the workflow for a couple of things seems like it's much more complicated than it should be.

    The first issue is the remapping process. The process for a single texture is not so bad, but having to repeat those steps for every single texture (normal, emission, specular, etc) is a pain. On the Unwrapper asset... Why not point to the material instead of a single texture? That would allow the remap function to perform the remap function for all the material's textures instead of one by one. It would work for at least the standard materials like Lit, URP Lit, URP Simple Lit, etc. I have been using SimpleBake which is a Blender plugin that does this same thing all in one step.

    The second issue is similar... Making a brush seems more complicated than it needs to be at least for standard shaders like Lit, URP Lit, URP Simple Lit, etc. Having to setup all the texture files with a specific naming convention is annoying. With a little bit of code, the brush creation function could instead read a material and then create the brush using all the existing textures within the material. This would be so much more convenient - people could just choose materials to paint with instead of fussing around with a lengthy process of creating brushes.

    Leaving the old way of creating brushes and remapping the hard way might be useful for nonstandard shaders/materials. But for 90% of us, it would be so much cleaner to be able to perform these functions using the new way.

    Perhaps I missed it, and maybe there is a simpler way to perform remapping and make brushes. If so, please let me know. If not, maybe you would consider adding it? I don't think it would be too difficult to add that functionality at least for standard shaders/materials.
     
    Last edited: Feb 24, 2024
    crash_over likes this.
  35. vertexx

    vertexx

    Joined:
    Mar 18, 2014
    Posts:
    384
    There are a few such like assets in the Store. All need some patience and practice in order to be used "properly."
    But for painting.. this one for me tops the rest of them. And at least it doesn't say "Simple" or "Easy" or "EZ" like many other Devs do about their assets. The feedback by Darkcoder is quite unique (and fast) by Unity standards and valuable to read. Iclemans..Please continue with this asset. Sure it's not "drag and drop" but with a little patience and help from the Dev you'll soon be bursting with confidence and ideas.
     
    lclemens and Darkcoder like this.
  36. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,423
    [/QUOTE]

    Thanks, I'll check it out next week.



    The unwrap and remap features were originally designed as a kind of fallback feature in the scenario that specific meshes aren't paintable. If you have a lot of meshes that aren't originally paintable then I can understand that it would be very time consuming to configure, as this wasnt a scenario I considered. What I could do is make some kind of tool/wizard that allows you to unwrap and remap them in bulk?

    Regarding brushes, it's the same thing really. However, typically all textures in your texture set have the same name with the specific texture type appended to it which is what I designed it for. Can you show me what your texture naming convention is like and I can consider adding support for it?
     
    lclemens likes this.
  37. lclemens

    lclemens

    Joined:
    Feb 15, 2020
    Posts:
    765
    Ah that makes sense - the remapping thing isn't really the main focus of the asset. Myself and a few others have been looking all over for a tool to do texture remapping and Paint in Editor is the closest thing we've found so far in Unity. There's a Blender plugin called SimpleBake that works as well, but it's less convenient because it's outside of Unity. I have been using UModelerX for painting, but it doesn't have a remapping function, so remapping was one of the main reasons I bought this asset. I admit that my use-case is probably not super common.

    The thing is that I'm using lots of 3D assets and materials from the asset store, cgtrader.com, sketchfab.com, etc. Also sometimes we're generating textures/materials with other tools, or AI. It's really common for me (and others) to be working on a design and thinking - hey, I'd like to paint that one brick material from asset X or that circuit material from asset Y onto this portion of my model. Sometimes their textures use the a standard naming convention, other times they don't. It would be super useful if instead of renaming texture files and right-clicking on them and choosing "Create/CW/Paint in Editor/Brush (Wallpaper)".... we could rick-click a Material and choose "Create/CW/Paint in Editor/Brush (Wallpaper)" and it would create the scriptable object and extract whatever pointers to textures it could from the material. Even better yet - it would also be super useful in the Paint in Editor UI to create a new brush right there and click a button to select the material from which to create it. Of course because different shaders use different names for textures ("_BaseMap" for URP, "_MainTex" for standard, etc) it won't be correct 100% of the time but the user could drag in the new ones for those rare cases which is not much different than how it works now. It would be pretty easy to write a function that would simply check for the existence of the textures in the material via their common string names like material.GetTexture("_BumpMap", x), material.GetTexture("_NormalMap"), etc and if it's not null, then toss its asset reference into the appropriate field for the Scriptable Object. It might even work for some custom shaders since they often use similar names as the URP/HDRP/Legacy materials.

    That same function could be reused for the remapping tool as well to provide an additional auto-remap function for all/most of the textures in a material instead of doing each texture individually. So the user could do a remap by individual texture, or a whole material - whichever makes sense in their particular context.

    I think I'll keep the asset, even though it's not perfect. Between UModelerX and this I can do all of my painting in Unity. It's still faster than switching over to Blender and importing/exporting fbx files, materials, and textures.
     
    Last edited: Feb 25, 2024
  38. Gssev7

    Gssev7

    Joined:
    Jul 9, 2014
    Posts:
    39
    Hi, I'm back to looking at modifying paintable mesh textures at runtime in a build. I am able to copy 3 paintable mesh textures on to a newly imported model but their values/ properties did not copy so I need to change the slot which works with the example you wrote above but also I would like to change the group and also the texture size. These don't show up using playmaker when trying set properties. I am able to change the conversion setting.
     
  39. Gssev7

    Gssev7

    Joined:
    Jul 9, 2014
    Posts:
    39
    Ok , I seem to have it working, landed up using a script to copy each paintable textures values from the source object to the imported model. I do have to activate the source object for a moment to get the texture working on the imported model.
     
    Darkcoder likes this.
  40. Kellyrayj

    Kellyrayj

    Joined:
    Aug 29, 2011
    Posts:
    938
    Hey friends, loving this so far. Thanks for the awesome asset.

    I'm wondering if you have any thoughts on this. I consistently get a few alpha islands when I'm painting. I want to be able to fill in these islands similar to the method used in the Solidify plugin in photoshop where it fills in the alpha with the average of nearby colors.

    Screenshot 2024-02-27 at 10.00.29 AM.png
     
  41. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,423


    This makes sense, I'll see if I can implement some kind of wizard in the next version. I'm thinking you select a directory(or multiple) and it builds a preview of a best guess of how they link up, and you can quickly drag and drop the meshes and textures around if it gets it wrong. Then finally you can click Create, and it will build the actual Brush and Unwrapper assets for you.


    You'll probably have to extend the example script a bit for each additional setting. Luckily, Group/Width/Height are single values, so it's much easier. You just need to make a public field with the correct type (e.g. public int Width; public CwGroup Group;) Then make a function to assign them (e.g. public void ApplySettingsToWidth() { paintableTexture.Width = Width; }).


    This is typically called texture dilation. Assuming you're talking about Paint in 3D: The latest versions include this via CwDilate.Dilate(renderTex, mesh, uv_channel, radius). For a CwPaintableMeshTexture you should be able to call: CwDilate.Dilate(yourPaintableMeshTexture.Current, yourPaintableMesh, 0, 16);
     
    lclemens likes this.
  42. lclemens

    lclemens

    Joined:
    Feb 15, 2020
    Posts:
    765
    Yeah man this took me like 15 minutes to figure out what it meant by "Mesh Inspector Context Menu". It turns out that you need to select the standalone mesh in the project explorer view (NOT the hierarchy). So something like this:

    upload_2024-3-2_16-42-24.png

    Then, the "No Mesh Selected" error message says there is a gear icon - but that must be for an old version of unity because it's actually three vertical dots now.

    upload_2024-3-2_16-43-36.png

    Selecting Mesh Unwrapper will work.

    The "No Mesh Selected" error message says that an other way to do it is by clicking "Analyze Mesh" from the CwPaintable component, but I'm not really sure where the CwPaintable component is found or where/how to add it.
     
  43. lclemens

    lclemens

    Joined:
    Feb 15, 2020
    Posts:
    765
    I created a Mesh Unwrapper by selecting the mesh in the Project files view and choosing "Mesh Unwrapper (Paint in Editor)" from the three vertical dots in the top right of the inspector window, then pressed "Generate".

    The first time I click "Generate, nothing happens".. No error or anything.

    The second time I click "Generate" it creates a new mesh underneath the mesh unwrapper asset and it spits out errors.

    Mesh.vertices is too small. The supplied vertex array has less vertices than are referenced by the triangles array.
    UnityEngine.Mesh:SetVertices (System.Collections.Generic.List`1<UnityEngine.Vector3>)
    PaintInEditor.CwMeshUnwrapper:CopyMesh (UnityEngine.Mesh,UnityEngine.Mesh,System.Collections.Generic.List`1<System.Collections.Generic.List`1<int>>) (at Assets/Plugins/CW/PaintInEditor/Required/Scripts/CwMeshUnwrapper.cs:165)
    PaintInEditor.CwMeshUnwrapper:Generate (UnityEngine.Mesh,UnityEngine.Mesh) (at Assets/Plugins/CW/PaintInEditor/Required/Scripts/CwMeshUnwrapper.cs:123)
    PaintInEditor.CwMeshUnwrapper:Generate () (at Assets/Plugins/CW/PaintInEditor/Required/Scripts/CwMeshUnwrapper.cs:56)
    PaintInEditor.CwMeshUnwrapper_Editor/<>c:<OnInspector>b__4_1 (PaintInEditor.CwMeshUnwrapper) (at Assets/Plugins/CW/PaintInEditor/Required/Scripts/CwMeshUnwrapper.cs:325)
    CW.Common.CwEditor:Each<PaintInEditor.CwMeshUnwrapper> (PaintInEditor.CwMeshUnwrapper[],System.Action`1<PaintInEditor.CwMeshUnwrapper>,bool,bool,string) (at Assets/Plugins/CW/Shared/Common/Required/Scripts/CwEditor.cs:75)
    PaintInEditor.CwMeshUnwrapper_Editor:OnInspector () (at Assets/Plugins/CW/PaintInEditor/Required/Scripts/CwMeshUnwrapper.cs:325)
    CW.Common.CwEditor:OnInspectorGUI () (at Assets/Plugins/CW/Shared/Common/Required/Scripts/CwEditor.cs:51)
    UnityEngine.GUIUtility:processEvent (int,intptr,bool&)

    Mesh.normals is out of bounds. The supplied array needs to be the same size as the Mesh.vertices array.
    UnityEngine.Mesh:SetNormals (System.Collections.Generic.List`1<UnityEngine.Vector3>)
    PaintInEditor.CwMeshUnwrapper:CopyMesh (UnityEngine.Mesh,UnityEngine.Mesh,System.Collections.Generic.List`1<System.Collections.Generic.List`1<int>>) (at Assets/Plugins/CW/PaintInEditor/Required/Scripts/CwMeshUnwrapper.cs:182)
    PaintInEditor.CwMeshUnwrapper:Generate (UnityEngine.Mesh,UnityEngine.Mesh) (at Assets/Plugins/CW/PaintInEditor/Required/Scripts/CwMeshUnwrapper.cs:123)
    PaintInEditor.CwMeshUnwrapper:Generate () (at Assets/Plugins/CW/PaintInEditor/Required/Scripts/CwMeshUnwrapper.cs:56)
    PaintInEditor.CwMeshUnwrapper_Editor/<>c:<OnInspector>b__4_1 (PaintInEditor.CwMeshUnwrapper) (at Assets/Plugins/CW/PaintInEditor/Required/Scripts/CwMeshUnwrapper.cs:325)
    CW.Common.CwEditor:Each<PaintInEditor.CwMeshUnwrapper> (PaintInEditor.CwMeshUnwrapper[],System.Action`1<PaintInEditor.CwMeshUnwrapper>,bool,bool,string) (at Assets/Plugins/CW/Shared/Common/Required/Scripts/CwEditor.cs:75)
    PaintInEditor.CwMeshUnwrapper_Editor:OnInspector () (at Assets/Plugins/CW/PaintInEditor/Required/Scripts/CwMeshUnwrapper.cs:325)
    CW.Common.CwEditor:OnInspectorGUI () (at Assets/Plugins/CW/Shared/Common/Required/Scripts/CwEditor.cs:51)
    UnityEngine.GUIUtility:processEvent (int,intptr,bool&)

    Mesh.uv is out of bounds. The supplied array needs to be the same size as the Mesh.vertices array.
    UnityEngine.Mesh:SetUVs (int,System.Collections.Generic.List`1<UnityEngine.Vector4>)
    PaintInEditor.CwMeshUnwrapper:CopyMesh (UnityEngine.Mesh,UnityEngine.Mesh,System.Collections.Generic.List`1<System.Collections.Generic.List`1<int>>) (at Assets/Plugins/CW/PaintInEditor/Required/Scripts/CwMeshUnwrapper.cs:184)
    PaintInEditor.CwMeshUnwrapper:Generate (UnityEngine.Mesh,UnityEngine.Mesh) (at Assets/Plugins/CW/PaintInEditor/Required/Scripts/CwMeshUnwrapper.cs:123)
    PaintInEditor.CwMeshUnwrapper:Generate () (at Assets/Plugins/CW/PaintInEditor/Required/Scripts/CwMeshUnwrapper.cs:56)
    PaintInEditor.CwMeshUnwrapper_Editor/<>c:<OnInspector>b__4_1 (PaintInEditor.CwMeshUnwrapper) (at Assets/Plugins/CW/PaintInEditor/Required/Scripts/CwMeshUnwrapper.cs:325)
    CW.Common.CwEditor:Each<PaintInEditor.CwMeshUnwrapper> (PaintInEditor.CwMeshUnwrapper[],System.Action`1<PaintInEditor.CwMeshUnwrapper>,bool,bool,string) (at Assets/Plugins/CW/Shared/Common/Required/Scripts/CwEditor.cs:75)
    PaintInEditor.CwMeshUnwrapper_Editor:OnInspector () (at Assets/Plugins/CW/PaintInEditor/Required/Scripts/CwMeshUnwrapper.cs:325)
    CW.Common.CwEditor:OnInspectorGUI () (at Assets/Plugins/CW/Shared/Common/Required/Scripts/CwEditor.cs:51)
    UnityEngine.GUIUtility:processEvent (int,intptr,bool&)

    If I click "Analyze Old" or "Analyze New", then the "Editor Mesh Analysis" window pops up which says "No Mesh Selected. To select a mesh, click Analyze Mesh from the CwPaintable component, or from the Mesh inspector context menu (gear icon at the top right)" and it gives this error in the console:
    ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
    Parameter name: index
    System.Collections.Generic.List`1[T].get_Item (System.Int32 index) (at <dc753a1061284f8e971ee88ee4826eee>:0)
    PaintInEditor.CwEditorMesh.InsertTriangle (System.Int32 a, System.Int32 b, System.Int32 c) (at Assets/Plugins/CW/PaintInEditor/Required/Scripts/CwEditorMesh.cs:98)
    PaintInEditor.CwEditorMesh.GetProcessedCopy (UnityEngine.Mesh original, System.Int32 channel) (at Assets/Plugins/CW/PaintInEditor/Required/Scripts/CwEditorMesh.cs:44)
    PaintInEditor.CwEditorMeshAnalysis.OpenWith (UnityEngine.Object source, UnityEngine.Mesh mesh) (at Assets/Plugins/CW/PaintInEditor/Required/Scripts/CwEditorMeshAnalysis.cs:72)
    PaintInEditor.CwMeshUnwrapper_Editor.OnInspector () (at Assets/Plugins/CW/PaintInEditor/Required/Scripts/CwMeshUnwrapper.cs:303)
    CW.Common.CwEditor.OnInspectorGUI () (at Assets/Plugins/CW/Shared/Common/Required/Scripts/CwEditor.cs:51)
    UnityEditor.UIElements.InspectorElement+<>c__DisplayClass72_0.<CreateInspectorElementUsingIMGUI>b__0 () (at <5d5ebefe97114215928ac1d9cd096522>:0)
    UnityEngine.GUIUtility:processEvent(Int32, IntPtr, Boolean&)

    What mesh am I supposed to select? I thought I just did click the Analyze mesh button? Is it because I'm working in a prefab?

    If I try to do it from the main paint editor window I get:

    GUI Error: Invalid GUILayout state in CwPaintInEditor view. Verify that all layout Begin/End calls match
    UnityEngine.GUIUtility:processEvent (int,intptr,bool&)

    ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
    Parameter name: index
    System.Collections.Generic.List`1[T].get_Item (System.Int32 index) (at <dc753a1061284f8e971ee88ee4826eee>:0)
    PaintInEditor.CwEditorMesh.InsertTriangle (System.Int32 a, System.Int32 b, System.Int32 c) (at Assets/Plugins/CW/PaintInEditor/Required/Scripts/CwEditorMesh.cs:98)
    PaintInEditor.CwEditorMesh.GetProcessedCopy (UnityEngine.Mesh original, System.Int32 channel) (at Assets/Plugins/CW/PaintInEditor/Required/Scripts/CwEditorMesh.cs:44)
    PaintInEditor.CwEditorMeshAnalysis.OpenWith (UnityEngine.Object source, UnityEngine.Mesh mesh) (at Assets/Plugins/CW/PaintInEditor/Required/Scripts/CwEditorMeshAnalysis.cs:72)
    PaintInEditor.CwPaintInEditor.DrawObjectsTab () (at Assets/Plugins/CW/PaintInEditor/Required/Scripts/CwPaintInEditor_Objects.cs:98)
    PaintInEditor.CwPaintInEditor.Draw () (at Assets/Plugins/CW/PaintInEditor/Required/Scripts/CwPaintInEditor.cs:377)
    PaintInEditor.CwPaintInEditor.OnGUI () (at Assets/Plugins/CW/PaintInEditor/Required/Scripts/CwPaintInEditor.cs:307)
    UnityEditor.HostView.InvokeOnGUI (UnityEngine.Rect onGUIPosition) (at <5d5ebefe97114215928ac1d9cd096522>:0)
    UnityEditor.DockArea.DrawView (UnityEngine.Rect dockAreaRect) (at <5d5ebefe97114215928ac1d9cd096522>:0)
    UnityEditor.DockArea.OldOnGUI () (at <5d5ebefe97114215928ac1d9cd096522>:0)
    UnityEngine.UIElements.IMGUIContainer.DoOnGUI (UnityEngine.Event evt, UnityEngine.Matrix4x4 parentTransform, UnityEngine.Rect clippingRect, System.Boolean isComputingLayout, UnityEngine.Rect layoutSize, System.Action onGUIHandler, System.Boolean canAffectFocus) (at <f67debe1efd242948106f1922bfac1c7>:0)
    UnityEngine.UIElements.IMGUIContainer.HandleIMGUIEvent (UnityEngine.Event e, UnityEngine.Matrix4x4 worldTransform, UnityEngine.Rect clippingRect, System.Action onGUIHandler, System.Boolean canAffectFocus) (at <f67debe1efd242948106f1922bfac1c7>:0)
    UnityEngine.UIElements.IMGUIContainer.HandleIMGUIEvent (UnityEngine.Event e, System.Action onGUIHandler, System.Boolean canAffectFocus) (at <f67debe1efd242948106f1922bfac1c7>:0)
    UnityEngine.UIElements.IMGUIContainer.HandleIMGUIEvent (UnityEngine.Event e, System.Boolean canAffectFocus) (at <f67debe1efd242948106f1922bfac1c7>:0)
    UnityEngine.UIElements.IMGUIContainer.SendEventToIMGUIRaw (UnityEngine.UIElements.EventBase evt, System.Boolean canAffectFocus, System.Boolean verifyBounds) (at <f67debe1efd242948106f1922bfac1c7>:0)
    UnityEngine.UIElements.IMGUIContainer.SendEventToIMGUI (UnityEngine.UIElements.EventBase evt, System.Boolean canAffectFocus, System.Boolean verifyBounds) (at <f67debe1efd242948106f1922bfac1c7>:0)
    UnityEngine.UIElements.IMGUIContainer.ProcessEvent (UnityEngine.UIElements.EventBase evt) (at <f67debe1efd242948106f1922bfac1c7>:0)
    UnityEngine.UIElements.CallbackEventHandler.HandleEvent (UnityEngine.UIElements.EventBase evt) (at <f67debe1efd242948106f1922bfac1c7>:0)
    UnityEngine.UIElements.CallbackEventHandler.HandleEventAtCurrentTargetAndPhase (UnityEngine.UIElements.EventBase evt) (at <f67debe1efd242948106f1922bfac1c7>:0)
    UnityEngine.UIElements.CallbackEventHandler.HandleEventAtTargetPhase (UnityEngine.UIElements.EventBase evt) (at <f67debe1efd242948106f1922bfac1c7>:0)
    UnityEngine.UIElements.MouseCaptureDispatchingStrategy.DispatchEvent (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel panel) (at <f67debe1efd242948106f1922bfac1c7>:0)
    UnityEngine.UIElements.EventDispatcher.ApplyDispatchingStrategies (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel panel, System.Boolean imguiEventIsInitiallyUsed) (at <f67debe1efd242948106f1922bfac1c7>:0)
    UnityEngine.UIElements.EventDispatcher.ProcessEvent (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel panel) (at <f67debe1efd242948106f1922bfac1c7>:0)
    UnityEngine.UIElements.EventDispatcher.ProcessEventQueue () (at <f67debe1efd242948106f1922bfac1c7>:0)
    UnityEngine.UIElements.EventDispatcher.OpenGate () (at <f67debe1efd242948106f1922bfac1c7>:0)
    UnityEngine.UIElements.EventDispatcherGate.Dispose () (at <f67debe1efd242948106f1922bfac1c7>:0)
    UnityEngine.UIElements.EventDispatcher.ProcessEvent (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel panel) (at <f67debe1efd242948106f1922bfac1c7>:0)
    UnityEngine.UIElements.EventDispatcher.Dispatch (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel panel, UnityEngine.UIElements.DispatchMode dispatchMode) (at <f67debe1efd242948106f1922bfac1c7>:0)
    UnityEngine.UIElements.BaseVisualElementPanel.SendEvent (UnityEngine.UIElements.EventBase e, UnityEngine.UIElements.DispatchMode dispatchMode) (at <f67debe1efd242948106f1922bfac1c7>:0)
    UnityEngine.UIElements.UIElementsUtility.DoDispatch (UnityEngine.UIElements.BaseVisualElementPanel panel) (at <f67debe1efd242948106f1922bfac1c7>:0)
    UnityEngine.UIElements.UIElementsUtility.UnityEngine.UIElements.IUIElementsUtility.ProcessEvent (System.Int32 instanceID, System.IntPtr nativeEventPtr, System.Boolean& eventHandled) (at <f67debe1efd242948106f1922bfac1c7>:0)
    UnityEngine.UIElements.UIEventRegistration.ProcessEvent (System.Int32 instanceID, System.IntPtr nativeEventPtr) (at <f67debe1efd242948106f1922bfac1c7>:0)
    UnityEngine.UIElements.UIEventRegistration+<>c.<.cctor>b__1_2 (System.Int32 i, System.IntPtr ptr) (at <f67debe1efd242948106f1922bfac1c7>:0)
    UnityEngine.GUIUtility.ProcessEvent (System.Int32 instanceID, System.IntPtr nativeEventPtr, System.Boolean& result) (at <3787173144ff4a19b1a55d5938e19421>:0)

    I'm just getting errors all over the place. The mesh was created using UModelerX - maybe it's generating an invalid mesh or something?
     
    Last edited: Mar 3, 2024
  44. rabeel_unity

    rabeel_unity

    Joined:
    Mar 28, 2020
    Posts:
    1
    Hi,
    Can we paint smoothness using Paint in 3D.. so that the surface becomes smooth and shinny as we paint it
    Thanks in advance
     
  45. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,423
    Where in the documentation is "Mesh Inspector Context Menu" mentioned? The online documentation HERE is the same as the current one in the asset, and I don't see this line. It also makes no mention of gear icon.

    Can you send me this mesh to test out?


    Yes, the "PBR Painting" demo scene shows you how to paint two textures at the same time. In this scene it's painting the custom shader that come with Paint in 3D that combines the Metallic, Occlusion, and Smoothness into one texture, but it's the same process for other shaders that typically only have one or two for each texture slot.
     
  46. lclemens

    lclemens

    Joined:
    Feb 15, 2020
    Posts:
    765
    It's not in the documentation - it's in the editor info box and warning message.
     
  47. ykyrus

    ykyrus

    Joined:
    Dec 10, 2021
    Posts:
    2
    @Darkcoder Hello,
    I want to ask you one question how can I change the material if I use paint in 3D? I mean if I have a model with material A, after I paint with a decal, and paint with color,How can i change this model use to material B?
     
  48. Kp0LiK

    Kp0LiK

    Joined:
    May 2, 2022
    Posts:
    4
    Hello! How are you? I hope everything is going well.

    I have a question: is it possible to globally manage the CwPaintable Mesh and Texture scripts to somehow automate the process of adding these scripts and applying the necessary settings to objects?

    For example, let's say I have 1000 objects in the scene with which the user can interact (draw on them). Do I really need to go into each object and attach the CwPaintableMesh script, then the CwPaintableMeshTexture script, and apply the necessary settings in CwPaintableMeshTexture?
     
  49. Kellyrayj

    Kellyrayj

    Joined:
    Aug 29, 2011
    Posts:
    938
    Hey friend, thank you for your earlier response! I have another one that I'm hoping you can point me in the right direction. I'm using your example of the percentage fill in Paint in 3D and my object is clearly covered in paint all over. However, it only ever reads around 50% of alpha. Do you have any clues?
     

    Attached Files:

  50. Kellyrayj

    Kellyrayj

    Joined:
    Aug 29, 2011
    Posts:
    938
    Found the info I was looking for. I wasn't using the Mask Mesh correctly! Thanks for an awesome asset.