I have the following shader configuration code :

uint gBlendValue = 0xffffff00;

And I have the following shader code :

// extract blend weights from gBlendValue - produces bVn values in the range [0,1]
float bV1 = ((gBlendValue >> 24) & 0xff)/255.0;
float bV2 = ((gBlendValue >> 16) & 0xff)/255.0;
float bV3 = ((gBlendValue >> 8)  & 0xff)/255.0;
float bV4 = (gBlendValue & 0xff)/255.0;

// sum lerped blends
float3 finalColor = float3(0,0,0);
finalColor += lerp(float3(0,0,0), float3(1,0,0), bV1);
finalColor += lerp(float3(0,0,0), float3(0,1,0), bV2);
finalColor += lerp(float3(0,0,0), float3(0,0,1), bV3);

// return finalColor 
return float4(finalColor,1);

But this doesn't behave as expected. The geometry is a dark red, when it should be white. What the turtle is going on here.


You appear to have solved your problem by sending a raw value, but I suggest you do not attempt to send packed values to the shader unless you have a good reason to do so.

Right now computing bV1 to bV4 requires three shifts, four integer operations, four conversions to floating point, and four floating point multiplications by a constant. All these operations are done for every fragment. If you replaced gBlendValue with an array of floats that are already normalised to [0,1], the computation would be done only once on the CPU and your shader would be a lot simpler.

Also, this code chunk:

float3 finalColor = float3(0,0,0);
finalColor += lerp(float3(0,0,0), float3(1,0,0), bV1);
finalColor += lerp(float3(0,0,0), float3(0,1,0), bV2);
finalColor += lerp(float3(0,0,0), float3(0,0,1), bV3);

Can be replaced with:

float3 finalColor = lerp(float3(0,0,0), float3(1,1,1), float3(bV1, bV2, bV3));

Though I suppose (0,0,0) and (1,1,1) were only test values, I think it's worth noting that this is also equivalent to:

float3 finalColor = float3(bV1, bV2, bV3);
  • \$\begingroup\$ Hmm, very good point on the cost of my math. I should explain then why I chose this method... .NET Bitmap.FromFile() ignores alpha channel, so I can't use a 4 channel bitmap to store data. And I can't use the Texture2D.FromFile() because Texture2D doesn't expose the data so that I can build a system copy (which i am editing and sending to the Buffer via UpdateSubResource()). Also I couldn't get a dynamic texture working properly, so by doing it this way I'm taking absolute control over the data, so that I can see what's going on. My XNA version of this code was indeed just using floats. \$\endgroup\$ – Gavin Williams Dec 21 '11 at 23:30
  • \$\begingroup\$ There is another thought in my mind as well .. Here I'm only using 4 textures, but I can see how different 'packing' arrangements (I think that's the right term) can result in many more textures, 8, 16, 24 with 4bit weights and 256 textures if I only have 2 per tile. So I was considering these other blend arrangements. But yeah, if the cost is too high, I'll have to think of another way. \$\endgroup\$ – Gavin Williams Dec 21 '11 at 23:38
  • \$\begingroup\$ I'll finish the experiment with what I'm doing and I'll get around to thinking on what you've said. I see that you're right, that's a lot of computation to determine what I already know before the frame. \$\endgroup\$ – Gavin Williams Dec 21 '11 at 23:45

You should enable BlendState. BlendState is not enabled by default.

  1. Make BlendState structure like below.

    BlendState BlendAlpha {
        AlphaToCoverageEnable = FALSE;
        BlendEnable[0] = TRUE;
        SrcBlend = SRC_ALPHA ;
        DestBlend = INV_SRC_ALPHA ;
        BlendOp = ADD;
        SrcBlendAlpha = ONE;
        DestBlendAlpha = ZERO;
        BlendOpAlpha = ADD;
        RenderTargetWriteMask[0] = 0x0F;
  2. Add (BlendAlphaParticle, float4(0.0f, 0.0f, 0.0f, 0.0f), 0xFFFFFFFF); to your pass in your technique.

  3. After alpha blending is ended, call device->OMSetBlendState(NULL, 0, 0xffffffff); to set blendstate back to default.

  • \$\begingroup\$ I'm doing texture splatting, not alpha blending. I've just taken the texture sampling code out to focus on the particular issue. But thanks for that code anyway, It will come in handy in a couple of weeks im sure. But in this case the blendValue is a blendWeights composition \$\endgroup\$ – Gavin Williams Dec 21 '11 at 5:33
  • \$\begingroup\$ as uint, so 0xffffff00 is breaking down to 4 blendweights for each of the 4 textures i have available. blendweight1 (bV1) = 1, blendweight2 (bV2) = 1, blendweight3 (bV3) = 1, blendweight4 (bV4) = 0. So lerping those values with RGB should be producing white pixels. \$\endgroup\$ – Gavin Williams Dec 21 '11 at 5:39
  • \$\begingroup\$ the RGB values in the lerp functions would normally be the sampled colors from my terrain textures. \$\endgroup\$ – Gavin Williams Dec 21 '11 at 5:43
  • \$\begingroup\$ I think I've worked out whats wrong. AsScalar().Set(gBlendValue); is converting the uint to an int so I'm losing the high bit. So i need to work out how to get a uint into the shader. \$\endgroup\$ – Gavin Williams Dec 21 '11 at 6:35
  • \$\begingroup\$ Sorry for the wrong answer. I should have read the question more carefully. I am glad that the problem was solved anyway. \$\endgroup\$ – DevExcite Dec 21 '11 at 10:11

I can't find a way to simply set a uint to a shader constant variable. But the following is a workaround :

uint[] gBlendValue = new uint[1]{0x00ffff00}; // this is the packed blendweights
DataStream data = new DataStream(gBlendValue, true, true);
Terrain.Effect.GetVariableByName("gBlendValue").SetRawValue(data, 4);

If anyone knows how to set a uint to the shader that would be useful. Though now that I know the 'unpacking' works ok, I'll be passing in the blendweights via a Texture2D.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.