Browse Source

Improve dynamic split screen demo (#815)

Hugo Locurcio 2 years ago
parent
commit
682b933dac

+ 7 - 10
viewport/dynamic_split_screen/README.md

@@ -3,12 +3,9 @@
 This sample project showcases an implementation of dynamic
 This sample project showcases an implementation of dynamic
 split screen, also called Voronoi split screen.
 split screen, also called Voronoi split screen.
 
 
-Language: [GDSL](https://docs.godotengine.org/en/latest/tutorials/shaders/shader_reference/shading_language.html) and GDScript
+Language: [Godot shader language](https://docs.godotengine.org/en/latest/tutorials/shaders/shader_reference/shading_language.html) and GDScript
 
 
-Renderer: GLES 2
-
-Note: An HTML5 export is testable
-[here](https://benjaminnavarro.github.io/godot_dynamic_split_screen/index.html).
+Renderer: Forward Mobile
 
 
 Check out this demo on the asset library: https://godotengine.org/asset-library/asset/541
 Check out this demo on the asset library: https://godotengine.org/asset-library/asset/541
 
 
@@ -38,14 +35,14 @@ distance otherwise.
 
 
 ## How to use it
 ## How to use it
 
 
-Open and launch the project inside the Godot engine and then
-you can use WASD keys to move the first player and IJKL keys
-to move the second one.
+Open and launch the project inside the Godot engine, then
+use WASD to move the first player (in red) and IJKL (or arrow keys)
+to move the second player (in blue).
 
 
-The `Cameras` node has parameters to tune the distance at
+The `camera_controller.gd` script sets parameters to tune the distance at
 which the screen splits and also the width and color of
 which the screen splits and also the width and color of
 the splitting line.
 the splitting line.
 
 
 ## Screenshots
 ## Screenshots
 
 
-![Screenshots](screenshots/splitscreen.png)
+![Screenshots](screenshots/dynamic_split_screen.webp)

+ 1 - 0
viewport/dynamic_split_screen/camera_controller.gd

@@ -32,6 +32,7 @@ extends Node3D
 @onready var camera1 = viewport1.get_node(^"Camera1")
 @onready var camera1 = viewport1.get_node(^"Camera1")
 @onready var camera2 = viewport2.get_node(^"Camera2")
 @onready var camera2 = viewport2.get_node(^"Camera2")
 
 
+var viewport_base_height = ProjectSettings.get_setting("display/window/size/viewport_height")
 
 
 func _ready():
 func _ready():
 	_on_size_changed()
 	_on_size_changed()

+ 1 - 1
viewport/dynamic_split_screen/player.gd

@@ -3,7 +3,7 @@ extends CharacterBody3D
 # Moves the player
 # Moves the player
 
 
 @export_range(1, 2) var player_id: int = 1
 @export_range(1, 2) var player_id: int = 1
-@export var walk_speed: float = 2.5
+@export var walk_speed: float = 2
 
 
 
 
 func _physics_process(_delta):
 func _physics_process(_delta):

+ 2 - 1
viewport/dynamic_split_screen/project.godot

@@ -82,6 +82,7 @@ common/physics_ticks_per_second=120
 
 
 [rendering]
 [rendering]
 
 
-anti_aliasing/quality/msaa_3d=2
+renderer/rendering_method="mobile"
 environment/defaults/default_clear_color=Color(1, 1, 1, 1)
 environment/defaults/default_clear_color=Color(1, 1, 1, 1)
+anti_aliasing/quality/msaa_3d=2
 environment/default_environment="res://default_env.tres"
 environment/default_environment="res://default_env.tres"

BIN
viewport/dynamic_split_screen/screenshots/dynamic_split_screen.webp


BIN
viewport/dynamic_split_screen/screenshots/splitscreen.png


+ 27 - 28
viewport/dynamic_split_screen/split_screen.gdshader

@@ -1,18 +1,17 @@
 shader_type canvas_item;
 shader_type canvas_item;
 render_mode unshaded;
 render_mode unshaded;
 
 
-uniform vec2 viewport_size;         // size in pixels of the viewport. Cannot be access from the shader in GLES2
+uniform vec2 viewport_size;          // size in pixels of the viewport
 uniform sampler2D viewport1 : source_color;
 uniform sampler2D viewport1 : source_color;
 uniform sampler2D viewport2 : source_color;
 uniform sampler2D viewport2 : source_color;
-uniform bool split_active;          // true: split screen, false: use view1
-uniform vec2 player1_position;      // position of player 1 un UV coordinates
-uniform vec2 player2_position;      // position of player 2 un UV coordinates
-uniform float split_line_thickness; // width of the split boder
-uniform vec4 split_line_color;      // color of the split border
-
+uniform bool split_active;           // true: split screen, false: use view1
+uniform vec2 player1_position;       // position of player 1 un UV coordinates
+uniform vec2 player2_position;       // position of player 2 un UV coordinates
+uniform float split_line_thickness : hint_range(0, 10, 0.1);  // width of the split boder
+uniform vec3 split_line_color : source_color;       // color of the split border
 
 
 // from https://stackoverflow.com/questions/15276454/is-it-possible-to-draw-line-thickness-in-a-fragment-shader
 // from https://stackoverflow.com/questions/15276454/is-it-possible-to-draw-line-thickness-in-a-fragment-shader
-float distanceToLine(vec2 p1, vec2 p2, vec2 point) {
+float distance_to_line(vec2 p1, vec2 p2, vec2 point) {
 	float a = p1.y - p2.y;
 	float a = p1.y - p2.y;
 	float b = p2.x - p1.x;
 	float b = p2.x - p1.x;
 	return abs(a * point.x + b * point.y + p1.x * p2.y - p2.x * p1.y) / sqrt(a * a + b * b);
 	return abs(a * point.x + b * point.y + p1.x * p2.y - p2.x * p1.y) / sqrt(a * a + b * b);
@@ -27,8 +26,8 @@ void fragment() {
 
 
 	if (split_active) {
 	if (split_active) {
 		vec2 dx = player2_position - player1_position;
 		vec2 dx = player2_position - player1_position;
-		float split_slope;
 
 
+		float split_slope;
 		if (dx.y != 0.0) {
 		if (dx.y != 0.0) {
 			split_slope = dx.x / dx.y;
 			split_slope = dx.x / dx.y;
 		} else {
 		} else {
@@ -38,29 +37,29 @@ void fragment() {
 		vec2 split_origin = vec2(0.5, 0.5);
 		vec2 split_origin = vec2(0.5, 0.5);
 		vec2 split_line_start = vec2(0.0, height * ((split_origin.x - 0.0) * split_slope + split_origin.y));
 		vec2 split_line_start = vec2(0.0, height * ((split_origin.x - 0.0) * split_slope + split_origin.y));
 		vec2 split_line_end = vec2(width, height * ((split_origin.x - 1.0) * split_slope + split_origin.y));
 		vec2 split_line_end = vec2(width, height * ((split_origin.x - 1.0) * split_slope + split_origin.y));
-		float distance_to_split_line = distanceToLine(split_line_start, split_line_end, vec2(UV.x * width, UV.y * height));
 
 
-		// Draw split border if close enough
-		if (distance_to_split_line < split_line_thickness) {
-			COLOR = split_line_color;
-		} else {
-			float split_current_y = (split_origin.x - UV.x) * split_slope + split_origin.y;
-			float split_player1_position_y = (split_origin.x - player1_position.x) * split_slope + split_origin.y;
+		float split_current_y = (split_origin.x - UV.x) * split_slope + split_origin.y;
+		float split_player1_position_y = (split_origin.x - player1_position.x) * split_slope + split_origin.y;
 
 
-			// Check on which side of the split UV is and select the proper view
-			if (UV.y > split_current_y) {
-				if (player1_position.y > split_player1_position_y) {
-					COLOR = vec4(view1, 1.0);
-				} else {
-					COLOR = vec4(view2, 1.0);
-				}
+		// Check on which side of the split UV is and select the proper view.
+		if (UV.y > split_current_y) {
+			if (player1_position.y > split_player1_position_y) {
+				COLOR = vec4(view1, 1.0);
 			} else {
 			} else {
-				if (player1_position.y < split_player1_position_y) {
-					COLOR = vec4(view1, 1.0);
-				} else {
-					COLOR = vec4(view2, 1.0);
-				}
+				COLOR = vec4(view2, 1.0);
 			}
 			}
+		} else {
+			if (player1_position.y < split_player1_position_y) {
+				COLOR = vec4(view1, 1.0);
+			} else {
+				COLOR = vec4(view2, 1.0);
+			}
+		}
+
+		float distance_to_split_line = distance_to_line(split_line_start, split_line_end, vec2(UV.x * width, UV.y * height));
+		if (distance_to_split_line < split_line_thickness) {
+			// Draw antialiased split line.
+			COLOR.rgb = mix(split_line_color, COLOR.rgb, distance_to_split_line / split_line_thickness);
 		}
 		}
 	} else {
 	} else {
 		COLOR = vec4(view1, 1.0);
 		COLOR = vec4(view1, 1.0);

+ 46 - 6
viewport/dynamic_split_screen/split_screen.tscn

@@ -1,4 +1,4 @@
-[gd_scene load_steps=60 format=3 uid="uid://dksa68cph6y4b"]
+[gd_scene load_steps=63 format=3 uid="uid://dksa68cph6y4b"]
 
 
 [ext_resource type="Script" path="res://camera_controller.gd" id="2"]
 [ext_resource type="Script" path="res://camera_controller.gd" id="2"]
 [ext_resource type="Shader" path="res://split_screen.gdshader" id="3"]
 [ext_resource type="Shader" path="res://split_screen.gdshader" id="3"]
@@ -15,21 +15,26 @@ sky_material = SubResource("ProceduralSkyMaterial_16la2")
 [sub_resource type="Environment" id="Environment_vdrvu"]
 [sub_resource type="Environment" id="Environment_vdrvu"]
 background_mode = 2
 background_mode = 2
 sky = SubResource("Sky_i64ko")
 sky = SubResource("Sky_i64ko")
+ambient_light_source = 2
+ambient_light_color = Color(0.79, 0.8775, 1, 1)
+ambient_light_sky_contribution = 0.0
+ambient_light_energy = 0.33
 tonemap_mode = 2
 tonemap_mode = 2
 glow_enabled = true
 glow_enabled = true
 
 
 [sub_resource type="ShaderMaterial" id="1"]
 [sub_resource type="ShaderMaterial" id="1"]
 shader = ExtResource("3")
 shader = ExtResource("3")
+shader_parameter/viewport_size = null
+shader_parameter/split_active = false
 shader_parameter/player1_position = null
 shader_parameter/player1_position = null
 shader_parameter/player2_position = null
 shader_parameter/player2_position = null
-shader_parameter/split_active = null
-shader_parameter/split_line_color = null
-shader_parameter/split_line_thickness = null
-shader_parameter/viewport_size = null
+shader_parameter/split_line_thickness = 10.0
+shader_parameter/split_line_color = Vector3(0, 1, 0)
 
 
 [sub_resource type="CapsuleMesh" id="2"]
 [sub_resource type="CapsuleMesh" id="2"]
 radius = 0.375
 radius = 0.375
 height = 1.75
 height = 1.75
+rings = 4
 
 
 [sub_resource type="StandardMaterial3D" id="3"]
 [sub_resource type="StandardMaterial3D" id="3"]
 albedo_color = Color(0.933333, 0.0784314, 0.0784314, 1)
 albedo_color = Color(0.933333, 0.0784314, 0.0784314, 1)
@@ -38,9 +43,24 @@ albedo_color = Color(0.933333, 0.0784314, 0.0784314, 1)
 radius = 0.375
 radius = 0.375
 height = 1.75
 height = 1.75
 
 
+[sub_resource type="TorusMesh" id="TorusMesh_abtrc"]
+inner_radius = 0.4
+outer_radius = 0.6
+ring_segments = 6
+
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_63nwq"]
+albedo_color = Color(0.5, 0.5, 0.5, 1)
+emission_enabled = true
+emission = Color(1, 0, 0, 1)
+
 [sub_resource type="StandardMaterial3D" id="5"]
 [sub_resource type="StandardMaterial3D" id="5"]
 albedo_color = Color(0.0784314, 0.411765, 0.933333, 1)
 albedo_color = Color(0.0784314, 0.411765, 0.933333, 1)
 
 
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_wi7e2"]
+albedo_color = Color(0.5, 0.5, 0.5, 1)
+emission_enabled = true
+emission = Color(0.12549, 0.501961, 1, 1)
+
 [sub_resource type="StandardMaterial3D" id="6"]
 [sub_resource type="StandardMaterial3D" id="6"]
 
 
 [sub_resource type="PlaneMesh" id="7"]
 [sub_resource type="PlaneMesh" id="7"]
@@ -183,12 +203,15 @@ albedo_color = Color(0.791675, 0.946163, 0.317723, 1)
 
 
 [node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
 [node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
 transform = Transform3D(-0.866025, -0.433013, 0.25, 0, 0.5, 0.866025, -0.5, 0.75, -0.433013, 0, 0, 0)
 transform = Transform3D(-0.866025, -0.433013, 0.25, 0, 0.5, 0.866025, -0.5, 0.75, -0.433013, 0, 0, 0)
+light_energy = 0.75
 shadow_enabled = true
 shadow_enabled = true
+shadow_bias = 0.03
+shadow_blur = 2.0
 directional_shadow_mode = 0
 directional_shadow_mode = 0
 directional_shadow_split_3 = 0.25
 directional_shadow_split_3 = 0.25
 directional_shadow_blend_splits = true
 directional_shadow_blend_splits = true
 directional_shadow_fade_start = 1.0
 directional_shadow_fade_start = 1.0
-directional_shadow_max_distance = 25.0
+directional_shadow_max_distance = 12.0
 
 
 [node name="WorldEnvironment" type="WorldEnvironment" parent="."]
 [node name="WorldEnvironment" type="WorldEnvironment" parent="."]
 environment = SubResource("Environment_vdrvu")
 environment = SubResource("Environment_vdrvu")
@@ -235,6 +258,14 @@ surface_material_override/0 = SubResource("3")
 [node name="CollisionShape3D" type="CollisionShape3D" parent="Player1"]
 [node name="CollisionShape3D" type="CollisionShape3D" parent="Player1"]
 shape = SubResource("4")
 shape = SubResource("4")
 
 
+[node name="MeshInstance3D" type="MeshInstance3D" parent="Player1"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.6, 0)
+mesh = SubResource("TorusMesh_abtrc")
+surface_material_override/0 = SubResource("StandardMaterial3D_63nwq")
+
+[node name="OmniLight3D" type="OmniLight3D" parent="Player1"]
+light_color = Color(1, 0, 0, 1)
+
 [node name="Player2" type="CharacterBody3D" parent="."]
 [node name="Player2" type="CharacterBody3D" parent="."]
 transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4.184, 0.875, 3.019)
 transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4.184, 0.875, 3.019)
 script = ExtResource("5")
 script = ExtResource("5")
@@ -247,6 +278,15 @@ surface_material_override/0 = SubResource("5")
 [node name="CollisionShape3D" type="CollisionShape3D" parent="Player2"]
 [node name="CollisionShape3D" type="CollisionShape3D" parent="Player2"]
 shape = SubResource("4")
 shape = SubResource("4")
 
 
+[node name="MeshInstance3D2" type="MeshInstance3D" parent="Player2"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.7, 0)
+mesh = SubResource("TorusMesh_abtrc")
+skeleton = NodePath("../../Player1")
+surface_material_override/0 = SubResource("StandardMaterial3D_wi7e2")
+
+[node name="OmniLight3D" type="OmniLight3D" parent="Player2"]
+light_color = Color(0.12549, 0.501961, 1, 1)
+
 [node name="Ground" type="StaticBody3D" parent="."]
 [node name="Ground" type="StaticBody3D" parent="."]
 
 
 [node name="Mesh" type="MeshInstance3D" parent="Ground"]
 [node name="Mesh" type="MeshInstance3D" parent="Ground"]