Converted receptor ring to mesh with shader. WIP: Bezel changes

This commit is contained in:
Luke Hubmayer-Werner 2019-12-20 21:39:03 +10:30
parent ec8f1f2d53
commit 204aa83461
5 changed files with 180 additions and 54 deletions

View File

@ -8,7 +8,6 @@ func arc_point_list(center: Vector2, radius: float, angle_from:=0.0, angle_to:=3
var point_list = PoolVector2Array()
for i in range(points):
var angle = deg2rad(angle_from + i * (angle_to - angle_from) / (points-1))
# point_list.push_back(center + Vector2(cos(angle), sin(angle)) * radius)
point_list.push_back(center + polar2cartesian(radius, angle))
return point_list

View File

@ -443,6 +443,8 @@ func finished_song(song_key, score_data):
func _input(event):
if !visible:
return
if event is InputEventScreenTouch:
if event.pressed:
var pos = event.position - get_global_transform_with_canvas().get_origin()

View File

@ -1,9 +1,9 @@
#tool
extends Node2D
extends MeshInstance2D
var ring_px := 4
var receptor_px := 24
var shadow_px := 5
var ring_px := 4 # Analogous to diameter
var receptor_px := 24 # Diameter
var shadow_px := 8 # Outer edge, analogous to radius
var shadow_color := Color.black
var center := Vector2(0.0, 0.0)
@ -28,8 +28,11 @@ func make_ring_mesh(inner_vertices: int, thickness: float, radius: float, skew:=
# Outer polygon side-length = inner side-length / sin(inside angle/2)
# inside angle for a polygon is pi-tau/n. We already precalculated tau/n for other purposes.
var r2 = (radius + thickness*0.5)/sin((PI-angle_increment)/2)
var UV_r1 = r1/radius
var UV_r2 = r2/radius
var vertex_list = PoolVector2Array()
var UV_list = PoolVector2Array()
var inner_list = PoolVector2Array()
var outer_list = PoolVector2Array()
for i in inner_vertices:
@ -39,12 +42,16 @@ func make_ring_mesh(inner_vertices: int, thickness: float, radius: float, skew:=
vertex_list.push_back(polar2cartesian(r2, angle_o))
inner_list.push_back(vertex_list[-2])
outer_list.push_back(vertex_list[-1])
UV_list.push_back(polar2cartesian(UV_r1, angle_i))
UV_list.push_back(polar2cartesian(UV_r2, angle_o))
if repeat_start:
vertex_list.push_back(vertex_list[0])
vertex_list.push_back(vertex_list[1])
inner_list.push_back(vertex_list[0])
outer_list.push_back(vertex_list[1])
return [vertex_list, inner_list, outer_list]
UV_list.push_back(UV_list[0])
UV_list.push_back(UV_list[1])
return [vertex_list, inner_list, outer_list, UV_list]
func triangle_area(a: Vector2, b: Vector2, c: Vector2) -> float:
return 0.5 * abs((a.x-c.x)*(b.y-a.y) - (a.x-b.x)*(c.y-a.y))
@ -58,7 +65,6 @@ func arc_point_list(center: Vector2, radius: float, angle_from:=0.0, angle_to:=3
var point_list = PoolVector2Array()
for i in range(points):
var angle = deg2rad(angle_from + i * (angle_to - angle_from) / (points-1))
# point_list.push_back(center + Vector2(cos(angle), sin(angle)) * radius)
point_list.push_back(center + polar2cartesian(radius, angle))
return point_list
@ -67,42 +73,79 @@ func draw_old(circles:=true, shadows:=true): # Receptor ring
var receptor_centers := arc_point_list(center, GameTheme.receptor_ring_radius, Rules.FIRST_COLUMN_ANGLE_DEG, Rules.FIRST_COLUMN_ANGLE_DEG+360.0-Rules.COLS_ANGLE_DEG, Rules.COLS)
if shadows:
#draw_polyline(receptor_circle, shadow_color, ring_px + shadow_px, true)
draw_polyline(receptor_circle, Color.darkblue, ring_px + shadow_px, true)
draw_polyline(receptor_circle, shadow_color, ring_px + shadow_px/2, true)
if circles:
for i in range(len(receptor_centers)):
# draw_circle(receptor_centers[i], (receptor_px + shadow_px)/2, shadow_color)
draw_circle(receptor_centers[i], (receptor_px + shadow_px)/2, Color.darkblue)
draw_circle(receptor_centers[i], receptor_px/2 + shadow_px, shadow_color)
draw_polyline(receptor_circle, GameTheme.receptor_color, ring_px, true)
if circles:
for i in range(len(receptor_centers)):
draw_circle(receptor_centers[i], receptor_px/2, GameTheme.receptor_color)
func _draw():
draw_old(true, true)
var mesh_v = $VerticesSlider.value
var skew = $SkewSlider.value
var dbg_color = Color.red
var ring_thickness = receptor_px + shadow_px
var ring_vertices = make_ring_mesh(mesh_v, ring_thickness, GameTheme.receptor_ring_radius, skew)
var estimated_area = circumscribe_polygon_area(GameTheme.receptor_ring_radius+ring_thickness*0.5, mesh_v) - inscribe_polygon_area(GameTheme.receptor_ring_radius-ring_thickness*0.5, mesh_v)
var ideal_ring_area = PI * (pow(GameTheme.receptor_ring_radius+(receptor_px+shadow_px)/2, 2) - pow(GameTheme.receptor_ring_radius-(receptor_px+shadow_px)/2, 2))
func draw_tris():
var dbg_color = Color(1.0, 0.0, 0.0, 1.0)
draw_polyline(ring_vertices[0], dbg_color)
draw_polyline(ring_vertices[1], dbg_color)
draw_polyline(ring_vertices[2], dbg_color)
var ring_vertices
func update_ring_mesh():
var mesh_v = $VerticesSlider.value
var skew = $SkewSlider.value
var ring_thickness = receptor_px + shadow_px*2
ring_vertices = make_ring_mesh(mesh_v, ring_thickness, GameTheme.receptor_ring_radius, skew)
var temp_mesh = ArrayMesh.new()
var mesh_arrays = []
mesh_arrays.resize(Mesh.ARRAY_MAX)
mesh_arrays[Mesh.ARRAY_VERTEX] = ring_vertices[0]
mesh_arrays[Mesh.ARRAY_TEX_UV] = ring_vertices[3]
# mesh_arrays[Mesh.ARRAY_COLOR] = colors
temp_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLE_STRIP, mesh_arrays)
mesh = temp_mesh
func _draw():
# draw_old(true, true)
# draw_tris()
var mesh_v = $VerticesSlider.value
var skew = $SkewSlider.value
var ring_thickness = receptor_px + shadow_px*2
var estimated_area = circumscribe_polygon_area(GameTheme.receptor_ring_radius+ring_thickness*0.5, mesh_v) - inscribe_polygon_area(GameTheme.receptor_ring_radius-ring_thickness*0.5, mesh_v)
var ideal_ring_area = PI * (pow(GameTheme.receptor_ring_radius+receptor_px/2+shadow_px, 2) - pow(GameTheme.receptor_ring_radius-receptor_px/2-shadow_px, 2))
# var l = len(ring_vertices)
# for i in l:
## estimated_area += triangle_area(ring_vertices[i], ring_vertices[(i+1)%l], ring_vertices[(i+2)%l])
var quad_area = 4*pow(GameTheme.receptor_ring_radius+(receptor_px+shadow_px)/2, 2)
# estimated_area += triangle_area(ring_vertices[i], ring_vertices[(i+1)%l], ring_vertices[(i+2)%l])
var quad_area = 4*pow(GameTheme.receptor_ring_radius+receptor_px/2+shadow_px, 2)
var fps = Performance.get_monitor(Performance.TIME_FPS)
$"/root/main/InputHandler".text = "Vertices: %d*2 Skew: %.3f\nArea: %.0f\n(%.0f%% ideal ring)\n(%.0f%% quad)\nFPS: %.0f"%[mesh_v, skew, estimated_area, 100.0*estimated_area/ideal_ring_area, 100.0*estimated_area/quad_area, fps]
# ._draw()
material.set_shader_param("dot_radius", 0.5*receptor_px/GameTheme.receptor_ring_radius)
material.set_shader_param("line_thickness", 0.5*ring_px/GameTheme.receptor_ring_radius)
material.set_shader_param("shadow_thickness", shadow_px/GameTheme.receptor_ring_radius)
material.set_shader_param("shadow_thickness_taper", -0.75)
material.set_shader_param("px", 0.5/GameTheme.receptor_ring_radius)
func update_ring_mesh_1arg(arg1):
# Hack because signals can't discard arguments when connected to smaller slots :(
update_ring_mesh()
func _ready():
var receptor_array_image := Image.new()
receptor_array_image.create(8, 8, false, Image.FORMAT_RH)
receptor_array_image.lock()
for i in Rules.COLS:
receptor_array_image.set_pixel(i%8, i/8, Color(GameTheme.RADIAL_COL_ANGLES[i], 0.0, 0.0))
receptor_array_image.unlock()
var receptor_data_tex = ImageTexture.new()
receptor_data_tex.create_from_image(receptor_array_image, 0)
set_texture(receptor_data_tex)
material.set_shader_param("num_receptors", Rules.COLS)
update_ring_mesh()
$VerticesSlider.connect("value_changed", self, "update_ring_mesh_1arg")
$SkewSlider.connect("value_changed", self, "update_ring_mesh_1arg")
$"/root".connect("size_changed", self, "update")
func _process(delta):

View File

@ -1,22 +1,35 @@
[gd_scene load_steps=17 format=2]
[gd_scene load_steps=19 format=2]
[ext_resource path="res://main.gd" type="Script" id=1]
[ext_resource path="res://video.gd" type="Script" id=2]
[ext_resource path="res://ScreenFilter.gd" type="Script" id=3]
[ext_resource path="res://Receptors.gd" type="Script" id=4]
[ext_resource path="res://NoteHandler.gd" type="Script" id=5]
[ext_resource path="res://assets/text-4k.png" type="Texture" id=6]
[ext_resource path="res://shaders/notelines.shader" type="Shader" id=7]
[ext_resource path="res://shaders/notemesh.shader" type="Shader" id=8]
[ext_resource path="res://Menu.gd" type="Script" id=9]
[ext_resource path="res://shaders/scoretext.tres" type="Material" id=10]
[ext_resource path="res://ScoreText.gd" type="Script" id=11]
[ext_resource path="res://Bezel.gd" type="Script" id=12]
[ext_resource path="res://assets/NotoSans.tres" type="DynamicFont" id=13]
[ext_resource path="res://InputHandler.gd" type="Script" id=14]
[ext_resource path="res://shaders/receptors.shader" type="Shader" id=4]
[ext_resource path="res://Receptors.gd" type="Script" id=5]
[ext_resource path="res://NoteHandler.gd" type="Script" id=6]
[ext_resource path="res://assets/text-4k.png" type="Texture" id=7]
[ext_resource path="res://shaders/notelines.shader" type="Shader" id=8]
[ext_resource path="res://shaders/notemesh.shader" type="Shader" id=9]
[ext_resource path="res://Menu.gd" type="Script" id=10]
[ext_resource path="res://shaders/scoretext.tres" type="Material" id=11]
[ext_resource path="res://ScoreText.gd" type="Script" id=12]
[ext_resource path="res://Bezel.gd" type="Script" id=13]
[ext_resource path="res://assets/NotoSans.tres" type="DynamicFont" id=14]
[ext_resource path="res://InputHandler.gd" type="Script" id=15]
[sub_resource type="ShaderMaterial" id=1]
shader = ExtResource( 7 )
[sub_resource type="ShaderMaterial" id=4]
shader = ExtResource( 4 )
shader_param/num_receptors = 8
shader_param/line_color = Plane( 0, 0, 1, 1 )
shader_param/dot_color = Plane( 0, 0, 1, 1 )
shader_param/shadow_color = Plane( 0, 0, 0, 1 )
shader_param/line_thickness = 0.006
shader_param/dot_radius = 0.033
shader_param/shadow_thickness = 0.01
shader_param/shadow_thickness_taper = 0.33
shader_param/px = 0.002
[sub_resource type="ShaderMaterial" id=2]
shader = ExtResource( 8 )
shader_param/line_color = Plane( 0.8, 0.8, 1, 0.8 )
shader_param/line_color_double = Plane( 1, 1, 0.6, 0.9 )
shader_param/dot_color = Plane( 1, 1, 1, 0.8 )
@ -27,8 +40,8 @@ shader_param/dot_thickness = 0.033
shader_param/dot_fullbright_thickness = 0.013
shader_param/max_angle = 1.0708
[sub_resource type="ShaderMaterial" id=2]
shader = ExtResource( 8 )
[sub_resource type="ShaderMaterial" id=3]
shader = ExtResource( 9 )
shader_param/bps = null
shader_param/star_color = null
shader_param/held_color = null
@ -63,9 +76,11 @@ __meta__ = {
script = ExtResource( 3 )
[node name="Receptors" type="MeshInstance2D" parent="."]
script = ExtResource( 4 )
material = SubResource( 4 )
script = ExtResource( 5 )
[node name="SkewSlider" type="HSlider" parent="Receptors"]
visible = false
margin_left = -200.0
margin_top = -30.0
margin_right = 200.0
@ -80,6 +95,7 @@ tick_count = 3
ticks_on_borders = true
[node name="VerticesSlider" type="HSlider" parent="Receptors"]
visible = false
margin_left = -200.0
margin_top = -100.0
margin_right = 200.0
@ -88,40 +104,40 @@ min_value = 3.0
max_value = 72.0
value = 36.0
tick_count = 2
ticks_on_borders = true
[node name="NoteHandler" type="Node2D" parent="."]
script = ExtResource( 5 )
script = ExtResource( 6 )
[node name="SlideTrailHandler" type="Node2D" parent="NoteHandler"]
[node name="JudgeText" type="MeshInstance2D" parent="NoteHandler"]
texture = ExtResource( 6 )
texture = ExtResource( 7 )
[node name="notelines" type="MeshInstance2D" parent="NoteHandler"]
material = SubResource( 1 )
[node name="meshinstance" type="MeshInstance2D" parent="NoteHandler"]
material = SubResource( 2 )
[node name="meshinstance" type="MeshInstance2D" parent="NoteHandler"]
material = SubResource( 3 )
[node name="Menu" type="Node2D" parent="."]
visible = false
script = ExtResource( 9 )
script = ExtResource( 10 )
[node name="ScoreText" type="Node2D" parent="Menu"]
material = ExtResource( 10 )
script = ExtResource( 11 )
material = ExtResource( 11 )
script = ExtResource( 12 )
[node name="Bezel" type="Node2D" parent="."]
script = ExtResource( 12 )
script = ExtResource( 13 )
[node name="InputHandler" type="Label" parent="."]
margin_left = -540.0
margin_top = -540.0
margin_right = 540.0
margin_bottom = 540.0
custom_fonts/font = ExtResource( 13 )
custom_fonts/font = ExtResource( 14 )
text = "Fingers on the screen:"
script = ExtResource( 14 )
script = ExtResource( 15 )
__meta__ = {
"_edit_lock_": true
}

66
shaders/receptors.shader Normal file
View File

@ -0,0 +1,66 @@
shader_type canvas_item;
render_mode blend_premul_alpha;
uniform int num_receptors = 8;
uniform vec4 line_color = vec4(0.0, 0.0, 1.0, 1.0);
uniform vec4 dot_color = vec4(0.0, 0.0, 1.0, 1.0);
uniform vec4 shadow_color = vec4(0.0, 0.0, 0.0, 1.0);
//uniform float bps = 1.0;
uniform float line_thickness = 0.006;
uniform float dot_radius = 0.033;
uniform float shadow_thickness = 0.01;
uniform float shadow_thickness_taper = 0.33;
uniform float px = 0.002; // Represents 1px in UV space, for AA purposes
//void vertex() {
//}
float angle_diff(float a, float b) {
float d = mod((a - b), 6.28318);
if (d > 3.14159) d = 6.28318 - d;
return d;
}
void fragment() {
if (COLOR.rgba != vec4(1.0, 0.0, 0.0, 1.0)) {
COLOR.rgba = vec4(0.0);
lowp float dist = distance(UV, vec2(0.0));
lowp float angle = atan(-UV.y, UV.x);
float line_alpha = 0.0;
float dot_alpha = 0.0;
float shadow_alpha = 0.0;
float px2 = px/2.0;
float diff = abs(dist - 1.0);
float d2 = diff - line_thickness;
if (d2 < -px2){
line_alpha = 1.0;
} else if (d2 < shadow_thickness){
if (d2 < px2)
line_alpha = 1.0 - (d2 + px2)/px;
shadow_alpha = 1.0 - min((d2 - shadow_thickness*shadow_thickness_taper)/(shadow_thickness*(1.0-shadow_thickness_taper)), 1.0);
}
// Iterate over all the receptors and check distance to them
for (int i=0; i<num_receptors; i++){
lowp float rads = texelFetch(TEXTURE, ivec2(i%8, i/8), 0).x;
// Check for dot distance
vec2 uv = vec2(cos(rads), -sin(rads));
float dist2 = distance(UV, uv);
float diff2 = dist2 - dot_radius;
if (diff2 < -px2){
dot_alpha = 1.0;
} else if (diff2 < shadow_thickness){
if (diff2 < px2)
dot_alpha = 1.0 - (diff2 + px2)/px;
shadow_alpha = max(shadow_alpha, 1.0-min((diff2 - shadow_thickness*shadow_thickness_taper)/(shadow_thickness*(1.0-shadow_thickness_taper)), 1.0));
}
}
line_alpha = max(line_alpha - dot_alpha, 0.0);
COLOR.rgb = (dot_color.rgb*dot_alpha) + (line_color.rgb*line_alpha) + (shadow_color.rgb*shadow_alpha);
COLOR.a = dot_alpha + line_alpha*(1.0-dot_alpha);
COLOR.a = COLOR.a + shadow_alpha*(1.0-COLOR.a);
COLOR.a = clamp(COLOR.a, 0.0, 1.0); }
}