- Home /
WorldNormalVector(IN, o.Normal): how is it calculated?
Hi all, I'd like to know how does unity create the normal vector resulting from the world space normal vector and the tangent space normal map: where can I find any documentation?
Thanks
The reason you are not getting an answer might be because it's not very clear what you're asking. At least I have no clue. What are the world space normal vector and tangent space normal map you're talking about?
Same here, I think only god (that you begged for help) can hear what you mean.
yea, sorry if I did not write all the infos
So, in the cg shader language there's a function : link text
float3 worldNormal; INTERNAL_DATA - will contain world normal vector if surface shader writes to o.Normal. To get the normal vector based on per-pixel normal map, use WorldNormalVector (IN, o.Normal).
just how is this computed? I ask this because I noticed it reduces a lot the number of variables I can use
You could take a look at the compiled shader... I can't see the code in any of the includes.
yes, I searched it in the compiled shader and in the cginc files, but it's not here. I think this is a internal function :(
However, does someone know how to create a inverse matrix given one?
Thanks :D
Answer by Bas-Smit · Feb 24, 2014 at 10:18 PM
So I know Im late to the party, but maybe this will help someone someday. WorldNormalVector is a define that applies a rotation matrix to a vector, you can find it by opening a compiled shader:
#define WorldNormalVector(data,normal) fixed3(dot(data.TtoW0,
dot(data.TtoW1,normal), dot(data.TtoW2,normal))
The TtoW values come from the vertex program output when you use INTERNAL_DATA, it is calculated as follows:
TANGENT_SPACE_ROTATION;
o.TtoW0 = mul(rotation, ((float3x3)_Object2World)[0].xyz)*unity_Scale.w;
o.TtoW1 = mul(rotation, ((float3x3)_Object2World)[1].xyz)*unity_Scale.w;
o.TtoW2 = mul(rotation, ((float3x3)_Object2World)[2].xyz)*unity_Scale.w;
TANGENT_SPACE_ROTATION is a define that can be found in UnityCG.cginc:
// Declares 3x3 matrix 'rotation', filled with tangent space basis
#define TANGENT_SPACE_ROTATION \
float3 binormal = cross( v.normal, v.tangent.xyz ) * v.tangent.w; \
float3x3 rotation = float3x3( v.tangent.xyz, binormal, v.normal )
Answer by OP_toss · Sep 10, 2013 at 08:55 PM
I learned a bit answering this :)
So basically you can do it almost the same way you'd do it for vertices. There's an _ObjectToWorld matrix.
float3 worldPosition = mul( _Object2World, float4( v.vertex, 1.0 ) ).xyz;
The problem is we're dealing with vectors and not positions, so we don't want to account for the translation component of the matrix. So we need to ignore the 4th columns of the matrix or the vector. So all you do is cast your vertex normal to a float4 with zero as its w component.
float3 worldNormal = mul( _Object2World, float4( v.normal, 0.0 ) ).xyz;
So a full test shader looks something like this:
Shader "Custom/Display Normals" {
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f {
float4 pos : SV_POSITION;
float3 wNormal : COLOR0;
};
v2f vert (appdata_base v)
{
v2f o;
o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
o.wNormal = mul( _Object2World, float4( v.normal, 0.0 ) ).xyz;
return o;
}
half4 frag (v2f i) : COLOR
{
return half4 (i.wNormal, 1);
}
ENDCG
}
}
Fallback "VertexLit"
}
Credit to Patapom for the answer on a Unity forum.
Thanks for the information, but I already knew that. I am trying to understand the code beghind the function worldnormalvector( IN, o. Normal)
Answer by GearKlik · Jul 14, 2017 at 06:49 PM
Unity 5.6 Update
In UnityCG.cginc you'll find:
// Transforms direction from object to world space
inline float3 UnityObjectToWorldDir( in float3 dir )
{
return normalize(mul((float3x3)unity_ObjectToWorld, dir));
}
// Transforms direction from world to object space
inline float3 UnityWorldToObjectDir( in float3 dir )
{
return normalize(mul((float3x3)unity_WorldToObject, dir));
}
// Transforms normal from object to world space
inline float3 UnityObjectToWorldNormal( in float3 norm )
{
#ifdef UNITY_ASSUME_UNIFORM_SCALING
return UnityObjectToWorldDir(norm);
#else
// mul(IT_M, norm) => mul(norm, I_M) => {dot(norm, I_M.col0), dot(norm, I_M.col1), dot(norm, I_M.col2)}
return normalize(mul(norm, (float3x3)unity_WorldToObject));
#endif
}
Using normals in a vertex shader:
struct app2vert
{
...
float4 normal : NORMAL; // Use Fixed4?
...
};
...
float3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
float localSpaceMask = dot(v.normal, float4(myVector.xyz,0));
float WorldSpaceMask = dot(worldNormal, float4(myVector.xyz,0));
Your answer
Follow this Question
Related Questions
Problem of color in custom vertex shader 0 Answers
how can i catch the sky box and do a reflection in object 0 Answers
Why does my shader only shade objects based on their normals in the X axis? 1 Answer
Why changing the normal affects the viewDir? 1 Answer
How to add Bump/Normal Map to surface shader? (CG) 0 Answers