【问题标题】:How do I Implement an Instanced Billboard In Three.JS?如何在 Three.JS 中实现实例化广告牌?
【发布时间】:2019-04-12 19:09:39
【问题描述】:

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

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 构造函数中传递“位置”会按预期呈现形状,所以我知道计算有问题。

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

这里的答案看起来也很有希望,但我什么都做不了。 THREE.JS GLSL sprite always front to camera1

这个问题的解决方案:THREE.js - Billboard Vertex Shader 是正确的,但对于我的用例来说并不准确。

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

Three.js 在顶点着色器中传递相机位置。我在想可以根据相机位置和广告牌中心位置之间的减法对每个顶点应用一些变换。这会影响性能吗?

最后,因为这将被实例化,使用 Sprite 对象或网格并将 LookAt 设置为每帧的相机位置不是一个选项。

感谢您的帮助!

【问题讨论】:

    标签: javascript three.js


    【解决方案1】:

    我刚刚解决了!

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

    顶点着色器:

    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/ 让我越过了终点线。

    编辑 4/12/19 我在上述解决方案中发现了一个非常严重的工件: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;
                }
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-04
    相关资源
    最近更新 更多