如何在Three.JS中实现实例广告牌?

时间:2019-04-08 22:53:05

标签: javascript three.js

我需要一个实例化的网格,以使所有实例都面向相机。

uniform vec2 size;
uniform vec3 center;

vec3 billboard(vec3 v, mat4 view) {
    vec3 up = vec3(view[0][1], view[1][1], view[2][1]);
    vec3 right = vec3(view[0][0], view[1][0], view[2][0]);
    vec3 pos = center + right * v.x * size.x + up * v.y * size.y;
    return pos;
}

void main() {
   vec3 worldPos = billboard(position, viewMatrix);
   gl_Position = projectionMatrix * modelViewMatrix * vec4(worldPos, 1.0);
}

这是我目前渲染一个广告牌的代码。这不会显示任何内容。在vec4构造函数的最后一行传递'position'会呈现预期的形状,所以我知道计算有问题。

我一直在尝试遵循本教程:http://www.opengl-tutorial.org/intermediate-tutorials/billboards-particles/billboards/ 1,特别是解决方案2,但是,要弄清楚这一点我没有太多运气。

这里的答案看起来也很有希望,但我无能为力。 THREE.JS GLSL sprite always front to camera 1

此问题的解决方案:THREE.js - Billboard Vertex Shader处于正确的轨道,但对于我的用例而言并不准确。

我的理解是,需要在对几何体或网格进行任何平移后发送中心位置,以便在世界空间中进行正确的计算。

Three.js在顶点着色器中传递相机位置。我当时认为可以基于相机位置和广告牌中心位置之间的差值对每个顶点进行某种变换。这样会影响性能吗?

最后,使用Sprite对象或网格物体将其实例化,然后将LookAt设置为每帧相机的位置不是一个选择。

感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

我刚刚解决了!

区别是我不希望所有广告牌都平行于摄像机前向矢量。在大多数情况下,它看起来不错,但是在广告牌不靠近相机正向矢量的情况下,这看起来是错误的,因为广告牌面向相机位置以外的其他点。

顶点着色器:

uniform vec2 size;
uniform vec3 center;

vec3 look = normalize(cameraPosition - center);
vec3 cameraUp = vec3(view[0][1], view[1][1], view[2][1]);
vec3 billboardRight = cross(cameraUp, look);
vec3 billboardUp = cross(look, billboardRight);
vec3 pos = center + billboardRight * v.x * size.x + billboardUp * v.y * size.y;
return pos;

JS:

        const fullWidth = 0.75;
        const fullHeight = 0.25;

        containerShape.moveTo(0, 0);
        containerShape.lineTo(0, fullHeight);
        containerShape.lineTo(fullWidth, fullHeight);
        containerShape.lineTo(fullWidth, 0);
        containerShape.lineTo(0, 0);

        const containerGeo = new ShapeBufferGeometry(containerShape);
        containerGeo.translate(-fullWidth / 2, -fullHeight / 2, 0);

        const containerMaterial = new ShaderMaterial({
            uniforms: {
                size: {
                    value: new Vector2(fullWidth, fullHeight),
                },
                center: {
                    value: new Vector3(1, 0.5, 1),
                },
            },
        });

这应该是一切。尽管缺少图片和链接断开,但这http://nehe.gamedev.net/article/billboarding_how_to/18011/还是使我超越了终点线。

修改19年4月12日 通过上述解决方案,我发现了一个相当严重的工件:http://prntscr.com/nayjic。如果您愿意将广告牌固定在一个轴上,则下面的代码可以解决问题。如果不将广告牌向上向量设置为固定值,则无法修复故障。

如果摄像头位于广告牌(http://prntscr.com/naz4iy)上方,则可以更轻松地看出广告牌并不是真的在“看着”摄像头。如果有人对此有解决方案,请发布!

            vec3 billboard(vec3 v, mat4 view) {
                vec3 look = cameraPosition - instanceOffset;
                look.y = 0.0;
                look = normalize(look);
                // vec3 cameraUp = vec3(view[0][1], view[1][1], view[2][1]);
                vec3 billboardUp = vec3(0, 1, 0);
                vec3 billboardRight = cross(billboardUp, look);
                vec3 pos = instanceOffset + billboardRight * v.x * size.x + billboardUp * v.y * size.y;
                return pos;
            }