昔洛 的个人博客

Bug不空,誓不成佛

目录
(一)WebGL Threejs 学习 ----- 基础
/        

(一)WebGL Threejs 学习 ----- 基础

学习内容

  • 什么是 WebGL
  • 什么是 Three.js
  • Three 的框架
    • 三大组件
    • 相机
    • 渲染器
    • 添加物体到场景中
    • 渲染
    • 渲染循环
    • 场景,相机,渲染器之间的关系
  • 重构框架

说明

此次系列的学习是通过 http://www.hewebgl.com/ 网站进行学习的,大部分笔记资料均从该网站获得,感谢这些技术大佬提供的帮助!

什么是 WebGL

WebGL 就是在浏览器中实现三维效果的一套规范

什么是 Three.js

简单来说就是 three + js。three 表示 3D 的意思,js 即 JavaScript,就是用 JavaScript 来编写 3D 程序

three.js 要做的事就是比 c++ 用更少的代码,更容易,更快的开发 3D 程序。

GitHub 地址:https://github.com/mrdoob/three.js
中文文档地址:http://www.webgl3d.cn/threejs/docs/#api/zh

兼容问题:Three.js 本质上就是 WebGL,如果浏览器不支持 WebGL 那么浏览器肯定不能完整运行 Three.js ,当下许多浏览器是支持 WebGL 的,如 Chrome,FireFox,360 等,强烈推荐使用 Chrome 浏览器进行开发。

  • 编辑器的选择:
    学习的网站中推荐使用 WebStorm,因为可以很好地进行 JS 代码提示,但是博主已经完全习惯使用 vscode 了,用其他的编辑器会不舒服(vscode 天下第一huaji),但是 vscode 的代码提示并不是很好,建议使用 node.js 的包管理 npm 创建一个包,然后同级建立 js 文件就有了 three 的提示,关键代码 npm i three,详情可以百度,这里不多介绍

Three 的框架

简单混杂框架

  • 示例代码如下:
    var scene = new THREE.Scene();
    var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 100);
    var renderer = new THREE.WebGLRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);
    var geometry = new THREE.CubeGeometry(1, 1, 1);
    var material = new THREE.MeshBasicMaterial({
      color: 0x00ff00
    });
    var cube = new THREE.Mesh(geometry, material);
    scene.add(cube);
    camera.position.z = 5;
    
    function render() {
      requestAnimationFrame(render);
      cube.rotation.x += 0.1;
      cube.rotation.y += 0.1;
      renderer.render(scene, camera);
    }
    render();
    

    以上代码就是简单画了一个立方体,不同版本的 three.js 默认的背景色可能不同

三大组件

在 Three.js 中,要渲染物体到网页中,需要用到如下三个组件
* 场景(scene)
* 相机(camera)
* 渲染器(renderer)
* 创建三大组件代码如下:

var scene = new THREE.Scene();	// 场景
var camera = new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHegith,0.1,1000);	// 透视相机
var renderer = new THREE.WebGLRenderer();	// 渲染器
renderer.setSize(window.innerWidth,window.innerHeight);	// 设置渲染器的大小为窗口的内宽度,也就是内容区的宽度
document.body.appendChild(renderer.domElement);	// 将元素直接添加到 body 上方便显示

相机

另一个组建是相机,相机决定了场景中那个角度的景色会显示出来。相机就像人的眼睛一样,人站在不同位置,抬头或者低头都能够看到不同的景色。场景只有一种,但是相机却又很多种。和现实中一样,不同的相机确定了呈相的各个方面。比如有的相机适合人像,有的相机适合风景,专业的摄影师根据实际用途不一样,选择不同的相机。对程序员来说,只要设置不同的相机参数,就能够让相机产生不一样的效果。
在Threejs中有多种相机,这里介绍两种,它们是:透视相机(PerspectiveCamera)正交相机(OrthographicCamera)

渲染器

渲染器决定了渲染的结果应该画在页面的什么元素上,并且以怎样的方式来绘制,如下代码:

var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth,window.innerHeight);
document.body.appendChild(renderer.domElement);

注意:渲染器 renderer 的 domElement 表示渲染器的画布,是一个 dom 元素,所有的渲染都是画在 domElement 上。

添加物体到场景中

var geometry = new THREE.CubeGeometry(1,1,1);
var material = new THREE.MeshBasicMaterial({color: 0x00ff00});
var cube = new THREE.Mesh(geometry,material);
scene.add(cube);

以上代码就是简单地绘制一个立方体,立方体的方法及参数如下所示:

CubeGeometry(width, height, depth, segmentsWidth, segmentsHeight, segmentsDepth, materials, sides)
  • width:立方体 x 轴长度
  • height:立方体 y 轴长度
  • depth:立方体 z 轴的深度,也就是长度

渲染

渲染应该使用渲染器,结合相机和场景来得到结果画面,实现这个功能的函数是:renderer.render(scene,camera);
渲染函数的原型如下:
render(scene,camera,renderTarget,forceClear

  • scene:前面定义的场景
  • camera:前面定义的相机
  • renderTarget:渲染的目标,默认是渲染到前面定义的 render 变量中
  • forceClear:每次绘制之前都将画布的内容弄清除,即使自动清除标志 autoClear 为 false,也会清除。

渲染循环

  • 渲染的方式
    • 离线渲染:像电影一样,事先将每一帧每一张图片渲染好,然后拼接而成
    • 实时渲染:就是需要不停的对画面进行渲染,即使画面中什么也没有改变,也需要重新渲染。
    function render() {
    	cube.rotation.x += 0.1;
    	cube.rotation.y += 0.1;
    	renderer.render(scene,camera);
    	requestAnimationFrame(render);
    }
    

以上代码为一个实时渲染的代码片段,其中一个重要的函数是 requestAnimationFrame,这个函数就是让浏览器去执行一次参数中的函数,这样通过上面 render 中调用 requestAnimationFrame() 函数,requestAnimationFrame 又 让 rander 再执行,从而达到循环效果。20130810150021257.jpg

重构框架

第一个框架是将所有代码在一段脚本中完成,当逻辑复杂一点后,就比较难读。因此将其三大组件按功能分成函数,代码如下:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Three框架</title>
  <script src="../js/three.js" data-ke-src="../js/three.js"></script>
  <style type="text/css">
    div#canvas-frame {
      border: none;
      cursor: pointer;
      width: 100%;
      height: 600px;
      background-color: #EEEEEE;
    }
  </style>
  <script>
    var renderer;
    function initThree() {
      width = document.getElementById('canvas-frame').clientWidth;
      height = document.getElementById('canvas-frame').clientHeight;
      renderer = new THREE.WebGLRenderer({
        antialias: true
      });
      renderer.setSize(width, height);
      document.getElementById('canvas-frame').appendChild(renderer.domElement);
      renderer.setClearColor(0xFFFFFF, 1.0);
    }
    var camera;
    function initCamera() {
      camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
      camera.position.x = 0;
      camera.position.y = 1000;
      camera.position.z = 0;
      camera.up.x = 0;
      camera.up.y = 0;
      camera.up.z = 1;
      camera.lookAt({
        x: 0,
        y: 0,
        z: 0
      });
    }

    var scene;

    function initScene() {
      scene = new THREE.Scene();
    }
    var light;
    function initLight() {
      light = new THREE.DirectionalLight(0xFF0000, 1.0, 0);
      light.position.set(100, 100, 200);
      scene.add(light);
    }
    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, 100);
      var p2 = new THREE.Vector3(100, 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);
    }
    function render() {
      renderer.clear();
      renderer.render(scene, camera);
      requestAnimationFrame(render);
    }
    function threeStart() {
      initThree();
      initCamera();
      initScene();
      initLight();
      initObject();
      render();
    }
  </script>
</head>
<body onload="threeStart();">
  <div id="canvas-frame"></div>
</body>
</html>

所谓框架的重构,就是将框架一的代码放到了不同函数中,最终通过 threeStart 函数调用

内事不懂问百度,外事不懂问谷歌~
评论
歌名 - 歌手
0:00