Auf dieser Seite

Qt Quick 3D - Beispiel für benutzerdefinierte Materialien

Veranschaulicht das Schreiben von benutzerdefinierten Materialien mit Schattierung.

Sechs Objekte mit unterschiedlichen Formen und individuellen Materialien

Dieses Beispiel zeigt, wie man schattierte „ custom materials “ schreibt. Bei schattierten Materialien müssen wir keine vollständigen Shader-Programme schreiben. Stattdessen schreiben wir Funktionen, die die Standard-Shader von Qt modifizieren. Auf diese Weise nimmt das resultierende Material standardmäßig an der Beleuchtung und dem Shadow-Mapping teil und ist mit Light-Probes kompatibel. Wir müssen nur dann benutzerdefinierte Logik schreiben, wenn wir ein spezielles Verhalten wünschen. Dies erreichen wir, indem wir den Shader-Code, der für ein „ PrincipledMaterial “ generiert würde, effektiv durch unsere eigenen benutzerdefinierten Funktionen ergänzen, die in bestimmten Phasen der Vertex- und Fragment-Shader aufgerufen werden.

Um ein benutzerdefiniertes Material mit Shading zu erstellen, setzen Sie die Eigenschaft „ shadingMode “ auf „ CustomMaterial.Shaded “.

Ein einfaches Material

Das erste Modell verwendet ein einfaches Material, das keine benutzerdefinierte Logik enthält. Wir weisen dem Modell das benutzerdefinierte Material genau wie jedes andere Material zu:

Model {
    source: "weirdShape.mesh"
    scale: Qt.vector3d(100, 100, 100)
    rotation: Quaternion.fromEulerAngles(-90, 0, 0)
    x: v3d.radius

    materials: [
        CustomMaterial {
            shadingMode: CustomMaterial.Shaded
            fragmentShader: "material_simple.frag"
            property color uDiffuse: "fuchsia"
            property real uSpecular: 1.0
        }
    ]
}

Zusätzlich zur Einstellung von „ shadingMode “ und „ fragmentShader “ fügen wir dem Material zwei weitere Eigenschaften hinzu: „ uDiffuse “ und „ Specular “. Diese werden vom Fragment-Shader übernommen.

Der Code für den Fragment-Shader ist kurz:

void MAIN()
{
    SPECULAR_AMOUNT = uSpecular;
    BASE_COLOR = uDiffuse;
}

Alle Shader müssen die Funktion ` MAIN ` implementieren. In diesem Fall verwenden wir die im Material definierten Eigenschaften, um Werte festzulegen, die vom Standard-Shader-Code von Qt verwendet werden. Beachten Sie, dass wir diese nicht als Uniforms deklarieren müssen: Wir müssen lediglich sicherstellen, dass die Namen übereinstimmen. Es würde zu einem Shader-Kompilierungsfehler kommen, wenn das Material keine passenden Eigenschaften hätte.

Die speziellen Variablen ` SPECULAR_AMOUNT ` und ` BASE_COLOR ` entsprechen ` specularAmount ` und ` baseColor ` aus PrincipledMaterial. Diese werden dann vom Standard-Shader-Code verwendet, um Beleuchtungsberechnungen durchzuführen, genau so, als hätten wir einen PrincipledMaterial verwendet.

Benutzerdefinierte Behandlung von Lichtern

Das nächste Objekt verwendet ein komplexeres Material, das eine benutzerdefinierte Beleuchtung implementiert. Das Material hat andere Uniform-Namen, wird aber ansonsten auf dieselbe Weise verwendet:

materials: [
    CustomMaterial {
        shadingMode: CustomMaterial.Shaded
        fragmentShader: "material_customlights.frag"
        property color uDiffuse: "orange"
        property real uShininess: 150
    }
]

Der Fragment-Shader implementiert eine benutzerdefinierte Logik für alle verschiedenen Lichttypen:

void MAIN()
{
    SPECULAR_AMOUNT = 1.0;
    ROUGHNESS = 0.5;
    BASE_COLOR = uDiffuse;
}

void AMBIENT_LIGHT()
{
    DIFFUSE += uDiffuse.rgb * TOTAL_AMBIENT_COLOR;
}

void DIRECTIONAL_LIGHT()
{
    DIFFUSE += uDiffuse.rgb * LIGHT_COLOR * SHADOW_CONTRIB * vec3(max(0.0, dot(normalize(NORMAL), TO_LIGHT_DIR)));
}

void POINT_LIGHT()
{
    DIFFUSE += uDiffuse.rgb * LIGHT_COLOR * LIGHT_ATTENUATION * SHADOW_CONTRIB * vec3(max(0.0, dot(normalize(NORMAL), TO_LIGHT_DIR)));
}

void SPOT_LIGHT()
{
     DIFFUSE += uDiffuse.rgb * LIGHT_COLOR * LIGHT_ATTENUATION * SPOT_FACTOR * SHADOW_CONTRIB * vec3(max(0.0, dot(normalize(VAR_WORLD_NORMAL), TO_LIGHT_DIR)));
}

Hier verwenden wir viele neue spezielle Schlüsselwörter, die sich auf Eigenschaften der verschiedenen Lichtarten beziehen. Eine Beschreibung der einzelnen Schlüsselwörter findest du in der Dokumentation zu „ CustomMaterial “. Beachte, dass jede Lichtart ihre eigene Funktion hat. Jede nicht implementierte Funktion verwendet die Standardimplementierung und verhält sich wie „ PrincipledMaterial “. Beispiel: In diesem Shader haben wir „ SPECULAR_LIGHT() “ nicht implementiert, daher erhalten wir die integrierte Spiegelreflexion.

Hinzufügen eines Vertex-Shaders

Ein benutzerdefiniertes Material kann auch einen Vertex-Shader verwenden, um die Geometrie des Modells zu verändern. Hier legen wir sowohl den Fragment- als auch den Vertex-Shader fest und fügen mehrere weitere Eigenschaften hinzu, die als Uniform-Werte übernommen werden:

materials: [
    CustomMaterial {
        id: material
        shadingMode: CustomMaterial.Shaded
        vertexShader: "material_distortion.vert"
        fragmentShader: "material_customlights.frag"
        property real uTime: 0.0
        property real uAmplitude: 0.3
        property color uDiffuse: "yellow"
        property real uShininess: 50
        NumberAnimation {
            target: material
            property: "uTime"
            from: 0.0
            to: 31.4
            duration: 10000
            loops: Animation.Infinite
            running: true
        }
    }
]

Der Vertex-Shader ist sehr kurz:

// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

void MAIN()
{
    VERTEX.y += sin(uTime + VERTEX.x*10.0) * uAmplitude;
}

Dadurch wird das Modell verformt, indem jeder Scheitelpunkt entsprechend einer sich mit der Zeit ändernden Sinuswelle verschoben wird.

Ein transparentes Material

Abschließend fügen wir eine Kugel mit einem transparenten Material hinzu. Aus Leistungsgründen implementiert Qt Transparenz nicht auf vollständig realistische Weise. Stattdessen rendert Qt alle undurchsichtigen Objekte in der Szene in eine Textur, und transparente Materialien lesen dann aus dieser Textur. Das bedeutet, dass transparente Materialien das beste Ergebnis liefern, wenn sie vor anderen Objekten platziert werden:

Model {
    id: screenSphere
    source: "#Sphere"
    scale: Qt.vector3d(0.75, 0.75, 0.75)
    y: 60
    z: 750;
    materials: [
        CustomMaterial {
            shadingMode: CustomMaterial.Shaded
            fragmentShader: "material_transparent.frag"
        }
    ]

Für dieses Beispiel implementieren wir eine vereinfachte Verzerrungsfunktion, die keine echte physikalische Lichtbrechung simuliert:

void MAIN()
{
    vec2 size = vec2(textureSize(SCREEN_TEXTURE, 0));
    vec2 uv = FRAGCOORD.xy / size;

    vec3 view = normalize(VIEW_VECTOR);
    vec3 projection = view - view * normalize(NORMAL);
    vec3 refraction = projection * projection;
    uv += refraction.xy * 0.5;

    vec3 col = texture(SCREEN_TEXTURE, uv).rgb;
    col = col * 0.8 + vec3(0.2);

    BASE_COLOR = vec4(col, 1.0);
}

SCREEN_TEXTURE bezieht sich auf die Textur, die alle undurchsichtigen Objekte in der Szene zeigt. Zunächst berechnen wir die UV-Koordinaten innerhalb dieser Textur, die der Bildschirmposition des aktuellen Scheitelpunkts entsprechen. Anschließend fügen wir dieser Position einen Versatz hinzu, um einen Brechungseffekt zu simulieren, bevor wir einen Textur-Lookup durchführen.

Abschließend mischen wir 20 % Weiß bei, um eine leichte Trübung zu erzielen. Beachten Sie, dass die Ausgabe „ BASE_COLOR “ zugewiesen wird, sodass Qt zusätzlich eine Beleuchtung darüberlegt. Aus diesem Grund sind Reflexionen auf der Oberfläche der Kugel zu sehen.

Unbeschattete Materialien

Es ist auch möglich, benutzerdefinierte Materialien zu verwenden, die vollständige Shader-Programme nutzen (wobei weiterhin die Komfort-Schlüsselwörter verwendet werden). Das Beispiel „customshaders“ veranschaulicht die andere Gruppe benutzerdefinierter Materialien: ungeschattete benutzerdefinierte Materialien.

Beispielprojekt @ code.qt.io

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.