ThreeJs入门03-重构框架并绘制一条线

1,816 阅读4分钟

「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战

示例代码采用three.js-r73版本:cdnjs.cloudflare.com/ajax/libs/t…

注:之前的文章《ThreeJs 入门01-编写第一个three.js程序》应该是02,有时间再写下01

yuque_diagram (1).jpg

我们之前写的代码,都是在一段脚本中完成,逻辑复杂后,比较难读懂。我们将其按照功能拆分成函数,进行封装调用

重新定义html

  • 我们定义一个高600px、宽为100%、 id 为 canvas-frame的元素
  • 当页面加载完成后,把我们要渲染的场景,添加到这个元素中。
 <style type="text/css">
    div#canvas-frame {
        border: none;
        cursor: pointer;
        width: 100%;
        height: 600px;
        background-color: #EEEEEE;
    }
</style>
<body onload="threeStart();">
    <div id="canvas-frame"></div>
</body>

编写js脚本

threeStart 作为页面加载完成之后执行入口,我们需要依次实现

  • initThree 初始化渲染函数
  • initCamera 初始化摄像机
  • initScene 初始化场景
  • initLight 初始化平行光
  • initObject 初始化几何体
  • render 渲染场景
function threeStart(){
    initThree();
    initCamera();
    initScene();
    initLight();
    initObject();
    render();
}

initThree 初始化渲染函数

  • 我们获取canvas-frame元素的宽度和高度,用来计算画布和场景大小
  • 初始化渲染器时,开启antialias,渲染器会通过更好的一个算法,把我们的图像计算的更清晰。效果,可以看下图
    • 设置为true,会占用更多的 gpu 资源。大数据量时,我们设置为false,提高性能

抗锯齿前 image.png 抗锯齿后 image.png 效果提升了不少

  • 渲染器创建好后,把我们的渲染器添加到 canvas-frame元素中
  • 设置清除颜色setClearColor,当我们绘制每一帧的时候,我们会用灰色或者白色,把画布刷新一下,重新绘制
    • 如果不重新绘制,会造成重复效果
var width,height
var renderer;
function initThree() {
  width = document.getElementById("canvas-frame").clientWidth;
  height = document.getElementById("canvas-frame").clientHeight;
  renderer = new THREE.WebGLRenderer({
    antialias: true, // 是否开启反锯齿,设置为true开启反锯齿,可以提升画质
  });
  renderer.setSize(width, height); // 设置画布大小
  document.getElementById("canvas-frame").appendChild(renderer.domElement); // 将画布添加到页面上
  renderer.setClearColor(0xffffff, 1.0); // 设置画布颜色
}

initCamera 初始化摄像机

  • 使用正投影相机,最近为1,最远为1000
  • 相机的位置,放在y轴 1000 的位置,类似于在空中
  • camera.lookAt通过这个属性,让物体一直面朝摄像机
var camera;
function initCamera(){
    camera = new THREE.PerspectiveCamera(45, width/height, 1, 10000)
    // 表示对象局部位置的Vector3。默认值为(0, 0, 0)。
    camera.position.x = 0
    camera.position.y = 1000
    camera.position.z = 0
    // up 这个属性由lookAt方法所使用,例如,来决定结果的朝向。
    camera.up.x = 0
    camera.up.y = 0
    camera.up.z = 1
    // 旋转物体使其在世界空间中面朝一个点。
    // 这一方法不支持其父级被旋转过或者被位移过的物体。
    camera.lookAt({
        x:0,
        y:0,
        z:0
    })
}

initScene 初始化场景

  • 我们初始化场景,不需要做什么操作
var scene;
function initScene() {
  scene = new THREE.Scene();
}

initLight 初始化平行光

  • 平行光是沿着特定方向发射的光。这种光的表现像是无限远,从它发出的光线都是平行的。
  • 常常用平行光来模拟太阳光的效果;
  • 太阳足够远,因此我们可以认为太阳的位置是无限远,所以我们认为从太阳发出的光线也都是平行的。
var light;
function initLight() {
  // 定义平行光
  light = new THREE.DirectionalLight(0xff0000, 1.0, 0);
  // 设置平行光位置
  light.position.set(100, 100, 200);
  //   将平行光添加到场景
  scene.add(light);
}
  • color - (可选参数) 16进制表示光的颜色。 缺省值为 0xffffff (白色)。
  • intensity - (可选参数) 光照的强度。缺省值为1

initObject 初始化几何体

 var cube;
function initObject() {
  // 创建几何体
  var geometry = new THREE.Geometry();
  //   创建线的材质
  var material = new THREE.LineBasicMaterial({
    vertexColors: THREE.VertexColors, // 使用顶点颜色
  });
  //   定义颜色,用来表示端点的颜色
  var color1 = new THREE.Color(0x444444),
    	color2 = new THREE.Color(0xff0000);

  // 线的材质可以由2个端点的颜色决定
  var p1 = new THREE.Vector3(-100, 0, 1000);
  var p2 = new THREE.Vector3(1000, 0, -100);
  // 把两个端点添加到几何体中
  geometry.vertices.push(p1);
  geometry.vertices.push(p2);
  // 把颜色添加到几何体中,与顶点数量对应
  geometry.colors.push(color1, color2);
  //   创建线
  var line = new THREE.Line(geometry, material, THREE.LinePieces);
  scene.add(line);
}
  • 我们这里创建了一条线
  • 我们这里使用了顶点颜色vertexColors: THREE.VertexColors,就是线条的颜色会根据顶点来计算。
  • 然后定义了两个颜色,用来表示两个端点的颜色
  • 把两个顶点添加到几何体中
  • geometry中colors表示顶点的颜色,必须材质中vertexColors等于THREE.VertexColors 时,颜色才有效,如果vertexColors等于THREE.NoColors时,颜色就没有效果了。那么就会去取材质中color的值,这个很重要

render 渲染场景

  • 每次渲染场景之前,先对场景进行清空
  • renderer.clear通过setClearColor值,来对场景进行刷新
  • 刷新完之后再进行渲染
function render() {
  renderer.clear(); // 通过setClearColor值,来对场景进行刷新
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}

至此我们的代码重构就完成了,实现效果 image.png