最近前端实现的量子纠缠在网络上火了起来,作者bgstaal
的推文:
效果如下:
量子纠缠那我们一起来看下什么是量子纠缠,以及前端是如何实现的。
在量子力学里,当几个粒子在彼此相互作用后,由于各个粒子所拥有的特性已综合成为整体性质,无法单独描述各个粒子的性质,只能描述整体系统的性质,则称这现象为量子缠结或量子纠缠。量子纠缠是一种奇怪的量子力学现象,处于纠缠态的两个量子不论相距多远都存在一种关联,其中一个量子状态发生改变,另一个的状态会瞬时发生相应改变。
作者bgstaal
在github上开源了一个项目,r说明如何使用 Three.js 和 localStorage 在多个窗口中设置3D场景。一起来看下代码如何实现的。
首先,从 Github 上克隆 multipleWindow3dScene
项目:
git clone https://github.com/bgstaal/multipleWindow3dScene.git
接下来,通过 vscode 中的 Live Server, 启动该项目,并在浏览器中打开项目主页 http://127.0.0.1:5500/index.html
。效果如下:
展示效果现在我们看下项目目录,如下图所示:
index.html:设置 HTML 结构的入口点,引入了压缩后的three.js
以及main.js
。
<!DOCTYPE html>
<html lang="en">
<head>
<title>3d example using three.js and multiple windows</title>
<script type="text/javascript" src="three.r124.min.js"></script>
<style type="text/css">
*{
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<script type="module" src="main.js"></script>
</body>
</html>
下来我们先看下main.js。
定义了存放3d场景以及时间变量,在网站加载成功,页面可见时,则执行初始化init函数,设置场景,窗口管理器等相关配置。
init 函数负责设置场景、窗口管理器、调整渲染器大小以适应窗口,并开始渲染循环。
function init () {
initialized = true;
// add a short timeout because window.offsetX reports wrong values before a short period
setTimeout(() => {
setupScene();
setupWindowManager();
resize();
updateWindowShape(false);
render();
window.addEventListener('resize', resize);
}, 500)
}
这里添加了一个定时器,主要是因为window.offsetX在短时间内会返回错误的值。
setupScene函数创建了相机、场景、渲染器和3D世界对象,并将渲染器的DOM元素添加到文档体中。
// 设置场景
function setupScene() {
// 创建正交相机
camera = new t.OrthographicCamera(0, 0, window.innerWidth, window.innerHeight, -10000, 10000);
// 设置相机位置
camera.position.z = 2.5;
near = camera.position.z - .5;
far = camera.position.z + 0.5;
// 创建场景
scene = new t.Scene();
scene.background = new t.Color(0.0);
scene.add(camera);
// 创建渲染器
renderer = new t.WebGLRenderer({ antialias: true, depthBuffer: true });
renderer.setPixelRatio(pixR);
// 创建对象3D
world = new t.Object3D();
scene.add(world);
// 设置渲染器的id
renderer.domElement.setAttribute("id", "scene");
// 将渲染器添加到body中
document.body.appendChild(renderer.domElement);
}
窗口管理器的设置通过setupWindowManager函数完成,它实例化WindowManager,并定义窗口形状变化和窗口改变的回调函数。
窗口形状变化用于跟踪和反应窗口位置的移动。窗口改变的回调函数用于更新场景中的立方体数量。
// 创建一个WindowManager实例
function setupWindowManager() {
windowManager = new WindowManager();
// 设置窗口形状改变回调函数
windowManager.setWinShapeChangeCallback(updateWindowShape);
// 设置窗口改变回调函数
windowManager.setWinChangeCallback(windowsUpdated);
// here you can add your custom metadata to each windows instance
// 在这里,您可以向每个窗口实例添加自定义元数据
let metaData = { foo: "bar" };
// this will init the windowmanager and add this window to the centralised pool of windows
// 这将初始化窗口管理器并将此窗口添加到集中的窗口池中
windowManager.init(metaData);
// call update windows initially (it will later be called by the win change callback)
// 调用updateWindows函数
windowsUpdated();
}
// 当窗口更新时调用该函数
function windowsUpdated() {
// 更新立方体数量
updateNumberOfCubes();
}
// 更新立方体数量
function updateNumberOfCubes() {
// 获取所有窗口
let wins = windowManager.getWindows();
// remove all cubes
// 移除所有立方体
cubes.forEach((c) => {
world.remove(c);
})
// 重新初始化立方体数组
cubes = [];
// add new cubes based on the current window setup
// 根据当前窗口设置添加新的立方体
for (let i = 0; i < wins.length; i++) {
let win = wins[i];
// 设置立方体的颜色
let c = new t.Color();
c.setHSL(i * .1, 1.0, .5);
// 设置立方体的尺寸
let s = 100 + i * 50;
// 创建立方体
let cube = new t.Mesh(new t.BoxGeometry(s, s, s), new t.MeshBasicMaterial({ color: c, wireframe: true }));
// 设置立方体的位置
cube.position.x = win.shape.x + (win.shape.w * .5);
cube.position.y = win.shape.y + (win.shape.h * .5);
// 将立方体添加到场景中
world.add(cube);
cubes.push(cube);
}
}
// 更新窗口形状函数,easing参数默认为true
function updateWindowShape(easing = true) {
// storing the actual offset in a proxy that we update against in the render function
// 将当前的偏移量存储在代理中,以便在渲染函数中更新
sceneOffsetTarget = { x: -window.screenX, y: -window.screenY };
// 如果easing参数为false,则将sceneOffset设置为sceneOffsetTarget
if (!easing) sceneOffset = sceneOffsetTarget;
}
render函数是这段代码的核心,主要是获取当前时间,计算出每个立方体每一帧的动画,来处理窗口的变化,并渲染到页面上。还使用了浏览器的 requestAnimationFrame
方法,让render方法在下一次浏览器重绘之前执行,通常最常见的刷新率是 60hz(每秒 60 个周期/帧),以匹配大多数显示器的刷新率,起到优化动画性能的作用。
// 渲染函数,更新和渲染场景
function render() {
// 获取当前时间
let t = getTime();
// update the window manager
// 更新窗口管理器
windowManager.update();
// update the scene offset based on the current window manager state
// this will create a smooth transition between the current scene offset and the target scene offset
// calculate the new position based on the delta between current offset and new offset times a falloff value (to create the nice smoothing effect)
let falloff = .05;
// 计算场景偏移量
sceneOffset.x = sceneOffset.x + ((sceneOffsetTarget.x - sceneOffset.x) * falloff);
sceneOffset.y = sceneOffset.y + ((sceneOffsetTarget.y - sceneOffset.y) * falloff);
// set the world position to the offset
//设置场景偏移量
world.position.x = sceneOffset.x;
world.position.y = sceneOffset.y;
// get the window manager and the window
// 获取所有窗口
let wins = windowManager.getWindows();
// loop through all our cubes and update their positions based on current window positions
// 遍历cubes数组,更新立方体的位置
for (let i = 0; i < cubes.length; i++) {
// 获取cubes数组中的第i个元素
let cube = cubes[i];
// 获取wins数组中的第i个元素
let win = wins[i];
// 将t赋值给_t
let _t = t;
// + i * .2;
let posTarget = { x: win.shape.x + (win.shape.w * .5), y: win.shape.y + (win.shape.h * .5) }
// 计算cube当前位置到目标位置的距离,并乘以衰减系数
cube.position.x = cube.position.x + (posTarget.x - cube.position.x) * falloff;
cube.position.y = cube.position.y + (posTarget.y - cube.position.y) * falloff;
// 计算cube的旋转角度
cube.rotation.x = _t * .5;
cube.rotation.y = _t * .3;
};
// render the scene
renderer.render(scene, camera);
requestAnimationFrame(render);
}
resize函数,在浏览器窗口大小改变时,调整渲染器的尺寸以适应窗口大小,相机和渲染器也进行更新调整。
// 调整渲染器的尺寸以适应窗口大小
function resize() {
// 获取窗口的宽度
let width = window.innerWidth;
// 获取窗口的高度
let height = window.innerHeight
// 创建一个正交相机,参数为:left,right,top,bottom,near,far
camera = new t.OrthographicCamera(0, width, 0, height, -10000, 10000);
// 更新相机的投影矩阵
camera.updateProjectionMatrix();
// 设置渲染器的尺寸
renderer.setSize(width, height);
}
接下来看下我们看下WindowManager文件
窗口管理器WindowManager函数,主要是监听 localStorage 变化,刷新渲染立方体的位置。其中 localStorage,存储了立方体在浏览器窗口的位置,包含距离屏幕左上角x轴y轴的距离,和浏览器窗口的宽和高这些信息。
我们看下localStorage的信息,如下图所示:
通过监听beforeunload事件监听窗口是否关闭,关闭则删除浏览器对应的立方体的信息。
// 当前窗口即将关闭时的事件监听器
window.addEventListener('beforeunload', function (e) {
// 获取窗口索引
let index = that.getWindowIndexFromId(that.#id);
//remove this window from the list and update local storage
// 从列表中删除此窗口并更新本地存储
that.#windows.splice(index, 1);
that.updateWindowsLocalStorage();
});
窗口管理器的init方法,根据当前窗口的位置,创建当前窗口唯一的id,创建一个立方体的位置数据,存储在localStorage,方便监听,最后执行了windowsUpdated 方法,更新立方体数量,首先通过 getWindows方法,拿到所有立方体的数据,绘制出新的立方体信息。
// initiate current window (add metadata for custom data to store with each window instance)
// 初始化当前窗口(添加元数据以将自定义数据存储到每个窗口实例中)
init(metaData) {
//将本地存储中的windows数据转换为JSON格式,若未存储,则初始化为空数组
this.#windows = JSON.parse(localStorage.getItem("windows")) || [];
//获取本地存储中的count值,若未存储,则初始化为0
this.#count = localStorage.getItem("count") || 0;
this.#count++;
this.#id = this.#count;
//获取窗口形状
let shape = this.getWinShape();
//将窗口数据赋值给this.#winData
this.#winData = { id: this.#id, shape: shape, metaData: metaData };
//将this.#winData添加到this.#windows数组中
this.#windows.push(this.#winData);
//将this.#count存储到本地
localStorage.setItem("count", this.#count);
//更新本地存储中的windows数据
this.updateWindowsLocalStorage();
}
以上就是主要的核心效果代码。
参考来源
本文由微信公众号奇舞精选原创,哈喽比特收录。
文章来源:https://mp.weixin.qq.com/s/uWxidIPcDcp0WMp2A-j7Hw
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。