Skip to content
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

Add access to the viewport's G-buffers (and depth). #38926

Open
wants to merge 6 commits into
base: 3.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion core/image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ const char *Image::format_names[Image::FORMAT_MAX] = {
"ETC2_RGB8",
"ETC2_RGBA8",
"ETC2_RGB8A1",

};

SavePNGFunc Image::save_png_func = NULL;
Expand Down
5 changes: 4 additions & 1 deletion doc/classes/Viewport.xml
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
<return type="ViewportTexture">
</return>
<description>
Returns the viewport's texture.
Returns the viewport's color texture.
[b]Note:[/b] Due to the way OpenGL works, the resulting [ViewportTexture] is flipped vertically. You can use [method Image.flip_y] on the result of [method Texture.get_data] to flip it back, for example:
[codeblock]
var img = get_viewport().get_texture().get_data()
Expand Down Expand Up @@ -235,6 +235,9 @@
<member name="disable_3d" type="bool" setter="set_disable_3d" getter="is_3d_disabled" default="false">
If [code]true[/code], the viewport will disable 3D rendering. For actual disabling use [code]usage[/code].
</member>
<member name="force_mrt" type="bool" setter="set_force_mrt" getter="is_force_mrt" default="false">
If [code]true[/code], the viewport will use multiple render targets even when effects like screen space reflections aren't enabled. This can be used to ensure that some buffers in a [ViewportTexture] stay available. It won't however work if the viewport were transparent, or if its usage is anything other than [constant USAGE_3D].
</member>
<member name="global_canvas_transform" type="Transform2D" setter="set_global_canvas_transform" getter="get_global_canvas_transform">
The global canvas transform of the viewport. The canvas transform is relative to this.
</member>
Expand Down
3 changes: 3 additions & 0 deletions doc/classes/ViewportTexture.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
<member name="viewport_path" type="NodePath" setter="set_viewport_path_in_scene" getter="get_viewport_path_in_scene" default="NodePath(&quot;&quot;)">
The path to the [Viewport] node to display. This is relative to the scene root, not to the node which uses the texture.
</member>
<member name="buffer_mode" type="int" setter="set_buffer_mode" getter="get_buffer_mode">
The kind of buffer the [ViewportTexture] will represent. Some buffers won't be available depending on the graphics driver, and the accosiated viewport's settings (see [enum VisualServer.ViewportTextureBuffer]).
</member>
</members>
<constants>
</constants>
Expand Down
29 changes: 29 additions & 0 deletions doc/classes/VisualServer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4039,6 +4039,17 @@
If [code]true[/code], rendering of a viewport's environment is disabled.
</description>
</method>
<method name="viewport_set_force_mrt">
<return type="void">
</return>
<argument index="0" name="viewport" type="RID">
</argument>
<argument index="1" name="force_mrt" type="bool">
</argument>
<description>
If [code]true[/code], then multiple render targets will be used by this [Viewport] no matter what. (See [member Viewport.force_mrt]).
</description>
</method>
<method name="viewport_set_global_canvas_transform">
<return type="void">
</return>
Expand Down Expand Up @@ -4610,6 +4621,24 @@
<constant name="VIEWPORT_RENDER_INFO_MAX" value="8" enum="ViewportRenderInfo">
Represents the size of the [enum ViewportRenderInfo] enum.
</constant>
<constant name="VIEWPORT_TEXTURE_BUFFER_COLOR" value="0" enum="ViewportTextureBuffer">
The color buffer of the [Viewport].
</constant>
<constant name="VIEWPORT_TEXTURE_BUFFER_DEPTH" value="1" enum="ViewportTextureBuffer">
The depth buffer of the [Viewport]. It is currently not possible to read it's data.
</constant>
<constant name="VIEWPORT_TEXTURE_BUFFER_DIFFUSE" value="2" enum="ViewportTextureBuffer">
The diffuse buffer of the [Viewport]. More specifically, it contains emission, diffuse and ambient light combined in the RGB channels, and ambient contribution in the alpha channel for SSAO. [b]GLES3 only.[/b]
</constant>
<constant name="VIEWPORT_TEXTURE_BUFFER_SPECULAR" value="3" enum="ViewportTextureBuffer">
The specular buffer of the [Viewport]. The RGB channels contain the specular color, and the alpha channel contains the metalness. [b]GLES3 only.[/b]
</constant>
<constant name="VIEWPORT_TEXTURE_BUFFER_NORMAL_ROUGH" value="4" enum="ViewportTextureBuffer">
The normal and roughness buffer of the [Viewport]. The RGB channels contain the normals in view space, and the alpha channel contains the roughness. [b]GLES3 only.[/b]
</constant>
<constant name="VIEWPORT_TEXTURE_BUFFER_SUBSURFACE" value="5" enum="ViewportTextureBuffer">
The subsurface scattering buffer of the [Viewport]. It's used for subsurface scattering effects. [b]GLES3 only.[/b]
</constant>
<constant name="VIEWPORT_DEBUG_DRAW_DISABLED" value="0" enum="ViewportDebugDraw">
Debug draw is disabled. Default setting.
</constant>
Expand Down
3 changes: 2 additions & 1 deletion drivers/dummy/rasterizer_dummy.h
Original file line number Diff line number Diff line change
Expand Up @@ -700,12 +700,13 @@ class RasterizerStorageDummy : public RasterizerStorage {
RID render_target_create() { return RID(); }
void render_target_set_position(RID p_render_target, int p_x, int p_y) {}
void render_target_set_size(RID p_render_target, int p_width, int p_height) {}
RID render_target_get_texture(RID p_render_target) const { return RID(); }
RID render_target_get_texture(RID p_render_target, VS::ViewportTextureBuffer p_buffer) const { return RID(); }
void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) {}
void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) {}
bool render_target_was_used(RID p_render_target) { return false; }
void render_target_clear_used(RID p_render_target) {}
void render_target_set_msaa(RID p_render_target, VS::ViewportMSAA p_msaa) {}
void render_target_set_force_mrt(RID p_render_target, bool p_force_mrt) {}

/* CANVAS SHADOW */

Expand Down
73 changes: 68 additions & 5 deletions drivers/gles2/rasterizer_storage_gles2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4704,6 +4704,8 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) {
// depth

if (config.support_depth_texture) {
Texture *depth_texture = texture_owner.getornull(rt->depth_texture);
ERR_FAIL_COND(!depth_texture);

glGenTextures(1, &rt->depth);
glBindTexture(GL_TEXTURE_2D, rt->depth);
Expand All @@ -4715,6 +4717,19 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0);

depth_texture->format = Image::FORMAT_RF;
depth_texture->gl_format_cache = GL_DEPTH_COMPONENT;
depth_texture->gl_type_cache = config.depth_type;
depth_texture->gl_internal_format_cache = config.depth_internalformat;
depth_texture->tex_id = rt->depth;
depth_texture->width = rt->width;
depth_texture->alloc_width = rt->width;
depth_texture->height = rt->height;
depth_texture->alloc_height = rt->height;
depth_texture->active = true;

texture_set_flags(rt->depth_texture, depth_texture->flags);
} else {

glGenRenderbuffers(1, &rt->depth);
Expand Down Expand Up @@ -5040,6 +5055,13 @@ void RasterizerStorageGLES2::_render_target_clear(RenderTarget *rt) {
if (rt->depth) {
if (config.support_depth_texture) {
glDeleteTextures(1, &rt->depth);

Texture *depth_tex = texture_owner.get(rt->depth_texture);
depth_tex->alloc_height = 0;
depth_tex->alloc_width = 0;
depth_tex->width = 0;
depth_tex->height = 0;
depth_tex->active = false;
} else {
glDeleteRenderbuffers(1, &rt->depth);
}
Expand Down Expand Up @@ -5119,6 +5141,30 @@ RID RasterizerStorageGLES2::render_target_create() {

rt->texture = texture_owner.make_rid(t);

Texture *dt = memnew(Texture);

dt->type = VS::TEXTURE_TYPE_2D;
dt->flags = 0;
dt->width = 0;
dt->height = 0;
dt->alloc_height = 0;
dt->alloc_width = 0;
dt->format = Image::FORMAT_R8;
dt->target = GL_TEXTURE_2D;
dt->gl_format_cache = 0;
dt->gl_internal_format_cache = 0;
dt->gl_type_cache = 0;
dt->data_size = 0;
dt->total_data_size = 0;
dt->ignore_mipmaps = false;
dt->compressed = false;
dt->mipmaps = 1;
dt->active = true;
dt->tex_id = 0;
dt->render_target = rt;

rt->depth_texture = texture_owner.make_rid(dt);

return render_target_owner.make_rid(rt);
}

Expand Down Expand Up @@ -5147,15 +5193,23 @@ void RasterizerStorageGLES2::render_target_set_size(RID p_render_target, int p_w
_render_target_allocate(rt);
}

RID RasterizerStorageGLES2::render_target_get_texture(RID p_render_target) const {
RID RasterizerStorageGLES2::render_target_get_texture(RID p_render_target, VS::ViewportTextureBuffer p_buffer) const {

RenderTarget *rt = render_target_owner.getornull(p_render_target);
ERR_FAIL_COND_V(!rt, RID());

if (rt->external.fbo == 0) {
return rt->texture;
} else {
return rt->external.texture;
switch (p_buffer) {
case VS::VIEWPORT_TEXTURE_BUFFER_COLOR:
if (rt->external.fbo == 0) {
return rt->texture;
} else {
return rt->external.texture;
}
case VS::VIEWPORT_TEXTURE_BUFFER_DEPTH:
return rt->depth_texture;
default:
//printf("The buffer ", p_buffer, " is not available in GLES2.");
SIsilicon marked this conversation as resolved.
Show resolved Hide resolved
return RID();
}
}

Expand Down Expand Up @@ -5350,6 +5404,10 @@ void RasterizerStorageGLES2::render_target_set_msaa(RID p_render_target, VS::Vie
_render_target_allocate(rt);
}

void RasterizerStorageGLES2::render_target_set_force_mrt(RID p_render_target, bool p_force_mrt) {
// Only available in GLES3.
}

/* CANVAS SHADOW */

RID RasterizerStorageGLES2::canvas_light_shadow_buffer_create(int p_width) {
Expand Down Expand Up @@ -5536,6 +5594,11 @@ bool RasterizerStorageGLES2::free(RID p_rid) {
Texture *t = texture_owner.get(rt->texture);
texture_owner.free(rt->texture);
memdelete(t);
if (config.support_depth_texture) {
Texture *dt = texture_owner.get(rt->depth_texture);
texture_owner.free(rt->depth_texture);
memdelete(dt);
}
render_target_owner.free(p_rid);
memdelete(rt);

Expand Down
4 changes: 3 additions & 1 deletion drivers/gles2/rasterizer_storage_gles2.h
Original file line number Diff line number Diff line change
Expand Up @@ -1216,6 +1216,7 @@ class RasterizerStorageGLES2 : public RasterizerStorage {
VS::ViewportMSAA msaa;

RID texture;
RID depth_texture;

bool used_dof_blur_near;
bool mip_maps_allocated;
Expand Down Expand Up @@ -1251,13 +1252,14 @@ class RasterizerStorageGLES2 : public RasterizerStorage {
virtual RID render_target_create();
virtual void render_target_set_position(RID p_render_target, int p_x, int p_y);
virtual void render_target_set_size(RID p_render_target, int p_width, int p_height);
virtual RID render_target_get_texture(RID p_render_target) const;
virtual RID render_target_get_texture(RID p_render_target, VS::ViewportTextureBuffer p_buffer) const;
virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id);

virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value);
virtual bool render_target_was_used(RID p_render_target);
virtual void render_target_clear_used(RID p_render_target);
virtual void render_target_set_msaa(RID p_render_target, VS::ViewportMSAA p_msaa);
virtual void render_target_set_force_mrt(RID p_render_target, bool p_force_mrt);

/* CANVAS SHADOW */

Expand Down
53 changes: 52 additions & 1 deletion drivers/gles3/rasterizer_scene_gles3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,12 @@
#include "core/os/os.h"
#include "core/project_settings.h"
#include "rasterizer_canvas_gles3.h"
#include "rasterizer_storage_gles3.h"
#include "servers/camera/camera_feed.h"
#include "servers/visual/visual_server_raster.h"

#include <iostream>
SIsilicon marked this conversation as resolved.
Show resolved Hide resolved

#ifndef GLES_OVER_GL
#define glClearDepth glClearDepthf
#endif
Expand Down Expand Up @@ -4254,6 +4257,8 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const
} else {

use_mrt = env && (state.used_sss || env->ssao_enabled || env->ssr_enabled || env->dof_blur_far_enabled || env->dof_blur_near_enabled); //only enable MRT rendering if any of these is enabled
use_mrt = use_mrt || storage->frame.current_rt->force_mrt; // or if it's force to be used.

//effects disabled and transparency also prevent using MRTs
use_mrt = use_mrt && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT];
use_mrt = use_mrt && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_NO_3D_EFFECTS];
Expand Down Expand Up @@ -4515,8 +4520,49 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const

//state.scene_shader.set_conditional( SceneShaderGLES3::USE_FOG,false);

if (use_mrt) {
// resolve buffers to textures
if (storage->frame.current_rt->buffers.active && use_mrt) {
SIsilicon marked this conversation as resolved.
Show resolved Hide resolved
RID_Owner<RasterizerStorageGLES3::Texture> *texture_owner = &(storage->texture_owner);
RasterizerStorageGLES3::RenderTarget *rt = storage->frame.current_rt;

glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, rt->fbo);
glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->buffers.fbo);

GLenum gldb = GL_COLOR_ATTACHMENT0;
glDrawBuffers(1, &gldb);

// diffuse
glReadBuffer(GL_COLOR_ATTACHMENT0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_owner->getornull(rt->buffers.diffuse_texture)->tex_id, 0);
glBlitFramebuffer(0, 0, rt->width, rt->height, 0, 0, rt->width, rt->height, GL_COLOR_BUFFER_BIT, GL_LINEAR);

if (rt->buffers.effects_active) {

// specular
glReadBuffer(GL_COLOR_ATTACHMENT1);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_owner->getornull(rt->buffers.specular_texture)->tex_id, 0);
glBlitFramebuffer(0, 0, rt->width, rt->height, 0, 0, rt->width, rt->height, GL_COLOR_BUFFER_BIT, GL_LINEAR);

// normal roughness
glReadBuffer(GL_COLOR_ATTACHMENT2);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_owner->getornull(rt->buffers.normal_rough_texture)->tex_id, 0);
glBlitFramebuffer(0, 0, rt->width, rt->height, 0, 0, rt->width, rt->height, GL_COLOR_BUFFER_BIT, GL_LINEAR);

// subsurface
glReadBuffer(GL_COLOR_ATTACHMENT3);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_owner->getornull(rt->buffers.sss_texture)->tex_id, 0);
glBlitFramebuffer(0, 0, rt->width, rt->height, 0, 0, rt->width, rt->height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
}

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glBindFramebuffer(GL_FRAMEBUFFER, rt->buffers.fbo);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}

if (use_mrt) {
_render_mrts(env, p_cam_projection);
} else {
// Here we have to do the blits/resolves that otherwise are done in the MRT rendering, in particular
Expand Down Expand Up @@ -4583,6 +4629,11 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const
if (env && (env->dof_blur_far_enabled || env->dof_blur_near_enabled) && storage->frame.current_rt && storage->frame.current_rt->buffers.active)
_prepare_depth_texture();
_post_process(env, p_cam_projection);

// Force the depth texture to be updated
state.prepared_depth_texture = false;
_prepare_depth_texture();

// Needed only for debugging
/* if (shadow_atlas && storage->frame.current_rt) {

Expand Down
Loading