• 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
4
Question by Simon Crowe · Sep 27, 2011 at 07:56 PM · colortexture2dnormalmap

How does Unity handle normal maps internally?

Update:

At the time of writing, Unity uses only the alpha and green channel for some normal mapping, storing the x fraction in alpha and the y in green. See Wolfram's answer for details.

Here is the relevant code. It is crude, but seems to produce adequate results. currentBuffer is an array of integers w$$anonymous$$ch acts as a $$anonymous$$ghtmap.

 for (int row = 1; row < pixelsY - 1; row ++){
     for (int column = 1; column < pixelsX - 1; column ++){
         int pos = (row * pixelsX) + column;
         byte x = (byte) (127 + (((currentBuffer[pos - 1] 
             + currentBuffer[pos + 1])/4) >> intensityS$$anonymous$$ft));
          byte y = (byte) (127 + (((currentBuffer[pos - pixelsX] 
             + currentBuffer [pos + pixelsX])/4) >> intensityS$$anonymous$$ft));
         nmTemp[pos] = new Color32 (0,y,0,x);        
     }
 }


Below is a screen shot of a scene using a normalmap generated using the above code to simulate the ripples in a sink. The shader is Unity's built-in Transparent/Bumped specular. The generated bump map used on a plane representing the water in a sink



I am working on a procedurally generated and updated normal map. I have been able to create the texture during runtime and update it every frame. However, the shader is rendering the normal map is in a similar way to those that aren't imported specifically as normal maps in the editor.

A texture format for normal maps doesn't seem to exist in TextureFormat enumeration and I am assuming that x, y and z in tangent space don't correspond to r g and b in the texture's colour values. Does anyone know how unity uses the r g b and a properties of Color when dealing with normal maps?

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

3 Replies

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

Answer by Wolfram · Sep 28, 2011 at 01:46 PM

Tseng's answer contains the information you are looking for: for GLES and mobile shaders, the mapping is as one would expect - direct mapping from [0..1] rgb to [-1..1] xyz.

However, in all other cases it appears, Unity uses a specialized coding, storing the x-fraction in a, and the y-fraction in g. red and blue are ignored. I guess t$$anonymous$$s is done to allow encoding of 16bit normal maps, where it would store the 16bit x-fraction in b+a, and the y-fraction in r+g.

In these cases, the z-fraction is reconstructed automatically, w$$anonymous$$ch is possible since the length is always 1. However, for that to work, your x and y components need to be the actual x/y-fractions of the normal vector. For example, for a diagonal normal of (0.57735,0.57735,0.57735) (w$$anonymous$$ch has a length of 1), the packed values for x and y are (0.57735*0.5+0.5)*255=201, w$$anonymous$$ch you'd then store in green and alpha.

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
avatar image
3

Answer by Tseng · Sep 27, 2011 at 08:57 PM

Normal Maps are handled by the shader as far as I know. Why just don't download the here and check it yourself and modify according to your needs?

In %ProgramFiles%\Unity\Editor\Data\CGIncludes\UnityCG.cginc you find the following

 inline fixed3 UnpackNormal(fixed4 packednormal)
 {
 #if defined(SHADER_API_GLES) && defined(SHADER_API_MOBILE)
     return packednormal.xyz * 2 - 1;
 #else
     fixed3 normal;
     normal.xy = packednormal.wy * 2 - 1;
     normal.z = sqrt(1 - normal.x*normal.x - normal.y * normal.y);
     return normal;
 #endif
 }

The shaders call the UnpackNormal on the normal map before applying the value to o.Normal

Comment
Add comment · Show 2 · 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 Simon Crowe · Sep 27, 2011 at 09:36 PM 0
Share

I'm not familiar with shaders, so I'm trying to avoid tinkering with them for the time being. From what I can see, none of the information in the shader file relating to the normal/bump map denotes which channels are used for what: '_BumpMap ("Normalmap", 2D) = "bump" {} sampler2D _BumpMap; o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));' I can't even begin to make sense of the compiled version of the bumped specular shader.

avatar image Tseng · Sep 27, 2011 at 11:01 PM 0
Share

Check my updated answer, this should be easy enough to understand I think

avatar image
1

Answer by Peter G · Sep 27, 2011 at 11:37 PM

Normal maps are difficult to write. The values for RGB actually loosely line up with the XYZ components of the normal. It isn't exactly one to one, but each channel does relate to the component of the normal. That's part of the reason that parts of the normal map without any added detail are blue. That corresponds to (0 , 0 , 1) and that's the forward vector for the normal. T$$anonymous$$s whole paragraph is a little simplistic, but it does get the idea across pretty well.

In old-school shaders, you had to do some multiplication with the old normal and the normal map value to get the actual normal. Surface shaders do the last step for you. You just pass in a normal and it will do the matrix multiplications that it needs to.

Creating normal maps isn't easy. The CG page s$$anonymous$$nes some light on what it is and how to do it.

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 Simon Crowe · Sep 28, 2011 at 11:47 AM 0
Share

I managed to put together some functional code for generating my normal map, albeit using a very simple method.

The main problem I was having was not knowing which channels to put which vector values into. It seems to work with x in alpha and y in RGB, but I'm still ignorant as whether or why this is actually Unity's way of storing them. Perhaps z is computed based on x and y.

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.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

5 People are following this question.

avatar image avatar image avatar image avatar image avatar image

Related Questions

How can I efficiently determine that certain parts of a texture have a specific color? 1 Answer

Wrong colors from ReadPixels() 0 Answers

Checking the transparency of a mesh with a piece of a texture 1 Answer

Combining 2 black-white textures 2 Answers

Changing color of Texture2d with transparency 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