Backface shading in 3DTiles


Is it possible to enable backface shading in 3DTiles. I am trying to visualize a city model where some buildings have wrongly oriented faces pointing inwards. As a result, these faces appear transparent.


As of now there isn’t a global setting for controlling this.

Back face culling is typically controlled by the glTF models embedded in the tiles. If the glTFs are 1.0, you can remove the value 2884 from the technique state’s section. 2884 is the state for CULL_FACE. If the glTF is using the KHR_materials_common extension or is a glTF 2.0 model you can set doubleSided to false.

If you don’t have control over the pipeline generating the 3D Tiles but are willing to modify the source code you can disable back-face culling by going to (cull face) and setting enabled to false. This will disable back-face culling for all models though.


I believe I have a similar issue. I used FME 2017 to export the 3D Tiles and placed them at the right spot. But some of the faces are missing and show up when the camera is rotated to the opposite side. My colleagues told me it’s because the normals are rendered in the opposite direction and pointed me to the “backface” issue.

I followed Sean’s description but I couldn’t find the line (2730) to disable the flag/field.

Please let me know if this is really the issue and how do I fix it. I’m using Cesium 1.41.



Hi Victor,

A lot of stuff moved around in Model.js lately so the new line number is

Specifically the line is:

enabled : booleanStates[WebGLConstants.CULL_FACE],


which can turned to:

enabled : false,

While a bit cumbersome, this is still the best way to disable back face culling without modifying the tileset.

Thanks Sean!

I changed the code and unfortunately the faces were still missing. We ended up fixing the normals (we were using AutoCAD and it was not trivial to flip the normals there, for those who have the same issues this plug-in would help and the faces are showing now.

Another thing I wanted to do is to remove the day/night effect on the face rendering, as this is what I have just after mid-night:

For the style I’m using the code from the workshop tutorial, with globe lighting disabled:

//Stylize the 3D Tiles

var defaultStyle = new Cesium.Cesium3DTileStyle({

color : “color(‘white’)”,

show : true

}); = defaultStyle;

// Enable/Disable lighting based on sun/moon positions

viewer.scene.globe.enableLighting = false;

However, I don’t think the globe lighting flag is for this because when I tried this code in the Cesium demos of the Manhattan city the same darkening occurred.

Any ideas?


The day-night lighting is added automatically from inside the Model class, and unfortunately isn’t configurable right now. If you are willing to modify the Cesium source code, in Model.js there is a line that sets optimizeForCesium to true. If this is set to false instead the model will not be shaded by the sun’s direction.

Thanks again. I did modify the code (line 4652 in the Cesium 1.41 version) in Cesium-1.41\Source\Scene\Model.js to this:

4651 var options = {

4652 optimizeForCesium: false,

4653 addBatchIdToGeneratedShaders : this._addBatchIdToGeneratedShaders

4654 };

But the lighting effect is still there (I’ve saved, restarted the server, refreshed the page… typical stuff). Did I miss something?

Another question is what does “viewer.scene.globe.enableLighting = false;” actually do then?


It’s possible the tileset has its own built-in shaders, in which case there’s not much that can be done. Could you send me the tileset so I could check? (My email address is

viewer.scene.globe.enableLighting is just for the globe. If you turn it on and zoom out you will see that the Earth is shaded based on day/night. But it has no effect on other primitives in the scene.

If you’re looking for a cheap workaround you could set the clock to a good time of day and then pause the clock, something like:

viewer.clock.currentTime = new Cesium.JulianDate(2457522.154792);

viewer.clock.multiplier = 0.0;

But definitely send over the tileset so I can see what can be done with it.

Unfortunately I’m using a model from our school library which is only available for students/staff (I can check if they have changed their rules), so I don’t have the right to forward it… sorry.

However, based on your suggestion I can look into removing the built-in shaders. On that note could you give me some advice on whether you can do it in FME, or AutoCAD?

Yeah I did think about the cheap workaround. But since a person can rotate the view however they like it, there is really no perfect time… But this gives me an idea. Can I add a light source (or move the sun) to match with the camera’s position?

Thanks a lot for your help!


If there is an option for removing shaders it would probably be in the FME export. I haven’t used FME personally so I’m not sure what to suggest. Did you verify if the model actually has shaders?

Cesium only supports a single light source. Your idea for attaching a light source to the camera is definitely the right approach, that’s what I had in mind for the shader fix.

Sorry for the late reply, I’m in fact learning about shaders, modelling, and BIM stuff as I’m working on the project. Turns out the 3D Tiles we have been using for Kingston, ON is publicly available so I can totally send that to you :smiley:

This file contains only those demolished buildings in Kingston (so it’s very sparse with a very small file size), and for your convenience there are the lat lon coordinates of one of the buildings: Lon: -76.56° Lat: 44.22°

What we did was we extruded the 2D plan from within FME and exported the 3D Tiles, which has the same shading issue. We are hoping to “fix” this within FME since it retains the geospatial data while doing the export.

Thanks Sean! (466 KB)

It turns out that tileset doesn’t actually have shaders built in, so that’s good!

I was able to achieve the desired lighting by changing optimizeForCesium: true to optimizeForCesium: false in Model.js. This eventually led me down the path of just adding enableLighting as an option for tileset and models so people don’t have to edit the library code.

If you try the branch in this PR and pass in

enableLighting : false


to the tileset, the lighting should look better.

Cool. I ended up replacing those 17 files instead of pulling (I’m on a computer without SourceTree or any Git clients). Doesn’t seem to change anything but I suspect that’s because I haven’t set the “enableLighting” field you mentioned to false.

Could you explain a bit more on that “enableLighting : false”? I’m not sure which file(s) I’m looking at. Also in the PR you mentioned something about “sunLighting”, does that mean I use looking for this field instead?

Sorry about the confusion, enableLighting was renamed to sunLighting.

When creating the Cesium3DTileset, do something like:

var tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({

url : ‘my-url’,

sunLighting : false



Let me know how that goes.

Thanks for the clarification!

I’ve added in the following line to create the tileset:

var kingston = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
url: ‘3DTileSet/tileset_Kingston_Demolished/tileset.json’,
sunLighting: false,
maximumScreenSpaceError: 32


and have also noted the reference to “sunLighting” in the Model.js file:

var options = {
optimizeForCesium: false,
sunLighting: this._sunLighting,
addBatchIdToGeneratedShaders : this._addBatchIdToGeneratedShaders


but I still see this…

Could you upload how it shows on your end?

Strange… it’s working fine for me. I attached an image of what I see.

My only guess at this point is either the new branch isn’t hooked up correctly or the browser has an old version of the code cached. Could you try clearing your cache or running in Incognito mode (if Chrome)?


hm… peculiar. I’ll try to pull this version and give it a try sometime. In the meantime I’m working on incorporating point clouds and photogrammetry formats for greater details. Will be asking these questions in a separate thread.

Thanks a lot for your help, Sean! I’ll get back to you once I get it working.