Hi lovers of Shaders and Materials. The last days playing with unity i found something that i don't know if is a Unity error, a Shader error or what's the problem with it. I have a character on screen with Diffuse and Normal Map, the shader is "Bumped Specular", the model looks great but in the game im making, im use a negative size (-X) to turn my player and play all the animations in a mirror form. Imagine like a fighting game, P1 vs P2, where the P2 is the same of P1 but with a negative scale (-X) This model that i use the negative Scale X show bad the normal maps. here a comparative pic of the positive and negative scale X. Any idea if this is a error of the shader, unity3D or something else? thanks
You'd need to also invert the green channel of your normal map. Or multiply the y component of the normal in the shader by -1. I wouldn't use minus scales to do character mirroring, though... that seems a pretty hacky workaround.
Thanks Farfarer, I see, is possible invert the green channel by code? or must create other shader and change it when i set my X to a negative value?
In the shader you could add a float and set it to 1 or -1 in code. Then multiply the normal's y component by that float inside the shader.
Can you show us the normal map you're using? It looks to me like more than the green channel needs inverting. This sort of thing is best to get figured out on your content creation side rather than in Unity, because Unity will convert your normal maps to its internal format before your code gets to see the data.
It could be the red channel needs inverting (if it's an X invert) - but I think it's definitely one of the two channels are simply flipped.
I understand that the UDK works with flipped channel, that cause the normal map looks orange. there is any way to make normal map works correctly in positive and negative X scale?
Ah, I misread why you were using a negative X scale. In that case, you should use a script to duplicate the mesh using the Mesh class. Then you can iterate through all the vertices and negate their tangent.w values. This will invert your the tangent space bases to compensate for your scaling. I believe this is more efficient than making a custom shader or a custom normal map for the mirrored actor.
Uh... you might be able to use the unity_scale value in the shader to multiply the normal channel by either 1 or -1?
The Scale X=1 is for the Player 1 the Scale X=-1 is for the Player 2 (Mirror of Player 1) so i use all the animations mirrored. My only problem is that the Player 2 (Scale X=-1) show bad the Normal Map, The Player 1 Show the normal map correctly. So for fix the player 2 maybe i have to do something like Daniel B. But honestly, i have not idea how to make it
Mirroring the verts of the model would not work because the animations would play the same, just that the verts would be mirrored. Unless you did this in lateupdate each and every frame (which is woefully inefficient compared to simply mirroring the object in X). The shader has a value which contains the object's scale, you could use that to invert the channel of the normal map; Code (csharp): // In your shader... o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv)); o.Normal.x *= sign(unity_Scale.x); // Swap this line for the next line if it still appears wrong. //o.Normal.y *= sign(unity_Scale.x);
I suggested negating the W components of the tangents to mirror the tangent space. The vertex mirroring would still be done by a negative X scale, allowing the animations to continue working. Ratonmalo, have you looked at the documentation I linked?
Thanks to both for the help! right now im testing the Farfarer way, if you Daniel Brauer don mind can you enplane me how to do this or post any example? I want to try both ways. Thanks.
My bad, I misread your post. Yeah, that'd work too I think, and not require the if statement in the shader. Ratonmalo : Check out the mesh documentation. You copy out the tangent values to a Vector4 array, loop through that and multiply the w component of each entry by -1, then pass the array back into the mesh.
Hi, checking the mesh documentation i found this : Code (csharp): var mesh : Mesh = GetComponent(MeshFilter).mesh; var vertices : Vector3[] = mesh.vertices; var normals : Vector3[] = mesh.normals; for (var i = 0; i < vertices.Length; i++) vertices[i] += normals[i] * Mathf.Sin(Time.time); mesh.vertices = vertices; That suppose to : 1) get vertices 2) modify them 3) assign them back to the mesh. So i have to multiply the vertex by -1?
No, multiply the tangent's w component by -1. Code (csharp): var mesh : Mesh = GetComponent(MeshFilter).mesh; var tangents : Vector4[] = mesh.tangents; var i : int = tangents.Length; while ( i ) { tangents[i].w = tangents[i].w * -1; i--; } mesh.tangents = tangents;
Hi, i still testing it for a couple of days and i can/t get it working. here what im trying to do. Code (csharp): var mesh : Mesh = GetComponent(MeshFilter).mesh; var tangents : Vector4[] = mesh.tangents; var i : int = tangents.Length; function Update () { if (Input.GetKey("w")) { while ( i ) { tangents[i].w = tangents[i].w * -1; i--; } mesh.tangents = tangents; } }
If Anyone is still looking.. her is the fixed C# version of the script. Just drop this into Any game object and it should work. using UnityEngine; using System.Collections; public class NormalInverter : MonoBehaviour { private MeshFilter filter; private Mesh mesh; private Vector4[] tangents; void Start () { if (transform.lossyScale.x < 0 || transform.lossyScale.y < 0 || transform.lossyScale.z < 0) { filter = gameObject.GetComponent<MeshFilter>(); mesh = filter.mesh; tangents = mesh.tangents; for (int i = 0; i < tangents.Length; i++) { tangents.w = tangents.w * -1; } mesh.tangents = tangents; } } }
You, Sir, are my hero tonight. Five minutes of search saved me countless hours of work thanks to your contribution.