threejs在透视相机模式下,绘制像素大小固定的元素

要求:在透视相机模式下绘制一个图标,图标大小始终为32*32px。图标如下:

实现思路:

使用THREE.Sprite。因为 SpriteMaterial 支持配置 sizeAttenuation 使Sprite大小不随相机的深度而衰减。所以我们只要保证sprite的初始的大小合适,在以后的相机深度变化的时候就不会改变大小了。

开始操作

第一次的操作:

javascript 复制代码
drawAddSprite(type: InterActiveType = InterActiveType.Default) {
    // 这个sprite我是自己用canvas画出来的,比较简单,就不贴了
    const texture = generateAddIconCanvasTexture(type);
    const material = new THREE.SpriteMaterial({ map: texture, sizeAttenuation: false });
    material.map.colorSpace = 'srgb';
    const sprite = new THREE.Sprite(material);
    scene.add(sprite)
}

我们看一下效果

我设置sizeAttenuation: false之前,我以为这个图标会占满屏(高度上满屏),毕竟这个图标跟相机没关系了。但是并没有。后来意识到sizeAttenuation: false 只是设置了相机的深度跟Sprite没有关系,但是透视相机的fov还是会影响到sprite的大小的。我们去验证一下,当我不断修改相机的fov时,图标随着fov的增大而减小。

思路:

  1. 第一步,我们找到一个fov值,在这个值下,我们看到的图标是占满屏幕的

  2. 在第一步的fov值下,我们要求图标大小是32*32的,那只需要设置Sprite的scale为 32 / canvas.clientHeight

我们来实现一下上面的思路:

  1. 我们来找这个fov

这个d就是相机的深度,既然设置了 sizeAttenuation: false,sprite不随相机的深度变化而变化,那这个d就要有一个默认值。我盲猜这个默认值是1。那这个fov的值计算如下

javascript 复制代码
Math.atan(0.5) * 180 / Math.PI * 2

这个值经过计算是53.13010235415598

现在我们设置相机fov为这个值去看一下效果

果然是满屏的。所以这个d确实是1.

找到了这个fov,我们设计相机的fov为这个值,现在我们去设置sprite的scale去改变Sprite的大小

javascript 复制代码
drawAddSprite(type: InterActiveType = InterActiveType.Default) {
    const texture = generateAddIconCanvasTexture(type);
    const material = new THREE.SpriteMaterial({ map: texture, sizeAttenuation: false });
    material.map.colorSpace = 'srgb';
    const sprite = new THREE.Sprite(material);
    const scale = 32 / canvas.clientHeight;
    sprite.scale.set(scale, scale, 1);
    scene.add(sprite)
}

看一下效果,已经实现了。

但是呢,我们如果我们的fov不是固定的怎么办呢,只需要加上如下配置就可以动态的根据fov去获得这个scale了。

javascript 复制代码
drawAddSprite(type: InterActiveType = InterActiveType.Default) {
    const texture = generateAddIconCanvasTexture(type);
    const material = new THREE.SpriteMaterial({ map: texture, sizeAttenuation: false });
    material.map.colorSpace = 'srgb';
    const sprite = new THREE.Sprite(material);
    const fullFov = ((Math.atan(0.5) * 180) / Math.PI) * 2;
    const { fov } = camera;
    let scale = 32 / dom.clientHeight;
    scale *= Math.tan((fov / 2 / 180) * Math.PI) / Math.tan((fullFov / 2 / 180) * Math.PI);
    sprite.scale.set(scale, scale, 1);
    scene.add(sprite)
}

完成。

相关推荐
烛阴1 天前
Three.js 材质完全入门指南:让你的 3D 物体「活」起来
webgl·three.js
cTz6FE7gA2 天前
WebGL实战:用Three.js创建3D场景,实现沉浸式Web体验
前端·javascript·webgl
三维搬砖者7 天前
AI 解密大厂 Three.js 三维引擎开发 03|从经纬度到三维世界的坐标解码
webgl·three.js
threelab11 天前
引擎案例分析 02|GeoLayer 大厂地理可视化方案深度拆解
javascript·3d·webgl
山海鲸可视化11 天前
【山海鲸功能演示】如何设置选中按钮的时候其他按钮切换为默认样式?
webgl·可视化·数据可视化·数据表格·搜索框
kadog11 天前
GraphX:基于 WebGL 区间算术的 GPU 加速隐函数绘图器
前端·javascript·数学建模·webgl
ct97812 天前
Cesium的Primitive API
gis·webgl·cesium
sin°θ_陈15 天前
前馈式3D Gaussian Splatting 研究地图(路线二):几何优先的前馈式 3DGS——前馈式 3DGS 如何重新拥抱多视图几何
深度学习·3d·webgl·三维重建·空间计算·3dgs·空间智能
星河耀银海16 天前
3D效果:HTML5 WebGL结合AI实现智能3D场景渲染
前端·人工智能·深度学习·3d·html5·webgl
点量云实时渲染-小芹17 天前
Unity模型数字孪生虚拟仿真webgl推流卡实时云渲染推流
unity·webgl·数字孪生·实时云渲染·虚拟仿真·云推流