0
votes

The AFrame performance docs (https://github.com/aframevr/aframe/blob/master/docs/introduction/best-practices.md) recommend pre-baked lighting. I have done this, so now I'd like my mesh to use flat shading. However I'm unclear how to do this?

<a-gltf-model src="..." material="shader: flat">

This has no effect. I also tried iterating the nodes in three.js and setting each material to flat, but that didn't work either. Complete code trying a bunch of things:

<html>
  <head>
    <script src="https://aframe.io/releases/0.9.2/aframe.min.js"></script>
  </head>
  <body>
    <a-scene background="color: #000000">
        <!-- Box.gltf from https://github.com/KhronosGroup/glTF-Sample-Models/blob/master/2.0/Box/glTF -->
        <a-gltf-model id="gltf" src="Box.gltf" position="-1 1 -2"></a-gltf-model>
        <a-box position="1 1 -2" material="shader: flat; color: red"></a-box>
    </a-scene>
    <script>
        var office = document.getElementById( 'gltf' );

        office.addEventListener( 'object3dset', () => {

            const mesh = office.getObject3D( 'mesh' );
            mesh.children[0].material.flatShading = true;
            mesh.children[0].material.needsUpdate = true;
            mesh.children[0].geometry.normalsNeedUpdate = true;

            mesh.traverse( node => {

                if ( node.isMesh === undefined || node.isMesh === false ) {
                    return;
                }

                node.material.flatShading = true;
                node.material.needsUpdate = true;
                node.geometry.normalsNeedUpdate = true;
            } );
        } );
    </script>
  </body>
</html>

This renders like this:

enter image description here

The mesh (on the left) has shading, whereas the box (on the right) is flat shaded. How can I set my mesh to use flat shading?

3
"flat shading" in three.js means the shading is "faceted". Maybe what you want is "un-lit shading". Use MeshBasicMaterial for that; it does not respond to lights.WestLangley
Thanks for your comment and apologies for using the incorrect terminology. Yes, 'un-lit shading' sounds right. Can you suggest how I can do this within the AFrame/Three.js code above?Richard Kennard
Oooh actually that worked! Thanks! Will post an answerRichard Kennard

3 Answers

1
votes

Based on clues from @WestLangley, this code works:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <script src="https://aframe.io/releases/0.9.2/aframe.min.js"></script>
  </head>
  <body>
    <a-scene background="color: #000000">
        <!-- Box.gltf from https://github.com/KhronosGroup/glTF-Sample-Models/blob/master/2.0/Box/glTF -->
        <a-gltf-model id="gltf" src="Box.gltf" position="-1 1 -2"></a-gltf-model>
        <a-box position="1 1 -2" material="shader: flat; color: red"></a-box>
    </a-scene>
    <script>
        var office = document.getElementById( 'gltf' );

        office.addEventListener( 'object3dset', () => {

            const mesh = office.getObject3D( 'mesh' );
            mesh.children[0].material = new THREE.MeshBasicMaterial({map: mesh.children[0].material.map});
        } );
    </script>
  </body>
</html>
1
votes

OP mistakenly referred to unlit shading as flat shading. The later is usually a reference to non-interpolated normal shading. I've kept the original answer below, because it can still be useful for future reference.


Updated Answer:

MeshBasicMaterial can be used to render unlit faces.


Original Answer:

I don't know for sure if there's a way of modifying this on aframe instantiation, but on the three.js side you can update material shading like the following:

node.material.flatShading = true;
node.material.needsUpdate = true;

This JSFiddle illustrates this.

1
votes

I used the answers here to put together an a-frame component that sets an a-entity as unlit, including with meshes that have child meshes

AFRAME.registerComponent('unlit', {

    init: function () {

        function recursivelySetChildrenUnlit(mesh) {

            if (mesh.material && mesh.material.map) {
                mesh.material = new THREE.MeshBasicMaterial({ map: mesh.material.map });
            }

            if (mesh.children) {
                for (var i = 0; i < mesh.children.length; i++) {
                    recursivelySetChildrenUnlit(mesh.children[i]);
                }
            }
        }

        this.el.addEventListener('model-loaded', (e) => {

            const mesh = e.target.getObject3D('mesh');
            for (var i = 0; i < mesh.children.length; i++) {
                recursivelySetChildrenUnlit(mesh.children[i]);
            }

        });
    }
});

All you need to do then is add unlit as a component, like so

<a-entity unlit gltf-model="#model">