• 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
3
Question by lucky_sama · Jun 12, 2017 at 06:47 PM · shader programming

z and w output of UnityObjectToClipPos()

Hi. As we are instructed to migrate to UnityObjectToClipPos() instead of doing the matrix multiplication ourselves, we are changing our shader and some of our previous calculation relies on the z and w output of the MVP transform was broken.

As far as the document says, Unity uses the openGL style projection matrix, which looks like:

 [ 2n/r-l     0      r+l/r-l        0
     0      2n/t-b    t+b/t-b        0
     0         0      -(f+n)/f-n  -2fn/f-n
     0         0        -1           0    ]

Let's assume we have an input vector in.vertex, and z on the RHS below corresponds to in.vertex's z coordinate in the camera space. If the above matrix is to be taken in its literal sense, after we do

 out.vertex = UnityObjectToClipPos(in.vertex);

The content of out.vertex should be

 out.vertex.z = -(z*(f+n) + 2fn)/(f-n);
 out.vertex.w = -z;

This doesn't seems to be the case. After some hacking it seems we're getting:

  out.vertex.z >> 1 (z >> near plane), >>0 (z >> far plane);
  out.vertex.w = +z;

in the output of UnityObjectToClipPos(). Note that if the openGL textbook math is actually used, out.vertex.z's absolute value should increase while z's absolute value is increasing, regardless of z's sign on the RHS and the output's sign.

We're wondering if anyone from Unity can confirm this? Our calculation can be easily fixed as long as we know the exact formulae under the hood. Thanks.

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

1 Reply

· Add your reply
  • Sort: 
avatar image
1

Answer by Bunny83 · Jun 12, 2017 at 07:52 PM

Well, what you have to understand is that camera space is a right-hand space while object space in Unity is a left-hand space. In camera space the z value is always negative. That's why you have a "-1" in the third column fourth row instead of a "1" to get the new "w" value into the positive.

Keep in mind that the GPU does perform the perspective / homogeneous divide after your shader. It will bring the "w" component back to "1" and the "z" that is written to the depth buffer is:

 -(z*(f+n) + 2fn)/((f-n)*w)

or

 (f+n)/(f-n) - 2fn/((f-n)*w)

(If i calculated correctly) which basically results in a value between "-1"(near distance) and "1"(far distance).

Example:

 // at near distance you get:
 (f+n)/(f-n)-2fn/((f-n)*n)  --> (f+n)/(f-n)-2f/(f-n)  --> (f+n-2f)/(f-n)  --> (n-f)/(f-n) --> -1
 // at far distance you get:
 (f+n)/(f-n)-2fn/((f-n)*f)  --> (f+n)/(f-n)-2n/(f-n)  --> (f+n-2n)/(f-n)  --> (f-n)/(f-n) --> 1


I recently posted a more detailed answer on how the projection matrix works. I've linked this paper from my other answer

Comment
Add comment · Show 8 · 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 Bunny83 · Jun 12, 2017 at 08:10 PM 0
Share

ps: "UnityObjectToClipPos" is defined inside the "UnityShaderUtilities.cginc" file like this:

 inline float4 UnityObjectToClipPos(in float3 pos)
 {
     // $$anonymous$$ore efficient than computing $$anonymous$$*VP matrix product
     return mul(UNITY_$$anonymous$$ATRIX_VP, mul(unity_ObjectToWorld, float4(pos, 1.0)));
 }

So it actually calculates the same as $$anonymous$$VP * pos. It seems Unity doesn't provide the $$anonymous$$VP to the shader anymore. $$anonymous$$ultiplying the pos first with "$$anonymous$$" (object to world) and then with "VP" (combined camera and projection matrix) is more efficient than combining $$anonymous$$ and VP before the multiplication with pos.

avatar image lucky_sama Bunny83 · Jun 12, 2017 at 08:21 PM 0
Share

what confuse me is exactly this - the function doesn't seems to do what was in UnityShaderUtilities.cginc

avatar image Bunny83 lucky_sama · Jun 12, 2017 at 08:46 PM 0
Share

Well, what exactly did you use before you used "UnityObjectToClipPos"? "UNITY_$$anonymous$$ATRIX_$$anonymous$$VP" is just a define inside "UnityShaderVariables.cginc" which looks like this:

 #define UNITY_$$anonymous$$ATRIX_$$anonymous$$VP mul(unity_$$anonymous$$atrixVP, unity_ObjectToWorld)
Show more comments
avatar image lucky_sama · Jun 12, 2017 at 08:15 PM 0
Share

I never said anything about the actual value of z in my post, whether it is positive or negative. And I am not concerning about the normalization of the pipeline. I use the z and w output in the vertex shader, immediately after out.vertex = UnityObjectToClipPos(in.vertex);, and I need to know what those values are.

avatar image Bunny83 lucky_sama · Jun 12, 2017 at 08:37 PM 0
Share

Well, i did explain what happens with the value afterwards. The actual value of the outgoing "z" component is pretty irrelevant as it's based on the near and far clipping plane as well as the inco$$anonymous$$g z value. The point of the projection matrix is to bring the value into a range that, after normalization, is in the range -1 to 1.

That means at the near distance the outgoing z value is "-n" and at the far distance it's "+f". In between it's something between "-n" and "f". $$anonymous$$eep in $$anonymous$$d that the depth resolution is not linear. for example at half the distance between near and far ((far+near)/2) the depth value would be "0.9994001799". So almost 1. You never want to tinker with the projected z value. For most cases you want to use the unprojected camera space z value.

avatar image lucky_sama Bunny83 · Jun 12, 2017 at 09:03 PM 0
Share

I know what I need to do and I am not asking an explanation of the basic math stuff. Since I don't have Unity Pro, I would appreciate that if the answer can confirm that in the vertex shader, Unity actually called mul(UNITY_$$anonymous$$ATRIX_VP, mul(unity_ObjectToWorld, float4(pos, 1.0))); and UNITY_$$anonymous$$ATRIX_VP actually is the openGL matrix in the documentation. There is nothing to do with normalization here, my math is completely within the vertex shader.

Let me put it clear, I want a definitive pick of either of the following two:

  1. By executing out.vertex = UnityObjectToClipPos(in.vertex);, the output immediately after this call, in the vertex shader, is out.vertex.z = -(z*(f+n) + 2fn)/(f-n); out.vertex.w = -z;. I am wrong with my debugging code of shader dump and I should check that.

  2. UnityObjectToClipPos();, or UNITY_$$anonymous$$ATRIX_VP; or any other part of the Unity viewing transformation pipeline, is implemented in a (maybe slightly) different way (maybe depends on the compilation platform) from the matrix on the openGL textbook. This is very understandable since Unity needs to talk to many different platforms, but we need to know this difference in its very detail.

Show more comments

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

67 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Shader graph equivelent of Unreal's StaticBool? 2 Answers

Making a rather simple shader.shader 0 Answers

Why doesn't my new shader property show up in the inspector? 0 Answers

How to write an additive HDRP shader without glow 0 Answers

Get shadowmap in HDRP with commandBuffer 0 Answers


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