Improve dynamic split screen demo (#815)

This commit is contained in:
Hugo Locurcio
2023-01-17 21:41:02 +01:00
committed by GitHub
parent ee5862a782
commit 682b933dac
8 changed files with 84 additions and 46 deletions

View File

@@ -3,12 +3,9 @@
This sample project showcases an implementation of dynamic
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
@@ -38,14 +35,14 @@ distance otherwise.
## 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
the splitting line.
## Screenshots
![Screenshots](screenshots/splitscreen.png)
![Screenshots](screenshots/dynamic_split_screen.webp)

View File

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

View File

@@ -3,7 +3,7 @@ extends CharacterBody3D
# Moves the player
@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):

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -1,18 +1,17 @@
shader_type canvas_item;
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 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 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
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 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);
@@ -27,8 +26,8 @@ void fragment() {
if (split_active) {
vec2 dx = player2_position - player1_position;
float split_slope;
float split_slope;
if (dx.y != 0.0) {
split_slope = dx.x / dx.y;
} else {
@@ -38,16 +37,11 @@ void fragment() {
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_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;
// Check on which side of the split UV is and select the proper view
// 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);
@@ -61,6 +55,11 @@ void fragment() {
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 {
COLOR = vec4(view1, 1.0);

View File

@@ -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="Shader" path="res://split_screen.gdshader" id="3"]
@@ -15,21 +15,26 @@ sky_material = SubResource("ProceduralSkyMaterial_16la2")
[sub_resource type="Environment" id="Environment_vdrvu"]
background_mode = 2
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
glow_enabled = true
[sub_resource type="ShaderMaterial" id="1"]
shader = ExtResource("3")
shader_parameter/viewport_size = null
shader_parameter/split_active = false
shader_parameter/player1_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"]
radius = 0.375
height = 1.75
rings = 4
[sub_resource type="StandardMaterial3D" id="3"]
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
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"]
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="PlaneMesh" id="7"]
@@ -183,12 +203,15 @@ albedo_color = Color(0.791675, 0.946163, 0.317723, 1)
[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)
light_energy = 0.75
shadow_enabled = true
shadow_bias = 0.03
shadow_blur = 2.0
directional_shadow_mode = 0
directional_shadow_split_3 = 0.25
directional_shadow_blend_splits = true
directional_shadow_fade_start = 1.0
directional_shadow_max_distance = 25.0
directional_shadow_max_distance = 12.0
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_vdrvu")
@@ -235,6 +258,14 @@ surface_material_override/0 = SubResource("3")
[node name="CollisionShape3D" type="CollisionShape3D" parent="Player1"]
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="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4.184, 0.875, 3.019)
script = ExtResource("5")
@@ -247,6 +278,15 @@ surface_material_override/0 = SubResource("5")
[node name="CollisionShape3D" type="CollisionShape3D" parent="Player2"]
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="Mesh" type="MeshInstance3D" parent="Ground"]