Skip to content

Commit

Permalink
Merge pull request #743 from Calinou/add-3d-antialiasing-demo
Browse files Browse the repository at this point in the history
Add a 3D antialiasing demo
  • Loading branch information
aaronfranke authored Jul 11, 2022
2 parents 5efee67 + 9dbd05a commit 044afe7
Show file tree
Hide file tree
Showing 39 changed files with 2,045 additions and 0 deletions.
41 changes: 41 additions & 0 deletions 3d/antialiasing/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# 3D Anti-Aliasing

This project showcases the various 3D antialiasing techniques supported by Godot.

- **Multisample antialiasing (MSAA):** High quality, high performance cost.
Does not blur the image.
- Does not affect shader-induced aliasing (such as specular aliasing) or alpha
scissor materials, so these will remain aliased.
- **Fast approximate antialiasing (FXAA):** Medium quality, low performance cost.
Slightly blurs the image.
- **Temporal antialiasing (TAA):** High-quality, low performance cost. Slightly
blurs the image (but less so than FXAA).
- Antialiasing quality is worse on fast-moving objects than other methods,
especially at lower framerates since the TAA won't have enough time to
converge on those objects.
- Can introduce ghosting artifacts on moving objects, especially if motion
vectors are not correctly generated from a given material shader.
- **Supersampling (SSAA):** The highest-quality technique, but also the most
expensive. Does not blur the image.
- 200% resolution scale is equivalent to 4× SSAA, as each dimension is
doubled. For example, if running in a 1920×1080 window at 200% render scale,
the 3D framebuffer will be 3840×2160.
- SSAA can be used together with FXAA or TAA to counter the blurring added by
those algorithms, while further improving antialiasing quality.

Godot allows using multiple antialiasing techniques at the same time. This can
be useful to obtain the best possible quality, or to find a better performance
tradeoff.

Language: GDScript

Renderer: Vulkan Clustered

## Screenshots

![Screenshot](screenshots/3d_anti_aliasing.png)

## Licenses

Files in the `polyhaven/` folder are downloaded from <https://polyhaven.com/a/dutch_ship_medium>
and are licensed under CC0 1.0 Universal.
100 changes: 100 additions & 0 deletions 3d/antialiasing/anti_aliasing.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
extends Node

const ROT_SPEED = 0.003
const ZOOM_SPEED = 0.125
const MAIN_BUTTONS = MOUSE_BUTTON_MASK_LEFT | MOUSE_BUTTON_MASK_RIGHT | MOUSE_BUTTON_MASK_MIDDLE

var tester_index = 0
var rot_x = -TAU / 16 # This must be kept in sync with RotationX.
var rot_y = TAU / 8 # This must be kept in sync with CameraHolder.
var camera_distance = 2.0
var base_height = ProjectSettings.get_setting("display/window/size/viewport_height")

@onready var testers = $Testers
@onready var camera_holder = $CameraHolder # Has a position and rotates on Y.
@onready var rotation_x = $CameraHolder/RotationX
@onready var camera = $CameraHolder/RotationX/Camera3D


func _ready():
camera_holder.transform.basis = Basis.from_euler(Vector3(0, rot_y, 0))
rotation_x.transform.basis = Basis.from_euler(Vector3(rot_x, 0, 0))
update_gui()


func _unhandled_input(event):
if event.is_action_pressed("ui_left"):
_on_previous_pressed()
if event.is_action_pressed("ui_right"):
_on_next_pressed()

if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_WHEEL_UP:
camera_distance -= ZOOM_SPEED
if event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
camera_distance += ZOOM_SPEED
camera_distance = clamp(camera_distance, 1.5, 6)

if event is InputEventMouseMotion and event.button_mask & MAIN_BUTTONS:
# Compensate motion speed to be resolution-independent (based on the window height).
var relative_motion = event.relative * DisplayServer.window_get_size().y / base_height
rot_y -= relative_motion.x * ROT_SPEED
rot_x -= relative_motion.y * ROT_SPEED
rot_x = clamp(rot_x, -1.57, 0)
camera_holder.transform.basis = Basis.from_euler(Vector3(0, rot_y, 0))
rotation_x.transform.basis = Basis.from_euler(Vector3(rot_x, 0, 0))


func _process(delta):
var current_tester = testers.get_child(tester_index)
# This code assumes CameraHolder's X and Y coordinates are already correct.
var current_position = camera_holder.global_transform.origin.z
var target_position = current_tester.global_transform.origin.z
camera_holder.global_transform.origin.z = lerp(current_position, target_position, 3 * delta)
camera.position.z = lerp(camera.position.z, camera_distance, 10 * delta)


func _on_previous_pressed():
tester_index = max(0, tester_index - 1)
update_gui()


func _on_next_pressed():
tester_index = min(tester_index + 1, testers.get_child_count() - 1)
update_gui()


func update_gui():
$TestName.text = str(testers.get_child(tester_index).name).capitalize()
$Previous.disabled = tester_index == 0
$Next.disabled = tester_index == testers.get_child_count() - 1


func _on_fxaa_toggled(button_pressed):
get_viewport().screen_space_aa = Viewport.SCREEN_SPACE_AA_FXAA if button_pressed else Viewport.SCREEN_SPACE_AA_DISABLED


func _on_temporal_antialiasing_toggled(button_pressed):
get_viewport().use_taa = button_pressed


func _on_msaa_item_selected(index):
get_viewport().msaa = index


func _on_render_scale_item_selected(index):
match index:
0:
get_viewport().scaling_3d_scale = 0.5
1:
get_viewport().scaling_3d_scale = 0.75
2:
get_viewport().scaling_3d_scale = 1.0
3:
get_viewport().scaling_3d_scale = 1.25
4:
get_viewport().scaling_3d_scale = 1.5
5:
get_viewport().scaling_3d_scale = 1.75
6:
get_viewport().scaling_3d_scale = 2.0
Loading

0 comments on commit 044afe7

Please sign in to comment.