Text2DEntity渲染不透明并在其后隐藏其他实体 [英] Text2DEntity renders opaque and hides other entities behind it

查看:193
本文介绍了Text2DEntity渲染不透明并在其后隐藏其他实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Qt3D QML场景中绘制了一些2d文本实体,但某些文本始终呈现不透明,即将内容隐藏在它们后面.从后面看场景(将相机的位置更改为Qt.vector3d(0,0,-40))时,所有文本均显示为正常.

I draw some 2d text entities in a Qt3D QML scene but some of the texts always render opaque, i.e hide the contents behind them. When looking at the scene from behind ( changing the position of the camera to Qt.vector3d(0,0,-40) ) all texts render OK.

下图显示了错误的行为,我希望文本"AAARGH"不会呈现在白色背景上,而绿色文本会闪烁.

The following image shows the wrong behaviour, I would expect the text "AAARGH" not to be rendered on a white background, but the green text shining through.

平台是Windows 64位,Qt5.13.0和Visual Studio 2019.

Platform is Windows 64-bit, Qt5.13.0, and Visual Studio 2019.

请参见下面的小示例来演示该问题:

See the following small example that demonstrates the issue:

BrokenEntity.qml

import Qt3D.Core 2.0
import Qt3D.Render 2.0
import Qt3D.Input 2.0
import Qt3D.Extras 2.13

import QtQuick 2.0 as QQ2

Entity {
    id: sceneRoot

    Camera {
        id: camera
        projectionType: CameraLens.PerspectiveProjection
        fieldOfView: 45
        nearPlane : 0.1
        farPlane : 1000.0
        position: Qt.vector3d( 0.0, 0.0, 40 )
        upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
        viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
    }

    OrbitCameraController { camera: camera }

    components: [
        RenderSettings {
            activeFrameGraph: ForwardRenderer {
                camera: camera
                clearColor: "transparent"
            }
        },

        InputSettings { }
    ]

    Entity {
        components: [ Transform { translation: Qt.vector3d(-12.5,-5,-20) } ]
        Text2DEntity {
            font.family: "Sans Serif"
            font.pointSize: 5
            color: Qt.rgba(0, 0, 1, 0.5)
            text: "AAARGH"
            width: text.length * font.pointSize
            height: font.pointSize * 1.2
        }
    }
    Entity {
        PhongMaterial {
            id: material
            ambient: Qt.rgba(1, 1, 0, 1)
            diffuse: Qt.rgba(1, 1, 0, 1)
        }
        SphereMesh {
            id: sphereMesh
            radius: 1
            rings: 50
            slices: 50
        }
        Transform {
            id: sphereTransform
            translation: Qt.vector3d(0,0,-25)
            scale3D: Qt.vector3d(1, 1, 1)
        }
        components: [ sphereMesh, material, sphereTransform ]
    }
    Entity {
        components: [ Transform { translation: Qt.vector3d(-25,-5,-30) } ]
        Text2DEntity {
            font.family: "Sans Serif"
            font.pointSize: 10
            color: Qt.rgba(0, 1, 0, 1.0)
            text: "BBBRGH"
            width: text.length * font.pointSize
            height: font.pointSize * 1.2
        }
    }
}

main.qml

import QtQuick 2.0
import QtQuick.Scene3D 2.0

Item {
    Rectangle {
        id: scene
        anchors.fill: parent
        anchors.margins: 50
        color: "white"

        Scene3D {
            id: scene3d
            anchors.fill: parent
            anchors.margins: 10
            focus: true
            aspects: ["input", "logic"]
            cameraAspectRatioMode: Scene3D.AutomaticAspectRatio

            BrokenEntity {}
        }
    }
}

main.cpp

#include <QGuiApplication>
#include <QQuickView>

int main(int argc, char **argv)
{
    QGuiApplication app(argc, argv);

    QQuickView view;

    view.resize(500, 500);
    view.setResizeMode(QQuickView::SizeRootObjectToView);
    view.setSource(QUrl("qrc:/main.qml"));
    view.show();

    return app.exec();
}

我猜想这种现象的原因来自Qt3D中用于渲染Text2dEntity的GLSL着色器(distancefieldtext.vertdistancefieldtext.frag).

I suppose the reason of this behaviour comes from the GLSL shaders (distancefieldtext.vert and distancefieldtext.frag) that are used in Qt3D to render the Text2dEntity.

请参阅附加的着色器源.

See attached shader sources.

distancefieldtext.vert

#version 150 core

in vec3 vertexPosition;
in vec2 vertexTexCoord;

out vec2 texCoord;
out float zValue;

uniform mat4 modelView;
uniform mat4 mvp;

void main()
{
    texCoord = vertexTexCoord;
    zValue = vertexPosition.z;

    gl_Position = mvp * vec4(vertexPosition.xy, 0.0, 1.0);
}

distancefieldtext.frag

#version 150 core

uniform sampler2D distanceFieldTexture;
uniform float minAlpha;
uniform float maxAlpha;
uniform float textureSize;
uniform vec4 color;

in vec2 texCoord;
in float zValue;

out vec4 fragColor;

void main()
{
    // determine the scale of the glyph texture within pixel-space coordinates
    // (that is, how many pixels are drawn for each texel)
    vec2 texelDeltaX = abs(dFdx(texCoord));
    vec2 texelDeltaY = abs(dFdy(texCoord));
    float avgTexelDelta = textureSize * 0.5 * (texelDeltaX.x + texelDeltaX.y + texelDeltaY.x + texelDeltaY.y);
    float texScale = 1.0 / avgTexelDelta;

    // scaled to interval [0.0, 0.15]
    float devScaleMin = 0.00;
    float devScaleMax = 0.15;
    float scaled = (clamp(texScale, devScaleMin, devScaleMax) - devScaleMin) / (devScaleMax - devScaleMin);

    // thickness of glyphs should increase a lot for very small glyphs to make them readable
    float base = 0.5;
    float threshold = base * scaled;
    float range = 0.06 / texScale;

    float minAlpha = threshold - range;
    float maxAlpha = threshold + range;

    float distVal = texture(distanceFieldTexture, texCoord).r;
    fragColor = color * smoothstep(minAlpha, maxAlpha, distVal);
    gl_FragDepth = gl_FragCoord.z - zValue * 0.00001;
}

关于此的任何想法如何使Qt3D渲染text2DEntities时,文本本身不透明,并且文本之间的空间透明(独立于查看方向)?预先感谢.

Any ideas on this how to make Qt3D render the text2DEntities with the text itself opaque and the spaces between the text transparant, independent on the viewing direction? Thanks in advance.

修改

我必须在示例中无意中更改了某些内容,因为更改相机的位置不再显示预期的行为.我将在周一可以访问我的工作环境时更正此问题.

I must have inadvertently changed something in the example, as changing the position of the camera does not show the expected behaviour anymore. I will correct that on Monday when I have access to my work environment.

更新

由于我需要为实体提供双面照明,因此我在RenderStateSet中添加了CullFace组件,并添加了NoCulling组件,这可以解释这种行为.我的FrameGraph看起来像这样:

As I needed double sided lighting for my entities, I had an additional CullFace component with NoCulling added to the RenderStateSet, that explains this behaviour. My FrameGraph was looking like this:

components: [
    RenderSettings {
        activeFrameGraph: RenderStateSet {
            renderStates: [
                CullFace { mode: CullFace.NoCulling }
            ]
            ForwardRenderer {
                camera: camera
                clearColor: "transparent"
            }
        }
    },

    InputSettings { }
]

从背面查看时,由于实体是从背面到正面定义的,因此渲染是正确的. SortPolicy :

When viewing from the back side, as the entities were defined from back to front the rendering was correct. This is stated explicitly in the documentation of SortPolicy:

如果FrameGraph中不存在QSortPolicy,则绘制实体 按照它们在实体层次结构中出现的顺序."

"If QSortPolicy is not present in the FrameGraph, entities are drawn in the order they appear in the entity hierarchy."

在FrameGraph中添加带有BackToFront的其他SortPolicy组件时,渲染是正确的,与查看方向无关.然后,FrameGraph如下所示:

When adding an additional SortPolicy component with BackToFront to the FrameGraph the rendering was correct independent of the viewing direction. The FrameGraph then looked like this:

components: [
    RenderSettings {
        activeFrameGraph: SortPolicy {
            sortTypes: [ SortPolicy.BackToFront ]
            RenderStateSet {
                renderStates: [
                    CullFace { mode: CullFace.NoCulling }
                ]
                ForwardRenderer {
                    camera: camera
                    clearColor: "transparent"
                }
            }
        }
    },

    InputSettings { }
]

推荐答案

问题似乎出在

zValue = vertexPosition.z;

顶点着色器中的

. vertexPosition是模型空间中的坐标.如果要计算到相机的z距离,则必须通过modelView矩阵将坐标转换为视图空间:

in the vertex shader. vertexPosition is a coordinate in model space. If you want to calculate the the z distance to the camera then you've to transform the coordinate to view space by the modelView matrix:

vec4 viewPosition = modelView * vec4(vertexPosition.xyz, 1.0);
zValue = -viewPosition.z;

请注意,由于视图空间z轴指向视口之外,因此必须反转坐标以获取与相机的距离.

Note, since the view space z axis points out of the viewport, the coordinate has to be inverted to get the distance to the camera.

对我来说,似乎更正确的另一种可能性是计算剪辑空间坐标,再计算归一化的设备坐标.剪辑空间坐标是通过模型视图矩阵(mvp)和归一化的设备坐标通过转换来计算的,通过

Another possibility, which seems even be more correct to me, is to calculate the clip space coordinate and further the normalized device coordinate. The clip space coordinate is calculated by the transformation by the model view matrix (mvp) and the normalized device coordinate, by Perspective divide:

vec4 clipPosition = modelView * vec4(vertexPosition.xyz, 1.0);
zValue = clipPosition.z / clipPosition.w;

标准化设备坐标在[-1,1]范围内. z分量可以线性映射到片段的深度.默认情况下,深度范围为[0,1](除非已通过

The normalized device coordinates are in range [-1, 1]. The z component can linearly be mapped to the depth of the fragment. By default the depth range is [0, 1] (except it is changed by glDepthRange.
So in the fragment shader gl_FragDepth can be set by:

gl_FragDepth = zValue * 0.5 + 0.5;


如果您使用字母混合,则


If you use alpha Blending, then the Depth Test has to be disabled.

其他对象后面的对象可能根本无法绘制,因为深度测试将其丢弃. 当然,这取决于绘制顺序.如果首先绘制了所覆盖的文本,则它将起作用.但是,如果最后绘制,则将其丢弃.这解释了取决于视线方向的不同行为.
请注意,启用混合功能后,颜色不会影响颜色缓冲区(如果alpha为0),但是如果启用了深度测试,则当然会将深度写入深度缓冲区.

The objects behind other objects may not be drawn at all, because they are discarded by the depth test. Of course this depends on the drawing order. If the text which is covered is drawn first, then it will work. But if it is drawn last, then it is discarded. This explains the different behavior dependent on the direction of view.
Note, when blending is active, then the color doesn't affect the color buffer (if alpha is 0), but if the depth test is enable, then of course the depth is written to the depth buffer.

唯一的选择是以从后到前的顺序按顺序绘制对象.当然,顺序取决于视角,因此必须按帧对对象进行排序.

The only alternative is to draw the objects in sorted order form the back to the front. Of course the order depends on the direction of view, so the objects would have to be sorted per frame.

这篇关于Text2DEntity渲染不透明并在其后隐藏其他实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆