顶点着色器中的广告牌顶点

杰瑞德

演示问题的代码(注释/取消注释gl_Position顶点着色器中行)

    var scene;
    var book;
    var shaderMaterial;

    var renderer = new THREE.WebGLRenderer({
        antialias: true
    });
    renderer.setClearColor(0x000000);
    document.body.appendChild(renderer.domElement);

    var camera = new THREE.PerspectiveCamera(55, 1, 0.1, 40000);


    window.onresize = function () {
        renderer.setSize(window.innerWidth, window.innerHeight);
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
    };
    window.onresize();

    scene = new THREE.Scene();

    camera.position.z = 25;
    camera.position.y = 15;
    scene.add(camera);


    var grid = new THREE.GridHelper(100, 10);
    scene.add(grid);


    var controls = new THREE.OrbitControls(camera);
    controls.damping = 0.2;
    var lettersPerSide = 16;

    function createGlpyhSheet() {

        var fontSize = 64;

        var c = document.createElement('canvas');
        c.width = c.height = fontSize * lettersPerSide;
        var ctx = c.getContext('2d');
        ctx.font = fontSize + 'px Monospace';
        var i = 0;

        for (var y = 0; y < lettersPerSide; y++) {
            for (var x = 0; x < lettersPerSide; x++, i++) {
                var ch = String.fromCharCode(i);
                ctx.fillText(ch, x * fontSize, -(8 / 32) * fontSize + (y + 1) * fontSize);
            }
        }

        var tex = new THREE.Texture(c);
        tex.flipY = false;
        tex.needsUpdate = true;

        return tex;
    }


    function createLabels(textArrays, positions) {
        //console.log(textArrays, positions);

        var master_geometry = new THREE.Geometry();


        for (var k = 0; k < textArrays.length; k++) {

            var geo = new THREE.Geometry();
            geo.dynamic = true;

            var str = textArrays[k];
            var vec = positions[k];
            //console.log(shaderMaterial);

            //console.log('str is', str, 'vec is', vec);


            var j = 0,
                ln = 0;

            for (i = 0; i < str.length; i++) {

                //console.log('creating glyph', str[i]);

                var code = str.charCodeAt(i);
                var cx = code % lettersPerSide;
                var cy = Math.floor(code / lettersPerSide);
                var oneDotOne = .55;

                geo.vertices.push(
                new THREE.Vector3(j * oneDotOne + 0.05, ln * oneDotOne + 0.05, 0).add(vec),
                new THREE.Vector3(j * oneDotOne + 1.05, ln * oneDotOne + 0.05, 0).add(vec),
                new THREE.Vector3(j * oneDotOne + 1.05, ln * oneDotOne + 1.05, 0).add(vec),
                new THREE.Vector3(j * oneDotOne + 0.05, ln * oneDotOne + 1.05, 0).add(vec));
                shaderMaterial.attributes.labelpos.value.push(vec);
                shaderMaterial.attributes.labelpos.value.push(vec);
                shaderMaterial.attributes.labelpos.value.push(vec);
                shaderMaterial.attributes.labelpos.value.push(vec);

                var face = new THREE.Face3(i * 4 + 0, i * 4 + 1, i * 4 + 2);
                geo.faces.push(face);
                face = new THREE.Face3(i * 4 + 0, i * 4 + 2, i * 4 + 3);
                geo.faces.push(face);

                var ox = (cx + 0.05) / lettersPerSide;
                var oy = (cy + 0.05) / lettersPerSide;
                var off = 0.9 / lettersPerSide;

                geo.faceVertexUvs[0].push([
                new THREE.Vector2(ox, oy + off),
                new THREE.Vector2(ox + off, oy + off),
                new THREE.Vector2(ox + off, oy)]);
                geo.faceVertexUvs[0].push([
                new THREE.Vector2(ox, oy + off),
                new THREE.Vector2(ox + off, oy),
                new THREE.Vector2(ox, oy)]);
                if (code == 10) {
                    ln--;
                    j = 0;
                } else {
                    j++;
                }
            }

            // i can only get this working with merge.
            // Building one giant geometry doesn't work for some reason
            master_geometry.merge(geo);

        }

        console.log(shaderMaterial);
        shaderMaterial.attributes.labelpos.needsUpdate = true;

        book = new THREE.Mesh(
        master_geometry,
        shaderMaterial);

        //book.doubleSided = true;
        scene.add(book);

    }


    var uniforms = {
        map: {
            type: "t",
            value: createGlpyhSheet()
        }
    };

    var attributes = {
        labelpos: {
            type: 'v3',
            value: []
        }
    };

    shaderMaterial = new THREE.ShaderMaterial({
        attributes: attributes,
        uniforms: uniforms,
        vertexShader: document.querySelector('#vertex').textContent,
        fragmentShader: document.querySelector('#fragment').textContent
    });
    shaderMaterial.transparent = true;
    shaderMaterial.depthTest = false;


    strings = [];
    vectors = [];
    var sizeOfWorld = 100;
    var halfSize = sizeOfWorld * 0.5;

    for (var i = 0; i < 500; i++) {

        strings.push('test' + i);
        var vector = new THREE.Vector3();
        vector.x = Math.random() * sizeOfWorld - halfSize;
        vector.y = Math.random() * sizeOfWorld - halfSize;
        vector.z = Math.random() * sizeOfWorld - halfSize;
        vectors.push(vector);

    }

    console.log('creating labels');
    createLabels(strings, vectors);

    function animate() {
        controls.update();
        renderer.render(scene, camera);
        requestAnimationFrame(animate, renderer.domElement);
    }

    animate();
        html {
            background-color: #ffffff;
        }
        * {
            margin: 0;
            padding: 0;
        }
<script src="http://threejs.org/build/three.min.js"></script>
<script src="http://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script id="vertex" type="text/x-glsl-vert">
    varying vec2 vUv;
    attribute vec3 labelpos;

    void main() {
        vUv = uv;


        // standard gl_Position.  Labels stay in the correct place, but do not billboard.
        gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );

        // this is the billboarding position as described by:
        // http://stackoverflow.com/questions/22053932/three-js-billboard-vertex-shader
    //gl_Position = projectionMatrix * (modelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0) + vec4(position.x, position.y, 0.0, 0.0));

        // this gets a little closer
        //gl_Position = projectionMatrix * (modelViewMatrix * vec4(0.0, 0.0, position.z, 1.0) + vec4(position.x, position.y, 0.0, 0.0));

    }
</script>
<script id="fragment" type="text/x-glsl-frag">
    varying vec2 vUv;
    uniform sampler2D map;
    void main() {
        vec4 diffuse = texture2D(map, vUv);
        vec4 letters = mix(diffuse, vec4(1.0, 1.0, 1.0, diffuse.a), 1.0);
        gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0) * letters;
    }
</script>

我需要场景中的广告牌标签帮助。我的最后一幕将有数百个我想面对相机的标签。我无法找出通过单个网格几何体执行此操作的方法。我尝试了几种不同的gl_Position方法来获得广告牌外观:

// standard gl_Position.  Labels stay in the correct place, but do not billboard.
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );

// this is the billboarding position as described by:
// http://stackoverflow.com/questions/22053932/three-js-billboard-vertex-shader
gl_Position = projectionMatrix * (modelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0) + vec4(position.x, position.y, 0.0, 0.0));

// this gets a little closer
gl_Position = projectionMatrix * (modelViewMatrix * vec4(0.0, 0.0, position.z, 1.0) + vec4(position.x, position.y, 0.0, 0.0));

我的想法是向每个顶点发送一个着色器属性,以帮助进行广告牌计算,因此这就是为什么我label_pos在顶点着色器中具有属性的原因

得到确切的外观和感觉我想如果每个标签(字符组成)单独添加到场景。不幸的是,这导致每个渲染循环的绘制调用过多,因此是将它们全部添加到单个几何图形的原因。

谢谢您的协助。

man

我想你要

gl_Position = projectionMatrix * 
              (modelViewMatrix * vec4(labelpos, 1) +
               vec4(position.xy, 0, 0));

并且您无需将位置添加到顶点

geo.vertices.push(
  new THREE.Vector3(j * oneDotOne + 0.05, ln * oneDotOne + 0.05, 0),
  new THREE.Vector3(j * oneDotOne + 1.05, ln * oneDotOne + 0.05, 0),
  new THREE.Vector3(j * oneDotOne + 1.05, ln * oneDotOne + 1.05, 0),
  new THREE.Vector3(j * oneDotOne + 0.05, ln * oneDotOne + 1.05, 0));

否则,您将两次担任该职位。

因为所有标签都在同一个网格中,所以只有1个绘制调用,这意味着除非传递了标签,否则您将不会为每个标签得到不同的位置(这是您在labelpos中使用的,但并未使用)

在这种情况下modelViewMatrix * vec4(0,0,0,1),就像说的一样,modelViewMatrix[3]您要做的就是获取包含所有标签的模型的翻译。如果每个标签是一个单独的网格并具有自己的矩阵,那将起作用,但是由于您将它们全部放入一个网格中,因此将无法使用。

您的解决方法是在已经包含的单独属性中传递每个标签的位置,您只需要使用它即可。

modelViewMatrix * vec4(labelpos, 1)

让您成为标签的根源

vec4(position.x, position.y, 0.0, 0.0)

在视图空间的角落添加

var scene;
    var book;
    var shaderMaterial;

    var renderer = new THREE.WebGLRenderer({
        antialias: true
    });
    renderer.setClearColor(0x000000);
    document.body.appendChild(renderer.domElement);

    var camera = new THREE.PerspectiveCamera(55, 1, 0.1, 40000);


    window.onresize = function () {
        renderer.setSize(window.innerWidth, window.innerHeight);
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
    };
    window.onresize();

    scene = new THREE.Scene();

    camera.position.z = 25;
    camera.position.y = 15;
    scene.add(camera);


    var grid = new THREE.GridHelper(100, 10);
    scene.add(grid);


    var controls = new THREE.OrbitControls(camera);
    controls.damping = 0.2;
    var lettersPerSide = 16;

    function createGlpyhSheet() {

        var fontSize = 64;

        var c = document.createElement('canvas');
        c.width = c.height = fontSize * lettersPerSide;
        var ctx = c.getContext('2d');
        ctx.font = fontSize + 'px Monospace';
        var i = 0;

        for (var y = 0; y < lettersPerSide; y++) {
            for (var x = 0; x < lettersPerSide; x++, i++) {
                var ch = String.fromCharCode(i);
                ctx.fillText(ch, x * fontSize, -(8 / 32) * fontSize + (y + 1) * fontSize);
            }
        }

        var tex = new THREE.Texture(c);
        tex.flipY = false;
        tex.needsUpdate = true;

        return tex;
    }


    function createLabels(textArrays, positions) {
        //console.log(textArrays, positions);

        var master_geometry = new THREE.Geometry();


        for (var k = 0; k < textArrays.length; k++) {

            var geo = new THREE.Geometry();
            geo.dynamic = true;

            var str = textArrays[k];
            var vec = positions[k];
            //console.log(shaderMaterial);

            //console.log('str is', str, 'vec is', vec);


            var j = 0,
                ln = 0;

            for (i = 0; i < str.length; i++) {

                //console.log('creating glyph', str[i]);

                var code = str.charCodeAt(i);
                var cx = code % lettersPerSide;
                var cy = Math.floor(code / lettersPerSide);
                var oneDotOne = .55;

                geo.vertices.push(
                new THREE.Vector3(j * oneDotOne + 0.05, ln * oneDotOne + 0.05, 0),
                new THREE.Vector3(j * oneDotOne + 1.05, ln * oneDotOne + 0.05, 0),
                new THREE.Vector3(j * oneDotOne + 1.05, ln * oneDotOne + 1.05, 0),
                new THREE.Vector3(j * oneDotOne + 0.05, ln * oneDotOne + 1.05, 0));
                shaderMaterial.attributes.labelpos.value.push(vec);
                shaderMaterial.attributes.labelpos.value.push(vec);
                shaderMaterial.attributes.labelpos.value.push(vec);
                shaderMaterial.attributes.labelpos.value.push(vec);

                var face = new THREE.Face3(i * 4 + 0, i * 4 + 1, i * 4 + 2);
                geo.faces.push(face);
                face = new THREE.Face3(i * 4 + 0, i * 4 + 2, i * 4 + 3);
                geo.faces.push(face);

                var ox = (cx + 0.05) / lettersPerSide;
                var oy = (cy + 0.05) / lettersPerSide;
                var off = 0.9 / lettersPerSide;

                geo.faceVertexUvs[0].push([
                new THREE.Vector2(ox, oy + off),
                new THREE.Vector2(ox + off, oy + off),
                new THREE.Vector2(ox + off, oy)]);
                geo.faceVertexUvs[0].push([
                new THREE.Vector2(ox, oy + off),
                new THREE.Vector2(ox + off, oy),
                new THREE.Vector2(ox, oy)]);
                if (code == 10) {
                    ln--;
                    j = 0;
                } else {
                    j++;
                }
            }

            // i can only get this working with merge.
            // Building one giant geometry doesn't work for some reason
            master_geometry.merge(geo);

        }

        console.log(shaderMaterial);
        shaderMaterial.attributes.labelpos.needsUpdate = true;

        book = new THREE.Mesh(
        master_geometry,
        shaderMaterial);

        //book.doubleSided = true;
        scene.add(book);

    }


    var uniforms = {
        map: {
            type: "t",
            value: createGlpyhSheet()
        }
    };

    var attributes = {
        labelpos: {
            type: 'v3',
            value: []
        }
    };

    shaderMaterial = new THREE.ShaderMaterial({
        attributes: attributes,
        uniforms: uniforms,
        vertexShader: document.querySelector('#vertex').textContent,
        fragmentShader: document.querySelector('#fragment').textContent
    });
    shaderMaterial.transparent = true;
    shaderMaterial.depthTest = false;


    strings = [];
    vectors = [];
    var sizeOfWorld = 100;
    var halfSize = sizeOfWorld * 0.5;

    for (var i = 0; i < 500; i++) {

        strings.push('test' + i);
        var vector = new THREE.Vector3();
        vector.x = Math.random() * sizeOfWorld - halfSize;
        vector.y = Math.random() * sizeOfWorld - halfSize;
        vector.z = Math.random() * sizeOfWorld - halfSize;
        vectors.push(vector);

    }

    console.log('creating labels');
    createLabels(strings, vectors);

    function animate() {
        controls.update();
        renderer.render(scene, camera);
        requestAnimationFrame(animate, renderer.domElement);
    }

    animate();
html {
            background-color: #ffffff;
        }
        * {
            margin: 0;
            padding: 0;
        }
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/69/three.min.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/4862f5f1111346a957ac3e0cb0858be1568d0e03/examples/js/controls/OrbitControls.js"></script>
<script id="vertex" type="text/x-glsl-vert">
    varying vec2 vUv;
    attribute vec3 labelpos;

    void main() {
        vUv = uv;


        gl_Position = projectionMatrix * 
                      (modelViewMatrix * vec4(labelpos, 1) +
                       vec4(position.xy, 0, 0));

    }
</script>
<script id="fragment" type="text/x-glsl-frag">
    varying vec2 vUv;
    uniform sampler2D map;
    void main() {
        vec4 diffuse = texture2D(map, vUv);
        vec4 letters = mix(diffuse, vec4(1.0, 1.0, 1.0, diffuse.a), 1.0);
        gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0) * letters;
    }
</script>

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章