-
-
Notifications
You must be signed in to change notification settings - Fork 21.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[3.x] Window transparency support on Android #51935
[3.x] Window transparency support on Android #51935
Conversation
@@ -139,6 +140,7 @@ private void init(XRMode xrMode, boolean translucent, int depth, int stencil) { | |||
* is interpreted as any 32-bit surface with alpha by SurfaceFlinger. | |||
*/ | |||
if (translucent) { | |||
this.setZOrderOnTop(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pouleyKetchoupp Can you clarify what this does? According to the documentation:
By setting this, you cause it to be placed above the window. This means that none of the contents of the window this SurfaceView is in will be visible on top of its surface.
Which would mean that it would prevent additional component from rendering on top of the surface; is that the desired behavior?
Could you also walk me through how per-pixel transparency is achieved; it may help me understand better the logic in the PR.
Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which would mean that it would prevent additional component from rendering on top of the surface; is that the desired behavior?
Yes, this allows Godot rendering to be displayed on top, so a plugin can render behind the transparent surface, rather than always in front (like it does by default). As a side effect, plugins can't render on top of the surface when this is enabled, as you mentioned, but it's the only way I've found to achieve transparent rendering.
Could you also walk me through how per-pixel transparency is achieved; it may help me understand better the logic in the PR.
Transparent rendering is achieved this way:
per_pixel_transparency/allowed
&per_pixel_transparency/enabled
are both set to true in Project Settingsget_tree().get_root().transparent_bg = true;
is called at runtime to make the viewport transparent- At Android export time,
--translucent
is added to the command line (this step is needed on 3.x becauseMain::setup()
is called after the surface is initialized, it won't be needed on master). - At Android runtime,
--translucent
command line is checked to create a surface with transparent capabilities (on master it will just check the project settings directly) - When the plugin is initialized, its own rendering frame is placed on top of the main frame by default, so this can be used to move it behind:
ViewGroup parentView = (ViewGroup)pluginFrame.getParent();
parentView.removeView(pluginFrame);
parentView.addView(pluginFrame, 0);
(from what I've seen, both this and setZOrderOnTop(true)
are needed for transparency to work correctly)
The result is the plugin does its custom rendering (for example camera preview) and Godot draws on top of it with transparent background (for example to add UI elements).
Let me know if there's more I can clarify!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remember that transparent viewports aren't supported yet with the Vulkan renderer: #40651
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pouleyKetchoupp Sorry for the delay, I was out for the past week.
Regarding ordering of the surface and of the plugins' views, we control that logic here and here, so couldn't just have a flag that tells us if translucent
is enabled, and changed the order of the views as shown in your sample code?
With that approach, would we still need to set the setZOrderOnTop(...)
flag?
Also, when you say the surface is transparent, does that mean that any view(s) behind
it will be visible? I'm trying to clarify here since making the background transparent in Godot may not mean the same as making the surface view background transparent (which would allow to see underlying views).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No worries!
Regarding ordering of the surface and of the plugins' views, we control that logic here and here, so couldn't just have a flag that tells us if
translucent
is enabled, and changed the order of the views as shown in your sample code?
With that approach, would we still need to set thesetZOrderOnTop(...)
flag?
I'm not sure why (it could be the way GL surfaces work), but both are needed for the system to work correctly.
I've tested again since last time and here's how it goes:
-setZOrderOnTop
is needed for transparent rendering, without it the Godot surface renders with black background and any view behind it is not visible.
-Changing the order of views is not strictly needed if setZOrderOnTop
is set, but it helps with inputs as it allows Godot inputs to be taken over views placed behind.
Also, when you say the surface is transparent, does that mean that any view(s)
behind
it will be visible? I'm trying to clarify here since making the background transparent in Godot may not mean the same as making the surface view background transparent (which would allow to see underlying views).
Yes, it allows other views to be visible behind it.
Using this feature, you can also make a transparent app and see the device desktop in the background. But that requires to also change the style of the main Godot app to this:
<style name="GodotAppMainTheme" parent="@android:style/Theme.Black.NoTitleBar.Fullscreen">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
</style>
So far I haven't found a nice way to enable it in the export process or by code, but it would be a nice addition to this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
About setting the transparent theme in the app:
From what I've just tested, changing the theme to a new one with windowIsTranslucent
attribute even in the app onCreate
function is not enough to make it work. It can modify the color but not the translucent flag.
I guess the best way to handle it would be to change the theme in the manifest file during export, but do you know how to handle it with custom builds? It looks like the export process fixes the manifest file only for standard builds.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pouleyKetchoupp Do you have an example for the logic you use to update the theme?
In general, the theme needs to be set before even calling setContentView(...)
.
So the logic should look something like:
public void onCreate(Bundle savedInstanceState) {
if (hasTranslucentFlag())
setTheme(R.style.GodotAppTranslucentTheme);
else
setTheme(R.style.GodotAppMainTheme);
super.onCreate(savedInstanceState);
}
where GodotAppTranslucentTheme
would be as you described above:
<style name="GodotAppTranslucentTheme" parent="@android:style/Theme.Black.NoTitleBar.Fullscreen">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
</style>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on your example, even just setting the transparent theme without checking any flag like this:
public void onCreate(Bundle savedInstanceState) {
setTheme(R.style.GodotAppTranslucentTheme);
super.onCreate(savedInstanceState);
}
doesn't seem to work, unless windowIsTranslucent is set to true in the default theme as well.
It looks like this flag can't be changed once the app is being created, and it works by adding it in the default theme only because the splash theme inherits from the default theme (unless I'm missing something).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this flag can't be changed once the app is being created, and it works by adding it in the default theme only because the splash theme inherits from the default theme (unless I'm missing something).
@pouleyKetchoupp I thought you were still looking into this. If not, I'm good with approving and unblocking this PR, and attempting to update the app theme for translucency in another PR. For that approach, can you create an issue that documents what you already tried; I can then take a look and see if anything is missing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the confusion! Yes let me finalize this PR and open an issue to solve the app theme thing separately.
@pouleyKetchoupp For this and #52320, do we want to cherry-pick them into the |
@m4gr3d I was thinking it's small enough not to causes regressions, but you're right, since it should be just bug fixing these changes should go on 3.x only. I'll remove the tags. |
platform/android/java/lib/src/org/godotengine/godot/GodotView.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems good to me, but I'll let @m4gr3d give the final seal of approval/merge.
Might be worth updating the doc since it's not longer limited to "desktop window"s:
Might be worth specifying which platforms this is implemented for now that it's not just desktop platforms. |
641faea
to
17756f8
Compare
Implements per-pixel transparency feature on Android. Allows plugins to do specific rendering and render godot UI on top (useful for camera support with drawing on top).
17756f8
to
52fdb4e
Compare
I've made the last documentation updates and opened an issue for the app theme: #52725 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
Thanks! |
Implements per-pixel transparency feature on Android.
Allows plugins to do specific rendering and render godot UI on top (useful for camera support with drawing on top).
In order to do that, the plugin itself needs to move its own frame behind the main godot frame with something like that in java:
3.x only for now, because I haven't looked into how to do it with Vulkan yet.