three.js 自定义sprite进阶

class WebGLSprite {
    constructor(text) {
        let config = {
            uv1: {
                us: [0, 5/256, 250/256, 1.0],
                vs: [0, 78/128, 126/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 - 10, -textInfo.width * 0.5, textInfo.width * 0.5, textInfo.width * 0.5 + 10],
            pointYs: [0, 100, textInfo.height + 100, textInfo.height + 110]
        };

        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.addAttribute('position', new THREE.BufferAttribute(vertices, 3));
        geometry.addAttribute('uv', new THREE.BufferAttribute(uv1s, 2));
        geometry.addAttribute('uvtext', new THREE.BufferAttribute(uv2s, 2));

        var textureLoader = new THREE.TextureLoader();
        this.background = textureLoader.load('../content/terrain/label/test5.png');

        let sprite = new THREE.Mesh(geometry, new THREE.ShaderMaterial({
            uniforms: {
                uPos: { value: new THREE.Vector3(0) },
                uSize: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) },
                uSizeAttenuation: { value: 0 }, 
                uColor: { value: new THREE.Vector4(0.2, 0.8, 0.2, 1) },
                uMap: { value: this.background },
                uText: { value: textInfo.texture },
                //transparent: true,
                alphaTest: 0.5, 
            },
            vertexShader: `    
                        in vec2 uvtext;
                        uniform vec3 uPos;
                        uniform vec2 uSize;
                        uniform int  uSizeAttenuation;
                        varying vec2 vUv;
                        varying vec2 vUv2;
                        void main() {
                            vUv = uv;
                            vUv2 = uvtext;
                            vec4 mvPosition = modelViewMatrix * vec4( uPos, 1.0 );
                            vec4 screenpos = projectionMatrix * mvPosition;                
                            if(uSizeAttenuation == 1){

                               vec3 v = vec3(position.x,  position.y, 0);
                                screenpos += vec4(v, 0);
                            } else {

                               vec3 v = vec3(position.x / uSize.x,  position.y / uSize.y, 0);
                                screenpos += vec4(v * screenpos.w, 0);
                            }                
                            gl_Position = screenpos;
                        }`,
            fragmentShader: ` 
                        uniform vec4 uColor;
                        uniform sampler2D uMap;
                        uniform sampler2D uText;
                        varying vec2 vUv;
                        varying vec2 vUv2;
                        void main() {
                            vec4 color = texture2D( uMap, vUv);// * uColor;
                            vec4 color2 = texture2D( uText, vUv2);// * uColor;
                            if(color.a < 0.2)
                                discard;
                            else
                                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');
        canvas.style.background = 'rgba(255, 255, 255, 0)';
        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(0, 255, 0, 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) {

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值