马黑黑 发表于 2025-6-30 14:12

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">
&lt;img style="position:absolute;width:200px;height:200px;z-index:10;" src="https://638183.freep.cn/638183/web/svg/sunfl-2.svg" alt="" title="纹理原图" /&gt;
&lt;script type="module"&gt;
        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)
        );
&lt;/script&gt;
        </pre></div>
        <blockquote><button id="btnPrev1">运行代码</button></blockquote>
        <p>运行代码可以看到球体不完美,球体图像中的点材质保留着矩形的形状,texture 纹理贴图以一个整体分摊给各个点,所有的点并不能完美以贴图构图。要让纹理成为每一个点的图像形状,需要对几何体进行重构,一个简单的实现思路是:创建一个缓冲几何体 BufferGeometry,它从球体几何体 SphereGeometry 那里获取所有顶点的位置(position)信息,然后,使用该缓冲几何体+点材质构建图像。具体代码如下:</p>
        <div class="hEdiv"><pre class="hEpre" id="pre2">
&lt;img style="position:absolute;width:200px;height:200px;z-index:10;" src="https://638183.freep.cn/638183/web/svg/sunfl-2.svg" alt="" title="纹理原图" /&gt;
&lt;script type="module"&gt;
        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)
        );
&lt;/script&gt;
        </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>

红影 发表于 2025-6-30 15:17

不使用缓冲几何体 BufferGeometry的时候,纹理贴图是用自身形状整个帖到球体上的,有些点处在纹理图上的空白的地方,不能完整地体现出球体。而使用缓冲几何体,每个点都被完整地帖上纹理图。
这个功能很奇妙{:4_199:}

红影 发表于 2025-6-30 15:17

一个是整体帖,每一个是逐点帖,效果完全不同呢。{:4_204:}

马黑黑 发表于 2025-6-30 18:09

红影 发表于 2025-6-30 15:17
不使用缓冲几何体 BufferGeometry的时候,纹理贴图是用自身形状整个帖到球体上的,有些点处在纹理图上的空 ...

但是不用贴图、不同每一个点颜色不同,那么没啥问题

杨帆 发表于 2025-6-30 19:51

神奇,纹理图片的形状就是每一个点的形状。谢谢马老师经典讲授{:4_190:}

红影 发表于 2025-6-30 21:11

马黑黑 发表于 2025-6-30 18:09
但是不用贴图、不同每一个点颜色不同,那么没啥问题

是的,虽然颜色不同的,但每个点都是有的。

马黑黑 发表于 2025-6-30 21:35

红影 发表于 2025-6-30 21:11
是的,虽然颜色不同的,但每个点都是有的。

嗯嗯

马黑黑 发表于 2025-6-30 21:35

杨帆 发表于 2025-6-30 19:51
神奇,纹理图片的形状就是每一个点的形状。谢谢马老师经典讲授

{:4_191:}

红影 发表于 2025-6-30 21:45

马黑黑 发表于 2025-6-30 21:35
嗯嗯

这些点里面的讲究的确太多了。

马黑黑 发表于 2025-6-30 21:47

红影 发表于 2025-6-30 21:45
这些点里面的讲究的确太多了。

接近于自定义顶点但又比自定义方便一点——充分利用了内置缓冲几何体的基类属性

泡沫 发表于 2025-6-30 22:01

看到这个神奇的几何体:缓冲几何体 BufferGeometry
这个是把球体几何体打散,得到每个点的位置重新组成球体。。
感觉它比较高级。。{:4_173:}

泡沫 发表于 2025-6-30 22:02

能想出这种法子的就是神人{:4_173:}

马黑黑 发表于 2025-6-30 22:04

泡沫 发表于 2025-6-30 22:01
看到这个神奇的几何体:缓冲几何体 BufferGeometry
这个是把球体几何体打散,得到每个点的位置重新组成球 ...
ThreeJS 立方体、圆环、球体等等都是 buffer(缓冲)几何体(Geometry),BufferGeometry 是未定型几何体,预留着缓冲区留待使用顶点区填充。所谓顶点,指构成图像的顶点,每个顶点是 xyz 点坐标(2d的话是xy点坐标)。

马黑黑 发表于 2025-6-30 22:08

泡沫 发表于 2025-6-30 22:02
能想出这种法子的就是神人

这个想想就可以的呀

泡沫 发表于 2025-6-30 22:39

马黑黑 发表于 2025-6-30 22:04
ThreeJS 立方体、圆环、球体等等都是 buffer(缓冲)几何体(Geometry),BufferGeometry 是未定型几何体 ...

未定型几何体那就是可以跟水一样让它变成各种形状。。。{:4_173:}
几何体中的变形金刚。。给点就成型

泡沫 发表于 2025-6-30 22:40

马黑黑 发表于 2025-6-30 22:08
这个想想就可以的呀

神脑袋想想就可以。。。我这样的笨脑袋不行滴{:4_170:}

泡沫 发表于 2025-6-30 22:41

马黑黑 发表于 2025-6-30 22:08
这个想想就可以的呀

{:4_185:}晚安了,白大神。

红影 发表于 2025-7-1 11:59

马黑黑 发表于 2025-6-30 21:47
接近于自定义顶点但又比自定义方便一点——充分利用了内置缓冲几何体的基类属性

其实我都不知道缓冲几何体的基类属性都是些什么呢{:4_173:}

马黑黑 发表于 2025-7-1 20:09

红影 发表于 2025-7-1 11:59
其实我都不知道缓冲几何体的基类属性都是些什么呢
基类就是一种类属的基本。

比方说鸡,确切说是原鸡,是鸡的一个基类,其它所有品种的鸡出自于它。

缓冲几何体,BufferGeometry,是一个待定型的几何体,它将因顶点的不同而创建出不同的形状。

ThreeJS 的 BoxGeometry(立方体几何体)是通过 Buffergeometry 构造出来的预设几何体,叫做内置几何体。它来源于 Buffergeometry,给它制定好了顶点数据,开箱即用。

马黑黑 发表于 2025-7-1 20:10

泡沫 发表于 2025-6-30 22:41
晚安了,白大神。

{:4_190:}
页: [1] 2 3 4 5 6 7
查看完整版本: ThreeJS点材质形状问题