ThreeJS透明PNG纹理黑色

时间:2019-12-22 22:11:05

标签: javascript three.js

我正试图了解ThreeJS所面临的问题。我在页面上有一个简单的多维数据集,并且我有一个白色问号的PNG,其余图像透明。当我将纹理添加到多维数据集时;

cubeGeometry = new THREE.BoxGeometry( 5, 5, 5 );
cubeMaterial = new THREE.MeshStandardMaterial( { color: this.cubeColor, flatShading: true, map:new THREE.TextureLoader().load( require("./question-mark.png") ) } );
cubeMesh = new THREE.Mesh( cubeGeometry, cubeMaterial );

无论我做什么,PNG中的透明像素都显示为黑色。更奇怪的是,PNG的白色像素显示this.cubeColor的颜色-设置为橙色。

我希望立方体颜色为橙色,而PNG的透明像素将采用该颜色,而PNG中的白色像素将保持白色。

有人揭露了吗?

我所看到的

what i see

纹理

texture

1 个答案:

答案 0 :(得分:0)

您可以应用2种以上的材料

  const geometry = new THREE.BoxBufferGeometry(boxWidth, boxHeight, boxDepth);

  // prepare geometry to use 2 materials
  geometry.clearGroups();
  geometry.addGroup( 0, Infinity, 0 );
  geometry.addGroup( 0, Infinity, 1 );

  const loader = new THREE.TextureLoader();

  // create 2 materials
  const material0 = new THREE.MeshBasicMaterial({
    color: 'orange',
  });
  const material1 = new THREE.MeshBasicMaterial({
    map: loader.load('https://i.imgur.com/iFom4eT.png'),
    transparent: true,
  });

  // apply 2 materials to geometry
  const materials = [material0, material1];
  const cube = new THREE.Mesh(geometry, materials);

例如,请注意它使用的是BoxBufferGeometry而不是BoxGeometry

function main() {
  const canvas = document.querySelector('#c');
  const renderer = new THREE.WebGLRenderer({canvas});

  const fov = 75;
  const aspect = 2;  // the canvas default
  const near = 0.1;
  const far = 5;
  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  camera.position.z = 2;

  const scene = new THREE.Scene();
  scene.background = new THREE.Color('purple');

  const boxWidth = 1;
  const boxHeight = 1;
  const boxDepth = 1;
  const geometry = new THREE.BoxBufferGeometry(boxWidth, boxHeight, boxDepth);
  
  // prepare geometry to use 2 materials
  geometry.clearGroups();
  geometry.addGroup( 0, Infinity, 0 );
  geometry.addGroup( 0, Infinity, 1 );

  const loader = new THREE.TextureLoader();
  
  // create 2 materials
  const material0 = new THREE.MeshBasicMaterial({
    color: 'orange',
  });
  const material1 = new THREE.MeshBasicMaterial({
    map: loader.load('https://i.imgur.com/hrzoDMj.png'),
    transparent: true,
  });
  
  // apply 2 materials to geometry
  const materials = [material0, material1];
  const cube = new THREE.Mesh(geometry, materials);
  scene.add(cube);

  function render(time) {
    time *= 0.001;  // convert time to seconds
    
    if (resizeRendererToDisplaySize(renderer)) {
      const canvas = renderer.domElement;
      camera.aspect = canvas.clientWidth / canvas.clientHeight;
      camera.updateProjectionMatrix();    
    }

    cube.rotation.x = time;
    cube.rotation.y = time;

    renderer.render(scene, camera);

    requestAnimationFrame(render);
  }
  requestAnimationFrame(render);

}

function resizeRendererToDisplaySize(renderer) {
  const canvas = renderer.domElement;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  const needResize = canvas.width !== width || canvas.height !== height;
  if (needResize) {
    renderer.setSize(width, height, false);
  }
  return needResize;
}

main();
body { margin: 0; }
#c { width: 100vw; height: 100vh; display: block; }
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r110/build/three.min.js"></script>
<canvas id="c"></canvas>

请注意,如果您将一种颜色和一个纹理(贴图)放在一种材质中,则两种颜色(即(1)您指定的颜色和(2)该纹理中的颜色)会彼此相乘。因此,无论纹理的零值是什么,RGBA = 0,0,0,0,那么结果都是0,0,0,0,因为任何乘以零的值都是零。这就是为什么获得原始结果的原因,问号外面是透明的,内部是橙色。

知道这一点后,您可以使用白色问号并通过在使用纹理的材质上设置颜色来更改其颜色。

function main() {
  const canvas = document.querySelector('#c');
  const renderer = new THREE.WebGLRenderer({canvas});

  const fov = 75;
  const aspect = 2;  // the canvas default
  const near = 0.1;
  const far = 5;
  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  camera.position.z = 2;

  const scene = new THREE.Scene();
  scene.background = new THREE.Color('purple');

  const boxWidth = 1;
  const boxHeight = 1;
  const boxDepth = 1;
  const geometry = new THREE.BoxBufferGeometry(boxWidth, boxHeight, boxDepth);
  
  // prepare geometry to use 2 materials
  geometry.clearGroups();
  geometry.addGroup( 0, Infinity, 0 );
  geometry.addGroup( 0, Infinity, 1 );

  const loader = new THREE.TextureLoader();
  
  // create 2 materials
  const material0 = new THREE.MeshBasicMaterial({
    color: 'orange',
  });
  const material1 = new THREE.MeshBasicMaterial({
    map: loader.load('https://i.imgur.com/hrzoDMj.png'),
    transparent: true,
  });
  
  // apply 2 materials to geometry
  const materials = [material0, material1];
  const cube = new THREE.Mesh(geometry, materials);
  scene.add(cube);

  function render(time) {
    time *= 0.001;  // convert time to seconds
    
    if (resizeRendererToDisplaySize(renderer)) {
      const canvas = renderer.domElement;
      camera.aspect = canvas.clientWidth / canvas.clientHeight;
      camera.updateProjectionMatrix();    
    }
    
    material1.color.setHSL(time, 1, 0.5);

    cube.rotation.x = time;
    cube.rotation.y = time;

    renderer.render(scene, camera);

    requestAnimationFrame(render);
  }
  requestAnimationFrame(render);

}

function resizeRendererToDisplaySize(renderer) {
  const canvas = renderer.domElement;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  const needResize = canvas.width !== width || canvas.height !== height;
  if (needResize) {
    renderer.setSize(width, height, false);
  }
  return needResize;
}

main();
body { margin: 0; }
#c { width: 100vw; height: 100vh; display: block; }
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r110/build/three.min.js"></script>
<canvas id="c"></canvas>