OpenGL广告牌顶点着色器重置比例

时间:2017-12-28 06:32:52

标签: opengl 3d lwjgl vertex-shader

我对OpenGL和3D图形一般都是新手,这是我第一次远离教程自己做点什么。我想创建广告牌纹理,以便这些纹理始终面向相机。 (我打算将它们用作光源的位置指示器等。)

经过一番研究,我发现这个网站为我的问题提供了一个相当简单的解决方案。

Simple Billboarding

我按照他们的步骤,一切都按预期工作,除了一件事。我的缩放参数被忽略,我用来绘制纹理的四边形没有被缩放。

这是我非常简单的着色器代码。

#version 400 core

in vec3 position;
in vec2 textureCoordinates;

out vec2 pass_textureCoordinates;

uniform mat4 transformationMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;

void main(void){

    mat4 modelView = viewMatrix * transformationMatrix;
    modelView[0][0] = 1;
    modelView[0][1] = 0;
    modelView[0][2] = 0;

    modelView[1][0] = 0;
    modelView[1][1] = 1;
    modelView[1][2] = 0;

    modelView[2][0] = 0;
    modelView[2][1] = 0;
    modelView[2][2] = 1;

    gl_Position = projectionMatrix * modelView * vec4(position,1.0);
    pass_textureCoordinates = textureCoordinates;
}

这是生成我的vieMatrix和transformationMatrix

的代码
 public static Matrix4f createTransformationMatrix(BillboardEntity billboardEntity) {
        Vector3f translation = billboardEntity.getTranslation();
        float rx = billboardEntity.getRotationX();
        float ry = billboardEntity.getRotationY();
        float rz = billboardEntity.getRotationZ();
        float scale = billboardEntity.getScale();
        Matrix4f matrix = new Matrix4f();
        matrix.setIdentity();
        Matrix4f.translate(translation, matrix, matrix);
        Matrix4f.rotate((float) Math.toRadians(rx), new Vector3f(1,0,0), matrix, matrix);
        Matrix4f.rotate((float) Math.toRadians(ry), new Vector3f(0,1,0), matrix, matrix);
        Matrix4f.rotate((float) Math.toRadians(rz), new Vector3f(0,0,1), matrix, matrix);
        Matrix4f.scale(new Vector3f(scale, scale, scale), matrix, matrix);

        return matrix;
    }

    public static Matrix4f createViewMatrix(Camera camera) {
        Matrix4f viewMatrix = new Matrix4f();
        viewMatrix.setIdentity();
        Matrix4f.rotate((float) Math.toRadians(camera.getPitch()), new Vector3f(1, 0, 0), viewMatrix,
                viewMatrix);
        Matrix4f.rotate((float) Math.toRadians(camera.getYaw()), new Vector3f(0, 1, 0), viewMatrix,
                viewMatrix);
        Vector3f cameraPos = camera.getPosition();
        Vector3f negativeCameraPos = new Vector3f(-cameraPos.x, -cameraPos.y, -cameraPos.z);
        Matrix4f.translate(negativeCameraPos, viewMatrix, viewMatrix);
        return viewMatrix;
    }

我应该提一下,我在我的项目中使用Java和LWJGL。知道为何忽略规模吗?另外,这是制作广告牌纹理的好方法吗?

1 个答案:

答案 0 :(得分:0)

我在 Google 上找到了这篇文章,所以我想分享我的解决方案(如果你不介意的话)。

如果您将 4x4 变换矩阵的左上角 3x3 部分设置为“恒等”矩阵(对角线上的所有“1”),您会核对旋转和缩放,因为它们都被存储

要修复它,在此特定示例中,您可以使用:

void main(){
    mat4 modelView = viewMatrix * transformationMatrix;
    modelView[0][0] = length(vec3(transformationMatrix[0]));
    modelView[0][1] = 0;
    modelView[0][2] = 0;

    modelView[1][0] = 0;
    modelView[1][1] = length(vec3(transformationMatrix[1]));
    modelView[1][2] = 0;

    modelView[2][0] = 0;
    modelView[2][1] = 0;
    modelView[2][2] = 1;

    gl_Position = projectionMatrix * modelView * vec4(position,1.0);
    pass_textureCoordinates = textureCoordinates;
}

它将保留来自变换(或model)矩阵的缩放信息。我对其进行了测试,它适用于 CPU 端的任何比例设置(在 .cpp 中)。

但是,您应该知道 length 通常是一个昂贵的过程。例如,在 GLM 中,它使用 sqrt(dot(v, v)),如果您不知道,sqrt 非常昂贵,特别是如果您希望场景中有许多广告牌(草、云、粒子等)。因此,您可以做的是使用处理缩放的制服,这要便宜得多:

uniform bool uIsSpherical;
uniform vec2 uSpriteScale; // Using a uniform instead

void main(){
    ...
    modelView[0][0] = uSpriteScale.x;
    modelView[0][1] = 0;
    modelView[0][2] = 0;

    if (uIsSpherical)
    {
        modelView[1][0] = 0;
        modelView[1][1] = uSpriteScale.y;
        modelView[1][2] = 0;
    }
    else
    {
        modelView[1][1] *= uSpriteScale.y;
    }

    modelView[2][0] = 0;
    modelView[2][1] = 0;
    modelView[2][2] = 1;

    ...
}

第二列 (if) 的 modelView[1][...] 条件是针对圆柱形广告牌,适用于远处的树木或其他类型的冒名顶替者,因为您不希望它们向后倾斜如果你从上面看到它们,比如从飞机上或其他东西。

现在,在着色器中制作广告牌的问题在于,在 CPU 端,在阴影渲染过程中,您仍在使用固定的变换矩阵。所以阴影不会跟随旋转的四边形,它仍然会“看到”它是静止的。有人告诉我,对此的“解决方案”是使用阴影广告牌着色器,并在那里进行相同的计算。显然,存储或缓存结果是不值得的,因为 GPU 再次执行相同的操作比执行内存提取要快得多,因为内存针对吞吐量而不是延迟进行了优化。但我还没有测试它。请记住,默认情况下,阴影不会随着广告牌旋转。