Open teemo25 opened 10 months ago
ImDrawList::AddRect( ... )
has an early out if the alpha is zero, therefore you have no vertices to manipulate. Because the color is supposed to be constant across the primitive, that's no error as an alpha of zero would have no visible effect.
Since you replace the vertex color without reading it, just give AddRect
a solid 0xFFFFFFFF
and you're good.
ImDrawList::AddRect( ... )
has an early out if the alpha is zero, therefore you have no vertices to manipulate. Because the color is supposed to be constant across the primitive, that's no error as an alpha of zero would have no visible effect.Since you replace the vertex color without reading it, just give
AddRect
a solid0xFFFFFFFF
and you're good.
Thank you very much, worked perfectly. Do you know if theres any other enhancements I can make to the function to allow for smoother rounded corners, they become very jagged when doing it this way.
With my function
With regular AddRect (same rounding & thickness)
You should preserve the current Alpha component (or multiply by the current Alpha component if you want to modify it), because we are using it for anti-aliasing.
See what eg the ShadeVertsLinearColorGradientKeepAlpha() function is doing.
As ocornut has pointed out, this commented part of your code will preserve the original alpha value:
final_color = (final_color & ~IM_COL32_A_MASK) | (v.col & IM_COL32_A_MASK);
If you're not familiar with bit operations, basically it equals to final_color.a = v.col.a
, in which v.col
is the original color.
If you want to multiply that with the current alpha, do this instead:
ImU32 original_alpha = (v.col & IM_COL32_A_MASK) >> 24ul;
ImU32 current_alpha = (final_color & IM_COL32_A_MASK) >> 24ul;
final_color = (final_color & ~IM_COL32_A_MASK) | ((original_alpha * current_alpha / 0xFFul) << 24ul);
However, this is not ideal due to the flooring issue of integer division, I'm not sure how much of a problem is that, but just to give you an idea.
As ocornut has pointed out, this commented part of your code will preserve the original alpha value:
final_color = (final_color & ~IM_COL32_A_MASK) | (v.col & IM_COL32_A_MASK);
If you're not familiar with bit operations, basically it equals to
final_color.a = v.col.a
, in whichv.col
is the original color.If you want to multiply that with the current alpha, do this instead:
ImU32 original_alpha = (v.col & IM_COL32_A_MASK) >> 24ul; ImU32 current_alpha = (final_color & IM_COL32_A_MASK) >> 24ul; final_color = (final_color & ~IM_COL32_A_MASK) | ((original_alpha * current_alpha / 0xFFul) << 24ul);
However, this is not ideal due to the flooring issue of integer division, I'm not sure how much of a problem is that, but just to give you an idea.
Thanks, this is working correctly the only issue now is that when a colors alpha is set to 0 it still exists or something?
ImU32 original_alpha = (v.col & IM_COL32_A_MASK) >> 24ul;
ImU32 current_alpha = (final_color & IM_COL32_A_MASK) >> 24ul;
final_color = (final_color & ~IM_COL32_A_MASK) | ((original_alpha * current_alpha / 0xFFul) << 24ul);
In this image the red (top) part of the rect has 0 alpha but its still very visible
In this image the red (top) part of the rect has 0 alpha but its still very visible
Doesn't the original code also suffer from this? This is because of how color works and it's a real pain in graphics programming, the changes between 00-7F are much greater visually than the changes between 7F-FF. Tom Scott's video explained this really well.
You might want to use non-linear interpolation for this, something simple like alpha = alpha * alpha / 0xFFull;
will work.
Code:
ImU32 original_alpha = (v.col & IM_COL32_A_MASK) >> 24ul;
ImU32 current_alpha = (final_color & IM_COL32_A_MASK) >> 24ul;
ImU32 alpha = original_alpha * current_alpha / 0xFFul;
alpha = alpha * alpha / 0xFFull;
final_color = (final_color & ~IM_COL32_A_MASK) | (alpha << 24ul);
Visualization: Red line is linear, blue line is y=x*x
Note: Ideally, you would want to use a cubic bezier curve function to adjust the alpha curve just how you like it.
In this image the red (top) part of the rect has 0 alpha but its still very visible
Doesn't the original code also suffer from this? This is because of how color works and it's a real pain in graphics programming, the changes between 00-7F are much greater visually than the changes between 7F-FF. Tom Scott's video explained this really well.
You might want to use non-linear interpolation for this, something simple like
alpha = alpha * alpha / 0xFFull;
will work.Code:
ImU32 original_alpha = (v.col & IM_COL32_A_MASK) >> 24ul; ImU32 current_alpha = (final_color & IM_COL32_A_MASK) >> 24ul; ImU32 alpha = original_alpha * current_alpha / 0xFFul; alpha = alpha * alpha / 0xFFull; final_color = (final_color & ~IM_COL32_A_MASK) | (alpha << 24ul);
Visualization: Red line is linear, blue line is y=x*x
Note: Ideally, you would want to use a cubic bezier curve function to adjust the alpha curve just how you like it.
Thanks for trying to explain, Im very new to graphics and such in computers, the non linear interpolation helped quite a lot but there is still just a little of that red color left even with 0 alpha.
Im trying to do this.
v.col = final_color;
if ((final_color & IM_COL32_A_MASK) == 0)
{
v.col = IM_COL32_BLACK_TRANS;
}
to make the color black transparent if the alpha is fully transparent but its not working at all, do you know why?
Edit: It does seem to work if the rounding isnt high:
But when I add rounding it makes the problem apparent again:
but its not working at all, do you know why?
I'm not sure what you're trying to achieve with that, because if its alpha is already 0, why set it to a black color with zero alpha (IM_COL32_BLACK_TRANS)?
The problem is because you set it to IM_COL32_BLACK_TRANS
, the color interpolation will fade from black, to red (your col_upr_left and col_upr_right), to green (your col_bot_right and col_bot_left).
The reason it doesn't have a red tint when there is no rounding. This is because there is no vertex in the middle of the rect for the red color to have alpha > 0, so it will be overridden by IM_COL32_BLACK_TRANS
.
If you don't know what a vertex is, it's the triangles that construct your shapes, the red lines in the following image are vertex, and your code will loop through all the yellow points:
In the left rect with no rounding, the first 4 points are IM_COL32_BLACK_TRANS
, yes, i calculated it, is y position is 10, rect height is 305, so its alpha should be 0.274/255 and floor down to 0, which triggered your if block.
This is quite hard to explain, hope I've made it easy to understand.
Version/Branch of Dear ImGui: Version: 1.9.0 WIP Branch: Master
Back-end/Renderer/Compiler/OS Back-ends: imgui_impl_win32.cpp, imgui_impl_dx11.cpp Operating System: Windows 10 Home 19045.3570
My Issue/Question: I created my own function for drawing a multi colored rect that allows for rounding. Its working well but if I change any of the colors alpha to 0 all of the colors in the rectangle become invisible, not only the corner thats suposed to.
Screenshots/Video https://github.com/ocornut/imgui/assets/142989758/d7440b0b-7d30-49f8-93bf-5527ef12e7b8 I am changing only the top colors alpha. There is a black background under the rect for more visibility.
Code