如何在Qt3D中绘制对象的轮廓?

时间:2018-09-29 13:00:42

标签: qt opengl graphics 3d qt3d

如何在Qt3D中的任何其他对象之上绘制对象的轮廓?例如要在3D编辑器中突出显示选定的对象?

1 个答案:

答案 0 :(得分:5)

如果您想始终画出实体的轮廓,即使该实体在其他实体的后面,一种解决方案是分两步进行:

  1. 正常绘制所有内容。
  2. 仅绘制所选对象的轮廓。

绘制轮廓时,您需要使用轮廓效果,可以在两个渲染过程中实现该效果:

  1. 使用简单的颜色着色器将几何图形渲染为纹理。
  2. 使用着色器渲染到屏幕,该着色器获取纹理中的每个像素并比较周围的像素。如果它们相等,则我们位于对象内部,并且可以丢弃该片段。如果它们不同,我们将位于对象的边缘,并且应该绘制颜色。

这是上述着色器的简单实现:

#version 150

uniform sampler2D color;
uniform vec2 winSize;

out vec4 fragColor;

void main()
{

    int lineWidth = 5;

    vec2 texCoord = gl_FragCoord.xy / winSize;
    vec2 texCoordUp = (gl_FragCoord.xy + vec2(0, lineWidth)) / winSize;
    vec2 texCoordDown = (gl_FragCoord.xy + vec2(0, -lineWidth)) / winSize;
    vec2 texCoordRight = (gl_FragCoord.xy + vec2(lineWidth, 0)) / winSize;
    vec2 texCoordLeft = (gl_FragCoord.xy + vec2(-lineWidth, 0)) / winSize;

    vec4 col = texture(color, texCoord);
    vec4 colUp = texture(color, texCoordUp);
    vec4 colDown = texture(color, texCoordDown);
    vec4 colRight = texture(color, texCoordRight);
    vec4 colLeft = texture(color, texCoordLeft);

    if ((colUp == colDown && colRight == colLeft) || col.a == 0.0)
        discard;

    fragColor = col;
}

注意:取两个值之间的差异而不是使用相等性可能是一个更好的主意。

使用这种方法,您不必担心深度测试和绘制对象的顺序:第二次绘制时,您将始终在其他所有对象之上绘制。

您可以通过使用两种具有不同滤镜键的技术添加单个效果来实现。另外,如果要使用Qt3D.Extras中的材质,则可以添加具有相同变换和网格的另一个实体以及使用轮廓技术的材质。

这里是一个示例,该示例使用两个渲染过程在所有其他对象的顶部绘制轮廓:

import QtQuick 2.2 as QQ2
import Qt3D.Core 2.0
import Qt3D.Render 2.0
import Qt3D.Input 2.0
import Qt3D.Extras 2.0

Entity {
    Camera {
        id: camera
        projectionType: CameraLens.PerspectiveProjection
        fieldOfView: 45
        aspectRatio: 16/9
        nearPlane : 0.1
        farPlane : 1000.0
        position: Qt.vector3d( 0.0, 0.0, -40.0 )
        upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
        viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
    }

    OrbitCameraController {
        camera: camera
    }

    components: [
        RenderSettings {
            activeFrameGraph: RenderSurfaceSelector {
                id: surfaceSelector
                Viewport {
                    CameraSelector {
                        camera: camera
                        FrustumCulling {
                            TechniqueFilter {
                                matchAll: [
                                    FilterKey { name: "renderingStyle"; value: "forward" }
                                ]
                                ClearBuffers {
                                    clearColor: Qt.rgba(0.1, 0.2, 0.3)
                                    buffers: ClearBuffers.ColorDepthStencilBuffer
                                }
                            }
                            TechniqueFilter {
                                matchAll: [
                                    FilterKey { name: "renderingStyle"; value: "outline" }
                                ]
                                RenderPassFilter {
                                    matchAny: [
                                        FilterKey {
                                            name: "pass"; value: "geometry"
                                        }
                                    ]
                                    ClearBuffers {
                                        buffers: ClearBuffers.ColorDepthStencilBuffer
                                        RenderTargetSelector {
                                            target: RenderTarget {
                                                attachments : [
                                                    RenderTargetOutput {
                                                        objectName : "color"
                                                        attachmentPoint : RenderTargetOutput.Color0
                                                        texture : Texture2D {
                                                            id : colorAttachment
                                                            width : surfaceSelector.surface.width
                                                            height : surfaceSelector.surface.height
                                                            format : Texture.RGBA32F
                                                        }
                                                    }
                                                ]
                                            }
                                        }
                                    }
                                }
                                RenderPassFilter {
                                    parameters: [
                                        Parameter { name: "color"; value: colorAttachment },
                                        Parameter { name: "winSize"; value : Qt.size(surfaceSelector.surface.width, surfaceSelector.surface.height) }
                                    ]
                                    matchAny: [
                                        FilterKey {
                                            name: "pass"; value: "outline"
                                        }
                                    ]
                                }
                            }
                        }
                    }
                }
            }
        },
        InputSettings { }
    ]

    PhongMaterial {
        id: material
    }

    Material {
        id: outlineMaterial

        effect: Effect {
            techniques: [
                Technique {
                    graphicsApiFilter {
                        api: GraphicsApiFilter.OpenGL
                        majorVersion: 3
                        minorVersion: 1
                        profile: GraphicsApiFilter.CoreProfile
                    }

                    filterKeys: [
                        FilterKey { name: "renderingStyle"; value: "outline" }
                    ]
                    renderPasses: [
                        RenderPass {
                            filterKeys: [
                                FilterKey { name: "pass"; value: "geometry" }
                            ]
                            shaderProgram: ShaderProgram {
                                vertexShaderCode: "
#version 150 core

in vec3 vertexPosition;

uniform mat4 modelViewProjection;

void main()
{
    gl_Position = modelViewProjection * vec4( vertexPosition, 1.0 );
}
"

                                fragmentShaderCode: "
#version 150 core

out vec4 fragColor;

void main()
{
    fragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
}
"
                            }
                        }
                    ]
                }
            ]
        }
    }

    SphereMesh {
        id: sphereMesh
        radius: 3
    }

    Transform {
        id: sphereTransform
    }

    Transform {
        id: sphereTransform2
        // TODO workaround because the transform cannot be shared
        matrix: sphereTransform.matrix
    }

    Entity {
        id: sphereEntity
        components: [ sphereMesh, material, sphereTransform ]
    }

    Entity {
        id: sphereOutlineEntity
        components: [ sphereMesh, outlineMaterial, sphereTransform2 ]
    }

    Entity {
        id: outlineQuad
        components: [
            PlaneMesh {
                width: 2.0
                height: 2.0
                meshResolution: Qt.size(2, 2)
            },
            Transform {
                rotation: fromAxisAndAngle(Qt.vector3d(1, 0, 0), 90)
            },
            Material {
                effect: Effect {
                    techniques: [
                        Technique {
                            filterKeys: [
                                FilterKey { name: "renderingStyle"; value: "outline" }
                            ]
                            graphicsApiFilter {
                                api: GraphicsApiFilter.OpenGL
                                profile: GraphicsApiFilter.CoreProfile
                                majorVersion: 3
                                minorVersion: 1
                            }
                            renderPasses : RenderPass {
                                filterKeys : FilterKey { name : "pass"; value : "outline" }
                                shaderProgram : ShaderProgram {
                                    vertexShaderCode: "
#version 150

in vec4 vertexPosition;
uniform mat4 modelMatrix;

void main()
{
    gl_Position = modelMatrix * vertexPosition;
}
"

                                    fragmentShaderCode: "
#version 150

uniform sampler2D color;
uniform vec2 winSize;

out vec4 fragColor;

void main()
{

    int lineWidth = 5;

    vec2 texCoord = gl_FragCoord.xy / winSize;
    vec2 texCoordUp = (gl_FragCoord.xy + vec2(0, lineWidth)) / winSize;
    vec2 texCoordDown = (gl_FragCoord.xy + vec2(0, -lineWidth)) / winSize;
    vec2 texCoordRight = (gl_FragCoord.xy + vec2(lineWidth, 0)) / winSize;
    vec2 texCoordLeft = (gl_FragCoord.xy + vec2(-lineWidth, 0)) / winSize;

    vec4 col = texture(color, texCoord);
    vec4 colUp = texture(color, texCoordUp);
    vec4 colDown = texture(color, texCoordDown);
    vec4 colRight = texture(color, texCoordRight);
    vec4 colLeft = texture(color, texCoordLeft);

    if ((colUp == colDown && colRight == colLeft) || col.a == 0.0)
        discard;

    fragColor = col;
}
"
                                }
                            }
                        }]
                }
            }

        ]
    }
}

结果:

Sphere rendered with outline