Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
6
Question by Lemon · Feb 08, 2011 at 10:18 PM · textureraycastpaintingsetpixelstexturecoord

Painting on a texture without crossing mesh triangle.

I am painting onto a mesh with the mouse. Wherever the user clicks, the current colour will be painted in a circular shape of about 32 pixels, centered around the click position. To find the position I have been using a Raycase:

RaycastHit hitInfo;
Ray ray = Camera.main.ScreenPointToRay (inputPos);
if (Physics.Raycast (ray, out hitInfo, Mathf.Infinity, planeMask)) {
    Vector2 hit = hitInfo.textureCoord;

which can be combined with texture.SetPixels() to change the texture to the correct colour.

My problem is this:

I want to only change the colour for the pixels which lie on the triangle I have hit by the raycast. I realize I can get the triangle index from the RaycastHit using hitInfo.triangleIndex which in turn can be used to calculate the pixel positions of each of the vertices in the triangle. But how do I restrict which pixels I want to update and send back to 'texture.SetPixels()'?

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
6
Best Answer

Answer by Bunny83 · Feb 09, 2011 at 02:15 AM

I just wrote my own barycentric calculation routine. It's not optimised and don't have error checking/handling, but it works great in my tests.

 Vector3 GetBarycentric (Vector2 v1,Vector2 v2,Vector2 v3,Vector2 p)
 {
     Vector3 B = new Vector3();
     B.x = ((v2.y - v3.y)*(p.x-v3.x) + (v3.x - v2.x)*(p.y - v3.y)) /
         ((v2.y-v3.y)*(v1.x-v3.x) + (v3.x-v2.x)*(v1.y -v3.y));
     B.y = ((v3.y - v1.y)*(p.x-v3.x) + (v1.x - v3.x)*(p.y - v3.y)) /
         ((v3.y-v1.y)*(v2.x-v3.x) + (v1.x-v3.x)*(v2.y -v3.y));
     B.z = 1 - B.x - B.y;
     return B;
 }
 
 bool InTriangle(Vector3 barycentric)
 {
     return (barycentric.x >= 0.0f) && (barycentric.x <= 1.0f)
         && (barycentric.y >= 0.0f) && (barycentric.y <= 1.0f)
         && (barycentric.z >= 0.0f); //(barycentric.z <= 1.0f)
 }

GetBarycentric just returns the same value you get from hit.barycentricCoordinate, but for any point you like. The point you offer have to be in uv coordinates. Just check every "pixel" you want to draw. If your "circular shape" is generated in pixels i guess that should work too but you have to use the pixelcoordinates instead of uvs for the 3 vertex positions.

 Mesh m = hit.collider.GetComponent<MeshFilter>().mesh;
 int index = hit.triangleIndex*3;            
 Vector2 uv1 = m.uv[m.triangles[index + 0]];
 Vector2 uv2 = m.uv[m.triangles[index + 1]];
 Vector2 uv3 = m.uv[m.triangles[index + 2]];
 
 Vector2 P = hit.textureCoord;
 
 Vector3 B = GetBarycentric(uv1,uv2,uv3,P);
 
 Debug.Log("hit:" + hit.barycentricCoordinate);
 Debug.Log("calculated:" + B);
 Debug.Log("inside triangle:" + InTriangle(B));

InTriangle is not tested, but it should work. z don't have to be tested for lower 1 since it's calculated out of x and y.

I hope that helps a bit ;) It's a pity that Unity don't offers a barycentric conversion routine. I just adapted the wikipedia formular

Comment
Add comment · Show 8 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Lemon · Feb 10, 2011 at 01:43 AM 0
Share

Thanks heaps, especially for the detailed example!

avatar image Lemon · Feb 11, 2011 at 01:02 AM 0
Share

I've mostly finished the implementation and the concept works. Just wanted to note that due to rounding errors it is possible that a hit coordinate ends up with a barycentric coordinate that is very slightly under 0.0f or over 1.0f. In this case a pixel may not be associated with any triangle. A quick fix which works in my situation was to simply add a alight error tollerance: (barycentric.x >= 0.0f - errorTol) && (barycentric.x <= 1.0f + errorTol) etc.

avatar image Bunny83 · Feb 11, 2011 at 12:37 PM 0
Share

Well, the float class have a special const that represents the smallest float value. float.Epsilon can be used to extend the range to reduce the precision problem. In the end i'm sure that one epsilon isn't enough. So setting up your own error tolerance is the best way ;)

avatar image ina · Nov 25, 2011 at 08:31 AM 0
Share

how do you convert raycast hit coordinates to uv coordinates:

avatar image Bunny83 · Nov 25, 2011 at 11:55 AM 0
Share

@ina: You don't have to convert anything. RaycastHit contains the texture coordinates of the point you've hit. This question was about testing if the hit coordinate is within a certain triangle.

You just need:

 hit.textureCoord

which holds the uv-coordinate of your hit point.

Show more comments

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

3 People are following this question.

avatar image avatar image avatar image

Related Questions

RaycastHit2D hit to texture coordinate 0 Answers

Using OpenGL instead of SetPixels-Apply 1 Answer

How can I tint a texture? 0 Answers

Painting on Textures 2 Answers

Raycast questions 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges