ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

常见3d动画框架three.js

2022-07-15 18:31:44  阅读:367  来源: 互联网

标签:gl const THREE three position new js 3d


 

canvas可以获取哪些上下文?也就是canvas.getContext()的参数有哪些?(多选)
A. 2d
B. webgl
C. webgl2
D. bitmaprenderer
E. 3d

正确答案:A、B、C、D

bitmaprenderer简绍文档:
https://developer.mozilla.org/zh-CN/docs/Web/API/ImageBitmapRenderingContext

WebGL从入门到放弃

如何使用WebGL?
1.创建 WebGL上下文;

2.创建 WebGL 程序(WebGL Program);

3.将数据存入缓冲区;

4.将缓冲区数据读取到 GPU;

5.GPU 执行 WebGL 程序,输出结果,呈现画面。

 

WebGL例子:

// 创建 WebGL上下文
// 思考起:如果我们下面这一行代码注释掉会有什么问题吗?
const canvas = document.getElementById('canvas');
const gl = canvas.getContext('webgl');

// 1. 使用GLSL语言
const vertex = `
  attribute vec2 position;
  varying vec3 color;
  void main() {
  gl_PointSize = 1.0;
  color = vec3(0.5 + position * 0.5, 0.0);
  gl_Position = vec4(position * 0.5, 1.0, 1.0);
  }
`;

// 渐变:gl_FragColor = vec4(color, 1.0)
// 红色:gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
// 黄色:gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0)
const fragment = `
  precision mediump float;
  varying vec3 color;
  void main()
  {
  gl_FragColor = vec4(color, 1.0);
  }    
`;

// 顶点着色器(Vertex Shader)
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertex);
gl.compileShader(vertexShader);

// 片元着色器(Fragment Shader)
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragment);
gl.compileShader(fragmentShader);


// 2. 创建 WebGL 程序(WebGL Program)
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);

const points = new Float32Array([
  -1, -1,
  0, 1,
  1, -1,
]);

// 将数据存入缓冲区
const bufferId = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, bufferId);
gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);

// 将缓冲区数据读取到GPU
const vPosition = gl.getAttribLocation(program, 'position');
gl.vertexAttribPointer(vPosition, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(vPosition);

// GPU 执行 WebGL 程序,输出结果,呈现画面
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, points.length / 2);

 

顶点着色器(Vertex Shader): 处理顶点的 GPU 程序代码。它可以改变顶点的信息(如顶点的坐标、法线方向、材质等等)

片元着色器(Fragment Shader): 处理光栅化后的像素信息。

 

原生的WebGL使用起来还是比较困难的,这个时候就是使用框架的时候了,比如集团的Oasis,或者社区的Three.js。

Oasis:https://oasisengine.cn/

Three.js:https://threejs.org/

mrdoob:https://github.com/mrdoob

Three.js初体验

 

如何使用three.js?

  1. 创建相机;
  2. 创建场景;
  3. 创建几何体,并且把几何体添加到场景中;
  4. 创建渲染器,关联场景和相机,并且添加DOM元素到html中。

 

入门的例子,我们直接使用Three.js官网提供的第一个例子:

import * as THREE from 'three';

// 创建相机
const camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 10 );
camera.position.z = 1;

// 创建场景
const scene = new THREE.Scene();

// 创建正方体
const geometry = new THREE.BoxGeometry( 0.2, 0.2, 0.2 );
const material = new THREE.MeshNormalMaterial();
const mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );

// 渲染器
const renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setAnimationLoop( animation );
document.body.appendChild( renderer.domElement );

// 动画
function animation( time ) {
  mesh.rotation.x = time / 2000;
  mesh.rotation.y = time / 1000;
  renderer.render( scene, camera );
}

 

上面有几个比较重要的概念:相机、场景、几何体、网格、材质、渲染器。

 

番外:浏览器原生es-module

Talk is cheap, show me the code.

 

export default {
  a: 1,
  sayHello: () => {
    console.log('hello');
  }
};

 

<script type="module">
  import test from './03_es_module.js';
  console.log(test.a);
  test.sayHello();
</script>


思考:官网的例子如果不使用importmap,那么怎么去使用es-module来引入three.js呢?

 

import * as THREE from '//unpkg.com/three@0.142.0/build/three.module.js';

场景

 

场景(Scene):相当于是一个容器,可以在它上面添加光线,物体等,最后Three.js把它和相机一起渲染到DOM中。

文档:https://threejs.org/docs/index.html?q=Scene#api/en/scenes/Scene

修改场景颜色:

scene.background = new THREE.Color('orange');


Three.js颜色表示:

// 颜色的关键字
var color = new THREE.Color('orange');

// 默认背景,白色的 注意Three.js渲染的默认背景是黑色的
var color = new THREE.Color();

// 十六进制数字
var color = new THREE.Color( 0xff0000 );

// RGB字符串
var color = new THREE.Color("rgb(255, 0, 0)");
var color = new THREE.Color("rgb(100%, 0%, 0%)");

// HSL字符串
var color = new THREE.Color("hsl(0, 100%, 50%)");

// RGB的值 取值范围0~1 如红色:
var color = new THREE.Color( 1, 0, 0 );

相机

文档:https://threejs.org/docs/index.html?q=Camera#api/en/cameras/Camera

 

Three.js支持两种摄像机透视投影摄像机正交投影摄像机

透视投影摄像机(PerspectiveCamera)是最常用的摄像机,他跟我们的眼睛类似,越近的物体看到的越大,越远的物体看到的越小。

PerspectiveCamera的构造方法有4个参数,分别是视场、长宽比、近处距离、远处距离,其中视场表示眼睛看到的度数。

正交投影摄像机(OrthographicCamera)看到相同大小的物体,都是一样大的。其实相当于平行光照射到一个平面上的映射。

OrthographicCamera的构造方法有6个参数,分别是left、right、top、bottom、near、far,即左边、右边、上边、下边、近处和远处的位置,6个值刚好确定了一个长方体,正是投射的长方体。

 

官方给的这个例子可以帮助我们去理解:https://threejs.org/examples/#webgl_camera


几何体

几何体(Geometry)描述了网格的形状。Three.js内置了好多的几何体,比如我们上面用到的BoxGeometry,此外还有PlaneGeometryCircleGeometryRingGeometrySphereGeometry等。

重要的公式:网格(Mesh) = 几何体(Geometry) + 材质(Material)

 

import * as THREE from 'three';

const camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.01, 100 );
camera.position.x = 0;
camera.position.y = 2;
camera.position.z = 50;

const scene = new THREE.Scene();

// 添加正方体
const cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
const cubeMaterial = new THREE.MeshNormalMaterial();
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
// 正方体位置
cube.position.x = -6;
cube.position.y = -6;
cube.position.z = 0;
// 把正方体添加到场景中
scene.add(cube);

// 添加小球
const sphereGeometry = new THREE.SphereGeometry(2, 20, 20);
const sphereMaterial = new THREE.MeshNormalMaterial();
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
// 小球位置
sphere.position.x = 6;
sphere.position.y = -6;
sphere.position.z = 0;
// 把小球添加到场景中
scene.add(sphere);

// 添加一片平地
const planeGeometry = new THREE.PlaneGeometry(30, 30, 100, 100);
const planeMaterial = new THREE.MeshNormalMaterial();
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
// 由于平地添加后默认是在正前方 所以需要旋转一下
plane.rotation.x = -0.5 * Math.PI;
plane.position.y = -10;
scene.add(plane);

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setAnimationLoop( animation );
document.body.appendChild( renderer.domElement );

// 看向场景
camera.lookAt(scene.position);


function animation(time) {
  cube.rotation.x = time / 2000;
  cube.rotation.y = time / 1000;
  sphere.rotation.x = time / 2000;
  sphere.rotation.y = time / 1000;
  renderer.render( scene, camera );
}

材质

在WebGL中只能绘制3种东西,分别是点、线和三角形。

材质描述了几何体的颜色、感光等信息。我们上面用到了MeshNormalMaterial,同样的Three.js也提供了很多材质,如MeshBasicMaterialMeshDepthMaterialMeshPhongMaterial等。

 

const cubeMaterial = new THREE.MeshBasicMaterial({
  color: '#ff0000',
  wireframe: true,
  opacity: 1,
});

const sphereMaterial = new THREE.MeshBasicMaterial({
  color: new THREE.Color('yellow'),
  wireframe: true,
  opacity: 0.5,
});

相如正方体这种也可以给一个数组:

const cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
const cubeMaterials = [];
cubeMaterials.push(new THREE.MeshBasicMaterial({color: 0xff0000}));
cubeMaterials.push(new THREE.MeshBasicMaterial({color: 0x00ff00}));
cubeMaterials.push(new THREE.MeshBasicMaterial({color: 0x0000ff}));
cubeMaterials.push(new THREE.MeshBasicMaterial({color: 'orange'}));
cubeMaterials.push(new THREE.MeshBasicMaterial({color: 'yellow'}));
cubeMaterials.push(new THREE.MeshBasicMaterial({color: 'grey'}));

const cube = new THREE.Mesh(cubeGeometry, cubeMaterials);

 

使用图片:

const texture = new THREE.TextureLoader().load('./asserts/lufei.jpeg');
const material = new THREE.MeshBasicMaterial({ map: texture });

// 添加正方体
const cubeGeometry = new THREE.BoxGeometry(8, 8, 8);
const cube = new THREE.Mesh(cubeGeometry, material);
// 正方体位置
cube.position.x = -6;
cube.position.y = -2;
cube.position.z = 0;
// 把正方体添加到场景中
scene.add(cube);

// 添加小球
const sphereGeometry = new THREE.SphereGeometry(5, 20, 20);
const sphere = new THREE.Mesh(sphereGeometry, material);
// 小球位置
sphere.position.x = 6;
sphere.position.y = -2;
sphere.position.z = 0;
// 把小球添加到场景中
scene.add(sphere);


更多Texture相关文档请看这里:https://threejs.org/docs/index.html?q=Texture#api/en/constants/Textures

光源

为了让3D效果更立体那么必须加入光源,加入光源后不同的物体还会形成阴影。Three.js也支持好几种光源,本节就简绍一下。
Three.js默认是不支持生成阴影的,主要是为了保证性能。这里我们详细以SpotLight(聚光灯光源)来简绍如何使用光源并生成阴影。

SpotLight(聚光灯光源)


使用光源并添加阴影主要分为4个步骤:

1.添加光源并设置可以传播阴影:

// 添加光源
const spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(0, 10, 0);
spotLight.castShadow = true;
scene.add(spotLight);

2.使用可以感光的材质。

const cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff0000});

const sphereMaterial = new THREE.MeshLambertMaterial({color: 0x00ff00});

const planeMaterial = new THREE.MeshLambertMaterial({color: 0xdddddd});

3.设置物体传播(产生)阴影或接收阴影:

cube.castShadow = true;

sphere.castShadow = true;

plane.receiveShadow = true;

4.渲染器开启阴影映射。

renderer.shadowMap.enabled = true;

 

PointLight(点光源)

PointLight(点光源)是从一个点散发出的光源,点光源不会产生阴影

 

const pointLight = new THREE.PointLight("#ffd200");
scene.add(pointLight);

DirectionalLight(直线光)

DirectionalLight(直线光)顾名思义是一种平行的直线光源(平行光光源)。平行光光源的光线是平行的,可以产生阴影,所有光的强度都一样。它有一个target属性表示照射到哪个位置上,另外可以使用directionalLight.shadow.camera.left来设置阴影的左边距,同样的也可以设置右边、上边、下边等边距,这样就可以确定一个阴影的范围(为了优化性能)。

// 添加光源
const directionalLight = new THREE.DirectionalLight('#ffffff');
directionalLight.position.set(0, 100, 0);
directionalLight.castShadow = true;
directionalLight.shadow.mapSize.width = 512;  // default
directionalLight.shadow.mapSize.height = 512; // default
directionalLight.shadow.camera.near = 0.5;
directionalLight.shadow.camera.far = 1000;
directionalLight.shadow.camera.left = -15;
directionalLight.shadow.camera.right = 15;
directionalLight.shadow.camera.top = 15;
directionalLight.shadow.camera.bottom = -15;
scene.add(directionalLight);

// 光照指向平地
directionalLight.target = plane;

其他光源

AmbientLight的作用是给场景添加一种全局的颜色。该光源没有方向,也不产生阴影。如果你需要给场景中添加一种额外的统一的颜色,那么可以考虑使用AmbientLight,比如在上一个例子中添加一种紫色来烘托氛围,那么就可以使用该光源。

AmbientLight主要的作用就是给环境中添加一种颜色,还有一种给环境中添加颜色的光源,就是HemisphereLight。HemisphereLight是一种更加贴近自然的光源,往往用于模拟天空的光源,它的第一个参数表示天空的颜色,第二个参数表示地面(或者环境)的颜色,第三个参数是intensity表示强度。使用方法都差不多,如下:

const ambientLight = new THREE.AmbientLight('#9370DB');
scene.add(ambientLight);

const hemisphereLight = new THREE.HemisphereLight('#87ceeb', '#f5deb3', 0.4);
scene.add(hemisphereLight);


至此Three.js的基本概念我们都已经讲明白了,我们再回顾一下Three.js的基本物体:相机、场景、几何体、网格、材质、渲染器。

加载模型

Three.js提供了好多的Geometry,也可以使用自定义Geometry。当然还有一种更简单的添加几何体的办法就是使用已有的模型。Three.js支持很多的模型加载器,使用方式大致相同,以obj模型为例。

 

let goku = null;

new MTLLoader().setPath('./asserts/goku/').load('Goku.mtl', function ( materials ) {
  materials.preload();

  new OBJLoader().setMaterials( materials ).setPath( './asserts/goku/' ).load( 'Goku.obj', function ( object ) {
    goku = object;
    goku.position.y = -6;
    goku.children.forEach(mesh => {
      mesh.castShadow = true;
    });
    scene.add( goku );
  });
});

控制器

Three.js提供了好多控制器,使用方式都是一样的,这里主要简绍一下TrackballControls(轨迹器控制器)

const controls = new TrackballControls( camera, renderer.domElement );
controls.rotateSpeed = 1.0;
controls.zoomSpeed = 1.2;
controls.panSpeed = 0.8;

function animation(time) {
  controls.update();
  renderer.render( scene, camera );
}

document.addEventListener('dblclick',() => {
  controls.reset();
});

function onWindowResize() {
  const aspect = window.innerWidth / window.innerHeight;

  camera.aspect = aspect;
  camera.updateProjectionMatrix();

  renderer.setSize( window.innerWidth, window.innerHeight );
  controls.handleResize();
}

window.addEventListener( 'resize', onWindowResize );

 

学习资源

分享中的代码:

标签:gl,const,THREE,three,position,new,js,3d
来源: https://www.cnblogs.com/yujiawen/p/16482442.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有