godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
90.75k stars 21.12k forks source link

No normals for 2d meshes #47182

Open tripodsan opened 3 years ago

tripodsan commented 3 years ago

Godot version: 3.2.4.RC4

OS/device including version: macOS BigSur, GLES2 / GLES3

Issue description: The normals (Mesh.ARRAY_NORMAL) are not passed to the canvas shader when using a mesh in 2d.

Steps to reproduce:

  1. create a 2d scene with a MeshInstance2D
  2. attach a script to create a mesh (see below)
  3. add a light to the scene
  4. add a light occluder for more light debugging
  5. verify that the mesh is lit (anim 1)
  6. observe that the mesh looks flat, even though it has normals. also, the inspector in the editor lights it better
  7. create a simple shader that create normals:
    
    shader_type canvas_item;

void fragment() { NORMAL = normalize(UV.x < 0.5 ? vec3(-1, 0, 1) : vec3(1, 0, 1)); COLOR = vec4(0.5, 0.5, 0.5, 1.0); }

8. see that it now lights the shape better

**Workaround**
the only workaround I found is to encode the normals in the colors and change the shader:

```swift
  # convert normals to colors
  colors = PoolColorArray();
  for n in normals:
    var c = (n.normalized() + Vector3(1, 1, 1)) / 2.0
    colors.append(Color(c.x, c.y, c.z))
shader_type canvas_item;

void fragment() {
  NORMAL = (COLOR.rgb * 2.0) - vec3(1, 1, 1);
  COLOR = vec4(0.5, 0.5, 0.5, 1.0);
}

Inspector

image

No Normals

https://user-images.githubusercontent.com/917628/111858429-4d413080-897c-11eb-9bbf-527ef64668ee.mp4

With normals via shader

https://user-images.githubusercontent.com/917628/111858546-423ad000-897d-11eb-8e31-6d7a9d4b4be8.mp4

Use color as normals

https://user-images.githubusercontent.com/917628/111858641-dc9b1380-897d-11eb-95be-9cd546245241.mp4

script

tool
extends MeshInstance2D

func _ready() -> void:
  _update_mesh()

func _update_mesh()->void:
  var newMesh = ArrayMesh.new()

  var verts = PoolVector3Array()
  var uvs = PoolVector2Array()
  var normals = PoolVector3Array()
  var indices = PoolIntArray()
  var colors = PoolColorArray()

  verts.append(Vector3(0, 0, 0))
  uvs.append(Vector2(0,0))
  normals.append(Vector3(-1, 0, 1))

  verts.append(Vector3(1, 0, 0))
  uvs.append(Vector2(1,0))
  normals.append(Vector3(1, 0, 1))

  verts.append(Vector3(1, 1, 0))
  uvs.append(Vector2(1,1))
  normals.append(Vector3(1, 0, 1))

  verts.append(Vector3(0, 1, 0))
  uvs.append(Vector2(0,1))
  normals.append(Vector3(-1, 0, 1))

  indices.append_array([0, 3, 1])
  indices.append_array([1, 3, 2])

  # convert normals to colors
  colors = PoolColorArray();
  for n in normals:
    var c = (n.normalized() + Vector3(1, 1, 1)) / 2.0
    colors.append(Color(c.x, c.y, c.z))

  var arr = [];
  arr.resize(Mesh.ARRAY_MAX)
  arr[Mesh.ARRAY_VERTEX] = verts
  arr[Mesh.ARRAY_COLOR] = colors
  arr[Mesh.ARRAY_TEX_UV] = uvs
  arr[Mesh.ARRAY_NORMAL] = normals

  arr[Mesh.ARRAY_INDEX] = indices
  newMesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arr)
  set_mesh(newMesh)

Minimal reproduction project: https://github.com/tripodsan/mesh-test

Calinou commented 3 years ago

@tripodsan Can you reproduce this after disabling batching for both the project and editor in the Project Settings?

tripodsan commented 3 years ago

@tripodsan Can you reproduce this after disabling batching for both the project and editor in the Project Settings?

yeah. same behaviour.

clayjohn commented 3 years ago

2D meshes don't have per-vertex normals. Adding them should be a feature proposal.

We should probably add a note in array mesh, and surface tool.