Search Unity

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

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

  1. fleity

    fleity

    Joined:
    Oct 13, 2015
    Posts:
    345
    For anyone interested I made a fill tool for in editor painting.
    p3d_fill.gif upload_2022-10-31_11-40-8.png

    I had to make a few adjustments to make it work though:

    Code (CSharp):
    1.  
    2. // P3dHitScreenBase.cs line 247: Changed DoQuery to return a Transform
    3. protected virtual Transform DoQuery(Vector2 screenPosition, ref Camera camera, ref Ray ray, ref RaycastHit hit3D, ref RaycastHit2D hit2D)
    4. {
    5. ...
    6.             return hit3D.transform;
    7. }
    Code (CSharp):
    1.  
    2. // P3dHitScreenBase.cs line 274: Use new DoQuery transform
    3. Transform hitTransform = DoQuery(screenPosition, ref camera, ref ray, ref hit3D, ref hit2D);
    4.  
    5. // P3dHitScreenBase.cs line 298: PointsOnUV case does not create a valid p3dhit therefore we create one here before invoking hitcache
    6. else if (emit == EmitType.PointsOnUV)
    7.             {
    8.                 P3dHit p3dHit = hit3D.collider
    9.                         ? new P3dHit(hit3D)
    10.                         : new P3dHit
    11.                         {
    12.                                 Root = hitTransform,
    13.                                 First = hit3D.textureCoord,
    14.                                 Second = hit3D.textureCoord2
    15.                         };
    16.                hitCache.InvokeCoord(gameObject, preview, priority, pressure, p3dHit, finalRotation);
    17.  
    Code (CSharp):
    1.  
    2. // P3dHitScreen_InEditor.cs line 26: Change editor DoQuery to return a transform as well
    3. protected override Transform DoQuery(...
    4.  
    5. // P3dHitScreen_InEditor.cs line 32:
    6. Transform hitTransform = null;
    7.  
    8. // P3dHitScreen_InEditor.cs line 49: assign hitTransform if hit has been found
    9. hitTransform = model.transform;
    10.  
    11. // P3dHitScreen_InEditor.cs line 55:
    12. return hitTransform;
    13.  

    Code (CSharp):
    1.  
    2. // P3dWindow_Paint line 334:
    3.                 foreach (var paintFill in materialInstance.GetComponentsInChildren<P3dPaintFill>())
    4.                 {
    5.                     if (paintFill.Group == Settings.ColorGroup)
    6.                     {
    7.                         if (Settings.OverrideColor == true)
    8.                         {
    9.                             paintFill.Color  = Settings.Color;
    10.                         }
    11.                     }
    12.                
    13.                     if (Settings.OverrideModifiers == true)
    14.                     {
    15.                         paintFill.Modifiers.Instances.Clear();
    16.  
    17.                         foreach (var modifier in Settings.Modifiers.Instances)
    18.                         {
    19.                             paintFill.Modifiers.Instances.Add(modifier);
    20.                         }
    21.                     }
    22.                 }
    23.  
    24. // P3dWindow_Paint line 370:
    25.                     if (Settings.OverrideModifiers == true)
    26.                     {
    27.                         paintSphere.Modifiers.Instances.Clear();
    28.  
    29.                         foreach (var modifier in Settings.Modifiers.Instances)
    30.                         {
    31.                             paintSphere.Modifiers.Instances.Add(modifier);
    32.                         }
    33.                     }
    34.  

    Code (CSharp):
    1.  
    2. // P3dPaintFill line 64:
    3. P3dCommandFill.Instance.SetMaterial(blendMode, finalTexture, finalColor, finalOpacity, minimum);
    4.  
     
  2. Likesundayqaq

    Likesundayqaq

    Joined:
    Jun 13, 2022
    Posts:
    9
    I have a need, I have two models to be drawn, one model is a piece of paper with holes in it, and then I put another one like a wooden model under it, using P3D paint sphere and P3D hit Particles, and then the top model to draw, it will penetrate the paper, but I just want the bottom model to be drawn the shape I need.how to solve this problem.
    pls
     
  3. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,414
    Looks good! I'll check it out soon :D

    You must use the P3dMask component ("17 Mask" demo scene) on your paper with holes in.
     
  4. Abnormalia_

    Abnormalia_

    Joined:
    Jul 23, 2013
    Posts:
    128
    I am using your amazing asset in almost every project so thanks once more. I am away from PC ATM, so cannot test this, but if it’s possible to make game object paintable at runtime, do some painting and remove afterwards. Will it be too much performance wise? Thanks in advance.
     
  5. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,414
    The "73 Procedural Setup" demo scene shows you how to generate a new mesh and configure it to be paintable entirely from code. The performance should be the same as configuring it in the editor.
     
    Abnormalia_ likes this.
  6. Ceciaman

    Ceciaman

    Joined:
    Jul 30, 2013
    Posts:
    52
    Greetings,
    congratulations for the asset.
    I would have a problem.

    On a texture on a plane I make holes, and everything is fine.

    I would like that by putting this plane on a wall and painting on it I would like the color to pass only in the holes made.
    How can I do?
     
  7. Ceciaman

    Ceciaman

    Joined:
    Jul 30, 2013
    Posts:
    52
  8. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,414
    This can be done using the P3dMask component, which will block paint near the current GameObject using the texture mask you specify. There's a demo scene called Mask that shows how to use it.
     
  9. Ceciaman

    Ceciaman

    Joined:
    Jul 30, 2013
    Posts:
    52
    I've already seen the example.
    But I don't have preset masks.
    The texture is generated on the fly.
    Do I have to use the perforated texture as a mask?
     
  10. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,414
    The Texture you specify in the P3dMask component can be any Texture, including a RenderTexture or Texture2D generated in-game. If you want to set this to a P3dPaintableTexture's texture then you can access it via the .Current property.
     
  11. Ceciaman

    Ceciaman

    Joined:
    Jul 30, 2013
    Posts:
    52
    thank's
     
    Darkcoder likes this.
  12. shahryarsheikhwork

    shahryarsheikhwork

    Joined:
    Oct 17, 2022
    Posts:
    3
    Hi,
    I have been using this asset from a long time and it is a great asset but now i am facing an issue i am trying to create a activity to paint an spinning object and it is not behaving in the way i wanted it to. I am using paint sphere with P3D hit screen and it is skipping some points while painting i have tried different methods/components but they are all behaving in the same manner so kindly help me to figure out a solution.As you can see in the image below there is like a dotted line with spaces in between and i want to paint an smooth line.

    @Darkcoder
     

    Attached Files:

  13. fleity

    fleity

    Joined:
    Oct 13, 2015
    Posts:
    345
    Did you try the connect hits setting?
     
  14. shahryarsheikhwork

    shahryarsheikhwork

    Joined:
    Oct 17, 2022
    Posts:
    3
    Yes i tried that still the issue was there :( the only way i was able to solve it to some extent was by slowing down the object rotation but it was effecting the feel i wanted to create
     
  15. emrecangoktepe

    emrecangoktepe

    Joined:
    Jan 26, 2019
    Posts:
    4
    hello darkcoder.

    I am working on a coloring application. The current fill feature works by drawing a certain area and filling it. (I looked at all the examples and couldn't find what I wanted.).

    I followed a method like this. Using the P3D Paint Sphere class, if the fill option is selected, if it is pressed a certain amount, I fill it by enlarging the radius.

    To give an example of my application, there is a white heart mesh on the screen. I can fill this heart mesh exactly as I want by holding down.
    But the real problem is, let's say I draw a straight line down the middle of the heart. Afterwards, I apply the fill option to the left side of the heart. It works as I want on the heart edges, but I don't want it to go to the right of the red line.

    If I want to give a more detailed example. Suppose I draw a circle in the middle of the heart. When I press and hold inside the circle in the middle of the heart, I just want to fill the circle. How can I do that? In short, when you fill in photoshop or paint, other colors do not pass over.

    By the way, the slowly growing circle filling shape allows me to get exactly the image I want.
     

    Attached Files:

  16. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,414
    The ConnectHits setting connects the previous and current mouse/finger/controller positions together using a line. However, if your object is moving or rotating when it gets painted then from the perspective of the object, these connected lines are no longer connected, so you get these gaps.

    The only way to get these lines to connect is to manually calculate the object's local space paint point, store it, and then transform the points to world space before you apply each paint. Or... just don't rotate or move your objects when painting if you want connected hits.



    What you're describing is called Flood Fill, which Paint in 3D doesn't support. It's not supported because all painting is done on the GPU, and flood fill is difficult to implement on GPUs. If it were on the CPU then flood fill is very easy to implement, but copying data from the GPU and CPU is immensely slow. Flood fill is easier to implement with compute shaders, but they have platform and device restrictions, so I'd rather not use them. Maybe in the future I will implement this, but not now.
     
  17. magglemitch

    magglemitch

    Joined:
    Dec 8, 2013
    Posts:
    112
    When using undo/redo, is it easy to set a state limit if you're using the local command copy?
     
  18. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,414
    If you don't record all local commands, then it will be impossible to undo even one step without there being a massive change to the texture. The only solution would be to implement some kind of hybrid undo system that periodically stores snapshots of the texture at specific local command depths, and then deles commands older than the snapshot. This is tricky to implement and has some performance implications, so I haven't had time to look into it.
     
  19. emrecangoktepe

    emrecangoktepe

    Joined:
    Jan 26, 2019
    Posts:
    4
    Thanks for the reply.
    I decided to solve it with a different approach. I cut the mesh of the objects I want to paint and make them behave like a separate piece. It's fine for a now
     
    Darkcoder likes this.
  20. fleity

    fleity

    Joined:
    Oct 13, 2015
    Posts:
    345
    This sounds much more like a problem which should be solved in the controller class which calls the undo command. Simply count how often the user has pressed undo and do not call it if counter is at a certain number? (at least if that case concers during runtime)
     
  21. tianlinzhang

    tianlinzhang

    Joined:
    Mar 18, 2021
    Posts:
    8
    Hello! I have used your wonderful Paint3D for several days, most of time it works on URP well but I have found one problem: if the mesh has only one color, no texture is used, P3d cannot paint anything on top of it, I have tried second UV using second overlay material following your example, it still does not work, I have also tried the this kind of surface is very common, can you provide some clues on how to handle such mesh surface? thank you very much!
     

    Attached Files:

  22. Lemovision

    Lemovision

    Joined:
    Apr 6, 2020
    Posts:
    34
    Hi I would like to share this little project I made with Paint In 3D



    https://www.elephantparade.com/digital-artbox

    Mostly worked on this last year actually, but they finally decided to release it on their website today
    So the organization is Elephant Parade, who makes painted elephant statues with artists all around the world
    They have exhibitions and sell replicas, partly contributing to conservation funds for elephants in Thailand



    And to share this creative endeavor with their fans around the world, I suggested a digital painting experience
    This relies of course heavily on Paint In 3D, to which I added plenty of tools and painting options
    Also comes with a stamp library, and options to load any picture as a stamp from user's computer
    When painting is done, Unity exports the texture to the server, which creates a link to share with friends

    https://www.elephantparade.com/view/?e=5

    Thanks Carlos for this great plugin (my only wish for it would be pen pressure support on webgl...)
    If anyone try this, make sure to use the save and share button to upload your designs
    Have a good painting day!
     
  23. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,414
    You must set the color to white, otherwise the final pixel color will always be tinted by the color you choose. The "10 Base Color" demo scene shows this.


    Wow, looks like a great use of the asset! Good job!!
     
  24. tianlinzhang

    tianlinzhang

    Joined:
    Mar 18, 2021
    Posts:
    8
    Thank you very much for your help!
     
    Darkcoder likes this.
  25. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Hi! I used this asset a couple years ago, but just today found I have a need for it in a new project. However I'm struggling with one issue: I can't get a soft brush to work, even in the Basic Setup demo.

    My P3DPaintSphere settings look like:
    upload_2022-12-2_7-48-48.png

    And the preview spot when I mouse over the model reflects this low hardness perfectly:
    upload_2022-12-2_7-49-28.png

    ...but when I actually click, I get:
    upload_2022-12-2_7-49-56.png

    For my purposes I need a very soft, extended gradient around the edges. What am I doing wrong?

    EDIT: Figured it out. In the P3DHitScreen component, I needed to change the Frequency from "Once Every Frame" to "Once On Press." I was getting over 500 fps in this scene, so my quick click was applying the paint probably dozens of times!
     
    Last edited: Dec 2, 2022
    Darkcoder likes this.
  26. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Some of the objects we are painting are fairly thin — like a box only 10 cm thick. We are painting directly using P3dCommandSphere, like so:

    Code (CSharp):
    1.             P3dCommandSphere.Instance.SetState(false, 1);
    2.             P3dCommandSphere.Instance.SetLocation(position);          
    3.             P3dCommandSphere.Instance.SetShape(Quaternion.identity, Vector3.one * outerRadius, 0);
    4.             P3dCommandSphere.Instance.SetMaterial(
    5.                 P3dBlendMode.AlphaBlend(Vector4.one),
    6.                 outerRadius / (outerRadius - innerRadius),  // hardness
    7.                 color,
    8.                 1,  // opacity
    9.                 null,   // tileTexture
    10.                 Matrix4x4.identity,     // tileMatrix
    11.                 1,      // tileOpacity
    12.                 4       // tileTransition
    13.             );
    14.             P3dCommandSphere.Instance.ClearMask();
    15.             P3dPaintableManager.SubmitAll(P3dCommandSphere.Instance, position, outerRadius, -1, default, null, null);
    Works great, except for one issue. How do I keep it from applying paint to the "back" side relative to the given position?

    I'd be happy if it just computed the angle between each triangle normal and the vector to the sphere center, and skipped all the backfaces. Is that possible?
     
  27. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,414
    As the name suggests, the sphere painting feature just paints everything within the sphere radius you specify. To make it only paint on one side you must use the slightly more advanced decal painting feature, which has front/back thresholds for the normal of the decal relative to the paint surface. Of course, a decal even with a circle texture will produce slightly different results than a sphere, but with decal's Wrapping = 1 setting it will be close. I guess there's no technical reason why I couldn't add a similar setting for sphere painting, I just wanted to make a really simple alternative component as an example.
     
  28. Christin2015

    Christin2015

    Joined:
    Dec 1, 2015
    Posts:
    48
    Hello, I have found this asset at the Unity Asset Store. Does it support Oculus VR with OpenXR, or Unity XR Interaction Toolkit? I would need it urgently. Thanks in advance for any hint.
     
  29. Likesundayqaq

    Likesundayqaq

    Joined:
    Jun 13, 2022
    Posts:
    9
    I ran into a problem when I typed an apk sample scene running on the android 10 mobile version, and when I quickly swiped the screen, the dots that appeared were incoherent
     

    Attached Files:

    • 1.jpeg
      1.jpeg
      File size:
      211.5 KB
      Views:
      93
    pamdor likes this.
  30. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,414
    The VR examples that come with Paint in 3D use Unity's old XR input system with a simple custom VR tool system. However, it's very easy to use the painting components with any other VR system, which I recommend.


    To prevent the game lagging from drawing too many times per frame, the P3dHitScreen component has the Advanced / HitLimit setting. Instead of increasing this, I recommend you enable the Advanced / ConnectHits setting. You can see demo scenes 11 and 12 for this.
     
    Christin2015 likes this.
  31. Likesundayqaq

    Likesundayqaq

    Joined:
    Jun 13, 2022
    Posts:
    9
    I have done what you said, but the result is the same,I also set each frame to be drawn multiple times
     
  32. xlarrode

    xlarrode

    Joined:
    Nov 9, 2012
    Posts:
    19
    Hello, Do you have any advice to change completely one mesh with one material texture in VR. I was considering using Paint Fill but it's not compatible with Nearby.
    Maybe with Decal and tiled texture also, but i didn't find a way right now.
    I'm on the version 1.9.3 may i need to update ?

    Thanks a lot
     
  33. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,414
    Does demo scene 12 work for you?


    PaintFill works differently because it needs to know exactly which object to paint, and this information is only available from components like HitBetween which perform a raycast. HitNearby just paints anything nearby the current Transform, so it doesn't know which object it's painting.

    To do what you want you need to use the PaintSphere/Decal component with the ReplaceOriginal or ReplaceCustom blending modes as seen in demo scenes 57 and 58.
     
  34. Likesundayqaq

    Likesundayqaq

    Joined:
    Jun 13, 2022
    Posts:
    9
    I am using version 2.0.0, is it relevant
     
  35. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,414
    Demo scene 12 is called "Connect Hits", maybe the number is different in 2.0.0.
     
  36. Likesundayqaq

    Likesundayqaq

    Joined:
    Jun 13, 2022
    Posts:
    9
    i use p3d paint decal instead of sphere,this leads to P3dMask have no effect. i need to change some parameter ?
     
  37. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,414
    Oops, I meant the "66 Mask" demo scene. This scene works with decals the same if you swap it out.

    Demo scene 17 is for local masks, which is a little different (though they should still work with decals).
     
  38. Likesundayqaq

    Likesundayqaq

    Joined:
    Jun 13, 2022
    Posts:
    9
    I did use the scene you said, but when I use p3d paint sphere, it behaved normally, and when I switched to p3d paint decal and change strtch , it was free to go beyond my limits 飞书20221210-143759.jpeg
     
  39. USFQ

    USFQ

    Joined:
    Feb 3, 2017
    Posts:
    1
    Hi! Awesome tool! Right now im using it for a VR project and it is amazing.
    I have 2 questions. The paint in some 3D objects gets very pixelated, also just some parts of the object are getting painted.
    Example: https://gyazo.com/0378edeaa870404be53839a807bf3ee7
    Also, i wanted to do a menu where you can change the painting color of the tool. I created my own tool and used te P3DHitBetween but im a little bit confused on how can i link te UI with that script so i can change the painting color.
    Thanks in advance and sorry for my english!
     
  40. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,414
    upload_2022-12-12_20-28-32.png

    upload_2022-12-12_20-29-2.png

    Works fine for me if I just replace the P3dPaintSphere with P3dPaintDecal. You can increase the mask's Stretch .x and .y to cover a larger area.

    If it still doesn't work then maybe you need to update to the latest version.


    You can increase the texture resolution from the P3dPaintableTexture component's Width and Height settings. You can also click "Analyze Mesh" to see the quality of your mesh UV data. If it's poorly done then you may be wasting a lot of texture space on nothing.

    Both P3dPaintSphere and P3dPaintDecal have the Color property, which can be set from code. You can't set colors from UI events, at least not directly.
     
  41. Abnormalia_

    Abnormalia_

    Joined:
    Jul 23, 2013
    Posts:
    128
    Cannot stop using it in various projects! Amazing asset. What approach/example would you recommend to make the bullet hit on Skinned mesh and make blood expand slowly on the hit point?
     
  42. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    I'm trying to apply decals wherever a projectile hits. When it works it works great, but in many cases it does not work — the same call to P3dPaintableManager.SubmitAll (with my P3dCommandDecal prepared in the same way) just has no effect at all. It seems to happen especially when the hit point is a long way from the camera, and/or at a shallow angle to the surface of the object. But this is despite all the arguments (position, rotation, SetState, SetLocation, SetMaterial, etc.) being very close to the same as they are when it works.

    What are the things that can cause a decal to fail to apply?

    And, should the position given in a P3dCommandDecal be on the surface, just above the surface, or something else? (Thinking that imprecision in how I calculate the hit point might be at fault here, but I'm not sure what position is correct/most reliable.)

    EDIT: Yep, our hit point was off — it seems to do nothing if the given position is within the object (which it was due to an incorrect sign). If on or above the surface, it works.
     
    Last edited: Dec 21, 2022
    Darkcoder likes this.
  43. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,414
    It depends on the exact effect you're after, but in general this kind of thing is very difficult to do. One approach is to paint a smooth blood brush that fades out toward the edges. You would then use another shader to gradually increase the opacity of this blood over time until it reaches maximum opacity. For non-animated meshes the more obvious approach is to use the 'Live Painting' setup with a blood decal that increases in scale that then gets applied when it reaches maximum size, but on an animated mesh this would look weird because the decal would appear to float above the mesh unless you attached it to the nearest bone or something.


    The decal has a thickness/depth based on your Scale.z * Radius setting, so you can apply it on the surface, or above/below, as long as it's within this boundary. By default the Scale and Radius are 1, so the extents of the decal will be -.5 to .5. The opacity of the decal pixels will fade as they approach the fear/far edges of the decal, and the rate of this fade depends on the Hardness setting. If you have Wrapping set to 1 then the x/y scale of the decal will also decrease as it approaches these edges, but if it's 0 then it will use a planar projection. The decal will also fade based on the Normal settings depending on the angle between the surface and the decal's z direction.
     
  44. Abnormalia_

    Abnormalia_

    Joined:
    Jul 23, 2013
    Posts:
    128
    I see, What I did here ( 1:45 its visible well ) is to spawn a ball with a collision at the hit point, It does a job but the effect is instant. Maybe I can apply it for some time?

     
  45. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,414
    Looks cool! Yeah, it depends how you're applying the paint right now. For example the P3dHitNearby component can apply at the current Transform position, so you could make it so at the bullet impact point you spawn a prefab with P3dHitNearby + P3dPaintDecal, and with a custom script you could make it so over time the radius increases, until it eventually gets destroyed. As I mentioned before, you would want this GameObject to be attached to the nearest bone, so that the blood follows the mesh as it animates. It won't follow it exactly in all situations, but it might look good enough.
     
  46. Tu-Le

    Tu-Le

    Joined:
    Jun 5, 2015
    Posts:
    14
    Hello, just found this package and its really easy to use. But im facing a minor issue or maybe i wrong at setup. But sometime the color counter script doesnt work right(i just pain 1 sphere but color counter move up to more than 20000 pixel. Can you if possible point me where i wrong
     
  47. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,414
    How many pixels are you expecting to see? Without a video or something I have no idea if this is a normal number or not. It also depends on the resolution of your texture, and where you paint.
     
  48. Tu-Le

    Tu-Le

    Joined:
    Jun 5, 2015
    Posts:
    14
    normally only 2-300 pixel on one draw in my game. and it's only happen with some specific color. I just check and the texturepainter have nothing draw before
     
  49. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,414
    Not enough information. The sphere in Unity his a higher pixel density at the poles, so if you paint there it can paint many more pixels than the equator.
     
  50. Tu-Le

    Tu-Le

    Joined:
    Jun 5, 2015
    Posts:
    14
    ok i'll try to make a video