storing two 16 bit floats in one 32 bit float (in HLSL)

Started by
9 comments, last by shultays 14 years, 1 month ago
is it possible? I am using directx 9.0 and as far as I know binary operations are not supported in dx9 I want to do something like that WORD x, y; DWORD z; z = x<<16 | y; but on HLSL and using floats. The reason is I want to store both color and normal of each pixel in a texture. I can do that using two textures but two rendering is very slow for me. Is there any other alternative for that?
taytay
Advertisement
D3DFMT_G16R16F
[EDIT]: Oops.. sorry, I misunderstood your problem. Ignore me.

[Edited by - Amr0 on February 25, 2010 4:49:42 AM]

I ran into a similar issue recently and as far as I know, this is not supported. At least the FX compiler complained that << is an unexpected token. From my Googling, I learned that bitwise operators are only supported in SM4 and onwards.

You could use Spherical coordinates to store a 3 float normal and a 3 float color value in a A32R32G32B32F (or any narrower you can get away with) texture though. Since both the normal and color can be normalized, you can drop the r component for the spherical coordinate and just store the theta and phi for both values. This is actually easier than it may sound, so check out that link on how to do the conversions [smile]

The only downside here is that you end up with sin and cos operations in your shader, which may potentially be slower than sampling two textures. If you're constraint on the number of input textures and/or the number of samples you want to fetch however, it might be a feasible alternative.

Edit - Reading ET3D's reply below though, this is not quite the easiest nor best solution, so you probably shouldn't use it. It is a fancy one though [grin]
Rim van Wersch [ MDXInfo ] [ XNAInfo ] [ YouTube ] - Do yourself a favor and bookmark this excellent free online D3D/shader book!
First of all, how slow? I agree that one texture access is likely to be faster than two, since each has some latency, but I can't imagine that two memory accesses per pixel will be extremely costly. What graphics card are you using?

Regarding storing them together, it's not that difficult to simulate shifts and or's with multiplication and addition, and so on. You don't need floats for normals. Low accuracy can work pretty well for them in most cases, and you can either store two shorts or three 10 bit values inside a DWORD.

So a format such as D3DFMT_A16B16G16R16 could be good enough. Your values will be transformed to the 0-1 range, and to extract a colour components you can use one directly and the other as frac(component*255).
remigius:
Thanks, I never thought about using spherical coordinates for color. I will try it and see how it works.

ET3D:
it is not the texture access I am worrying about. I need to do two rendering of the whole scene, one for colors and one for normals.

can you explain your suggestion a bit more? I am not sure if I get it right
taytay
You don't need to render the scene twice. What you can do is use multiple simultaneous render targets (MRT) to write to two render targets at the same time. This is often used in deferred shading.

Your code would look something like:

device->SetRenderTarget(0, colour_buffer);device->SetRenderTarget(1, normal_buffer);// Draw stuff with shader that outputs to both targets


Note that depending on your hardware both targets may need to be the same bit depth, but they can be different formats (e.g. one R32F and one D3DFMT_A2R10B10G10 is fine).
Quote:Original post by Adam_42
You don't need to render the scene twice. What you can do is use multiple simultaneous render targets (MRT) to write to two render targets at the same time. This is often used in deferred shading.

Your code would look something like:

device->SetRenderTarget(0, colour_buffer);device->SetRenderTarget(1, normal_buffer);// Draw stuff with shader that outputs to both targets


Note that depending on your hardware both targets may need to be the same bit depth, but they can be different formats (e.g. one R32F and one D3DFMT_A2R10B10G10 is fine).


Oh, I didn't know about that, thanks! But how should I configure my pixel shader for drawing on two targets?


float4 PS_COOR( in V2P4 IN) : COLOR0{
float4 TexColor = float4(IN.Norm.xyz, 1.0);
return TexColor;
}


so I guess COLOR0 means render target 0, can a shader return more than 1 value or do I need seperate shader for each render targer. if so how should I configure my technique
taytay

You can just stick the seperate values in a struct and the device will know what to do with the semantics. Something like this:

struct PSOutput{  float4 color : COLOR0; // to RT0  float4 normals : COLOR1; // to RT1};PSOutput PS_COOR( in V2P4 IN) {PSOutput output;output.color = float4(IN.Norm.xyz, 1.0);output.normals = float4(0,0,0,0);// whatever you needreturn output;}

Btw, I second the request to ET3D to elaborate on his suggestion. I Googled quite a bit, but I couldn't find any code that could reliably do back and forth bitwise operations. I was specifically looking for something to transform a float into 4 bytes and back again, if you happen to need a simple case to explain [smile]
Rim van Wersch [ MDXInfo ] [ XNAInfo ] [ YouTube ] - Do yourself a favor and bookmark this excellent free online D3D/shader book!
You just need to write to COLOR0, and COLOR1 from one shader, something like:

struct PS_OUT{  float4 colour : COLOR0;  float4 normal : COLOR1;};PS_OUT PS_COOR( in V2P4 IN){  PS_OUT out;  // TODO: fill in out  return out;}
thanks everyone!
taytay

This topic is closed to new replies.

Advertisement