ThreeJS点材质形状问题
<style>.artBox { font-size: 18px; }
.artBox > p { margin: 10px 0; line-height: 30px; }
.artBox mark { padding: 4px 6px; background: lightblue; }
#prevBox { position: fixed; top: 0; right: 0; bottom: 0; left: 0; background: #eee; display: none; padding: 0; overflow: hidden; z-index: 1000; margin: 0; }
#prevBox::after { position: absolute; content: '关闭预览'; bottom: 10px; left: calc(50% - 40px); padding: 0 4px; width: 80px; height: 30px; line-height: 30px; text-align: center; border: 1px solid #efe; border-radius: 6px; background: #eee; font-size: 14px; box-shadow: 2px 2px 6px rgba(0,0,0,.25); cursor: pointer; }
iframe { position: relative; width: 100%; height: 100%; border: none; outline: none; box-sizing: border-box; margin: 0; }
</style>
<div id="prevBox"></div>
<div class="artBox">
<p>和 SpriteMaterial 精灵材质一样,点材质<mark>THREE.PointsMaterial</mark>的形状默认也是矩形。改变点材质的形状就是给它贴个背景透明的纹理贴图,但对ThreeJS内置的几何体而言,依附其上的 map 并不能完美改变点材质的形状,试看:</p>
<div class="hEdiv"><pre class="hEpre" id="pre1">
<img style="position:absolute;width:200px;height:200px;z-index:10;" src="https://638183.freep.cn/638183/web/svg/sunfl-2.svg" alt="" title="纹理原图" />
<script type="module">
import { THREE, scene, camera, renderer, clock, basic3, click3 } from 'https://638183.freep.cn/638183/3dev/3/3basic.js';
basic3();
new THREE.TextureLoader().load(
'https://638183.freep.cn/638183/web/svg/sunfl-2.svg',
(texture) => {
texture.colorSpace = THREE.SRGBColorSpace;
const geometry = new THREE.SphereGeometry(); // 球体几何体
const material = new THREE.PointsMaterial({ size: 0.15, map: texture, transparent: true }); // 点材质
const points = new THREE.Points(geometry, material);
scene.add(points);
renderer.render(scene, camera);
}, undefined, (err) => console('error:', err)
);
</script>
</pre></div>
<blockquote><button id="btnPrev1">运行代码</button></blockquote>
<p>运行代码可以看到球体不完美,球体图像中的点材质保留着矩形的形状,texture 纹理贴图以一个整体分摊给各个点,所有的点并不能完美以贴图构图。要让纹理成为每一个点的图像形状,需要对几何体进行重构,一个简单的实现思路是:创建一个缓冲几何体 BufferGeometry,它从球体几何体 SphereGeometry 那里获取所有顶点的位置(position)信息,然后,使用该缓冲几何体+点材质构建图像。具体代码如下:</p>
<div class="hEdiv"><pre class="hEpre" id="pre2">
<img style="position:absolute;width:200px;height:200px;z-index:10;" src="https://638183.freep.cn/638183/web/svg/sunfl-2.svg" alt="" title="纹理原图" />
<script type="module">
import { THREE, scene, camera, renderer, clock, basic3, click3 } from 'https://638183.freep.cn/638183/3dev/3/3basic.js';
basic3();
const positions = new THREE.SphereGeometry().attributes.position;
new THREE.TextureLoader().load(
'https://638183.freep.cn/638183/web/svg/sunfl-2.svg',
(texture) => {
texture.colorSpace = THREE.SRGBColorSpace;
const geometry = new THREE.BufferGeometry(); // 球体几何体
geometry.setAttribute('position', positions);
const material = new THREE.PointsMaterial({ size: 0.15, map: texture, transparent: true }); // 点材质
const points = new THREE.Points(geometry, material);
scene.add(points);
renderer.render(scene, camera);
}, undefined, (err) => console('error:', err)
);
</script>
</pre></div>
<blockquote><button id="btnPrev2">运行代码</button></blockquote>
<p>这回球体图像是完整的,而且,重要的是,“绘制”球体的点材质完美贴上了纹理,纹理图片的形状就是每一个点的形状。</p>
</div>
<script type="module">
import hlight from 'https://638183.freep.cn/638183/web/helight/helight1.js';
const pres = document.querySelectorAll('.hEpre');
const divs = document.querySelectorAll('.hEdiv');
divs.forEach( (div, key) => hlight.hl(div, pres));
const preView = (htmlCode, targetBox) => {
if (targetBox.innerHTML) return;
const iframe = document.createElement('iframe');
htmlCode = htmlCode + '<style>body {margin: 0; }</style>';
iframe.srcdoc = htmlCode;
targetBox.appendChild(iframe);
targetBox.style.display = 'block';
targetBox.onclick = () => {
targetBox.innerHTML = '';
targetBox.style.display = 'none';
}
};
const btns = ;
const idPrevs = ;
btns.forEach( (btn, key) => {
btn.onclick = () => preView(idPrevs.textContent, prevBox);
});
</script> 不使用缓冲几何体 BufferGeometry的时候,纹理贴图是用自身形状整个帖到球体上的,有些点处在纹理图上的空白的地方,不能完整地体现出球体。而使用缓冲几何体,每个点都被完整地帖上纹理图。
这个功能很奇妙{:4_199:} 一个是整体帖,每一个是逐点帖,效果完全不同呢。{:4_204:} 红影 发表于 2025-6-30 15:17
不使用缓冲几何体 BufferGeometry的时候,纹理贴图是用自身形状整个帖到球体上的,有些点处在纹理图上的空 ...
但是不用贴图、不同每一个点颜色不同,那么没啥问题 神奇,纹理图片的形状就是每一个点的形状。谢谢马老师经典讲授{:4_190:} 马黑黑 发表于 2025-6-30 18:09
但是不用贴图、不同每一个点颜色不同,那么没啥问题
是的,虽然颜色不同的,但每个点都是有的。 红影 发表于 2025-6-30 21:11
是的,虽然颜色不同的,但每个点都是有的。
嗯嗯 杨帆 发表于 2025-6-30 19:51
神奇,纹理图片的形状就是每一个点的形状。谢谢马老师经典讲授
{:4_191:} 马黑黑 发表于 2025-6-30 21:35
嗯嗯
这些点里面的讲究的确太多了。 红影 发表于 2025-6-30 21:45
这些点里面的讲究的确太多了。
接近于自定义顶点但又比自定义方便一点——充分利用了内置缓冲几何体的基类属性 看到这个神奇的几何体:缓冲几何体 BufferGeometry
这个是把球体几何体打散,得到每个点的位置重新组成球体。。
感觉它比较高级。。{:4_173:} 能想出这种法子的就是神人{:4_173:} 泡沫 发表于 2025-6-30 22:01
看到这个神奇的几何体:缓冲几何体 BufferGeometry
这个是把球体几何体打散,得到每个点的位置重新组成球 ...
ThreeJS 立方体、圆环、球体等等都是 buffer(缓冲)几何体(Geometry),BufferGeometry 是未定型几何体,预留着缓冲区留待使用顶点区填充。所谓顶点,指构成图像的顶点,每个顶点是 xyz 点坐标(2d的话是xy点坐标)。 泡沫 发表于 2025-6-30 22:02
能想出这种法子的就是神人
这个想想就可以的呀 马黑黑 发表于 2025-6-30 22:04
ThreeJS 立方体、圆环、球体等等都是 buffer(缓冲)几何体(Geometry),BufferGeometry 是未定型几何体 ...
未定型几何体那就是可以跟水一样让它变成各种形状。。。{:4_173:}
几何体中的变形金刚。。给点就成型 马黑黑 发表于 2025-6-30 22:08
这个想想就可以的呀
神脑袋想想就可以。。。我这样的笨脑袋不行滴{:4_170:} 马黑黑 发表于 2025-6-30 22:08
这个想想就可以的呀
{:4_185:}晚安了,白大神。 马黑黑 发表于 2025-6-30 21:47
接近于自定义顶点但又比自定义方便一点——充分利用了内置缓冲几何体的基类属性
其实我都不知道缓冲几何体的基类属性都是些什么呢{:4_173:} 红影 发表于 2025-7-1 11:59
其实我都不知道缓冲几何体的基类属性都是些什么呢
基类就是一种类属的基本。
比方说鸡,确切说是原鸡,是鸡的一个基类,其它所有品种的鸡出自于它。
缓冲几何体,BufferGeometry,是一个待定型的几何体,它将因顶点的不同而创建出不同的形状。
ThreeJS 的 BoxGeometry(立方体几何体)是通过 Buffergeometry 构造出来的预设几何体,叫做内置几何体。它来源于 Buffergeometry,给它制定好了顶点数据,开箱即用。 泡沫 发表于 2025-6-30 22:41
晚安了,白大神。
{:4_190:}