Three.js: Skinned mesh with normal map lighting distortions

Created on 17 May 2018  路  13Comments  路  Source: mrdoob/three.js

Description of the problem

I have a flat mesh with skeletal animations and a normal map. When bones are rotated from the default position and alter the faces, the normals from the map seem to get distorted creating visible edges between triangles.

This occurs with both MeshStandardMaterial and MeshPhongMaterial.

Live preview: https://madisjanno.github.io/ProceduralCreatures/
distorted

Three.js version
  • [x] r87
  • [x] dev
Browser
  • [ ] All of them
  • [x] Chrome
  • [x] Firefox
  • [ ] Internet Explorer
OS
  • [ ] All of them
  • [x] Windows
  • [ ] macOS
  • [ ] Linux
  • [ ] Android
  • [ ] iOS
Bug

Most helpful comment

I put together a much shorter example here: https://jsfiddle.net/1d1hafg2/2/

Example of what I would expect: https://jsfiddle.net/rv54moep/1/

All 13 comments

Can you please provide a version without a normal map applied?

distorted2
Without the normal map, all normals point towards (0,0,1).

I tried setting the normals to (0,1,0)
image
There are no lighting discontinuities.

A similar setup with a normal map pointing towards (0,1,0) and regular normals being (0,0,1)
image
Has really bad discontinuities.

Sorry, we are not going to debug your app. You will need to provide a simple example.

Try applying your normal map to a tessellated PlaneGeometry.

I put together a much shorter example here: https://jsfiddle.net/1d1hafg2/2/

Example of what I would expect: https://jsfiddle.net/rv54moep/1/

it's almost as if material.shading is set to THREE.FlatShading by default. do we even still have this shading property?

@makc It's Material.flatShading now.

@Mugen87 setting that to true nukes the material entirely https://jsfiddle.net/rv54moep/2/

You cannot render normal maps with three.js the way you want to. Three does no averaging of the tangents so i think for the purposes of normal mapping it is as if you had FlatShading always set.

Pretty much the only thing you can do is:

Try applying your normal map to a ~tessellated~ PlaneGeometry.

_(it doesn't have to be tessellated actually, but yeah, a flat surface is the only thing that can be normal mapped with three)_

This is not a bug, this is a feature. Three.js has been designed to work this way.

I've made an example that illustrates this issue:

http://192.241.199.119:8080/dev/testwp/

screen shot 2018-05-22 at 4 06 31 pm

Notice how using a different normal mapping method works. It's hard to tell if the seams exist even in problematic places (like where uvs meet and such). It's all very continuous and smooth.

As soon as you flip to three.js you start seeing triangles everywhere.

This is not a bug, this is a feature.

What is the upside of this design?

I'm not sure i'm not aware of any, i hope others pitch in.

It's probably not a lot of code, and it all happens in the shader so it's somewhat self contained. This is the least you can do, in order to say "three.js can render normal maps".

It may also fail in places where you don't have derivatives but you could render normal maps perfectly fine with provided tangents.

I really think it would be beneficial to document this behavior. I think it would have saved some time here:

Sorry, we are not going to debug your app. You will need to provide a simple example.

There would be no need to provide a different example nor debug the app if this were known behavior.

Some upsides I thought of:

  1. You don鈥檛 need to provide any extra tangent information. (Saves some memory and such), makes it simple.

  2. It works really well on THREE.PlaneGeometry, so for effects like brick walls it does the job probably better than alternatives.

But its as you can see, fairly limited.

edit

I just looked it up, the non derived tangent space got nuked in r64, which was late 2013.

You can override this behaviour though, but it's not easy.

I think I need to correct myself, I don鈥檛 actually quite fully understand how this breaks down but the lee head looks decent. But it鈥檚 worth investigating and writing up some conclusions. It depends a lot on the normal map. Also if your geometry is heavily tessellated it may reduce this issue, but this kinda defeats the purpose of normal maps.

@madisjanno Your normal map is specifying normals which are tangent to the surface.

Closing. You can reopen if you can clearly demonstrate a three.js bug.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Horray picture Horray  路  3Comments

yqrashawn picture yqrashawn  路  3Comments

filharvey picture filharvey  路  3Comments

scrubs picture scrubs  路  3Comments

seep picture seep  路  3Comments