1
\$\begingroup\$

Godot 4.2

Background:

In my game prototype, I have a following player entity:

enter image description here

Paperdoll2D has a script that dynamically adds the weapon/armor/etc Sprite2D nodes to the main sprite to "dress-up" the character in-game, similar to this:

enter image description here

The game is 3D with flat textures used to represent in-game objects (thinks original Doom, Daggerfall etc).

Problem statement:

I would like the Player3D to have such a texture (for cutscenes, 3rd person etc). Already, the Paperdoll2D node basically composes a complete 2D texture with equipped gear and whatnot, so it makes sense to use it to produce a Sprite3D texture.

enter image description here

Suppose the green outline on the image above is the "Screenshot area". That area (and only that area of the 2D screen) is rendered to a texture and applied as a texture to the Sprite3D (non-realtime, only on demand).

enter image description here

Viewports would be great for this because they can "screenshot" the Paperdoll2D and provide a ViewportTexture for use in Sprite3D.

The problem is, to me Viewports were always non-intuitive. Every tutorial on YT and the official Documentation on Viewports lists the following method to have Viewport actually display something:

Node StructureNode structure within my game

It works, but all the "active" nodes (sprites, player, etc.) have to be "inside" the viewport. Also, it's very unwieldy - any children of the viewport cannot be moved, scaled, rotated, or anything. Moreover, it unnecessarily complicates the tree structure making it frustrating to work with.

How do I implement this without having to have the viewport inside the Player3D node or having to .reparent the Paperdoll2D to the viewport outside?

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

I can suggest a practical workaround that doesn't disrupt your workflow and requires minimal code/scene refactoring:

  • Save your Paperdoll2D branch as a new Scene.
  • Add a Sprite3D Node as a child of your Player3D Scene.
    • Add a SubViewport as a child of Sprite3D.
    • Reparent Paperdoll2D from Player3D to the SpriteViewport SubViewport.

Your player hierarchy should now look like this:

enter image description here

The last thing to do is select the Sprite3D, click on the Texture property in the Inspector, and select "New ViewportTexture". Pick the Player3D > Sprite3D > SubViewport Viewport.

You're done! Now the Sprite3D Node will draw whatever SpriteViewport is rendering but, at the same time, you can easily tweak the Paperdoll2D by editing it as a separate Scene, without the hassle of SubViewports not rendering in the editor.

You may also want to save time when working with many Sprite3Ds. Instead of using the Inspector, you can set the Sprite3D's texture programmatically:

extends Sprite3D

func _ready() -> void:
    texture = $SpriteViewport.get_texture()
\$\endgroup\$
3
  • \$\begingroup\$ Thanks! About 2 hrs after publishing this question I've come to a working solution that is similar to yours, but uses more nodes. I was convinced that Viewports would not work without the SubviewportContainer and .reparent() is unsafe, and needed a workaround. Your solution simplifies this and is indeed correct! \$\endgroup\$
    – Noideas
    Commented Apr 16 at 14:56
  • \$\begingroup\$ I extended my answer to offer an alternative to using the Inspector. This may be useful when working with many Sprite3D-based instances, or to ensure things don't break when moving nodes in the editor. \$\endgroup\$
    – liggiorgio
    Commented Apr 16 at 19:44
  • \$\begingroup\$ That is even better. A fully isolated, separate subsystem-like approach. Thanks again! \$\endgroup\$
    – Noideas
    Commented Apr 17 at 15:25

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .