瀏覽代碼

Merge pull request #22574 from BastiaanOlij/mobile_vr_gles2

Moving lens distortion shader into drivers and adding GLES2 support
Rémi Verschelde 7 年之前
父節點
當前提交
123931f7eb

+ 1 - 0
drivers/dummy/rasterizer_dummy.h

@@ -788,6 +788,7 @@ public:
 	void restore_render_target() {}
 	void clear_render_target(const Color &p_color) {}
 	void blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen = 0) {}
+	void output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) {}
 	void end_frame(bool p_swap_buffers) {}
 	void finalize() {}
 

+ 39 - 0
drivers/gles2/rasterizer_canvas_gles2.cpp

@@ -1049,6 +1049,43 @@ void RasterizerCanvasGLES2::draw_generic_textured_rect(const Rect2 &p_rect, cons
 	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 }
 
+void RasterizerCanvasGLES2::draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) {
+	Vector2 half_size;
+	if (storage->frame.current_rt) {
+		half_size = Vector2(storage->frame.current_rt->width, storage->frame.current_rt->height);
+	} else {
+		half_size = OS::get_singleton()->get_window_size();
+	}
+	half_size *= 0.5;
+	Vector2 offset((p_rect.position.x - half_size.x) / half_size.x, (p_rect.position.y - half_size.y) / half_size.y);
+	Vector2 scale(p_rect.size.x / half_size.x, p_rect.size.y / half_size.y);
+
+	float aspect_ratio = p_rect.size.x / p_rect.size.y;
+
+	// setup our lens shader
+	state.lens_shader.bind();
+	state.lens_shader.set_uniform(LensDistortedShaderGLES2::OFFSET, offset);
+	state.lens_shader.set_uniform(LensDistortedShaderGLES2::SCALE, scale);
+	state.lens_shader.set_uniform(LensDistortedShaderGLES2::K1, p_k1);
+	state.lens_shader.set_uniform(LensDistortedShaderGLES2::K2, p_k2);
+	state.lens_shader.set_uniform(LensDistortedShaderGLES2::EYE_CENTER, p_eye_center);
+	state.lens_shader.set_uniform(LensDistortedShaderGLES2::UPSCALE, p_oversample);
+	state.lens_shader.set_uniform(LensDistortedShaderGLES2::ASPECT_RATIO, aspect_ratio);
+
+	// bind our quad buffer
+	_bind_quad_buffer();
+
+	// and draw
+	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+	// and cleanup
+	glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+	for (int i = 0; i < VS::ARRAY_MAX; i++) {
+		glDisableVertexAttribArray(i);
+	}
+}
+
 void RasterizerCanvasGLES2::draw_window_margins(int *black_margin, RID *black_image) {
 }
 
@@ -1161,6 +1198,8 @@ void RasterizerCanvasGLES2::initialize() {
 	state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true);
 
 	state.canvas_shader.bind();
+
+	state.lens_shader.init();
 }
 
 void RasterizerCanvasGLES2::finalize() {

+ 3 - 0
drivers/gles2/rasterizer_canvas_gles2.h

@@ -34,6 +34,7 @@
 #include "servers/visual/rasterizer.h"
 
 #include "shaders/canvas.glsl.gen.h"
+#include "shaders/lens_distorted.glsl.gen.h"
 
 // #include "shaders/canvas_shadow.glsl.gen.h"
 
@@ -70,6 +71,7 @@ public:
 		bool canvas_texscreen_used;
 		CanvasShaderGLES2 canvas_shader;
 		// CanvasShadowShaderGLES3 canvas_shadow_shader;
+		LensDistortedShaderGLES2 lens_shader;
 
 		bool using_texture_rect;
 		bool using_ninepatch;
@@ -117,6 +119,7 @@ public:
 
 	void _bind_quad_buffer();
 	void draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src);
+	void draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample);
 
 	void initialize();
 	void finalize();

+ 20 - 0
drivers/gles2/rasterizer_gles2.cpp

@@ -406,6 +406,26 @@ void RasterizerGLES2::blit_render_target_to_screen(RID p_render_target, const Re
 	canvas->canvas_end();
 }
 
+void RasterizerGLES2::output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) {
+	ERR_FAIL_COND(storage->frame.current_rt);
+
+	RasterizerStorageGLES2::RenderTarget *rt = storage->render_target_owner.getornull(p_render_target);
+	ERR_FAIL_COND(!rt);
+
+	glDisable(GL_BLEND);
+
+	// render to our framebuffer
+	glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo);
+
+	// output our texture
+	glActiveTexture(GL_TEXTURE0);
+	glBindTexture(GL_TEXTURE_2D, rt->color);
+
+	canvas->draw_lens_distortion_rect(p_screen_rect, p_k1, p_k2, p_eye_center, p_oversample);
+
+	glBindTexture(GL_TEXTURE_2D, 0);
+}
+
 void RasterizerGLES2::end_frame(bool p_swap_buffers) {
 
 	if (OS::get_singleton()->is_layered_allowed()) {

+ 1 - 0
drivers/gles2/rasterizer_gles2.h

@@ -59,6 +59,7 @@ public:
 	virtual void restore_render_target();
 	virtual void clear_render_target(const Color &p_color);
 	virtual void blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen = 0);
+	virtual void output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample);
 	virtual void end_frame(bool p_swap_buffers);
 	virtual void finalize();
 

+ 1 - 0
drivers/gles2/shaders/SCsub

@@ -20,3 +20,4 @@ if 'GLES2_GLSL' in env['BUILDERS']:
 #    env.GLES2_GLSL('exposure.glsl');
 #    env.GLES2_GLSL('tonemap.glsl');
 #    env.GLES2_GLSL('particles.glsl');
+    env.GLES2_GLSL('lens_distorted.glsl');

+ 62 - 0
drivers/gles2/shaders/lens_distorted.glsl

@@ -0,0 +1,62 @@
+/* clang-format off */
+[vertex]
+
+attribute highp vec2 vertex; // attrib:0
+/* clang-format on */
+
+uniform vec2 offset;
+uniform vec2 scale;
+
+varying vec2 uv_interp;
+
+void main() {
+
+	uv_interp = vertex.xy * 2.0 - 1.0;
+
+	vec2 v = vertex.xy * scale + offset;
+	gl_Position = vec4(v, 0.0, 1.0);
+}
+
+/* clang-format off */
+[fragment]
+
+uniform sampler2D source; //texunit:0
+/* clang-format on */
+
+uniform vec2 eye_center;
+uniform float k1;
+uniform float k2;
+uniform float upscale;
+uniform float aspect_ratio;
+
+varying vec2 uv_interp;
+
+void main() {
+	vec2 coords = uv_interp;
+	vec2 offset = coords - eye_center;
+
+	// take aspect ratio into account
+	offset.y /= aspect_ratio;
+
+	// distort
+	vec2 offset_sq = offset * offset;
+	float radius_sq = offset_sq.x + offset_sq.y;
+	float radius_s4 = radius_sq * radius_sq;
+	float distortion_scale = 1.0 + (k1 * radius_sq) + (k2 * radius_s4);
+	offset *= distortion_scale;
+
+	// reapply aspect ratio
+	offset.y *= aspect_ratio;
+
+	// add our eye center back in
+	coords = offset + eye_center;
+	coords /= upscale;
+
+	// and check our color
+	if (coords.x < -1.0 || coords.y < -1.0 || coords.x > 1.0 || coords.y > 1.0) {
+		gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
+	} else {
+		coords = (coords + vec2(1.0)) / vec2(2.0);
+		gl_FragColor = texture2D(source, coords);
+	}
+}

+ 34 - 0
drivers/gles3/rasterizer_canvas_gles3.cpp

@@ -1869,6 +1869,39 @@ void RasterizerCanvasGLES3::draw_generic_textured_rect(const Rect2 &p_rect, cons
 	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 }
 
+void RasterizerCanvasGLES3::draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) {
+	Vector2 half_size;
+	if (storage->frame.current_rt) {
+		half_size = Vector2(storage->frame.current_rt->width, storage->frame.current_rt->height);
+	} else {
+		half_size = OS::get_singleton()->get_window_size();
+	}
+	half_size *= 0.5;
+	Vector2 offset((p_rect.position.x - half_size.x) / half_size.x, (p_rect.position.y - half_size.y) / half_size.y);
+	Vector2 scale(p_rect.size.x / half_size.x, p_rect.size.y / half_size.y);
+
+	float aspect_ratio = p_rect.size.x / p_rect.size.y;
+
+	// setup our lens shader
+	state.lens_shader.bind();
+	state.lens_shader.set_uniform(LensDistortedShaderGLES3::OFFSET, offset);
+	state.lens_shader.set_uniform(LensDistortedShaderGLES3::SCALE, scale);
+	state.lens_shader.set_uniform(LensDistortedShaderGLES3::K1, p_k1);
+	state.lens_shader.set_uniform(LensDistortedShaderGLES3::K2, p_k2);
+	state.lens_shader.set_uniform(LensDistortedShaderGLES3::EYE_CENTER, p_eye_center);
+	state.lens_shader.set_uniform(LensDistortedShaderGLES3::UPSCALE, p_oversample);
+	state.lens_shader.set_uniform(LensDistortedShaderGLES3::ASPECT_RATIO, aspect_ratio);
+
+	glBindBufferBase(GL_UNIFORM_BUFFER, 0, state.canvas_item_ubo);
+	glBindVertexArray(data.canvas_quad_array);
+
+	// and draw
+	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+	glBindVertexArray(0);
+	glBindBufferBase(GL_UNIFORM_BUFFER, 0, 0);
+}
+
 void RasterizerCanvasGLES3::draw_window_margins(int *black_margin, RID *black_image) {
 
 	Vector2 window_size = OS::get_singleton()->get_window_size();
@@ -2058,6 +2091,7 @@ void RasterizerCanvasGLES3::initialize() {
 	state.canvas_shader.init();
 	state.canvas_shader.set_base_material_tex_index(2);
 	state.canvas_shadow_shader.init();
+	state.lens_shader.init();
 
 	state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_RGBA_SHADOWS, storage->config.use_rgba_2d_shadows);
 	state.canvas_shadow_shader.set_conditional(CanvasShadowShaderGLES3::USE_RGBA_SHADOWS, storage->config.use_rgba_2d_shadows);

+ 3 - 0
drivers/gles3/rasterizer_canvas_gles3.h

@@ -35,6 +35,7 @@
 #include "servers/visual/rasterizer.h"
 
 #include "shaders/canvas_shadow.glsl.gen.h"
+#include "shaders/lens_distorted.glsl.gen.h"
 
 class RasterizerSceneGLES3;
 
@@ -72,6 +73,7 @@ public:
 		bool canvas_texscreen_used;
 		CanvasShaderGLES3 canvas_shader;
 		CanvasShadowShaderGLES3 canvas_shadow_shader;
+		LensDistortedShaderGLES3 lens_shader;
 
 		bool using_texture_rect;
 		bool using_ninepatch;
@@ -141,6 +143,7 @@ public:
 	virtual void reset_canvas();
 
 	void draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src);
+	void draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample);
 
 	void initialize();
 	void finalize();

+ 20 - 0
drivers/gles3/rasterizer_gles3.cpp

@@ -359,6 +359,26 @@ void RasterizerGLES3::blit_render_target_to_screen(RID p_render_target, const Re
 #endif
 }
 
+void RasterizerGLES3::output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) {
+	ERR_FAIL_COND(storage->frame.current_rt);
+
+	RasterizerStorageGLES3::RenderTarget *rt = storage->render_target_owner.getornull(p_render_target);
+	ERR_FAIL_COND(!rt);
+
+	glDisable(GL_BLEND);
+
+	// render to our framebuffer
+	glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo);
+
+	// output our texture
+	glActiveTexture(GL_TEXTURE0);
+	glBindTexture(GL_TEXTURE_2D, rt->color);
+
+	canvas->draw_lens_distortion_rect(p_screen_rect, p_k1, p_k2, p_eye_center, p_oversample);
+
+	glBindTexture(GL_TEXTURE_2D, 0);
+}
+
 void RasterizerGLES3::end_frame(bool p_swap_buffers) {
 
 	if (OS::get_singleton()->is_layered_allowed()) {

+ 1 - 0
drivers/gles3/rasterizer_gles3.h

@@ -59,6 +59,7 @@ public:
 	virtual void restore_render_target();
 	virtual void clear_render_target(const Color &p_color);
 	virtual void blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen = 0);
+	virtual void output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample);
 	virtual void end_frame(bool p_swap_buffers);
 	virtual void finalize();
 

+ 1 - 0
drivers/gles3/shaders/SCsub

@@ -20,3 +20,4 @@ if 'GLES3_GLSL' in env['BUILDERS']:
     env.GLES3_GLSL('exposure.glsl');
     env.GLES3_GLSL('tonemap.glsl');
     env.GLES3_GLSL('particles.glsl');
+    env.GLES3_GLSL('lens_distorted.glsl');

+ 6 - 4
modules/mobile_vr/shaders/lens_distorted.glsl → drivers/gles3/shaders/lens_distorted.glsl

@@ -3,16 +3,18 @@
 
 layout(location = 0) in highp vec4 vertex_attrib;
 /* clang-format on */
-layout(location = 4) in vec2 uv_in;
 
-uniform float offset_x;
+uniform vec2 offset;
+uniform vec2 scale;
 
 out vec2 uv_interp;
 
 void main() {
 
-	uv_interp = uv_in;
-	gl_Position = vec4(vertex_attrib.x + offset_x, vertex_attrib.y, 0.0, 1.0);
+	uv_interp = vertex_attrib.xy * 2.0 - 1.0;
+
+	vec2 v = vertex_attrib.xy * scale + offset;
+	gl_Position = vec4(v, 0.0, 1.0);
 }
 
 /* clang-format off */

+ 0 - 2
modules/mobile_vr/SCsub

@@ -6,5 +6,3 @@ Import('env_modules')
 env_mobile_vr = env_modules.Clone()
 
 env_mobile_vr.add_source_files(env.modules_sources, '*.cpp')
-
-SConscript("shaders/SCsub")

+ 9 - 83
modules/mobile_vr/mobile_vr_interface.cpp

@@ -297,49 +297,6 @@ bool MobileVRInterface::initialize() {
 		mag_current_min = Vector3(0, 0, 0);
 		mag_current_max = Vector3(0, 0, 0);
 
-#if !defined(SERVER_ENABLED)
-		// build our shader
-		if (lens_shader == NULL) {
-			///@TODO need to switch between GLES2 and GLES3 version, Reduz suggested moving this into our drivers and making this a core shader
-			// create a shader
-			lens_shader = new LensDistortedShaderGLES3();
-
-			// create our shader stuff
-			lens_shader->init();
-
-			glGenBuffers(1, &half_screen_quad);
-			glBindBuffer(GL_ARRAY_BUFFER, half_screen_quad);
-			{
-				/* clang-format off */
-				const float qv[16] = {
-					0, -1,
-					-1, -1,
-					0, 1,
-					-1, 1,
-					1, 1,
-					1, 1,
-					1, -1,
-					1, -1,
-				};
-				/* clang-format on */
-
-				glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 16, qv, GL_STATIC_DRAW);
-			}
-
-			glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
-
-			glGenVertexArrays(1, &half_screen_array);
-			glBindVertexArray(half_screen_array);
-			glBindBuffer(GL_ARRAY_BUFFER, half_screen_quad);
-			glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0);
-			glEnableVertexAttribArray(0);
-			glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, ((uint8_t *)NULL) + 8);
-			glEnableVertexAttribArray(4);
-			glBindVertexArray(0);
-			glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
-		}
-#endif
-
 		// reset our orientation
 		orientation = Basis();
 
@@ -362,17 +319,6 @@ void MobileVRInterface::uninitialize() {
 			arvr_server->clear_primary_interface_if(this);
 		}
 
-#if !defined(SERVER_ENABLED)
-		// cleanup our shader and buffers
-		if (lens_shader != NULL) {
-			glDeleteVertexArrays(1, &half_screen_array);
-			glDeleteBuffers(1, &half_screen_quad);
-
-			delete lens_shader;
-			lens_shader = NULL;
-		}
-#endif
-
 		initialized = false;
 	};
 };
@@ -448,48 +394,30 @@ void MobileVRInterface::commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_t
 	// We must have a valid render target
 	ERR_FAIL_COND(!p_render_target.is_valid());
 
-	// We must have an initialised shader
-	ERR_FAIL_COND(lens_shader != NULL);
-
 	// Because we are rendering to our device we must use our main viewport!
 	ERR_FAIL_COND(p_screen_rect == Rect2());
 
-	float offset_x = 0.0;
+	Rect2 dest = p_screen_rect;
 	float aspect_ratio = 0.5 * p_screen_rect.size.x / p_screen_rect.size.y;
 	Vector2 eye_center;
 
+	// we output half a screen
+	dest.size.x *= 0.5;
+
 	if (p_eye == ARVRInterface::EYE_LEFT) {
-		offset_x = -1.0;
 		eye_center.x = ((-intraocular_dist / 2.0) + (display_width / 4.0)) / (display_width / 2.0);
 	} else if (p_eye == ARVRInterface::EYE_RIGHT) {
+		dest.position.x = dest.size.x;
 		eye_center.x = ((intraocular_dist / 2.0) - (display_width / 4.0)) / (display_width / 2.0);
 	}
+	// we don't offset the eye center vertically (yet)
+	eye_center.y = 0.0;
 
 	// unset our render target so we are outputting to our main screen by making RasterizerStorageGLES3::system_fbo our current FBO
 	VSG::rasterizer->set_current_render_target(RID());
 
-	// now output to screen
-	//	VSG::rasterizer->blit_render_target_to_screen(p_render_target, screen_rect, 0);
-
-	// get our render target
-	RID eye_texture = VSG::storage->render_target_get_texture(p_render_target);
-	uint32_t texid = VS::get_singleton()->texture_get_texid(eye_texture);
-#if !defined(SERVER_ENABLED)
-	glActiveTexture(GL_TEXTURE0);
-	glBindTexture(GL_TEXTURE_2D, texid);
-
-	lens_shader->bind();
-	lens_shader->set_uniform(LensDistortedShaderGLES3::OFFSET_X, offset_x);
-	lens_shader->set_uniform(LensDistortedShaderGLES3::K1, k1);
-	lens_shader->set_uniform(LensDistortedShaderGLES3::K2, k2);
-	lens_shader->set_uniform(LensDistortedShaderGLES3::EYE_CENTER, eye_center);
-	lens_shader->set_uniform(LensDistortedShaderGLES3::UPSCALE, oversample);
-	lens_shader->set_uniform(LensDistortedShaderGLES3::ASPECT_RATIO, aspect_ratio);
-
-	glBindVertexArray(half_screen_array);
-	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-	glBindVertexArray(0);
-#endif
+	// and output
+	VSG::rasterizer->output_lens_distorted_to_screen(p_render_target, dest, k1, k2, eye_center, oversample);
 };
 
 void MobileVRInterface::process() {
@@ -512,8 +440,6 @@ MobileVRInterface::MobileVRInterface() {
 	k1 = 0.215;
 	k2 = 0.215;
 	last_ticks = 0;
-
-	lens_shader = NULL;
 };
 
 MobileVRInterface::~MobileVRInterface() {

+ 0 - 12
modules/mobile_vr/mobile_vr_interface.h

@@ -34,10 +34,6 @@
 #include "servers/arvr/arvr_interface.h"
 #include "servers/arvr/arvr_positional_tracker.h"
 
-#if !defined(SERVER_ENABLED)
-#include "shaders/lens_distorted.glsl.gen.h"
-#endif
-
 /**
 	@author Bastiaan Olij <[email protected]>
 
@@ -60,14 +56,6 @@ private:
 	float eye_height;
 	uint64_t last_ticks;
 
-#if !defined(SERVER_ENABLED)
-	LensDistortedShaderGLES3 *lens_shader;
-	GLuint half_screen_quad;
-	GLuint half_screen_array;
-#else
-	void *lens_shader;
-#endif
-
 	real_t intraocular_dist;
 	real_t display_width;
 	real_t display_to_lens;

+ 0 - 6
modules/mobile_vr/shaders/SCsub

@@ -1,6 +0,0 @@
-#!/usr/bin/env python
-
-Import('env')
-
-if 'GLES3_GLSL' in env['BUILDERS']:
-    env.GLES3_GLSL('lens_distorted.glsl');

+ 1 - 0
servers/visual/rasterizer.h

@@ -1104,6 +1104,7 @@ public:
 	virtual void restore_render_target() = 0;
 	virtual void clear_render_target(const Color &p_color) = 0;
 	virtual void blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen = 0) = 0;
+	virtual void output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) = 0;
 	virtual void end_frame(bool p_swap_buffers) = 0;
 	virtual void finalize() = 0;