ThreeJs自定义Sprite

该代码示例展示了如何在Three.js环境中创建一个WebGLSprite,使用文本作为精灵的内容。首先,它创建了一个配置对象,包含UV坐标和文本信息。然后,通过计算和处理这些信息,生成顶点数据和纹理坐标。最后,使用BufferGeometry和自定义着色器材质构建了精灵的网格,并加载了纹理。
摘要由CSDN通过智能技术生成

scene.add(new WebGLSprite('123'));

以下为WebGLSprite的全部源码

import * as THREE from 'three'
import * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils.js';
export class WebGLSprite {
    constructor(text) {
        let config = {
            uv1: {
                us: [0, 5/256, 250/256, 1.0],
                vs: [0, 20/128, 50/128, 1.0]
            },
            uv2: {
                us: [0, 0, 1.0, 1.0],
                vs: [0, 0, 1.0, 1.0]
            },
            text:text
        };

        this.sprite = this.createSprite(config);
    }

    getUv(uvs) {
        let uv = [];
        for (let i = 0; i < 4; i++) {
            for (let j = 0; j < 4; j++) {
                uv.push({ u: uvs.us[i], v: uvs.vs[j] });
            }
        }
        let uvs_data = [];
        for (let m = 0; m < 3; m++) {
            for (let n = 0; n < 3; n++) {
                uvs_data.push(uv[4 * m + n].u, uv[4 * m + n].v);
                uvs_data.push(uv[4 * (m + 1) + n + 1].u, uv[4 * (m + 1) + n + 1].v);
                uvs_data.push(uv[4 * m + n + 1].u, uv[4 * m + n + 1].v);

                uvs_data.push(uv[4 * m + n].u, uv[4 * m + n].v);
                uvs_data.push(uv[4 * (m + 1) + n].u, uv[4 * (m + 1) + n].v);
                uvs_data.push(uv[4 * (m + 1) + n + 1].u, uv[4 * (m + 1) + n + 1].v);
            }
        }
        return uvs_data;
    }

    getPoints(mesh) {
        let vv = [];
        for (let i = 0; i < 4; i++) {
            for (let j = 0; j < 4; j++) {
                vv.push({ x: mesh.pointXs[i], y: mesh.pointYs[j], z: 0 });
            }
        }

        let vertices_data = [];
        for (let m = 0; m < 3; m++) {
            for (let n = 0; n < 3; n++) {
                vertices_data.push(vv[4 * m + n].x, vv[4 * m + n].y, vv[4 * m + n].z);
                vertices_data.push(vv[4 * (m + 1) + n + 1].x, vv[4 * (m + 1) + n + 1].y, vv[4 * (m + 1) + n + 1].z);
                vertices_data.push(vv[4 * m + n + 1].x, vv[4 * m + n + 1].y, vv[4 * m + n + 1].z);

                vertices_data.push(vv[4 * m + n].x, vv[4 * m + n].y, vv[4 * m + n].z);
                vertices_data.push(vv[4 * (m + 1) + n].x, vv[4 * (m + 1) + n].y, vv[4 * (m + 1) + n].z);
                vertices_data.push(vv[4 * (m + 1) + n + 1].x, vv[4 * (m + 1) + n + 1].y, vv[4 * (m + 1) + n + 1].z);
            }
        }
        return vertices_data;
    }

    createSprite(config) {

        let textInfo = this.createText(config.text);

        //计算出2^n像素图片

        config.mesh = {
            pointXs: [-textInfo.width * 0.5, -textInfo.width * 0.5, textInfo.width * 0.5, textInfo.width * 0.5 ],
            pointYs: [0, 0, textInfo.height, textInfo.height]
        };
        console.log(config);
        let vertices_data = this.getPoints(config.mesh);
        let uv1s_data = this.getUv(config.uv1);
        let uv2s_data = this.getUv(config.uv2);

        var geometry = new THREE.BufferGeometry();
        var uv1s = new Float32Array(uv1s_data);
        var uv2s = new Float32Array(uv2s_data);
        var vertices = new Float32Array(vertices_data);

        geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
        geometry.setAttribute('uv', new THREE.BufferAttribute(uv1s, 2));
        geometry.setAttribute('uvtext', new THREE.BufferAttribute(uv2s, 2));
        var textureLoader = new THREE.TextureLoader();
        // let background = textureLoader.load('background.png');
        let background = new THREE.Texture();
        let sprite = new THREE.Mesh(geometry, new THREE.ShaderMaterial({
            uniforms: {
                uPos: { value: new THREE.Vector3(10,0,0) },
                uSize: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) },
                uText: { value: textInfo.texture },
                uMap: { value: background },
                transparent: true,
                alphaTest: 0.5,
            },
            vertexShader: `    
                        in vec2 uvtext;
                        uniform vec3 uPos;
                        uniform vec2 uSize;

                        varying vec2 vUv;
                        varying vec2 vUv2;
                        void main() {
                            vUv = uv;
                            vUv2 = uvtext;
                            vec4 mvPosition = modelViewMatrix * vec4( uPos, 1.0 );
                            vec4 screenpos = projectionMatrix * mvPosition;                
                           
                            vec3 v = vec3(position.x / uSize.x,  position.y / uSize.y, 0);
                            screenpos += vec4(v * screenpos.w, 0);
                           
                            gl_Position = screenpos;
                        }`,
            fragmentShader: ` 
                        uniform sampler2D uText;
                        varying vec2 vUv;
                        varying vec2 vUv2;
                        uniform sampler2D uMap;
                        
                        void main() {
                            vec4 color = texture2D( uMap, vUv);
                            vec4 color2 = texture2D( uText, vUv2);
                            
                            gl_FragColor = vec4(color .rgb, 1.0 - color2.a)  + color2;
                        }`
        }));

        sprite.onBeforeRender = function (renderer) {
            var size = renderer.getDrawingBufferSize(new THREE.Vector2());
            this.material.uniforms.uSize.value = size;
        };
        //mesh.receiveShadow = false;
        //mesh.castShadow = false;
        return sprite;
    }

    createText(text) {

        var canvas = document.createElement('canvas');
        var context = canvas.getContext('2d');

        let fontsize = 32;
        let fontface = 'Arial';

        let width = 0;
        let height = 0;

        context.font = fontsize + "px " + fontface;

        text.forEach(item => {
            var metrics = context.measureText(item);
            if (width < metrics.width)
                width = metrics.width;
            height += fontsize;
        });

        canvas.width = width + 8;
        canvas.height = height + 8;

        // text color
        context.fillStyle = "rgba(255,255 , 255, 1.0)";
        context.font = fontsize + "px " + fontface;
        for (let i = 0; i < text.length; i++) {
            context.fillText(text[i], 2, fontsize * (i + 1));
        }

        let texture = new THREE.Texture(canvas);
        texture.needsUpdate = true;

        return {
            texture: texture,
            width: canvas.width,
            height: canvas.height
        }
    }

    get() {
        return this.sprite;
    }

    update(position) {

    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值