• 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
2
Question by CHPedersen · Oct 14, 2013 at 06:52 AM · cg

How do I render scalars to a Floating Point RenderTexture?

Hi all,

I'm interested in transferring floats to a shader by rendering them into a RenderTexture using the RFloat RenderTextureFormat. But I find the documentation for this somewhat sparse, and it's unclear to me how I'm supposed to use this format, both on the CPU side and GPU side.

My goal is to give an object a color that corresponds to the float I need and then render this object using a camera that writes to the RFloat RenderTexture. Does anyone know how the RFloat format works when a camera is rendering into it?

Suppose I simply make a color out of the four 8 bit components stored in a 32bit float by bitshifting each color channel out of the float, i.e. Color.r becomes the first 8 bits of the float, Color.g the next 8 bits, and so on. If I use the camera to render an object with that color into the RFloat RenderTexture, will the texture then end up storing the original float? And if so, how do I get it back out of the texture in Cg?

Normally, when you read from a texture, you store the result in a float4, e.g. something like this:

float4 color = tex2D(sampler, uv_coords);

But in the shader, I don't want a 4 component color vector when reading from this texture, I want just a float - It's a floating point texture after all. Is there a version of tex2D that just returns float, or am I supposed to repack the float4 into the original float, or how does this work?

PS: I also posted this identical question on the forum: [link]

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

2 Replies

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

Answer by CHPedersen · Nov 12, 2014 at 02:00 PM

I have recently solved this problem in a very ugly and very low-level fashion myself. To get the floats properly transferred to the GPU, I encoded them into colors in Big Endian order like this:

 private Color EncodeFloatInColor(float scalar)
 {
     byte[] floatBytes = BitConverter.GetBytes(scalar);
     return new Color32(floatBytes[3], floatBytes[2], floatBytes[1], floatBytes[0]);
 }

I then spent an excruciating amount of time studying the bit pattern of 32 bit floats in Big Endian notation using the Wikipedia article on the IEEE 754 Single Precision floating-point format, which allowed me to come up with this decoder function for shaders, implemented in Cg/HLSL:

 inline float UnpackFloatRGBA(float4 c)
 {
     // First, convert the color to its byte values
     int4 bytes = c * 255;
 
     // Extract the sign byte of the float, i.e. the most significant bit in the red channel (and overall float structure)
     int sign = (bytes.r & 128) > 0 ? -1 : 1;
 
     // Extract the exponent's bit parts which are spread across both the red and the green channel
     int expR = (bytes.r & 127) << 1;
     int expG = bytes.g >> 7;
 
     int exponent = expR + expG;
 
     // The remaining 23 bits constitute the float's significand. They are spread across the green, blue and alpha channels
     int signifG = (bytes.g & 127) << 16;
     int signifB = bytes.b << 8;
 
     float significand = (signifG + signifB + bytes.a) / pow(2, 23);
 
     significand += 1;
 
     // We now know both the sign bit, the exponent and the significand of the float and can thus reconstruct it fully like so:
     return sign * significand * pow(2, exponent - 127);
 }

The idea is to assign the Color generated by EncodeFloatInColor to some object or series of objects (in my case I render them into individual pixels of a texture), and then read back the color with a call to tex2D in the shader. The returned float4 in the shader will contain the float data represented as an RGBA color with its 4x8 bits stored in the 4 channels of the color. The Cg function UnpackFloatRGBA takes that 'color' and restores the original float from it, without any precision loss.

I don't know if that's useful to anyone else but me, but it was a total pain in the ass to write, so I felt like sharing it. ;) I will close this question now.

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 EricWGD · Dec 29, 2018 at 07:17 PM 0
Share

Just wanted to say thank you for posting your solution. I've been looking all over and yours is the only one without the 0 to 1 limit on the input float. Copy-pasted and it works perfectly!

avatar image
1

Answer by Marco-Trivellato · Oct 16, 2013 at 10:35 AM

what's the range of your floating-point values ? If it's [0..1], then you can use a 32bit ARGB texture and use EncodeFloatRGBA / DecodeFloatRGBA in the shaders:

http://docs.unity3d.com/Documentation/Components/SL-BuiltinIncludes.html

Comment
Add comment · Show 5 · 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 CHPedersen · Oct 16, 2013 at 11:20 AM 0
Share

That's a great suggestion! :) I did not know those functions existed in UnityCG.cginc. It's definitely a step in the right direction, and I'm positive it will come in handy for me in another situation. But for this particular purpose, I fear it may not be enough, because the floats are not 0-1 to begin with, and I'd like to not have to map them to 0-1 range on the CPU side. The reason for this is that, to map the floats to 0-1, you must choose bounds, and it should be possible for the user to change the bounds on the fly. I.e. the user must be able to freely select which interval over the entire range of numbers representable by float32 he wants to correspond to the range 0-1. If this map is done CPU side, it means I have to re-encode the entire texture every time the bounds change, which will be very costly. If, ins$$anonymous$$d, the raw float is stored in the texture, I can perform the mapping in real-time in a pixel shader. Then the user can change the bounds as he sees fit to immediate effect.

avatar image Marco-Trivellato · Oct 16, 2013 at 12:30 PM 0
Share

if you really need to use RFloat, then you should output the float to the red channel, then when you sample the texture you should be able to retrieve the value with tex2D(...).r

no bit-shifting required.

avatar image CHPedersen · Oct 16, 2013 at 01:06 PM 0
Share

Okay, I understand. That solves it as far as reading back the value in the shader goes. But it's still unclear how exactly one outputs the full 32 bit to just the red channel. This is a render texture, so the point is to get a camera to render into it. How do I give an object rendered by the texture's camera a color that has 32 bit per channel, so I can stick the full float in that color's red channel? Colors set on materials are all 8 bit / channel.

avatar image Marco-Trivellato · Oct 16, 2013 at 02:20 PM 0
Share

the RFloat render target has only 1 channel (red), which is 32 bit per pixel. so, you just output the floating point value.

having said that, if the object is assigned an RGBA color, you need to encode it into 1 float somehow...but this is specific to what you are trying to do and to your project.

avatar image CHPedersen · Oct 18, 2013 at 08:37 AM 0
Share

That's the very core of the problem. :) Output where? How do I "output the float"? Rendering into the texture is the only way I know how to output data to a RenderTexture, and assigning a color to something which is rendered is the only way I can think of to do that. The color is never visible, by the way - it is never rendered to the screen. Only to this rendertexture. I just don't know how to get 32 bits of data into one red channel CPU side.

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

16 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

Related Questions

Is there a way to pass an array to a Cg shader? 2 Answers

Problem with lighting in CG Shader 1 Answer

ShaderLab builtin lighting properties are not correct? 0 Answers

tex2D in CG program - UVs at 0,0 0 Answers

Stippled Shader? 2 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