three.js : 独立控制图形对象
<style>#btnPrev { box-shadow: 2px 2px 6px rgba(0,0,0,.5); }
#btnPrev:hover { box-shadow: 2px 2px 12px rgba(0,0,0,.5); font-weight: bold; }
</style>
<p>以下代码,使用 cubes 数组变量保存立方体对象,每一个对象记为 { id: id, name: 'name', step: step },其中,id 指向所创建的立方体,name 指向立方体的名称,step 指向立方体运动歩幅。然后通过 three.js 射线类判断被点击的图形对象,若和 cubes 存储的 name 相一致,则驱动该图形对象的运动歩幅,从而达到每一个图形对象均可独立控制的目的。</p>
<div id="hEdiv"><pre id="hEpre">
<script type="module">
import * as THREE from 'https://esm.sh/three'; // 导入three.js模块
// 初始化场景、相机、渲染器
const scene = new THREE.Scene;
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 0, 5);
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
let cubes = [], intersects = []; // 立方体合集、几何体合集
// 正方体几何体
const geometry = new THREE.BoxGeometry(1, 1, 1);
geometry.rotateX(Math.PI / 3);
geometry.rotateY(Math.PI / 2);
// 创建两种标准材质 : 一种各面随机色,另一种金色
const material1 = Array.from({length: 6}, () => new THREE.MeshStandardMaterial({ color: 0xffffff * Math.random() }));
const material2 = new THREE.MeshStandardMaterial({ color: 0xffd700 });
const cube1 = new THREE.Mesh(geometry, material1);
const cube2 = new THREE.Mesh(geometry, material2);
cube1.position.y += 1;
cube2.position.y += -1;
cube1.name = 'cube1';
cube2.name = 'cube2';
cubes.push({ id: cube1, name: 'cube1', step: 0.01 }, { id: cube2, name: 'cube2', step: 0.01 });
scene.add(cube1, cube2);
// 环境光
const AmbientLight = new THREE.AmbientLight('yellow')
scene.add(AmbientLight)
// 自然光
const hemiLight = new THREE.HemisphereLight(0xffffff, 0x000000, 1)
hemiLight.position.set(0, 100, 0)
scene.add(hemiLight)
// 以下借助three射线类判断图形和设备指针的位置关系
let raycaster = new THREE.Raycaster(); // 实例化射线拾取模型
const pointer = new THREE.Vector2(); // 实例化二维向量点结构
// 判断函数 :检测指针是否在three绘制的图形上
const isMess = (event) => {
pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(pointer, camera);
intersects = raycaster.intersectObjects(, true); // 参数true表示为不拾取图形对象的子对象
return intersects.length > 0;
}
// 动画 :根据 step 变量值驱动对象运动或不运动
const animate = () => {
cubes.forEach(cube => cube.id.rotation.y += cube.step);
renderer.render(scene, camera);
requestAnimationFrame(animate);
};
// 页面单击事件 :点击到立方体对象控制其 step 变量的值
document.onclick = (e) => {
if (!isMess(e)) return;
const name = intersects.object.name; // 被点击的几何体名称
cubes.forEach(cube => {
// 立方体名称若等于几何体名称
if (cube.name === name) {
cube.step = cube.step === 0 ? 0.01 : 0;
}
});
};
// 鼠标指针移入立方体对象时显示手形图标
document.onmousemove = (e) => {
document.body.style.cursor = isMess(e) ? 'pointer' : 'default';
};
window.onresize = () => renderer.setSize(window.innerWidth, window.innerHeight); // 适应窗口变化
animate(); // 执行动画函数
</script>
<!-- 预览页面CSS -->
<style> body { margin: 0; background: linear-gradient(#eee, #333); } </style>
</pre></div>
<blockquote><button id="btnPrev" name="btnPrev" type="button" value="prev">运行代码</button></blockquote>
<script type="module">
import hlight from 'https://638183.freep.cn/638183/web/helight/helight1.js';
hlight.hl(hEdiv, hEpre);
btnPrev.onclick = () => {
const value = hEpre.textContent + '<style>body {margin: 0; }</style>';
const previewWindow = window.open('', 'preview1', 'width=1200,height=768,top=100,left=100');
previewWindow.document.open();
previewWindow.document.write(value);
setTimeout(function() { previewWindow.document.title = "预览" }, 100);
previewWindow.document.close();
};
</script> 谢谢老师辛苦。我怎么点不动“运行代码”{:4_190:} 分享精彩,恭喜老师又有新探索{:4_191:} 两个立方体在旋转。。这种亚光色真的好漂亮的。。
我在研究标题:为何叫做独立控制图形对象。
操作后发现,点击任何一个都可以单独停止,再击旋转。。
也可以叫做独立控制几何体{:4_173:} 对环境光和自然光很感兴趣,
试着换了一下,这跟PS里常用的渐变映射有点像。。。
环境光渲染的相当自然,在保持原本颜色的基础上,加上环境光,很自然的。{:4_199:} cubes 数组变量保存立方体对象,两个ID不同,名称不同。。步幅相同,当然也可以设为不同。。
通过three.js 射线判断点击的是谁,这个也是个新名词。。。
我们是看到成品,独立执行得相当完美~~
想想要构思设想,再到尝试,最后实现,这个过程小白就是仰望的存在。。
给白老师点一万个大赞{:4_173:} 上帝说要有光,于是今天就看到了光。。。真是让人欣喜。。{:4_173:} 梦江南 发表于 2025-5-14 15:34
谢谢老师辛苦。我怎么点不动“运行代码”
换个浏览器试一试,我点击正常的。 杨帆 发表于 2025-5-14 18:05
分享精彩,恭喜老师又有新探索
{:4_191:} 梦江南 发表于 2025-5-14 15:34
谢谢老师辛苦。我怎么点不动“运行代码”
原因可能有两个:
一,杂牌浏览器(使用规范浏览器);
二,缓存太多(清除缓存即可); 花飞飞 发表于 2025-5-14 19:48
上帝说要有光,于是今天就看到了光。。。真是让人欣喜。。
现在用的光源还是比较简单的光源 花飞飞 发表于 2025-5-14 19:47
cubes 数组变量保存立方体对象,两个ID不同,名称不同。。步幅相同,当然也可以设为不同。。
通过thre ...
谢一万 花飞飞 发表于 2025-5-14 19:40
对环境光和自然光很感兴趣,
试着换了一下,这跟PS里常用的渐变映射有点像。。。
环境光渲染的相当自然, ...
光源是一门比较复杂的学问 还真是独立控制的,而且停止后,再运行也是独立的呢{:4_187:} 这个有趣,想让哪个停,就能控制哪个{:4_187:} 红影 发表于 2025-5-14 21:06
这个有趣,想让哪个停,就能控制哪个
就是复杂得多 红影 发表于 2025-5-14 21:05
还真是独立控制的,而且停止后,再运行也是独立的呢
每一个子对象有自己的速度变量(歩幅) “检测指针是否在three绘制的图形上”
这个里面的判断方式没看懂。{:4_203:} 红影 发表于 2025-5-14 21:09
“检测指针是否在three绘制的图形上”
这个里面的判断方式没看懂。
而且不是特别准确,这是将就的方法。原理是将相机所拍到的图形的射线计算出二维平面的几何面,正常的时候大概准确,当图像旋转角度很大时,它就不那么精准了,你可以去看看牵引的原版 花飞飞 发表于 2025-5-14 19:49
换个浏览器试一试,我点击正常的。
早上问好飞飞老师,我只有一个2345浏览器。{:4_201:}