Code Monkey home page Code Monkey logo

Comments (11)

candycat1992 avatar candycat1992 commented on May 21, 2024

其实在定义切线空间的时候,Z轴方向即切线方向是有无数条的,建模软件在计算切线的时候会选择和UV展开方向相同的那个方向作为切线方向,这样的选择导致如果直接用法线插乘切线的方向也一定会和UV相关,但这可能不是模型的法线方向(可能是反的),因此w会再存储一个信息。

from unity_shaders_book.

777777716 avatar 777777716 commented on May 21, 2024

@candycat1992
书中说到“w分量决定副切线的方向性”,但如你所说,叉乘的结果可能是相反的,也可能是正确的。
又依据书中给出的计算方法,叉乘结果 * w = 正确结果
1.叉乘结果正确 -> w = 1
2.叉乘结果相反 -> w = -1
w在存储值时事先做了处理,预知了叉乘结果,并将对应“修正值”存储。
所以w并不能决定副切线的方向性,而应该是修正因子(标量)。

from unity_shaders_book.

candycat1992 avatar candycat1992 commented on May 21, 2024

我不明白你的意思,在我看来乘以w决定了副切线到底取哪个方向,这里说的方向性不是说左手性右手性,而是说方向,有什么不对么?

from unity_shaders_book.

777777716 avatar 777777716 commented on May 21, 2024

@candycat1992
1.w受什么控制(从何而得)
2.w可能的取值
3.叉乘方向 * w = 正确方向
4.
if(叉乘方向 == 正确方向){
//w为1
}else{
//w为-1
}
5.在我看来w已经是事先知道的,那么意味着这就预知了“叉乘方向和正确方向之间的关系”。
6.如果仅仅知道w就可以知道正确方向,那“.叉乘方向 * w = 正确方向”这个想法就是错的,打个比方,一维方向,w表示方向(-1或1),那应该是|A| * w = B,而不是 A * w = B

from unity_shaders_book.

candycat1992 avatar candycat1992 commented on May 21, 2024

是不是有些在概念上太钻牛角尖了?叉乘的结果会得到一个方向,然后w分量又进一步决定了最终的正确方向,没有人说仅仅知道w就可以知道正确方向呀~因为我对建模软件不够了解,因此我没法跟你解释清楚它们到底是怎么生成的。如果你这么想了解可以去建模软件自己生成一个法线贴图试一下呗。你的第5点我没看出来和我的观点有任何冲突的地方啊,本来就都是已知的,建模软件对法线纹理的生成是一个encode的过程,而我们在shader里做的是一个decode的工程,这样说你是不是会明白一些

from unity_shaders_book.

777777716 avatar 777777716 commented on May 21, 2024

@candycat1992
抱歉,这牛角确实钻得太深了。
我上一条回复内容只是简述了一下我的思考顺序和逻辑,感觉自己直接用类代码的东西可能更容易表述意思,并不是提问。
其实理论我都懂了,主要是书中说到“w分量决定副切线的方向性”,我将这句话理解成 “w分量代表了副切线的方向性”,然后认为这句话与实际情况不符。
给你带来困扰,实在不好意思

from unity_shaders_book.

candycat1992 avatar candycat1992 commented on May 21, 2024

没关系~说不定下一次钻牛角尖就能发现新的东西呀

感谢对书的支持 :)

from unity_shaders_book.

xwc2021 avatar xwc2021 commented on May 21, 2024

@777777716

這個問題我之前剛好有測試過

可以把下面這個script放到顯示你模型的GameObject上。

public class PeekGeo : MonoBehaviour {

    public Transform r;//自己準備1個紅色球
    public Transform g;//自己準備1個綠色球
    public Transform b;//自己準備1個藍色球
    public void createGS()
    {
        Mesh mesh = GetComponent<MeshFilter>().sharedMesh;

        int triCount = mesh.triangles.Length / 3;
        int[] triangles = mesh.triangles;

        Vector4[] tangents = mesh.tangents;
        Vector3[] normals = mesh.normals;
        Vector3[] vertices = mesh.vertices;
        for (int i = 0; i < triCount; i++)
        {
            //只查看你要的索引資料
            //if (i != 33 && i != 18)
            //    continue;

            int v0 = triangles[3 * i];
            int v1 = triangles[3 * i + 1];
            int v2 = triangles[3 * i + 2];





            Vector3 center = transform.position + vertices[v0] ;
            Instantiate(r, center, Quaternion.identity, this.transform);

            //紅球指向綠球就是normal的方向
            Vector3 normal = center + normals[v0];
            Instantiate(g, normal, Quaternion.identity, this.transform);

            //紅球指向藍球就是tangent的方向
            Vector3 temp = new Vector3(tangents[v0].x, tangents[v0].y, tangents[v0].z);
            Vector3 tangent = center + temp;
            Transform obj=Instantiate(b, tangent, Quaternion.identity, this.transform);
            obj.name = obj.name + "[("+i+")tangent.w=" + tangents[v0].w + "]";

            center = transform.position + vertices[v1];
            Instantiate(r, center, Quaternion.identity, this.transform);

           

            center = transform.position + vertices[v2];
            Instantiate(r, center, Quaternion.identity, this.transform);

           

        }

    }
}

再把下面這個script放到路徑Assets/Editor/的資料夾下。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(PeekGeo))]
public class PeekGeoEditor : UnityEditor.Editor
{

    PeekGeo behavior;
    void OnEnable()
    {
        behavior = (PeekGeo)target;
    }

    public override void OnInspectorGUI()
    {
        DrawDefaultInspector();

        if (GUILayout.Button("createGS"))
        {
            behavior.createGS();
        }

    }
}

(一個三角形有3個頂點ABC,它們的uv分別是abc,頂點順序是A->B->C)
測試後應該可以發現,如果你的模形裡的三角形存放的uv是正常的(abc的uv順序是順時針)
那麼tangent的w都是-1。

以下解釋原因:
3dsmax是使用右手座標來觀看和建立資料,在3dsmax裡:
(這裡是用右手法則作cross)
(一)當三角型的uv是正常的(abc的uv順序是順時針),tangent的w會是1,在3dsmax裡計算 cross (N,T)*tangent.w就可得到正確的BN。
(二)當三角型的uv是鏡射的(abc的uv順序是逆時針),tangent的w會是-1,在3dsmax裡計算 cross (N,T)*tangent.w就可得到正確的BN。

//////////////////////////分隔線

再來看看當模型從3dsmax被放入unity會怎麼被處理:

在3dsmax是z軸向上,假設在3dsmax裡建了1個模型,這個模型是一隻打開的右手掌,而且中指的方向指向世界的z軸,那這個手掌在3dsmax裡看起來就是立起來的(手心指向負y軸)。
unity是左手座標(在還沒到view space前都是),而且y軸向上.

「如果把3dsmax建的右手掌,沒作任何處理」就放進unity render,畫出來會是什麼?
你可以自己在筆記本上畫看看...
(具體的作法是,畫3軸和手簡單的輪廓,然後想像當這裡的資料,被放進那樣的3軸,會發生什麼事)

應該會發現1個「左」手掌平放在世界上,而且手背是向上的(在unity裡Y軸向上)
變成左手了,而且是平放的,這樣看起來跟3dsmax裡完全不一樣阿怎麼辦?

所以Unity「可以」對資料作下面這樣的處理
(1)先定義這樣的3軸對從3dsmax來的模型資料作一次轉換
X軸 (-1,0,0)
Y軸 (0,1,0)
Z軸 (0,0,1)
這樣一來至少可以得到平放的「右」手掌

(2)然後他對物件transform的x軸旋轉了-90度
這樣右手掌就又立起來了。

至於tangent,在Unity裡可以選擇[import]或是[cauculate tangent space]。
(tangent可以透過uv和vertex算出來)

不管選了那一個,因為有發生(1)這個轉換,所以normal和tangent在進入Unity後也被改變了。
這時在shader(用左手法則)裡作 cross (N,T)得到的BT,就需要乘上-1。
(你可以自己在筆記本上畫看看)
所以原本在3dsmax裡tangent.w是1的,到了unity就變成-1了。

//////////////////////////分隔線

順道在maya測試了一下發現maya是右手座標,但在maya裡向上是Y軸。
所以從maya滙入unity的資料,就不需要再對物件transform的x軸旋轉90度了。

//////////////////////////分隔線

「abc的uv順序是順時針」是指:
https://goo.gl/photos/yn9JXA2DLZrhNrwm9

//////////////////////////分隔線

3dsmax如何判定tangent.w是正還是負:
https://goo.gl/photos/DtRctCWYnjrmyjKh7
https://goo.gl/photos/f8WbG6MBdXYJQsWU9

//////////////////////////分隔線

如何計算tanget:
(只是用代數去推導,還沒實際帶資料進去驗證)
https://goo.gl/photos/DnrdqWmZRnv9uGsX8
https://goo.gl/photos/SKd5muzefZr1CCgS9

from unity_shaders_book.

xwc2021 avatar xwc2021 commented on May 21, 2024

又發現一種情況
當在3dsmax設定smooth時,頂點上的法向量Normal會由鄰近三角形原來的法向量作平均(大概吧)。
放入Unity測試後,發現這時Tangnet不再相切於平面了。
https://goo.gl/photos/YSPPdbzWmUaR1w4x5
(好吧其實是還蠻普遍情況,大多的模型都會作smooth)

google發現了這個
https://gist.github.com/aras-p/2843984

看起來如果有模型是有smooth的,會這樣:
void CreateTangentSpaceTangentsUnsplit..
先算完每個面的tangent和binormal
之後對每個頂點,找出相鄰頂點(meshConnection.vertices)的tangent和binormal作平均
(相鄰頂點是指所有position一樣的頂點,而這些頂點就存在於相鄰面上)
(這時的tanget和binormal未必會和normal垂直,所以要想辦法重新正交化)

(normal是建模軟體那傳過來的,建模軟體裡應該也是作平均)
最後一步,再比較cross(normal,tanent)的方向和真正的binormal有沒有一致來決定tangent.w是1還是負-1

但是為什麼可以直接對tanget和binormal作平均呢?

當沒有smooth:
因為tangent、binormal會和uv相關,可能導致cross(T,N)和BN方向不同。
所以只要在方向上作比較,就可以知道tanget.w是1或-1
而之後當shader在內插三角形上的T、N、BN時,T、BN是相切於三角形的,內插出來的T、BN也會和原來的三角形相切。

可是當smooth時:
直接把相鄰tanget和binormal,normal取平均,最後再正交化,那之前為了和uv相關所作的計算,還會有意義嗎?
而之後當shader在內插三角形時,3頂點上的T、BT並沒和三角形相切,那這樣內插出來的T、BN不是也很奇怪嗎?

from unity_shaders_book.

xwc2021 avatar xwc2021 commented on May 21, 2024

再可視化一次頂點的tangent,看看三角形內插時T、N、BN會怎麼變化
https://goo.gl/photos/kdht3gsNiRrDnxLt7
(因為T、N、BN在內插下還是平順的、連續的變化,所以肉眼也看不出有何異樣吧?)

from unity_shaders_book.

xwc2021 avatar xwc2021 commented on May 21, 2024

當沒有smooth時,4個頂點上的normal變化,可以想像成1張名片
當smooth時,4個頂點上的normal變化,可以想像成你把4個手指放在名片上,向內擠壓

from unity_shaders_book.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.