In HLSL I want to store a bitfield for each color in a texture. Specifically spanning 3 floats (RGB, not alpha).

Since each float has to be between 0 and 1 I can only use the significand/mantissa of each float (last 23 bits) which should give me 23*3 = 69 values for my bitfield.

How can I set and get specific bits? (without bitwise operators, obviously, since these are floats)

Remember to take floating point precision errors into consideration.

  • \$\begingroup\$ Why are you using Shader Model 2.0? Are you targeting Direct3D 11 9.x Feature Levels? \$\endgroup\$ Oct 20, 2018 at 17:41
  • \$\begingroup\$ Not really sure what you mean by that exactly. I'm making a 2D game, so I just figured the lower Shader Model the better because I can target older hardware and 2.0 is good enough for all my other shaders. I guess I could use 3.0 without any losses nowadays, but even if this was for 4.0 where bitwise operators for integers are supported, what difference would it make? You can set and get bits for integers with arithmetic operators as well, right? \$\endgroup\$
    – Martin
    Oct 20, 2018 at 19:28
  • \$\begingroup\$ If you look at the Steam hardware survey you capture like 95% of the market with D3D_FEATURE_LEVEL_11_0 (Shader Model 2.0); and 99% with D3D_FEATURE_LEVEL_10_0 (Shader Model 4.0). Just don't worry about it and focusing on making your game fun and cool. See this blog post \$\endgroup\$ Oct 21, 2018 at 0:05
  • \$\begingroup\$ D3D_FEATURE_LEVEL_11_0 is shader model 5.0 and I capture less of the market by using 2.0 than 4.0? That doesn't make any sense. \$\endgroup\$
    – Martin
    Oct 21, 2018 at 8:44
  • \$\begingroup\$ But yes I get your point. By using 3.0 instead of 2.0 I would only lose 0.01% of the people on Steam. Even if I used 1.0 I would only gain 0.94% and by using 4.0 instead of 1.0 I would only lose a total of 1.05% of the people on Steam. So using anything below 4.0 with the argument that it would expand the market is completely redundant. Thanks for the information. \$\endgroup\$
    – Martin
    Oct 21, 2018 at 8:52

1 Answer 1


Figured it out. The trick is you can clamp an integer between 0 and 1 by dividing 1 by it, to "unpack" it you divide 1 by the result and the way that floats work I think you could technically use all 32 bits in the 0-1 range. The problem is precision. If you're using Shader Model 4.0 you can use bitwise operators for the integer bitfield, otherwise, you can do this:

Read a bit from float:

fmod(1.0 / num, pow(2, bit + 1)) >= pow(2, bit);

Set bit that is 0 to 1 (when I set a bit to 1 I know it's 0 if that's not the case you could always read the bit to check first):

num = 1.0 / (round(1.0 / num) + pow(2, bit))

You can store a bitfield of 23 bits in a float with this method, but beyond 23 bits the precision is too bad for the round function to handle.

For RGB this gives you a bit field of 23*3 = 69 bits. You can access RGB component by integer division:

rgba[bit / 23]

Get bit in RGB component with modulus:

fmod(bit, 23)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .