WIP SSLO
This commit is contained in:
parent
209bafa5f1
commit
e54b8e3504
14 changed files with 204 additions and 117 deletions
|
@ -45,7 +45,6 @@ func refresh_sprite():
|
|||
Direction.RIGHT:
|
||||
$light.region_rect.position = Vector2(64, lit_offset)
|
||||
rot = PI/2
|
||||
$Light2D.rotation = rot
|
||||
$ActivationRange.rotation = rot
|
||||
|
||||
|
||||
|
@ -61,4 +60,4 @@ func _power_status_changed(_powered: bool) -> void:
|
|||
refresh_sprite()
|
||||
|
||||
func update_light():
|
||||
$Light2D.enabled = lit and (manager != null and manager.powered)
|
||||
pass
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
[gd_scene load_steps=8 format=2]
|
||||
[gd_scene load_steps=7 format=2]
|
||||
|
||||
[ext_resource path="res://Graphics/light_shadow_light.png" type="Texture" id=1]
|
||||
[ext_resource path="res://Graphics/tgstation/light.png" type="Texture" id=2]
|
||||
[ext_resource path="res://Actors/Objects/Lightbulb/Lightbulb.gd" type="Script" id=3]
|
||||
[ext_resource path="res://Actors/Components/ActivationRange.gd" type="Script" id=4]
|
||||
|
@ -23,19 +22,6 @@ texture = ExtResource( 2 )
|
|||
region_enabled = true
|
||||
region_rect = Rect2( 32, 0, 32, 32 )
|
||||
|
||||
[node name="Light2D" type="Light2D" parent="."]
|
||||
enabled = false
|
||||
texture = ExtResource( 1 )
|
||||
texture_scale = 3.5
|
||||
energy = 1.2
|
||||
mode = 2
|
||||
shadow_color = Color( 0, 0, 0, 1 )
|
||||
shadow_filter_smooth = 10.0
|
||||
__meta__ = {
|
||||
"_edit_group_": true,
|
||||
"_edit_lock_": true
|
||||
}
|
||||
|
||||
[node name="ActivationRange" type="Area2D" parent="."]
|
||||
visible = false
|
||||
script = ExtResource( 4 )
|
||||
|
|
|
@ -3,11 +3,13 @@ extends Node
|
|||
class_name GameInstance
|
||||
|
||||
onready var ui = $CanvasLayer/ui
|
||||
onready var lighting = $CanvasLayer/sslo
|
||||
onready var world = $world
|
||||
onready var systems = $systems
|
||||
|
||||
func _ready():
|
||||
ui.connect("command", world, "process_command")
|
||||
world.initiate()
|
||||
|
||||
func process_command(cmd: UICommand):
|
||||
match cmd.cmd_type:
|
||||
|
|
|
@ -20,7 +20,6 @@ onready var tilemaps = [ $base, $cables, $floor, $walls ]
|
|||
onready var pois = $pois
|
||||
|
||||
export var unlit = false setget set_unlit
|
||||
onready var darkness = $darkness
|
||||
|
||||
export var shadow_intensity = 0.2
|
||||
|
||||
|
@ -54,8 +53,6 @@ func _process(delta: float):
|
|||
|
||||
func set_unlit(val: bool):
|
||||
unlit = val
|
||||
if darkness:
|
||||
darkness.visible = not val
|
||||
|
||||
# Engine related functions
|
||||
|
||||
|
|
|
@ -7,3 +7,9 @@ func _ready():
|
|||
$floor,
|
||||
$walls
|
||||
]
|
||||
|
||||
func get_occlusion_mask():
|
||||
return $walls.create_occlusion_mask()
|
||||
|
||||
func get_occlusion_offset():
|
||||
return $walls.get_used_rect().position
|
||||
|
|
|
@ -22,10 +22,6 @@ light_mode = 1
|
|||
[node name="map" type="Node2D"]
|
||||
script = ExtResource( 5 )
|
||||
|
||||
[node name="darkness" type="CanvasModulate" parent="."]
|
||||
visible = false
|
||||
color = Color( 0, 0, 0, 1 )
|
||||
|
||||
[node name="editor" type="Node2D" parent="."]
|
||||
|
||||
[node name="deepspace" type="Sprite" parent="."]
|
||||
|
@ -92,14 +88,17 @@ __meta__ = {
|
|||
[node name="Engine" parent="engines" instance=ExtResource( 10 )]
|
||||
position = Vector2( -320, 321 )
|
||||
direction = 0
|
||||
strength = 1.0
|
||||
|
||||
[node name="Engine2" parent="engines" instance=ExtResource( 10 )]
|
||||
position = Vector2( -480, 208 )
|
||||
direction = 0
|
||||
strength = 1.0
|
||||
|
||||
[node name="Engine3" parent="engines" instance=ExtResource( 10 )]
|
||||
position = Vector2( -320, 96 )
|
||||
direction = 0
|
||||
strength = 1.0
|
||||
|
||||
[node name="objects" type="Node2D" parent="."]
|
||||
z_index = 10
|
||||
|
@ -450,10 +449,6 @@ flow = 1
|
|||
[node name="lights" type="Node2D" parent="."]
|
||||
modulate = Color( 0.980392, 0.980392, 0.980392, 1 )
|
||||
z_index = 11
|
||||
__meta__ = {
|
||||
"_edit_group_": true,
|
||||
"_edit_lock_": true
|
||||
}
|
||||
|
||||
[node name="Lighttube" parent="lights" instance=ExtResource( 8 )]
|
||||
position = Vector2( 80, 144 )
|
||||
|
|
|
@ -13,13 +13,9 @@ export var shadow_intensity = 0.2
|
|||
onready var extended_tilemap = get_node(extended_tilemap_node) as TileMap
|
||||
|
||||
func _ready():
|
||||
# Make occluders
|
||||
make_occluders()
|
||||
|
||||
# Convert 2x2 tiles to 1x1 if possible
|
||||
convert_extended()
|
||||
|
||||
|
||||
func convert_extended():
|
||||
var extended = extended_tilemap.tile_set
|
||||
for id in tile_set.get_tiles_ids():
|
||||
|
@ -40,31 +36,20 @@ func convert_extended():
|
|||
extended_tilemap.update_bitmask_region()
|
||||
extended_tilemap.update_dirty_quadrants()
|
||||
|
||||
func make_occluders():
|
||||
func create_occlusion_mask():
|
||||
var tile_size = get_used_rect()
|
||||
var mask_image = Image.new()
|
||||
mask_image.create(tile_size.size.x, tile_size.size.y, false, Image.FORMAT_L8)
|
||||
mask_image.fill(Color.black)
|
||||
mask_image.lock()
|
||||
var occluder_ids = []
|
||||
for occluder_name in occluders:
|
||||
var id = tile_set.find_tile_by_name(occluder_name)
|
||||
if id >= 0:
|
||||
occluder_ids.push_back(id)
|
||||
for id in tile_set.get_tiles_ids():
|
||||
if occluder_ids.find(id) < 0:
|
||||
# Not an occluder, skip it
|
||||
continue
|
||||
# Find all uses of this tile
|
||||
for cell in get_used_cells_by_id(id):
|
||||
# Check sides
|
||||
var occluder = Occluder.new()
|
||||
occluder.ignore_sides = [
|
||||
occluder_ids.find(get_cell(cell.x, cell.y-1)) >= 0, # Top
|
||||
occluder_ids.find(get_cell(cell.x+1, cell.y)) >= 0, # Right
|
||||
occluder_ids.find(get_cell(cell.x, cell.y+1)) >= 0, # Bottom
|
||||
occluder_ids.find(get_cell(cell.x-1, cell.y)) >= 0 # Left
|
||||
]
|
||||
occluder.transform.origin = map_to_world(cell)
|
||||
add_child(occluder)
|
||||
|
||||
|
||||
func set_occluder_origin(origin):
|
||||
for child in get_children():
|
||||
if child is Occluder:
|
||||
child.origin = origin
|
||||
for occluder in occluders:
|
||||
occluder_ids.append(tile_set.find_tile_by_name(occluder))
|
||||
for occluder_id in occluder_ids:
|
||||
for cell in get_used_cells_by_id(occluder_id):
|
||||
mask_image.set_pixelv(cell - tile_size.position, Color.white)
|
||||
mask_image.unlock()
|
||||
mask_image.save_png("res://test.png")
|
||||
var mask_texture = ImageTexture.new()
|
||||
mask_texture.create_from_image(mask_image, 0)
|
||||
return mask_texture
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
extends Node2D
|
||||
|
||||
class_name Occluder
|
||||
|
||||
const MAX_LENGTH = 200
|
||||
const EPSILON = 0.1
|
||||
const DEBUG = false
|
||||
|
||||
var ignore_sides = [false, false, false, false]
|
||||
var size = Vector2(32, 32)
|
||||
var origin = null
|
||||
var polygon: PoolVector2Array = [Vector2.ZERO, Vector2(size.x, 0), Vector2(size.x, size.y), Vector2(0, size.y)]
|
||||
|
||||
func _draw():
|
||||
if polygon == null:
|
||||
return
|
||||
|
||||
if origin == null:
|
||||
return
|
||||
|
||||
var player_position = origin.global_position - global_position
|
||||
|
||||
# Find what edges is the players looking at
|
||||
var edges = [
|
||||
player_position.y < 0, # TOP
|
||||
player_position.x > size.x*2, # RIGHT
|
||||
player_position.y > size.y*2, # BOTTOM
|
||||
player_position.x < 0 # LEFT
|
||||
]
|
||||
|
||||
for current in range(0, polygon.size()):
|
||||
var next = (current + 1) % polygon.size()
|
||||
|
||||
if not ignore_sides[current] and not edges[current]:
|
||||
var points = [
|
||||
(polygon[current] * 2.1 - origin.global_position + global_position) * MAX_LENGTH,
|
||||
polygon[current], polygon[next],
|
||||
(polygon[next] * 2.1 - origin.global_position + global_position) * MAX_LENGTH
|
||||
]
|
||||
draw_polygon(points, [Color.black])
|
||||
if DEBUG:
|
||||
draw_polyline(points, Color.rebeccapurple)
|
||||
else:
|
||||
if DEBUG:
|
||||
if ignore_sides[current]:
|
||||
draw_line(polygon[current], polygon[next], Color.red, 1)
|
||||
else:
|
||||
draw_line(polygon[current], polygon[next], Color.yellow, 2)
|
||||
|
||||
func _process(_delta):
|
||||
update()
|
||||
z_index = 999
|
15
Scenes/Rendering/SSLO.gd
Normal file
15
Scenes/Rendering/SSLO.gd
Normal file
|
@ -0,0 +1,15 @@
|
|||
extends ColorRect
|
||||
|
||||
var player = null
|
||||
var occlusion_mask: ImageTexture = null
|
||||
var occlusion_offset = Vector2.ZERO
|
||||
|
||||
onready var shader = (material as ShaderMaterial)
|
||||
|
||||
func _process(delta):
|
||||
if occlusion_mask != null:
|
||||
shader.set_shader_param("occlusion_mask", occlusion_mask)
|
||||
shader.set_shader_param("occlusion_rect", Color(occlusion_offset.x, occlusion_offset.y, occlusion_mask.get_width(), occlusion_mask.get_height()))
|
||||
var viewport_rect = get_viewport_rect()
|
||||
var camera_offset = player.camera.get_camera_position() - viewport_rect.size * 0.5
|
||||
shader.set_shader_param("viewport_rect", Color(camera_offset.x, camera_offset.y, viewport_rect.size.x, viewport_rect.size.y))
|
34
Scenes/Rendering/SSLO.shader
Normal file
34
Scenes/Rendering/SSLO.shader
Normal file
|
@ -0,0 +1,34 @@
|
|||
shader_type canvas_item;
|
||||
render_mode unshaded;
|
||||
|
||||
uniform vec4 viewport_rect;
|
||||
uniform sampler2D occlusion_mask;
|
||||
uniform vec4 occlusion_rect;
|
||||
uniform float cell_div = 0.03125; // 1/cell_size = 1/32
|
||||
uniform float diffusion = 0.3;
|
||||
uniform float scale_factor = 0.5;
|
||||
|
||||
float tile_at(vec2 coord, vec2 camera_tile_offset, vec2 occlusion_div) {
|
||||
return texture(occlusion_mask, (coord * cell_div - occlusion_rect.xy) * occlusion_div + camera_tile_offset).r;
|
||||
}
|
||||
|
||||
void fragment() {
|
||||
vec2 occlusion_div = 1.0 / occlusion_rect.zw;
|
||||
vec2 camera_offset = viewport_rect.xy * scale_factor;
|
||||
vec2 camera_tile_offset = camera_offset * cell_div * occlusion_div;
|
||||
|
||||
vec2 coords = UV.xy * viewport_rect.zw * scale_factor;
|
||||
float tile = tile_at(coords, camera_tile_offset, occlusion_div);
|
||||
|
||||
vec4 ray_coords = vec4(0,0, viewport_rect.zw/2.) * scale_factor;
|
||||
vec2 ray_dir = normalize(ray_coords.zw - ray_coords.xy);
|
||||
if (int(coords.x+camera_offset.x) % 32 < 1 || int(coords.y+camera_offset.y) % 32 < 1) {
|
||||
COLOR = vec4(1);
|
||||
} else if (distance(coords, ray_coords.xy) < 10.0 || distance(coords, ray_coords.zw) < 10.) {
|
||||
COLOR = vec4(0,1,0,1);
|
||||
} else if (tile >= diffusion) {
|
||||
COLOR = vec4(1,0,0,1);
|
||||
} else {
|
||||
COLOR = texture(SCREEN_TEXTURE, SCREEN_UV);
|
||||
}
|
||||
}
|
92
Scenes/SSLOTest.tscn
Normal file
92
Scenes/SSLOTest.tscn
Normal file
|
@ -0,0 +1,92 @@
|
|||
[gd_scene load_steps=9 format=2]
|
||||
|
||||
[ext_resource path="res://Scenes/Maps/odyssey.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://Scenes/Rendering/SSLO.shader" type="Shader" id=2]
|
||||
[ext_resource path="res://Scenes/UI.tscn" type="PackedScene" id=3]
|
||||
[ext_resource path="res://Scenes/Rendering/SSLO.gd" type="Script" id=4]
|
||||
[ext_resource path="res://Scenes/Game.gd" type="Script" id=5]
|
||||
[ext_resource path="res://test.png" type="Texture" id=6]
|
||||
|
||||
[sub_resource type="GDScript" id=1]
|
||||
script/source = "extends Node2D
|
||||
|
||||
enum Map { RUNTIME, ODYSSEY }
|
||||
|
||||
export(Map) var mapToLoad = Map.RUNTIME
|
||||
|
||||
const playerRes = preload(\"res://Actors/Player/Player.tscn\")
|
||||
|
||||
var map = null
|
||||
var player = null
|
||||
|
||||
func initiate():
|
||||
player = playerRes.instance()
|
||||
player.is_controlled = true
|
||||
map = $map
|
||||
var spawnpoints = map.get_pois(POIData.POIType.SpawnPoint, POIData.POIClass.Player)
|
||||
if spawnpoints.size() > 0:
|
||||
player.transform.origin = (spawnpoints[0] as Node2D).transform.origin
|
||||
else:
|
||||
print(\"Map does not have Player spawnpoint POI! Spawning at origin (very bad)\")
|
||||
$players.add_child(player)
|
||||
$\"/root/scene\".lighting.player = player
|
||||
var occlusion_mask = map.get_occlusion_mask()
|
||||
$\"/root/scene\".lighting.occlusion_mask = occlusion_mask
|
||||
$\"/root/scene\".lighting.occlusion_offset = map.get_occlusion_offset()
|
||||
print(map.get_occlusion_offset())
|
||||
($\"/root/scene/CanvasLayer/TextureRect\" as TextureRect).texture = occlusion_mask
|
||||
|
||||
func initiate_editor():
|
||||
map = $map
|
||||
var occlusion_mask = map.get_occlusion_mask()
|
||||
$\"/root/scene\".lighting.occlusion_mask = occlusion_mask
|
||||
($\"/root/scene/CanvasLayer/TextureRect\" as TextureRect).texture = occlusion_mask
|
||||
"
|
||||
|
||||
[sub_resource type="ShaderMaterial" id=2]
|
||||
shader = ExtResource( 2 )
|
||||
shader_param/viewport_rect = Plane( 0, 0, 1280, 800 )
|
||||
shader_param/occlusion_rect = Plane( -12, -9, 32, 33 )
|
||||
shader_param/cell_div = 0.03125
|
||||
shader_param/diffusion = 0.3
|
||||
shader_param/scale_factor = 0.5
|
||||
shader_param/occlusion_mask = ExtResource( 6 )
|
||||
|
||||
[node name="scene" type="Node"]
|
||||
script = ExtResource( 5 )
|
||||
|
||||
[node name="systems" type="Node" parent="."]
|
||||
|
||||
[node name="world" type="Node2D" parent="."]
|
||||
scale = Vector2( 2, 2 )
|
||||
script = SubResource( 1 )
|
||||
|
||||
[node name="map" parent="world" instance=ExtResource( 1 )]
|
||||
|
||||
[node name="players" type="Node2D" parent="world"]
|
||||
|
||||
[node name="CanvasLayer" type="CanvasLayer" parent="."]
|
||||
|
||||
[node name="TextureRect" type="TextureRect" parent="CanvasLayer"]
|
||||
visible = false
|
||||
margin_right = 20.0
|
||||
margin_bottom = 15.0
|
||||
rect_scale = Vector2( 4, 4 )
|
||||
mouse_filter = 2
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="sslo" type="ColorRect" parent="CanvasLayer"]
|
||||
material = SubResource( 2 )
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
mouse_filter = 2
|
||||
color = Color( 0, 0, 0, 0.764706 )
|
||||
script = ExtResource( 4 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="ui" parent="CanvasLayer" instance=ExtResource( 3 )]
|
||||
visible = false
|
|
@ -69,11 +69,6 @@ _global_script_classes=[ {
|
|||
"language": "GDScript",
|
||||
"path": "res://Scenes/Rendering/MapTiles.gd"
|
||||
}, {
|
||||
"base": "Node2D",
|
||||
"class": "Occluder",
|
||||
"language": "GDScript",
|
||||
"path": "res://Scenes/Rendering/Occluder.gd"
|
||||
}, {
|
||||
"base": "Reference",
|
||||
"class": "POIData",
|
||||
"language": "GDScript",
|
||||
|
@ -117,7 +112,6 @@ _global_script_class_icons={
|
|||
"GameObjectScanner": "",
|
||||
"GameWorld": "",
|
||||
"MapTiles": "",
|
||||
"Occluder": "",
|
||||
"POIData": "",
|
||||
"PowerManager": "",
|
||||
"PowerNetwork": "",
|
||||
|
|
BIN
test.png
Normal file
BIN
test.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 203 B |
34
test.png.import
Normal file
34
test.png.import
Normal file
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/test.png-2b0b935732229e5bd5e655f2644b2498.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://test.png"
|
||||
dest_files=[ "res://.import/test.png-2b0b935732229e5bd5e655f2644b2498.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=false
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
Reference in a new issue