首页 > 解决方案 > 具有统一 vec3 数组的 Qt3D 着色器图

问题描述

更新

因此,通过打印编译后的着色器代码,QShaderProgramBuilder我发现着色器几乎可以工作,唯一的问题是调用renderClicks. 这条线

fragColor = (((renderClicks(clicks[10], colors[10], (((((((phongFunction(ka, kd, ks, shininess, worldPosition, normalize(((eyePosition - worldPosition))), normalize(worldNormal)))))))))))));

应该是这样的

fragColor = (((renderClicks(clicks, colors, (((((((phongFunction(ka, kd, ks, shininess, worldPosition, normalize(((eyePosition - worldPosition))), normalize(worldNormal)))))))))))));

但由于制服的名称是clicks[10]colors[10]我不确定这是否可以修复。


问题

QSceneLoader在我的项目中使用自动加载对象。现在我想可视化对象 3D 表面上的点击。为此,我正在遍历场景加载器创建的实体层次结构,直到到达QShaderProgramBuilder. 接下来,我将替换着色器程序构建器中的片段着色器图setFragmentShaderGraph- 不幸的是,您无法提供包含普通着色器代码的文本文件。

我使用来自 GitHub 的默认 phong 图作为起点,并添加了我自己的制服——点击次数和点击次数的颜色,都是vec3数组。不幸的是,在我从两者中删除数组定义之前,着色器无法工作。

当我从任何地方删除数组定义(即vec3 clicks代替vec3 clicks[10])并传递 aQVector3D而不是 a 时,QVector<QVector3D>我得到了渲染的正常场景。

我也找不到这里提到的 Qt3D 节点编辑器,但我怀疑它能否解决我的问题,因为在 YouTube 上的视频中似乎没有任何选项可以声明数组。

那么,有什么想法可以在着色器图中正确使用统一数组吗?


注意:我已经检查了 4.6 的 OpenGL 版本,所以这不应该是问题。

注 2:如果有人需要示例项目,请告诉我。我开始创建一个,但即使我试图保持它很小,它也变得相当大。它还没有完成,但我可以完成它并将其上传到 GitHub。


编码

这是我从 C++ 提供数据作为参数的方式:

Qt3DRender::QParameter *clicksParameter = new Qt3DRender::QParameter(QStringLiteral("clicks"), m_clicks.constData());

我更改了着色器图以包含以下新内容prototype

"prototypes": {
        "renderClicks": {
            "inputs": ["clicks[10]", "colors[10]", "currentColor"],
            "outputs": ["result"],
            "parameters": {
                "type": {
                    "type": "QShaderLanguage::VariableType",
                    "value": "QShaderLanguage::Vec4"
                 }
             },
             "rules": [{
                "format": {
                    "api": "OpenGLCoreProfile",
                    "major": 3,
                    "minor": 0
                 },
                 "headerSnippets": [
                    "#pragma include :shaders/poseeditor/clicksRendering.inc.frag"
                 ],
                 "substitution": "vec4 $result = renderClicks($clicks, $colors, $currentColor);"
            }]
        }
    },
"nodes": ...

其中引用了以下着色器代码clicksRendering.inc.frag

vec4 renderClicks(vec3 clicks[10], vec3 colors[10], vec4 currentColor) {
    return currentColor;
}

然后我添加了以下新内容nodes

...
        {
            "uuid": "{00000000-0000-0000-0000-000000000026}",
            "type": "input",
            "parameters": {
                "name": "clicks[10]",
                "qualifier": {
                    "type": "QShaderLanguage::StorageQualifier",
                    "value": "QShaderLanguage::Uniform"
                },
                "type": {
                    "type": "QShaderLanguage::VariableType",
                    "value": "QShaderLanguage::Vec3"
                }
            }
        },
        {
            "uuid": "{00000000-0000-0000-0000-000000000027}",
            "type": "input",
            "parameters": {
                "name": "colors[10]",
                "qualifier": {
                    "type": "QShaderLanguage::StorageQualifier",
                    "value": "QShaderLanguage::Uniform"
                },
                "type": {
                    "type": "QShaderLanguage::VariableType",
                    "value": "QShaderLanguage::Vec3"
                }
            }
        },
        {
            "uuid": "{00000000-0000-0000-0000-000000000028}",
            "type": "renderClicks"
        },
...

我还更改了最后的边缘,以便最终的 phong 颜色通过我的自定义函数传递:

...
        {
            "sourceUuid": "{00000000-0000-0000-0000-000000000026}",
            "sourcePort": "value",
            "targetUuid": "{00000000-0000-0000-0000-000000000028}",
            "targetPort": "clicks"
        },
        {
            "sourceUuid": "{00000000-0000-0000-0000-000000000027}",
            "sourcePort": "value",
            "targetUuid": "{00000000-0000-0000-0000-000000000028}",
            "targetPort": "colors"
        },
        {
            "sourceUuid": "{00000000-0000-0000-0000-000000000024}",
            "sourcePort": "outputColor",
            "targetUuid": "{00000000-0000-0000-0000-000000000028}",
            "targetPort": "currentColor"
        },
        {
            "sourceUuid": "{00000000-0000-0000-0000-000000000028}",
            "sourcePort": "result",
            "targetUuid": "{00000000-0000-0000-0000-000000000025}",
            "targetPort": "fragColor"
        }
...

附加信息

我试图[10]从新inputsprototype. 这会输出一个错误和错误的着色器代码:

const int MAX_LIGHTS = 8;
const int TYPE_POINT = 0;
const int TYPE_DIRECTIONAL = 1;
const int TYPE_SPOT = 2;
struct Light {
    int type;
    vec3 position;
    vec3 color;
    float intensity;
    vec3 direction;
    float constantAttenuation;
    float linearAttenuation;
    float quadraticAttenuation;
    float cutOffAngle;
};
uniform Light lights[MAX_LIGHTS];
uniform int lightCount;

// Pre-convolved environment maps
struct EnvironmentLight {
    samplerCube irradiance; // For diffuse contribution
    samplerCube specular; // For specular contribution
};
uniform EnvironmentLight envLight;
uniform int envLightCount = 0;

#line 52

void adsModel(const in vec3 worldPos,
              const in vec3 worldNormal,
              const in vec3 worldView,
              const in float shininess,
              out vec3 diffuseColor,
              out vec3 specularColor)
{
    diffuseColor = vec3(0.0);
    specularColor = vec3(0.0);

    // We perform all work in world space
    vec3 n = normalize(worldNormal);
    vec3 s = vec3(0.0);

    for (int i = 0; i < lightCount; ++i) {
        float att = 1.0;
        float sDotN = 0.0;

        if (lights[i].type != TYPE_DIRECTIONAL) {
            // Point and Spot lights

            // Light position is already in world space
            vec3 sUnnormalized = lights[i].position - worldPos;
            s = normalize(sUnnormalized); // Light direction

            // Calculate the attenuation factor
            sDotN = dot(s, n);
            if (sDotN > 0.0) {
                if (lights[i].constantAttenuation != 0.0
                 || lights[i].linearAttenuation != 0.0
                 || lights[i].quadraticAttenuation != 0.0) {
                    float dist = length(sUnnormalized);
                    att = 1.0 / (lights[i].constantAttenuation +
                                 lights[i].linearAttenuation * dist +
                                 lights[i].quadraticAttenuation * dist * dist);
                }

                // The light direction is in world space already
                if (lights[i].type == TYPE_SPOT) {
                    // Check if fragment is inside or outside of the spot light cone
                    if (degrees(acos(dot(-s, lights[i].direction))) > lights[i].cutOffAngle)
                        sDotN = 0.0;
                }
            }
        } else {
            // Directional lights
            // The light direction is in world space already
            s = normalize(-lights[i].direction);
            sDotN = dot(s, n);
        }

        // Calculate the diffuse factor
        float diffuse = max(sDotN, 0.0);

        // Calculate the specular factor
        float specular = 0.0;
        if (diffuse > 0.0 && shininess > 0.0) {
            float normFactor = (shininess + 2.0) / 2.0;
            vec3 r = reflect(-s, n);   // Reflection direction in world space
            specular = normFactor * pow(max(dot(r, worldView), 0.0), shininess);
        }

        // Accumulate the diffuse and specular contributions
        diffuseColor += att * lights[i].intensity * diffuse * lights[i].color;
        specularColor += att * lights[i].intensity * specular * lights[i].color;
    }
}

vec4 phongFunction(const in vec4 ambient,
                   const in vec4 diffuse,
                   const in vec4 specular,
                   const in float shininess,
                   const in vec3 worldPosition,
                   const in vec3 worldView,
                   const in vec3 worldNormal)
{
    // Calculate the lighting model, keeping the specular component separate
    vec3 diffuseColor, specularColor;
    adsModel(worldPosition, worldNormal, worldView, shininess, diffuseColor, specularColor);

    // Combine spec with ambient+diffuse for final fragment color
    vec3 color = (ambient.rgb + diffuseColor) * diffuse.rgb
               + specularColor * specular.rgb;

    return vec4(color, diffuse.a);
}

#line 11
uniform vec3 clicks[10];
uniform vec3 colors[10];
vec4 renderClicks(vec3 clicks[10], vec3 colors[10], vec4 currentColor) {
    return currentColor;
}

#line 15
out vec4 fragColor;

void main()
{
    fragColor = (((renderClicks(clicks[10], colors[10], (((((((phongFunction(ka, kd, ks, shininess, worldPosition, normalize(((eyePosition - worldPosition))), normalize(worldNormal)))))))))))));
}

所以着色器看起来不错,除了调用renderClicks(clicks[10], colors[10], ...). 但我不知道我是否可以摆脱这些[10]部分,因为那是他们的名字。

标签: qtopenglshaderfragment-shaderqt3d

解决方案


推荐阅读