javascript 如何在Three.JS中实现一个示例化的广告牌?

ds97pgxw  于 2023-02-15  发布在  Java
关注(0)|答案(2)|浏览(233)

我需要一个示例化的网格有所有的示例面对相机。

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对象或网格并将"注视"设置为每帧的摄影机位置。
谢谢你的帮助!

6gpjuf90

6gpjuf901#

我刚解决了!
不同之处在于,我不希望所有广告牌都与相机前向向量平行。在大多数情况下,这看起来都很好,但在广告牌不靠近相机前向向量的情况下,看起来就不对了,因为广告牌面对的是相机位置以外的其他点。
顶点着色器:

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;

联森:

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

EDIT 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;
            }
u5rb5r59

u5rb5r592#

react-three-fiber中,这可以使用the drei package中的<Billboard />组件来完成:

import { Billboard, Text, OrbitControls } from '@react-three/drei'

...

<Billboard position={[0.5, 2.05, 0.5]}>
  <Text fontSize={1} outlineWidth={'5%'} outlineColor="#000000" outlineOpacity={1}>
    box
  </Text>
</Billboard>

相关问题