javascript - ThreeJS透明PNG纹理黑色

标签 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

最佳答案

您可以应用 2 种或更多这样的 Material

  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>

请注意,如果您将颜色和纹理(贴图)放入单个 Material 中,则两种颜色(1)您指定的颜色和(2)纹理中的颜色将相互相乘。因此,只要纹理有零,RGBA = 0,0,0,0,那么结果就是 0,0,0,0,因为任何乘以零的值都是零。这就是为什么你得到最初得到的结果,问号外面是透明的,里面是橙色的。

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

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>

关于javascript - ThreeJS透明PNG纹理黑色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59448382/

相关文章:

javascript - 两个模型的相同数据库表

javascript - 使用 JavaScript onclick 添加表格行

javascript - 无法获取多个 Canvas 饼图

javascript - 是否可以在 Three.js 中清晰地悬停在 LineSegment 的各个部分上,以识别那些只有一种几何形状的部分?

THREE.js:OrbitControls 平移和缩放问题

three.js - 是否可以在 Three.js 中合并多个断开的行?

javascript - 使用 alphaMap 不会在我的 Material 中提供透明度

three.js - 我无法在 JSFiddle 中输入 dat.gui

面向对象函数

javascript - 将一个子元素向左对齐,第二个子元素向右对齐 extjs