Three.js飞机上的材料与照明不匹配

时间:2017-11-13 11:52:10

标签: three.js

我通过合并一个曲面和两个平面在Three.Js中创建了一个形状。我已经使用MeshLambertMaterial作为材料。垂直平面和曲面连接完美。然而,水平面与曲线连接处存在明显的硬线。照明似乎没有对齐。我希望3个平面显示为具有平滑着色的一个对象。我做错了吗?

codepen

    addShape() {
                var radius =58, height=100, startAngle=THREE.Math.degToRad(0), endAngle=THREE.Math.degToRad(90), horizontalSegments=25, verticalSegments=25;
                var width = radius * 2 * Math.PI;
                var plane = new THREE.PlaneGeometry(width, height, horizontalSegments, verticalSegments);
                var index = 0;

                for(var i=0; i<=verticalSegments; i++) {
                    for(var j=0; j<=horizontalSegments; j++) {
                        var angle = startAngle + (j/horizontalSegments)*(endAngle - startAngle);
                        plane.vertices[index].z = radius * Math.cos(angle);
                        plane.vertices[index].x = radius * Math.sin(angle);
                        index++;
                    }
                }
                var material = new THREE.MeshLambertMaterial({color: 0xa2cddd, side: THREE.DoubleSide});
                var mesh = new THREE.Object3D();
                var curve = new THREE.Mesh(plane, material);
                curve.rotation.z = THREE.Math.degToRad(-90)


                var plane1 = new THREE.PlaneGeometry(height, height, horizontalSegments, verticalSegments);
                var side1 = new THREE.Mesh(plane1, material);
                side1.rotation.z = THREE.Math.degToRad(270)
                side1.position.z = radius;
                side1.position.x = -radius * 0.85;

                var plane2 = new THREE.PlaneGeometry(height, height, 1, 1);
                var side2 = new THREE.Mesh(plane2);
                side2.rotation.y = THREE.Math.degToRad(90)
                side2.position.x = radius * 1.0
                side2.position.z = -radius * 0.8;

                plane.mergeMesh(side1);
                plane.mergeMesh(side2);
                mesh.rotation.y = THREE.Math.degToRad(180);
                mesh.add(curve);
                this.mesh = mesh;
                this.scene.add(mesh);
            }
addLight() {
    let light1 = new THREE.PointLight(0xffffff, 1, 200);
    light1.position.set(0, 20, 10);
    this.scene.add(light1);

    let light2 = new THREE.AmbientLight(0x404040); // soft white light
    this.scene.add(light2);
  }

enter image description here

1 个答案:

答案 0 :(得分:2)

首先,你必须计算顶点法线。请使用THREE.Geometry.computeVertexNormals
THREE.Geometry

plane.computeVertexNormals();


更进一步,你可以简化一些事情,如果你在一个乐队中绘制THREE.PlaneGeometry使用这个解决方案,你可以根据自己的喜好选择起始角度和结束角度,并且开始和结束时的平面将始终能够无缝连接到弯曲部分:

var radius = 58, height = 100,
    startAngle = THREE.Math.degToRad(-20),
    endAngle = THREE.Math.degToRad(110),
    horSegs = 25, vertSegs = 25,
    startLen = 100, endLen = 100;
var width = startLen + endLen + radius * (endAngle-startAngle);
var plane = new THREE.PlaneGeometry( width, height, horSegs+2, vertSegs);

var index = 0;
for (var i = 0; i <= vertSegs; i++) {
  plane.vertices[index].z = radius * Math.cos(startAngle) + startLen * Math.sin(startAngle);
  plane.vertices[index].x = radius * Math.sin(startAngle) - startLen * Math.cos(startAngle);
  index++;
  for (var j = 0; j <= horSegs; j++) {
    var angle = startAngle + j / horSegs * (endAngle - startAngle);
    plane.vertices[index].z = radius * Math.cos(angle);
    plane.vertices[index].x = radius * Math.sin(angle);
    index++;
  }
  plane.vertices[index].z = radius * Math.cos(endAngle) - endLen * Math.sin(endAngle);
  plane.vertices[index].x = radius * Math.sin(endAngle) + endLen * Math.cos(endAngle);
  index++;
}
plane.computeVertexNormals();


请参阅代码段:

&#13;
&#13;
class World {
  constructor() {
    this.scene = new THREE.Scene();
    this.renderer = new THREE.WebGLRenderer();
    this.renderer.setClearColor(0x000000);
    document.body.appendChild(this.renderer.domElement);
    this.resize();

    // this.addCube();
    this.addShape();
    this.addLight();

    requestAnimationFrame(this.render.bind(this));
    window.addEventListener("resize", this.resize.bind(this));
  }

  update() {
    if (this.cube) this.cube.rotation.y += 0.01;
    if (this.mesh) this.mesh.rotation.y += 0.01;
  }

  addLight() {
    let light1 = new THREE.PointLight(0xffffff, 1, 200);
    light1.position.set(0, 20, 10);
    this.scene.add(light1);

    let light2 = new THREE.AmbientLight(0x404040); // soft white light
    this.scene.add(light2);
  }

  
  addShape() {
    var radius = 58, height = 100,
        startAngle = THREE.Math.degToRad(-20),
        endAngle = THREE.Math.degToRad(110),
        horSegs = 25, vertSegs = 25,
        startLen = 100, endLen = 100;
    var width = startLen + endLen + radius * (endAngle-startAngle);
    var plane = new THREE.PlaneGeometry( width, height, horSegs+2, vertSegs);
    
    var index = 0;
    for (var i = 0; i <= vertSegs; i++) {
      plane.vertices[index].z = radius * Math.cos(startAngle) + startLen * Math.sin(startAngle);
      plane.vertices[index].x = radius * Math.sin(startAngle) - startLen * Math.cos(startAngle);
      index++;
      for (var j = 0; j <= horSegs; j++) {
        var angle = startAngle + j / horSegs * (endAngle - startAngle);
        plane.vertices[index].z = radius * Math.cos(angle);
        plane.vertices[index].x = radius * Math.sin(angle);
        index++;
      }
      plane.vertices[index].z = radius * Math.cos(endAngle) - endLen * Math.sin(endAngle);
      plane.vertices[index].x = radius * Math.sin(endAngle) + endLen * Math.cos(endAngle);
      index++;
    }
    plane.computeVertexNormals();

    var material = new THREE.MeshLambertMaterial({
      color: 0xa2cddd,
      side: THREE.DoubleSide
    });
    
    var mesh = new THREE.Object3D();
    var curve = new THREE.Mesh(plane, material);
    curve.rotation.z = THREE.Math.degToRad(-90);

    mesh.add(curve);
    this.mesh = mesh;
    this.scene.add(mesh);
  }

  render() {
    this.update();
    requestAnimationFrame(this.render.bind(this));
    this.renderer.render(this.scene, this.camera);
  }

  resize() {
    this.camera = new THREE.PerspectiveCamera(
      75,
      window.innerWidth / window.innerHeight,
      0.1,
      1000
    );

    this.camera.position.z = 200;

    this.renderer.setSize(window.innerWidth, window.innerHeight);
  }
}

var _w = new World();
&#13;
<script src="https://threejs.org/build/three.min.js"></script>
&#13;
&#13;
&#13;