godotengine / godotengine/godot
When using a SubViewport to show 2D scenes the normal map information is lost.
- Dominant language
- C++
- Stars
- 117k
- Forks
- 26.8k
- PR merge metrics
- PR metrics pending
Description
### Tested versions
4.3.stable
### System information
Windows 11 - 4.3.stable.official Vulkan 1.3.280 - Forward+ - Using Device #0: NVIDIA - NVIDIA GeForce RTX 3060 Laptop GPU
### Issue description
When using a SubViewport to show 2D scenes the normal map information is lost.
SubViewport.get_texture() returns a ViewportTexture that does not contain the information regarding normal maps.
For example, if I wanted to project a scene containing some Sprite2D and related textures (CanvasTexture containing diffuse_texture and normal_texture) onto a PlaneMesh using a SubViewport, currently there is no way to make it interact properly with the light coming on the mesh in the 3D environment, because the data about the normal maps is lost.
Here I am projecting a 2D scene on a SubViewport rendered on a mesh, there is no way to retrieve the normal map informations to make it react to the light in the 3D environment (the relative Sprite2D in the 2D scene has a normal map):

On the contrary using a 3D scene it is possible to see its normal information and use it throught Rendering > Debug Draw > Normal Buffer:

I have thought of a few solutions:
- Set the diffuse_texture and normal_texture properties to ViewportTexture, mimicking the behavior of CanvasTexture.
- Add the get_normal() method to SubViewport.
- Make the SubViewport Rendering > Debug Draw > Normal Buffer feature that already works with 3D scenes work for 2D scenes as well.
### Steps to reproduce
- Create a 2D scene with one or more Sprite2D with a CanvasTexture and relative diffuse_texture and normal_texture.
- Create a 3D scene with a MeshInstance3D and a shape.
- Add a SubViewport node to the 3D scene and instantiate the 2D scene as a child of the SubViewport.
- Add a material to the mesh, and add the SubViewport as a ViewportTexture in the albedo property.
- From here there is no way to retrieve the normal map from the 2D scene and use it as a normal map for the material. Did not found any workaround.
### Minimal reproduction project (MRP)
Here there is a little project with a SubViewport where both 3D and 2D scenes projection can be experimented. I animated the lights so that the results can be seen easily.
[bug_sub_viewport_normals.zip](https://github.com/user-attachments/files/16998791/bug_sub_viewport_normals.zip)
Contributor guide
Research direction
Start with the attached minimal reproduction project and trace how SubViewport.get_texture() exposes a ViewportTexture when a CanvasTexture has diffuse and normal textures. Compare the 2D and 3D projection behavior described in the issue; done means the projected 2D scene's normal information can be retrieved and used for lighting on the 3D mesh.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- computer-graphics
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100