mrdoob / three.js

JavaScript 3D Library.
https://threejs.org/
MIT License
102.81k stars 35.38k forks source link

Black background on obj with PNG textures. #12148

Closed MarcinBorkowski03 closed 7 years ago

MarcinBorkowski03 commented 7 years ago
Description of the problem

Hello!

I have problem with transparent UV map in threejs. When I set texture in blender and I click "render" everything it's ok

but when I load model in threejs by JSONloader the black background load under PNG texture instead blender's material color.

How can I delete this black background in threejs and use blender material color?

Here is my code:

var scene, camera, renderer;
  var guiControls, controls, stats, axis, lightHelper;
  var sceneBackground;
  var spotLight;
  var cube, ground, toursKnot, text;
  var groundMaterial, boxMaterial, torMaterial, textMaterial;
  var groundGeometry, boxGeometry, torGeometry, textGeometry;
  var SCREEN_WIDTH, SCREEN_HEIGHT;

  var loader = new THREE.JSONLoader();
  loader.load('models/CupME9.json', addModel);

  function addModel(geometry, materials){
    var material = new THREE.MeshFaceMaterial(materials);
    model = new THREE.Mesh(geometry, material);
    model.scale.set(1,1,1);
    model.position.set(5,2,0);
    model.castShadow = true;
    scene.add(model);
  }

  function init(){
    scene = new THREE.Scene();
    camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, .1, 500);
    renderer = new THREE.WebGLRenderer({antialias:true });

    sceneBackground = renderer.setClearColor(0xdddddd);
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    renderer.shadowMapSoft = true;

  //Controls
    controls = new THREE.OrbitControls(camera,renderer.domElement);
    controls.addEventListener('change', render);

  //add helpers
    axis = new THREE.AxisHelper(10);
    scene.add(axis);

  //grid

    color = new THREE.Color("rgb(255,0,0)");
    lineColor = new THREE.Color(0x000000);
    grid = new THREE.GridHelper(50,20,color,lineColor);
    scene.add(grid);

  //camera
    camera.position.set(15,12,10);
    camera.lookAt(scene.position);

    guiControls = new function(){
      this.rotationX = 0.0;
      this.rotationY = 0.0;
      this.rotationZ = 0.0;

      this.lightX = 10;
      this.lightY = 10;
      this.lightZ = 15;
      this.intensity = 1;
      this.distance = 0;
      this.angle = 1.570;
      this.exponent = 0;
      this.shadowCameraNear = 1;
      this.shadowCameraFar = 100;
      this.shadowCameraFov = 50;
      this.shadowCameraVisible = true;
      this.shadowMapWidth = 1024;
      this.shadowMapHeigh = 1024;
      this.shadowBias = 0;
      this.shadowDarkness = 0.5;
      this.target = 'cube';
    }

  //lights
    var ambient = new THREE.AmbientLight(0x404040);
    scene.add(ambient);

    spotLight = new THREE.SpotLight(0xffffff);
    spotLight.position.set(10,10,15);
    spotLight.castShadow = true;
    spotLight.shadow.camera.left = -500;
    spotLight.shadow.camera.right = 500;
    spotLight.shadow.camera.top = 500;
    spotLight.shadow.camera.bottom = -500;
    spotLight.intensity = guiControls.intensity;
    spotLight.distance = guiControls.distance;
    spotLight.shadow.bias = guiControls.shadowBias;
    spotLight.shadow.camera.fov = guiControls.shadowCameraFov;
    spotLight.shadow.camera.near = guiControls.shadowCameraNear;
    spotLight.shadow.camera.far = guiControls.shadowCameraFar;
    spotLight.shadow.camera.visible = guiControls.shadowCameraVisible;
    spotLight.shadow.mapSize.width = guiControls.shadowMapWidth; // default is 512
    spotLight.shadow.mapSize.height = guiControls.shadowMapHeigh;
    spotLight.name = 'Spot light';

    lightHelper = new THREE.CameraHelper( spotLight.shadow.camera )
    scene.add(lightHelper);
    scene.add(spotLight);

  //Plane
    groundGeometry = new THREE.BoxGeometry(40,0,40);
    groundMaterial = new THREE.MeshPhongMaterial({
      color: 0xa0adaf,
      shininess: 150,
      specular: 0xffffff,
      flatShading : true
    });
    ground = new THREE.Mesh(groundGeometry, groundMaterial);
    ground.castShadow = false;
    ground.receiveShadow = true;
    scene.add(ground);

    var datGUI = new dat.GUI();

    datGUI.add(guiControls, 'rotationX', 0, 1);
    datGUI.add(guiControls, 'rotationY', 0, 1);
    datGUI.add(guiControls, 'rotationZ', 0, 1);
    datGUI.add(guiControls, 'lightX',-60,180);
    datGUI.add(guiControls, 'lightY',0,180);
    datGUI.add(guiControls, 'lightZ',-60,180);

    datGUI.add(guiControls, 'target', ['cube', 'torusKnot','text']).onChange(function(){
        if (guiControls.target == 'cube'){
            spotLight.target =  cube;
        }
        else if (guiControls.target == 'torusKnot'){
            spotLight.target =  toursKnot;
        }
        else if (guiControls.target == 'text'){
            spotLight.target =  text;
        }
    });

    datGUI.add(guiControls, 'intensity', 0.01, 5).onChange(function(value){
      spotLight.intensity = value;
    });

    datGUI.add(guiControls, 'distance', 0, 1000).onChange(function(value){
      spotLight.distance = value;
    });

    datGUI.add(guiControls, 'angle', 0.001, 1.570).onChange(function(value){
      spotLight.angle = value;
    });

    datGUI.add(guiControls, 'exponent', 0, 50).onChange(function(value){
      spotLight.exponent = value;
    });

    datGUI.add(guiControls, 'shadowCameraNear', 0 , 100).name("Near").onChange(function(value){
      spotLight.shadow.camera.near = value;
      spotLight.shadow.camera.updateProjectionMatrix();
      lightHelper.update();
    });

    datGUI.add(guiControls, 'shadowCameraFar', 0 , 100).name("Far").onChange(function(value){
      spotLight.shadow.camera.far = value;
      spotLight.shadow.camera.updateProjectionMatrix();
      lightHelper.update();
    });

    datGUI.add(guiControls, 'shadowCameraFov', 0 , 100).name("Fov").onChange(function(value){
      spotLight.shadow.camera.fov = value;
      spotLight.shadow.camera.updateProjectionMatrix();
      lightHelper.update();
    });

    datGUI.add(guiControls, 'shadowCameraVisible').onChange(function(value){
      spotLight.shadow.camera.visible = value;
      spotLight.shadow.camera.updateProjectionMatrix();
      //lightHelper.update();
    });
    //datGUI.close();

    datGUI.add(guiControls, 'shadowBias', 0 , 1).onChange(function(value){
      spotLight.shadow.bias = value;
      spotLight.shadow.camera.updateProjectionMatrix();
      lightHelper.update();
    });

    /*datGUI.add(guiControls, 'shadowDarkness', 0 , 1).onChange(function(value){
      spotLight.shadow.camera.darkness = value;
      spotLight.shadow.camera.updateProjectionMatrix();
    });*/
    $("#webGL-container").append(renderer.domElement);

    stats = new Stats();
    stats.domElement.style.position = 'absolute';
    stats.domElement.style.left = '0px';
    stats.domElement.style.top = '0px';

    $("#webGL-container").append(stats.domElement);

  }

  function render(){

    spotLight.position.x = guiControls.lightX;
    spotLight.position.y = guiControls.lightY;
    spotLight.position.z = guiControls.lightZ;

  }

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

  init();
  animate();

  $(window).resize(function(){
    SCREEN_WIDTH = window.innerWidth;
    SCREEN_HEIGHT = window.innerHeight;
    camera.aspect = SCREEN_WIDTH / SCREEN_HEIGHT;
    camera.updateProjectionMatrix();
    renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);

  });
Three.js version
Browser
OS
Hardware Requirements (graphics card, VR Device, ...)
WestLangley commented 7 years ago

Help question posted on stackoverflow.

WestLangley commented 7 years ago

Does Blender support decals? That is what this looks like.

If so, how does the exporter handle them?

WestLangley commented 7 years ago

/ping @Mugen87 Maybe you know something about this?

Mugen87 commented 7 years ago

@MarcinBorkowski03 Can you please share the .blend file and the corresponding JSON export?

MarcinBorkowski03 commented 7 years ago

Sure guys. Thanks for your help, here's my model in blender blenderModel.zip

looeee commented 7 years ago

I ran into the same problem with a model in 3DS Max recently - this is the workaround I used.

Use UV unwrapping to map your model (I've never done this in blender, docs are here though, and the process should be pretty similar to Max).

Map the polygons where you want the texture to show as normal - that is, get the model to the point where the texture looks the way it currently does in your screenshot. Then map all of the rest of the polygons to a small patch of the background colour of the texture.

This is probably best practice anyway, since otherwise it's hard to make the colour of the rest of your model blend with the background colour of your texture

Mugen87 commented 7 years ago

@MarcinBorkowski03 Can you also share the .blend file, please? I can only find in your zip file the JSON export data and the texture.

MarcinBorkowski03 commented 7 years ago

@looeee Thank you for your workaround but I need to make the whole black surface transparent beacuse I'm trying to create creator when customer can upload his PNG photo and change the model texture.

@Mugen87 I'm so sorry, sure here is .blend model. CupBlenderModel.zip

aamado1 commented 5 years ago

this is not fixed yet ritgh? I have the same problem

Mugen87 commented 5 years ago

this is not fixed yet ritgh?

There will be no fix since nothing is broken. As you can see here, the transparent part of a PNG is black per default (since no color is defined for transparent texels). You can change this behavior by setting Material.transparent to true so three.js can perform alpha blending with the respective background pixels. Another approach is to set Material.alphaTest to a value like 0.5. In this case the material is not marked as transparent but transparent texels are discared in the fragment shader in order to produce an alpha cutout.

aamado1 commented 5 years ago

Thanks , if the transparent part of a PNG is black per default , how can i make this default another color? The alphaTest = 0.5 is not working for me

Michael Herzog notifications@github.com escreveu no dia sexta, 29/03/2019 à(s) 21:02:

this is not fixed yet ritgh?

There will be no fix since nothing is broken. As you can see at here https://jsfiddle.net/16u8dmqv/1/, the transparent part of a PNG is black per default (since no color is defined for transparent texels). You can change this behavior by setting Material.transparent to true so three.js can perform alpha blending with the respective background pixels. Another approach is to set Material.alphaTest to a value like 0.5. In this case the material is not marked as transparent but transparent texels are discared in the fragment shader in order to produce an alpha cutout.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/mrdoob/three.js/issues/12148#issuecomment-478148568, or mute the thread https://github.com/notifications/unsubscribe-auth/AZR4Uge8JeuwVucMKjtehesWdmOBWCm7ks5vbn97gaJpZM4PPkh8 .

Mugen87 commented 5 years ago

Please redirect your questions to stackoverflow or the forum.

garyo commented 5 years ago

Just a quick note -- Material.transparent is a better solution than Material.alphaTest since the latter will cause hard edges and won't handle partially transparent PNGs well. You really want full alpha blending. https://en.wikipedia.org/wiki/Alpha_compositing

Mugen87 commented 5 years ago

You really want full alpha blending.

@garyo I think this really depends on the scenario. When rendering vegetation for example, using alpha cutouts is the better option and also more performant since you avoid any blending overhead.