0

This is a example.

I want to have a model with a color map and a normal map.

like this , in Microsoft 3D Viewer.

enter image description here

And,I have a model with a normal map .

Then I use the replacement method to replace the color normal map with the original map .

<script type="module">
    import * as THREE from './build/three.module.js';
    import { OrbitControls } from './jsm/controls/OrbitControls.js';
    import Stats from './jsm/libs/stats.module.js';
    import { GUI } from './jsm/libs/lil-gui.module.min.js';
    import { OBJLoader } from './Loader/OBJLoader.js';
    import { MTLLoader } from './Loader/MTLLoader.js';
    import { FBXLoader } from './Loader/FBXLoader/FBXLoader.js';


    const scene = new THREE.Scene();

    /*--------camera--------*/
    var camera = new THREE.PerspectiveCamera(80, window.innerWidth / window.innerHeight, 1, 2000);
    camera.position.set(0, 40, 20);
    camera.lookAt(0, 0, 0);

    /*--------renderer--------*/
    const renderer = new THREE.WebGLRenderer({
        antialias: true,
    });
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);
    renderer.shadowMap.enabled = true;
    renderer.shadowMap.type = THREE.PCFSoftShadowMap;
    renderer.toneMapping = THREE.ReinhardToneMapping;

    /*--------background--------*/
    scene.background = new THREE.Color(0xffffff);

    /*--------OrbitControls--------*/
    let controls = new OrbitControls(camera, renderer.domElement);
    controls.enablePan = false;
    controls.maxPolarAngle = Math.PI / 2;
    controls.enableDamping = true;
    // controls.minDistance = 100;
    // controls.maxDistance = 1000;

    //FBX
    let FBX_name = ['group0',];
    let FBX_loader = ['loader0',];
    let FBX_url = [
        './models/Normal-map-test/01-FBX/2022-05-25.fbx',
    ];

    //Normal map
    // const material = new THREE.MeshPhongMaterial()
    const baseColorMap = new THREE.TextureLoader().load("./models/Normal-map-test/00-Texture/base-color.png");
    const normalMap = new THREE.TextureLoader().load("./models/Normal-map-test/00-Texture/normal-1.png");
    const minigunMaterial = new THREE.MeshStandardMaterial({
        map: baseColorMap,
        normalMap: normalMap
    });

    //FBX
    function FBXimport(object_name, object_loader, object_url) {
        object_loader = new FBXLoader();
        object_loader.load(object_url, function (object) {
            object_loader = new THREE.AnimationMixer(object);
            object.traverse(function (child) {
                if (child.isMesh) {
                    child.material = minigunMaterial;
                    child.castShadow = true;
                    child.receiveShadow = true;
                }
            });
            object.position.set(0, 0, 0);
            object.name = object_name;
            object.children[0].name = object_name;
            scene.add(object);
        });
        const group = scene.getObjectByName(object_name);
    }

    for (let i = 0; i < FBX_name.length; i++) {
        FBXimport(FBX_name[i], FBX_loader[i], FBX_url[i]);
    }

    //light
    const light = new THREE.HemisphereLight(0xffeeb1, 0x080820, 4);
    scene.add(light);

    const directionalLight = new THREE.DirectionalLight(0xffa95c, 5);
    directionalLight.position.set(-50, 50, 50);
    directionalLight.castShadow = true;
    directionalLight.shadow.bias = -0.0001;
    directionalLight.shadow.mapSize.width = 1024 * 4; // default
    directionalLight.shadow.mapSize.height = 1024 * 4; // default
    scene.add(directionalLight);

    const helper = new THREE.DirectionalLightHelper(directionalLight, 5);
    scene.add(helper);

    //window.onresize
    window.onresize = function () {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    };

    function animate() {
        controls.update();
        // stats.update();
        requestAnimationFrame(animate);
        renderer.render(scene, camera);
    };
    animate();

</script>

Apparently he doesn't work .

enter image description here

Am I missing something, or is there a better solution?

This is my normal map looks like

enter image description here

jImmy
  • 15
  • 5

1 Answers1

0

You are using THREE.TextureLoader().load(...), this has a second parameter callback onLoad(texture), try to set textures in this callback like this:

THREE.TextureLoader().load("your-path-to-texture-normal.png", (texture)=>{
     minigunMaterial.normalMap = texture
     mingunMaterial.needsUpdate = true
})

I suspect your normal map is not yet loaded when you are creating material, this way you will be sure that when the texture is fully loaded you will set it to the material.

EDIT: After setting the texture in callback you should also update the material, this can be done by calling material.needsUpdate=true

  • I edited the code to look like this. – jImmy May 26 '22 at 04:19
  • const baseColorMap = new THREE.TextureLoader().load("./models/Normal-map-test/00-Texture/咖啡.png"); const normalMap = new THREE.TextureLoader().load("./models/Normal-map-test/00-Texture/normal-1.png", (texture) => { minigunMaterial.normalMap = texture }); const minigunMaterial = new THREE.MeshStandardMaterial({ map: baseColorMap, normalMap: normalMap }); – jImmy May 26 '22 at 04:19
  • but it still can't work – jImmy May 26 '22 at 04:19
  • He looks the same as before . – jImmy May 26 '22 at 04:20
  • Can you try to set it like that? const minigunMaterial = new THREE.MeshStandardMaterial() new THREE.TextureLoader().load("./models/Normal-map-test/00-Texture/咖啡.png", (baseColorMap)=>{ minigunMaterial.map = baseColorMap }); new THREE.TextureLoader().load("./models/Normal-map-test/00-Texture/normal-1.png", (normalMap)=>{ minigunMaterial.normalMap = normalMap }) also on the very end you should updateMaterial I will add this to the original answer – Sylwester Szymanski May 26 '22 at 04:27
  • Is there anything missing in this text ? const minigunMaterial = new THREE.MeshStandardMaterial() new THREE.TextureLoader().load(...) ,he has an error – jImmy May 26 '22 at 04:34
  • And ,Sorry, I didn't find PNG's name is Chinese . I have changed the name from "咖啡.png" to "base-color.png" – jImmy May 26 '22 at 04:37
  • Ok, did it work eventually? I am doing pretty much this in my workflow, I just have some helper functions for multiple map types. I can see you are using the correct material type as well, and lighting from what I see is also fine. I also force re-render it after updating the texture, but I don't think you should need it. Your normal map looks fine too. – Sylwester Szymanski May 26 '22 at 04:57
  • No, it's can't . the code is still have bug . Can I upload pictures in the comments ? I am new to stackoverflow .I tried it before , but failed . – jImmy May 26 '22 at 05:13
  • the mistake console is "Uncaught SyntaxError: Unexpected token 'new' (at test-2.html:75:66)" – jImmy May 26 '22 at 05:21
  • @ Sylwester Szymanski,bro do you have Discord? I can live stream you to see the current status. Of course, the solution, I will update it on stack overflow later. I'm sorry if I offended you . – jImmy May 26 '22 at 05:50
  • Sorry, I am at work at the moment, that's why I wasn't replying. I will give you my discord later, after work. and we can take a look. – Sylwester Szymanski May 26 '22 at 10:38
  • Ok, so I have discord, but cannot send it through Stack Overflow. Perhaps it is also against rules, as someone with a similar problem finding this thread would get annoyed if the solution is eventually moved to DM. Your error suggests that you have a javascript syntax error, the code that I sent as an example doesn't have this, so you can share a few lines where you are loading the normal texture here in the comments, and I can spot it. What about that? – Sylwester Szymanski May 26 '22 at 17:03
  • After I found the reason. The main problem is that the model when the 3D model is output has Bump texture and Normal texture at the same time. I speculate that it is the reason that Three.js cannot judge, so it shows abnormality. – jImmy Jun 03 '22 at 03:20
  • But in Microsoft 3D Viewer,it can't see any problem. – jImmy Jun 03 '22 at 03:21
  • So, if your FBX has already material, then you can try to export this FBX without materials. The bump map that you are saying about is on another material than the one that you try to set in three.js. Moreover, it most definitely uses a different shader as well that may be not supported by three.js, or may require some settings. I think if your theory is right, try to export this fbx without materials. You can do it in Blender3D pretty easily. First import your FBX, then take a look if there are some materials, delete it, export again. You can then check if Normal map will load. – Sylwester Szymanski Jun 03 '22 at 04:07
  • Thank you, I chose to use the bump map and remove the .tif (not supported by Three.js) . Successfully imported the model, thank you very much ! in any aspect. – jImmy Jun 08 '22 at 14:15
  • Glad you resolved it! Just remember the bump map has only one dimensional information about height, normal map is more accurate in this matter, as it holds vector3 values. I am not sure what do you mean about the tif, but normal map could be loaded as png as well. Regards – Sylwester Szymanski Jun 09 '22 at 04:18
  • Hi, in another post, I now have a problem with Bloom making the Sprite glow, can you give me some inspiration? https://stackoverflow.com/questions/72541758/sprite-use-png-map-but-it-doesnt-display-properly-when-scene-contains-bloom – jImmy Jun 09 '22 at 04:24