3D 扩展
加载3D渲染库的方式非常简单,你可以直接通过CND加载
只要确保加载在spritejs
的JS之后即可。
💡考虑到最佳性能,sprite-extend-3d.js
默认适配chrome59
及以上浏览器,所以你只要用spritejs的ES编译版本即可。如果你希望支持较早的浏览器,sprite-extend-3d.js
仍可支持早期版本,不过你需要在项目中修改babel配置,重新编译适配旧浏览器的版本。
加载之后,可以通过spritejs.ext3d
来访问3D的API,并且可以通过scene.layer3d(layerID)
来创建3D的渲染层。
const {Scene} = spritejs;
const {Cube, shaders} = spritejs.ext3d;
const container = document.getElementById('container');
const scene = new Scene({container});
const layer = scene.layer3d('fglayer', {
camera: {
fov: 35, // Field of view
},
});
layer.camera.attributes.pos = [3, 3, 5];
const program = layer.createProgram({
...shaders.NORMAL_GEOMETRY,
cullFace: null,
});
const cube = new Cube(program, {
colors: 'red red blue blue green green',
});
layer.append(cube);
layer.setOrbit(); // 开启旋转控制
当然,你也可以通过模块方式加载sprite-extend-3d
:
import {Scene} from 'spritejs';
import {Cube, shaders} from 'sprite-extend-3d';
坐标和相机
与2D的layer不同,layer3d采用WebGL坐标系,画布中心点的位置是[0,0,0],水平向右是x轴,垂直向上是y轴,垂直于屏幕向外的是z轴。
元素是否显示出来,显示在什么位置,与透视相机有关。
一个layer对应一个默认的透视相机,创建layer的时候可以初始化它,在后续渲染的时候也可以修改它的属性。上面的例子中,我们把相机放在坐标[3, 3, 5]
的位置。
透视相机有一些参数,如下:
- near: 相机可以拍摄到的最近距离,默认为 0.1
- far: 相机可以拍摄到的最远距离,默认为 100
- fov: 视野宽度,默认是45度
- aspect: 宽高比,默认是1:1,但是如果preserveAspect配置不为false,layer会根据resolution来设置相机的宽高比
- preserveAspect: 默认为true,根据画布宽高比来保持相机宽高比,这样元素就不会被拉伸或压缩
默认情况下,相机的方向是朝着z轴负向无穷远处,而相机有一个方法叫lookAt,传入一个坐标,可以让相机朝向该位置拍摄。
在3D的layer中,只要有顶点坐标就可以非常方便地绘制几何体。
上面的代码中,我们传入一组顶点坐标,绘制了一个正四面体。
绘制模型
const {Scene} = spritejs;
const {Mesh3d, shaders} = spritejs.ext3d;
const container = document.getElementById('container');
const scene = new Scene({
container,
displayRatio: 2,
});
const layer = scene.layer3d('fglayer', {
camera: {
fov: 45,
pos: [-2, 2, 2],
},
directionalLight: [0.5, 1.0, -0.3, 0.15],
});
const program = layer.createProgram(shaders.NORMAL);
const model = layer.loadModel('https://s2.ssl.qhres.com/static/bf607b5f64a91492.json');
const macow = new Mesh3d(program, {model});
layer.setOrbit({target: [0, 0.7, 0]});
注意上面的代码里layer.loadModel
是个异步方法,但是我们并不用等到model数据真正加载下来,可以直接把model(此时是一个promise)赋给Mesh3d元素,等数据加载完毕后,元素就会被渲染出来。
有了模型,我们可以把纹理加上:
const {Mesh3d, shaders} = spritejs.ext3d;
const container = document.getElementById('container');
const scene = new Scene({
container,
displayRatio: 2,
});
const layer = scene.layer3d('fglayer', {
camera: {
fov: 45,
pos: [-2, 2, 2],
},
directionalLight: [0.5, 1.0, -0.3, 0.15],
});
const texture = layer.createTexture('https://p1.ssl.qhimg.com/t01b4bd0e2fb9f47550.jpg');
const program = layer.createProgram({
...shaders.NORMAL_TEXTURE,
texture,
});
const model = layer.loadModel('https://s2.ssl.qhres.com/static/bf607b5f64a91492.json');
const macow = new Mesh3d(program, {model});
layer.append(macow);
layer.setOrbit({target: [0, 0.7, 0]});
我们只要通过layer.createTexture
创建texture对象,并将该对象赋给program(同时要将programe的shader类型改为NORMAL_TEXTURE),这样元素的纹理就能显示出来。注意createTexture方法也是一个异步方法,但我们同样不用等待图片加载完毕再创建元素。
SpriteJSNext默认支持几种常见的光源,我们可以设置环境光(ambientColor),方向光(directionalLight)和点光源(pointLight)。
与元素交互
SpriteJSNext的3D扩展中,与元素交互也非常简单,在前面的例子我们已经见过。
一种交互是通过鼠标或触屏旋转角度和缩放,只需要一条语句:
layer.setOrbit({target: [x, y, z]});
有了这条语句之后,我们就可以在元素上像2D那样注册鼠标或触屏事件了。