🏠 Go home.

"ThreeJS, CTMLoader and Flat Shading"

Published on

At work, we're doing some cool things using ThreeJS to render models for our customer-facing portal. To make this as smooth and fast as possible on the frontend, we've integrated this really great compressed mesh format called OpenCTM.

While implementing this, we stumbled across some problems in our 3JS renderer: the models looked like crap. Turns out by default ThreeJS's CTM loader was applying a strange shading to the models, which looks … odd for non-organic shapes. At the time I wrote it off thinking that CTM must be doctoring the normals when compressing and I would have to dive in to its code to figure out why this was happening.

[[/images/3js-smoothshading.png][![This should be a uniform, flat surface. FU CTM.]]](/images/3js-smoothshading.png)

I wrote this off when we were prototyping because we needed to have something that worked ASAP, but we're in to the polishing stages of the frontend which means that mess isn't okay.

Turns out that even when you try to force a flat shading, the mesh still looks like feet, and I couldn't make it render like any of the built in examples for a day or two, even though our STL loading fallback would function just fine. With the CTM loader in particular, it's using a method called BufferGeometry, which does the minimum amount of work possible to get a mesh up and running with minimal memory usage. I discovered this ThreeJS Github issue when I was trying to do, basically anything including wireframing.

You need to pass useBuffers: false in to your Three.CTMLoader.load call, or you're in for a world of hurt. This method could become troublesome when loading complex models, in which case you should probably load in a texturemap, or something like that, but for our usecase, disabling Buffer Loading did not negatively impact our site load time or memory usage.

loader.load( filePath, function(geometry) {
  console.log("I love 3JS");
}, {useWorker: true, useBuffers: false} );

I lost a good three hours on this today, and God knows how many in total, so let's just document this little corner case, shall we? :)

[[/images/3js-flatshading.png][![That's much better. Thank you 3JS]]](/images/3js-flatshading.png)

ThreeJS is a powerful tool, and can be wielded to do some very very cool things (Check out the examples in the ThreeJS link at the top of this post). Our site works across browsers, and takes advantage of cool Web2.4 technologies when they're available, and that's pretty much thanks to ThreeJS and it's no-nonsense APIs. Sure beats the heck out of trying to write an STL to PNG solution like I was trying to do back at the beginning of the year.

Respond to this note:

Ryan Rix is a computer infrastructure fanboy who dabbles in decentralized systems. Reach him on twitter as @rrrrrrrix, via email to ryan@whatthefuck.computer or on Facebook or on Matrix as @rrix:kickass.systems.