iTowns / itowns

A Three.js-based framework written in Javascript/WebGL for visualizing 3D geospatial data
http://www.itowns-project.org
Other
1.11k stars 299 forks source link

For 3d tiles, why texture from glTF was discarded? #621

Closed vigourwu closed 6 years ago

vigourwu commented 6 years ago

The code in 3dtiles_provider as below:

    const init = function f_init(mesh) {
        mesh.frustumCulled = false;
        if (mesh.material) {
            if (layer.overrideMaterials) {
                mesh.material.dispose();
                if (typeof (layer.overrideMaterials) === 'object' &&
                    layer.overrideMaterials.isMaterial) {
                    mesh.material = layer.overrideMaterials.clone();
                } else {
                    mesh.material = new THREE.MeshLambertMaterial({ color: 0xffffff });
                }
            } else if (Capabilities.isLogDepthBufferSupported()
                        && mesh.material.isRawShaderMaterial
                        && !layer.doNotPatchMaterial) {
                patchMaterialForLogDepthSupport(mesh.material);
                // eslint-disable-next-line no-console
                console.warn('b3dm shader has been patched to add log depth buffer support');
            }
            mesh.material.transparent = layer.opacity < 1.0;
            mesh.material.opacity = layer.opacity;
        }
    };

The below is my result:

20180123111953

Jeremy-Gaillard commented 6 years ago

This piece of code was implemented because some 3D Tiles assets use Cesium-specific shaders. We replace these shaders with a default Three shader so we can still view these assets.

You can disable this behaviour by setting the overrideMaterials property of the 3D Tiles layer to false.

vigourwu commented 6 years ago

Hi Jeremy-Gaillard, Thanks for your update. After set overrideMaterials = false, I can got a result with texture. But the result is not what I expected. Its transform is completely wrong. I think this is what you mentioned "some 3D Tiles assets use Cesium-specific shaders". Now, I want to know if is there a plan to support Cesium-specific shaders?

Jeremy-Gaillard commented 6 years ago

Supporting Cesium specific shaders is a feature we are interested in, but I am not aware of any plan that will implement it in the foreseeable future. I'm still not sure the problem comes from the shader, since in my last experience, the shader wouldn't even execute and nothing would be rendered. If you can share your 3D Tiles files, I could take a look to see if this is indeed the problem.

vigourwu commented 6 years ago

Hi Jeremy-Gaillard, I upload a data package as scene7.z7. You can download it from https://pan.baidu.com/s/1o9z1Ewa To view it, you can set "var positionOnGlobe = { longitude: 113.5629291, latitude: 22.5458987, altitude: 1000 };"

vigourwu commented 6 years ago

@Jeremy-Gaillard

If I replace mesh.material.vertexShader as following: ... attribute vec3 position uniform mat4 modelViewMatrix; uniform mat4 projectionMatrix; ... gl_Position = projectionMatrix modelViewMatrix vec4 (position, 1.0); ...

I got an expected result,

20180129110430

But it seems always under ground, I have to close global layer to view it. I have checked the position, it not under the ground, It seems a conflict between 2 texture layers. Is there any clue to fix it?

Jeremy-Gaillard commented 6 years ago

Your problem seems to be a conflict between the depth buffers of the different layer. There is a function "patchMaterialForLogDepthSupport" that should be called to fix this normally, you could check if this is the case.

In any case, I found a temporary fix for your problem with minimal change to the code. Here is the diff that you have to apply:

diff --git a/src/Core/Scheduler/Providers/3dTiles_Provider.js b/src/Core/Scheduler/Providers/3dTiles_Provider.js
index b319a52..0bc85ab 100644
--- a/src/Core/Scheduler/Providers/3dTiles_Provider.js
+++ b/src/Core/Scheduler/Providers/3dTiles_Provider.js
@@ -166,12 +166,13 @@ $3dTiles_Provider.prototype.b3dmToMesh = function b3dmToMesh(data, layer) {
             mesh.frustumCulled = false;
             if (mesh.material) {
                 if (layer.overrideMaterials) {
+                    const texture = mesh.material.uniforms.u_tex.value;
                     mesh.material.dispose();
                     if (typeof (layer.overrideMaterials) === 'object' &&
                         layer.overrideMaterials.isMaterial) {
                         mesh.material = layer.overrideMaterials.clone();
                     } else {
-                        mesh.material = new THREE.MeshLambertMaterial({ color: 0xffffff });
+                        mesh.material = new THREE.MeshLambertMaterial({map: texture}/*{ color: 0xffffff }*/);
                     }
                 } else if (Capabilities.isLogDepthBufferSupported()
                             && mesh.material.isRawShaderMaterial

Basically, I just transfer the texture of the old material to the new material.

You will also need to add an ambient light to the scene, otherwise you won't be able to see the colours.

EDIT: there's also a couple of bugs with sphere bounding volumes, I'll do a PR tomorrow to fix them

vigourwu commented 6 years ago

@Jeremy-Gaillard Thanks for your help. The last was a issue of depth buffer. patchMaterialForLogDepthSuppor can fix it. Thanks again.