简体   繁体   中英

How to render the normal map in Unity and Three.js with shader respectively?

I want to render the normal map in three.js and Unity,but i find the final output is different.

the Shader used in Unity as follows:

Shader "Unlit/normal"
{
Properties
{
    _MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
    Tags { "RenderType"="Opaque" }
    LOD 100

    Pass
    {
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        // make fog work
        #pragma multi_compile_fog

        #include "UnityCG.cginc"

        struct appdata
        {
            float4 vertex : POSITION;
            float2 uv : TEXCOORD0;
            float3 normal:NORMAL;
        };

        struct v2f
        {
            float2 uv : TEXCOORD0;
            UNITY_FOG_COORDS(1)
            float4 vertex : SV_POSITION;
            fixed4 color : COLOR;
        };

        sampler2D _MainTex;
        float4 _MainTex_ST;

        v2f vert (appdata v)
        {
            v2f o;
            o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
            o.color.xyz = mul(_Object2World, v.normal)*0.5+0.5 ;
            o.color.w = 1.0f;
            return o;
        }

        fixed4 frag (v2f i) : SV_Target
        {

            return i.color; //output normal
        }
        ENDCG
    }
}

}

In three.js,i use the MeshNormalMaterial to render normal map,but it is different from rendered in Unity.

Unity output Unity输出

threejs output threejs输出

I think the problem is that you are transforming the normal using the unity_ObjectToWorld matrix, which also includes the scale. This can result in scaled or sheared normals, which might be what's happening considering how much darker the Unity version looks. My advice is to instead use the built-in function included in UnityCG.cginc:

o.color.rgb = UnityObjectToWorldNormal(v.normal);

The normal should ideally be normalized in the fragment function too, since the hardware interpolators won't guarantee that your values stay normalized. Also, your shader has a bunch of extra stuff in it which isn't really needed - you can remove the following lines:

#pragma multi_compile_fog
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
sampler2D _MainTex;
float4 _MainTex_ST;

EDIT: Notice also that it seems like MeshNormalMaterial renders normals in view-space and not in world-space. This is how you transform a world normal into view space:

float3 viewNormal = normalize(mul((float3x3)UNITY_MATRIX_V, worldNormal));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM