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
5
Question by sanryoga · Nov 16, 2009 at 02:53 PM · importvectortangent

Calculating Tangents (Vector4)

Hello!

I'm writing an importer and I would like to know if there's a way to generate tangents from my vertex,uvs and normals. Because mesh.RecalculateNormals isn't giving me the result I want.

thx!

sanryoga

Comment
Add comment · Show 1
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 Dazzid · Sep 18, 2014 at 02:46 PM 0
Share

Hi, In c# I have an error. It says IndexOutOfRangeException in the Vector2 w1 = uv[i1]; Why? Thanks for the help

5 Replies

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

Answer by Aras · Nov 16, 2009 at 05:28 PM

I assume you know what tangent space is then (in short: it's a surface-relative coordinate system, and consists of tangent, bitangent and normal; mostly used for normal mapped shaders).

Tangents in Unity are Vector4. Three components (xyz) of it store the tangent vector itself, and w component is used to determine "handedness" of the bitangent. Bitangent (sometimes called binormal) is always computed from tangent and normal. In Cg shader code:

float3 binormal = cross (normal, tangent.xyz) * tangent.w;

Now, computing tangents needs a texture coordinate set (UVs). There's actually tons of resources for that, e.g. Lengyel's approach is a good starting point. NVIDIA also has a NVMeshMender library that does it. Calculating tangents can get quite nasty when you want to make it fully robust.

Comment
Add comment · Show 1 · 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 Zac - Midnight Studios · May 11, 2015 at 07:45 PM 0
Share

I've gotten some pretty awful results using the various scripts on this page. Aras posted the code Unity uses when importing meshes at https://gist.github.com/aras-p/2843984 but I'm having some trouble converting it to C#. I' not sure for example, what polygonSizes or faceOffsets are, among other things.

avatar image
11

Answer by N1nja · May 29, 2010 at 03:47 PM

and the same script in C#..

class TangentSolver { public static void Solve(Mesh mesh) { int triangleCount = mesh.triangles.Length / 3; int vertexCount = mesh.vertices.Length;

     Vector3[] tan1 = new Vector3[vertexCount];
     Vector3[] tan2 = new Vector3[vertexCount];

     Vector4[] tangents = new Vector4[vertexCount];

     for(long a = 0; a < triangleCount; a+=3)
     {
         long i1 = mesh.triangles[a+0];
         long i2 = mesh.triangles[a+1];
         long i3 = mesh.triangles[a+2];

         Vector3 v1 = mesh.vertices[i1];
         Vector3 v2 = mesh.vertices[i2];
         Vector3 v3 = mesh.vertices[i3];

         Vector2 w1 = mesh.uv[i1];
         Vector2 w2 = mesh.uv[i2];
         Vector2 w3 = mesh.uv[i3];

         float x1 = v2.x - v1.x;
         float x2 = v3.x - v1.x;
         float y1 = v2.y - v1.y;
         float y2 = v3.y - v1.y;
         float z1 = v2.z - v1.z;
         float z2 = v3.z - v1.z;

         float s1 = w2.x - w1.x;
         float s2 = w3.x - w1.x;
         float t1 = w2.y - w1.y;
         float t2 = w3.y - w1.y;

         float r = 1.0f / (s1 * t2 - s2 * t1);

         Vector3 sdir = new Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
         Vector3 tdir = new Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);

         tan1[i1] += sdir;
         tan1[i2] += sdir;
         tan1[i3] += sdir;

         tan2[i1] += tdir;
         tan2[i2] += tdir;
         tan2[i3] += tdir;
     }


     for (long a = 0; a < vertexCount; ++a)
     {
         Vector3 n = mesh.normals[a];
         Vector3 t = tan1[a];

         Vector3 tmp = (t - n * Vector3.Dot(n, t)).normalized;
         tangents[a] = new Vector4(tmp.x, tmp.y, tmp.z);

         tangents[a].w = (Vector3.Dot(Vector3.Cross(n, t), tan2[a]) < 0.0f) ? -1.0f : 1.0f;
     }

     mesh.tangents = tangents;
 }

}

Comment
Add comment · Show 6 · 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 Jon-Martin · Jan 24, 2011 at 11:38 AM 5
Share

Spent a couple of days trying to find a different script to the c# one above, as it didn't work!!! Simply replace:

int triangleCount = mesh.triangles.Length / 3;

with

int triangleCount = mesh.triangles.Length;

now it will work, dohhh!

avatar image Gillissie · Jun 20, 2011 at 05:45 PM 0
Share

Thanks for the code. Gotta wonder why Unity doesn't have this as a function like the RecalculatNormals() function.

avatar image Julien-Lynge · Nov 30, 2011 at 05:45 PM 0
Share

Is this code excessively slow for anyone else? I'm trying to use it to calculate tangents for a mesh with 4096 triangles (12,288 verts) and it's taking 1.4 seconds.

avatar image Julien-Lynge · Nov 30, 2011 at 06:04 PM 5
Share

I was able to speed the calculation up by a factor of 140 by a combination of suggestions from the related forum post (http://forum.unity3d.com/threads/38984-How-to-Calculate-$$anonymous$$esh-Tangents/page2)

 public static void calculate$$anonymous$$eshTangents($$anonymous$$esh mesh)
 {
     //speed up math by copying the mesh arrays
     int[] triangles = mesh.triangles;
     Vector3[] vertices = mesh.vertices;
     Vector2[] uv = mesh.uv;
     Vector3[] normals = mesh.normals;

     //variable definitions
     int triangleCount = triangles.Length;
     int vertexCount = vertices.Length;

     Vector3[] tan1 = new Vector3[vertexCount];
     Vector3[] tan2 = new Vector3[vertexCount];

     Vector4[] tangents = new Vector4[vertexCount];

     for (long a = 0; a < triangleCount; a += 3)
     {
         long i1 = triangles[a + 0];
         long i2 = triangles[a + 1];
         long i3 = triangles[a + 2];

         Vector3 v1 = vertices[i1];
         Vector3 v2 = vertices[i2];
         Vector3 v3 = vertices[i3];

         Vector2 w1 = uv[i1];
         Vector2 w2 = uv[i2];
         Vector2 w3 = uv[i3];

         float x1 = v2.x - v1.x;
         float x2 = v3.x - v1.x;
         float y1 = v2.y - v1.y;
         float y2 = v3.y - v1.y;
         float z1 = v2.z - v1.z;
         float z2 = v3.z - v1.z;

         float s1 = w2.x - w1.x;
         float s2 = w3.x - w1.x;
         float t1 = w2.y - w1.y;
         float t2 = w3.y - w1.y;

         float r = 1.0f / (s1 * t2 - s2 * t1);

         Vector3 sdir = new Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
         Vector3 tdir = new Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);

         tan1[i1] += sdir;
         tan1[i2] += sdir;
         tan1[i3] += sdir;

         tan2[i1] += tdir;
         tan2[i2] += tdir;
         tan2[i3] += tdir;
     }


     for (long a = 0; a < vertexCount; ++a)
     {
         Vector3 n = normals[a];
         Vector3 t = tan1[a];

         //Vector3 tmp = (t - n * Vector3.Dot(n, t)).normalized;
         //tangents[a] = new Vector4(tmp.x, tmp.y, tmp.z);
         Vector3.OrthoNormalize(ref n, ref t);
         tangents[a].x = t.x;
         tangents[a].y = t.y;
         tangents[a].z = t.z;

         tangents[a].w = (Vector3.Dot(Vector3.Cross(n, t), tan2[a]) < 0.0f) ? -1.0f : 1.0f;
     }

     mesh.tangents = tangents;
 }
avatar image martinz32 · May 22, 2012 at 04:37 PM 0
Share

The above code doesn't work in Unity 3.5. For some reason, tangents[0]=(NaN, NaN, NaN) which messes up the bump map of the first triangle. Rest of the tangents work perfectly.

EDIT: fixed by starting vertices array on 1 ins$$anonymous$$d of 0. I don't know why that is though...

Show more comments
avatar image
6

Answer by noontz · Mar 30, 2010 at 06:00 PM

Here is the javascript derived from the link above & developed with help from this thread http://forum.unity3d.com/viewtopic.php?t=41476


/* Derived from Lengyel, Eric. Computing Tangent Space Basis Vectors for an Arbitrary Mesh. Terathon Software 3D Graphics Library, 2001. http://www.terathon.com/code/tangent.html */

class TangentSolver { function TangentSolver(theMesh : Mesh) { vertexCount = theMesh.vertexCount; vertices = theMesh.vertices; normals = theMesh.normals; texcoords = theMesh.uv; triangles = theMesh.triangles; triangleCount = triangles.length/3; tangents = new Vector4[vertexCount]; tan1 = new Vector3[vertexCount]; tan2 = new Vector3[vertexCount]; tri = 0; for ( i = 0; i < (triangleCount); i++) { i1 = triangles[tri]; i2 = triangles[tri+1]; i3 = triangles[tri+2];

         v1 = vertices[i1];
         v2 = vertices[i2];
         v3 = vertices[i3];

         w1 = texcoords[i1];
         w2 = texcoords[i2];
         w3 = texcoords[i3];

         x1 = v2.x - v1.x;
         x2 = v3.x - v1.x;
         y1 = v2.y - v1.y;
         y2 = v3.y - v1.y;
         z1 = v2.z - v1.z;
         z2 = v3.z - v1.z;

         s1 = w2.x - w1.x;
         s2 = w3.x - w1.x;
         t1 = w2.y - w1.y;
         t2 = w3.y - w1.y;

         r = 1.0 / (s1 * t2 - s2 * t1);
         sdir = new Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
         tdir = new Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);

         tan1[i1] += sdir;
         tan1[i2] += sdir;
         tan1[i3] += sdir;

         tan2[i1] += tdir;
         tan2[i2] += tdir;
         tan2[i3] += tdir;

         tri += 3;
     }

     for (i = 0; i &lt; (vertexCount); i++)
     {
         n = normals[i];
         t = tan1[i];

         // Gram-Schmidt orthogonalize
         Vector3.OrthoNormalize( n, t );

         tangents[i].x  = t.x;
         tangents[i].y  = t.y;
         tangents[i].z  = t.z;

         // Calculate handedness
         tangents[i].w = ( Vector3.Dot(Vector3.Cross(n, t), tan2[i]) &lt; 0.0 ) ? -1.0 : 1.0;
     }       
     theMesh.tangents = tangents;
 }

}

Comment
Add comment · Show 1 · 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 DaveA · Jul 25, 2011 at 11:34 PM 0
Share

Why not also post this to the Script Wiki?

avatar image
5

Answer by cyble · Jul 07, 2012 at 01:50 PM

In the C# version: to prevent corrupt tangents, make sure you catch the division by zero as it will result in a NaN. You can do this by replacing the calculation of r with something like this:

 float div = s1 * t2 - s2 * t1;
 float r = div == 0.0f ? 0.0f : 1.0f / div;
Comment
Add comment · Show 1 · 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 Steven-1 · Dec 28, 2012 at 01:10 PM 0
Share

aha, thanks, yeah, the script doesn't work properly otherwise

avatar image
0

Answer by dvorm · Jul 09, 2019 at 06:45 AM

Thank you for this one. It works fine even today.

Both triangleCount vertexCount and are int while a is long. That seems inconsistent. Can anyone explain?

Comment
Add comment · 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

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

9 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Problem importing baked normal map from 3ds max 1 Answer

Tangent Space Normal Map to World Space Normal Vector in C# Script 0 Answers

Find tangent points on circle 0 Answers

Normal mapping mirrored UVs? 2 Answers

Generate cylindrical mesh around 3D Catmull-rom spline 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