Godot 4.3
I’m using decals to place posters on the walls of a 3D scene. They work fine, but I can’t maintain the aspect ratio of the image. In the editor, it has handles to stretch the extents of the decal but this deforms the image. Any ideas?
Godot 4.3
I’m using decals to place posters on the walls of a 3D scene. They work fine, but I can’t maintain the aspect ratio of the image. In the editor, it has handles to stretch the extents of the decal but this deforms the image. Any ideas?
2 options, use a script to enforce it or use Textured Quads Instead.
Create a script attached to your decal that enforces the aspect ratio.
@tool
extends Decal
@export var texture: Texture
@export var maintain_aspect_ratio: bool = true
@export var width: float = 1.0 : set = set_width
func _ready():
if texture and maintain_aspect_ratio:
update_size()
func set_width(new_width):
width = new_width
if texture and maintain_aspect_ratio:
update_size()
func update_size():
var aspect_ratio = float(texture.get_width()) / float(texture.get_height())
var height = width / aspect_ratio
extents = Vector3(width / 2, height / 2, extents.z)
Use Textured Quads Instead. For posters specifically, consider using simple flat meshes with textures:
Create a QuadMesh or PlaneMesh and Apply your poster texture to the material. Position it slightly offset from the wall to avoid z-fighting. This gives a more full control over proportions and often looks better for flat objects like posters.
This is awesome. Thanks!
There is a small problem on line 20 (see below). I checked the docs and Decal doesn’t have a property “extents”, but it does have “size”.
Sorry, I primarily program in C# and wasn’t testing before I sent it lol. You are right its size.
@tool
extends Decal
@export var texture: Texture
@export var maintain_aspect_ratio: bool = true
@export var width: float = 1.0 : set = set_width
func _ready():
if texture and maintain_aspect_ratio:
update_size()
func set_width(new_width):
width = new_width
if texture and maintain_aspect_ratio:
update_size()
func update_size():
var aspect_ratio = float(texture.get_width()) / float(texture.get_height())
var height = width / aspect_ratio
size = Vector3(width, height, size.z)
this should work now. Sorry bout that.
Okay, it works - except for 1 more problem:
Decals project their image from -Y local direction. The script seems to be maintaining the ratio but its from the +Z direction (the bottom box shown with the red arrow) where the image doesn’t project from.
You see, thats because im a big dummy and im writing code at 420 am my time lol
Godot Decals project along their negative Y axis , not along Z as my script was assuming.
func update_size():
var aspect_ratio = float(texture.get_width()) / float(texture.get_height())
# The height affects the Z dimension since decals project along -Y
var depth = width / aspect_ratio
# Keep Y dimension for projection depth, adjust X and Z for aspect ratio
size = Vector3(width, size.y, depth)
Huh, Weird. Sorry i have work in like 3 hours and I haven’t slept much. I can try and figure this out when I get to work. Id say just throw stuff at the wall and see if it sticks?
It works! I just had to close and re-open the scene.
Thanks for your help on this!
The script works great! Here is the complete code if anyone is interested:
# script used to maintain decal image aspect ratio
# add this script to a decal node
# you may need to reload the scene to get it working
@tool
extends Decal
@export var texture: Texture
@export var maintain_aspect_ratio: bool = true
@export var width: float = 1.0 : set = set_width
func _ready():
if texture and maintain_aspect_ratio:
update_size()
func set_width(new_width):
width = new_width
if texture and maintain_aspect_ratio:
update_size()
func update_size():
var aspect_ratio = float(texture.get_width()) / float(texture.get_height())
# The height affects the Z dimension since decals project along -Y
var depth = width / aspect_ratio
# Keep Y dimension for projection depth, adjust X and Z for aspect ratio
size = Vector3(width, size.y, depth)