summaryrefslogtreecommitdiffstats
path: root/tests/manual/shadow-map-qml
diff options
context:
space:
mode:
Diffstat (limited to 'tests/manual/shadow-map-qml')
-rw-r--r--tests/manual/shadow-map-qml/AdsEffect.qml129
-rw-r--r--tests/manual/shadow-map-qml/AdsMaterial.qml21
-rw-r--r--tests/manual/shadow-map-qml/CMakeLists.txt90
-rw-r--r--tests/manual/shadow-map-qml/GroundPlane.qml29
-rw-r--r--tests/manual/shadow-map-qml/ShadowMapFrameGraph.qml71
-rw-r--r--tests/manual/shadow-map-qml/ShadowMapLight.qml28
-rw-r--r--tests/manual/shadow-map-qml/Toyplane.qml94
-rw-r--r--tests/manual/shadow-map-qml/Trefoil.qml40
-rw-r--r--tests/manual/shadow-map-qml/doc/images/shadowmapping-depth.pngbin0 -> 23712 bytes
-rw-r--r--tests/manual/shadow-map-qml/doc/images/shadowmapping-qt3d.pngbin0 -> 39159 bytes
-rw-r--r--tests/manual/shadow-map-qml/doc/src/shadow-map-qml.qdoc252
-rw-r--r--tests/manual/shadow-map-qml/main.cpp22
-rw-r--r--tests/manual/shadow-map-qml/main.qml75
-rw-r--r--tests/manual/shadow-map-qml/shaders/ads.frag60
-rw-r--r--tests/manual/shadow-map-qml/shaders/ads.vert33
-rw-r--r--tests/manual/shadow-map-qml/shaders/es3/ads.frag59
-rw-r--r--tests/manual/shadow-map-qml/shaders/es3/ads.vert30
-rw-r--r--tests/manual/shadow-map-qml/shaders/es3/shadowmap.frag7
-rw-r--r--tests/manual/shadow-map-qml/shaders/es3/shadowmap.vert10
-rw-r--r--tests/manual/shadow-map-qml/shaders/rhi/ads.frag89
-rw-r--r--tests/manual/shadow-map-qml/shaders/rhi/ads.vert67
-rw-r--r--tests/manual/shadow-map-qml/shaders/rhi/shadowmap.frag8
-rw-r--r--tests/manual/shadow-map-qml/shaders/rhi/shadowmap.vert22
-rw-r--r--tests/manual/shadow-map-qml/shaders/shadowmap.frag8
-rw-r--r--tests/manual/shadow-map-qml/shaders/shadowmap.vert13
-rw-r--r--tests/manual/shadow-map-qml/shadow-map-qml.qrc24
26 files changed, 1281 insertions, 0 deletions
diff --git a/tests/manual/shadow-map-qml/AdsEffect.qml b/tests/manual/shadow-map-qml/AdsEffect.qml
new file mode 100644
index 000000000..8050ff01c
--- /dev/null
+++ b/tests/manual/shadow-map-qml/AdsEffect.qml
@@ -0,0 +1,129 @@
+// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import Qt3D.Core 2.0
+import Qt3D.Render 2.0
+
+Effect {
+ id: root
+
+ property Texture2D shadowTexture
+ property ShadowMapLight light
+
+ // These parameters act as default values for the effect. They take
+ // priority over any parameters specified in the RenderPasses below
+ // (none provided in this example). In turn these parameters can be
+ // overwritten by specifying them in a Material that references this
+ // effect.
+ // The priority order is:
+ //
+ // Material -> Effect -> Technique -> RenderPass -> GLSL default values
+ parameters: [
+ Parameter { name: "lightViewProjection"; value: root.light.lightViewProjection },
+ Parameter { name: "lightPosition"; value: root.light.lightPosition },
+ Parameter { name: "lightIntensity"; value: root.light.lightIntensity },
+ Parameter { name: "shadowMapTexture"; value: root.shadowTexture }
+ ]
+
+ techniques: [
+ Technique {
+ graphicsApiFilter {
+ api: GraphicsApiFilter.OpenGL
+ profile: GraphicsApiFilter.CoreProfile
+ majorVersion: 3
+ minorVersion: 2
+ }
+
+ renderPasses: [
+ RenderPass {
+ filterKeys: [ FilterKey { name: "pass"; value: "shadowmap" } ]
+
+ shaderProgram: ShaderProgram {
+ vertexShaderCode: loadSource("qrc:/shaders/shadowmap.vert")
+ fragmentShaderCode: loadSource("qrc:/shaders/shadowmap.frag")
+ }
+
+ renderStates: [
+ PolygonOffset { scaleFactor: 4; depthSteps: 4 },
+ DepthTest { depthFunction: DepthTest.Less }
+ ]
+ },
+
+ RenderPass {
+ filterKeys: [ FilterKey { name : "pass"; value : "forward" } ]
+
+ shaderProgram: ShaderProgram {
+ vertexShaderCode: loadSource("qrc:/shaders/ads.vert")
+ fragmentShaderCode: loadSource("qrc:/shaders/ads.frag")
+ }
+
+ // no special render state set => use the default set of states
+ }
+ ]
+ },
+ Technique {
+ graphicsApiFilter {
+ api: GraphicsApiFilter.OpenGLES
+ majorVersion: 3
+ minorVersion: 0
+ }
+
+ renderPasses: [
+ RenderPass {
+ filterKeys: [ FilterKey { name: "pass"; value: "shadowmap" } ]
+
+ shaderProgram: ShaderProgram {
+ vertexShaderCode: loadSource("qrc:/shaders/es3/shadowmap.vert")
+ fragmentShaderCode: loadSource("qrc:/shaders/es3/shadowmap.frag")
+ }
+
+ renderStates: [
+ PolygonOffset { scaleFactor: 4; depthSteps: 4 },
+ DepthTest { depthFunction: DepthTest.Less }
+ ]
+ },
+
+ RenderPass {
+ filterKeys: [ FilterKey { name : "pass"; value : "forward" } ]
+
+ shaderProgram: ShaderProgram {
+ vertexShaderCode: loadSource("qrc:/shaders/es3/ads.vert")
+ fragmentShaderCode: loadSource("qrc:/shaders/es3/ads.frag")
+ }
+ }
+ ]
+ },
+ Technique {
+ graphicsApiFilter {
+ api: GraphicsApiFilter.RHI
+ majorVersion: 1
+ minorVersion: 0
+ }
+
+ renderPasses: [
+ RenderPass {
+ filterKeys: [ FilterKey { name: "pass"; value: "shadowmap" } ]
+
+ shaderProgram: ShaderProgram {
+ vertexShaderCode: loadSource("qrc:/shaders/rhi/shadowmap.vert")
+ fragmentShaderCode: loadSource("qrc:/shaders/rhi/shadowmap.frag")
+ }
+
+ renderStates: [
+ PolygonOffset { scaleFactor: 4; depthSteps: 4 },
+ DepthTest { depthFunction: DepthTest.Less }
+ ]
+ },
+
+ RenderPass {
+ filterKeys: [ FilterKey { name : "pass"; value : "forward" } ]
+
+ shaderProgram: ShaderProgram {
+ vertexShaderCode: loadSource("qrc:/shaders/rhi/ads.vert")
+ fragmentShaderCode: loadSource("qrc:/shaders/rhi/ads.frag")
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/manual/shadow-map-qml/AdsMaterial.qml b/tests/manual/shadow-map-qml/AdsMaterial.qml
new file mode 100644
index 000000000..2ac53b987
--- /dev/null
+++ b/tests/manual/shadow-map-qml/AdsMaterial.qml
@@ -0,0 +1,21 @@
+// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick 2.1
+import Qt3D.Core 2.0
+import Qt3D.Render 2.0
+
+Material {
+ id: root
+ property color ambientColor: Qt.rgba(0.1, 0.1, 0.1, 1.0)
+ property color diffuseColor: Qt.rgba(0.7, 0.7, 0.9, 1.0)
+ property color specularColor: Qt.rgba(0.1, 0.1, 0.1, 1.0)
+ property real shininess: 150.0
+
+ parameters: [
+ Parameter { name: "ka"; value: Qt.vector3d(root.ambientColor.r, root.ambientColor.g, root.ambientColor.b) },
+ Parameter { name: "kd"; value: Qt.vector3d(root.diffuseColor.r, root.diffuseColor.g, root.diffuseColor.b) },
+ Parameter { name: "ks"; value: Qt.vector3d(root.specularColor.r, root.specularColor.g, root.specularColor.b) },
+ Parameter { name: "shininess"; value: root.shininess }
+ ]
+}
diff --git a/tests/manual/shadow-map-qml/CMakeLists.txt b/tests/manual/shadow-map-qml/CMakeLists.txt
new file mode 100644
index 000000000..d7fe2232b
--- /dev/null
+++ b/tests/manual/shadow-map-qml/CMakeLists.txt
@@ -0,0 +1,90 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(shadow-map-qml LANGUAGES CXX)
+
+set(CMAKE_AUTOMOC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}")
+
+find_package(Qt6 REQUIRED COMPONENTS 3DCore 3DInput 3DQuick 3DQuickExtras 3DRender Core Gui Qml Quick)
+
+qt_add_executable(shadow-map-qml
+ main.cpp
+)
+
+set_target_properties(shadow-map-qml PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(shadow-map-qml PUBLIC
+ Qt::3DCore
+ Qt::3DInput
+ Qt::3DQuick
+ Qt::3DQuickExtras
+ Qt::3DRender
+ Qt::Core
+ Qt::Gui
+ Qt::Qml
+ Qt::Quick
+)
+
+# Resources:
+set(shadow-map-qml_resource_files
+ "AdsEffect.qml"
+ "AdsMaterial.qml"
+ "GroundPlane.qml"
+ "ShadowMapFrameGraph.qml"
+ "ShadowMapLight.qml"
+ "Toyplane.qml"
+ "Trefoil.qml"
+ "main.qml"
+ "shaders/ads.frag"
+ "shaders/ads.vert"
+ "shaders/es3/ads.frag"
+ "shaders/es3/ads.vert"
+ "shaders/es3/shadowmap.frag"
+ "shaders/es3/shadowmap.vert"
+ "shaders/rhi/ads.frag"
+ "shaders/rhi/ads.vert"
+ "shaders/rhi/shadowmap.frag"
+ "shaders/rhi/shadowmap.vert"
+ "shaders/shadowmap.frag"
+ "shaders/shadowmap.vert"
+)
+
+qt6_add_resources(shadow-map-qml "shadow-map-qml"
+ PREFIX
+ "/"
+ FILES
+ ${shadow-map-qml_resource_files}
+)
+
+set(obj_resource_files
+ "../exampleresources/assets/obj/ball.obj"
+ "../exampleresources/assets/obj/material-sphere.obj"
+ "../exampleresources/assets/obj/plane-10x10.obj"
+ "../exampleresources/assets/obj/toyplane.obj"
+ "../exampleresources/assets/obj/trefoil.obj"
+)
+
+qt6_add_resources(shadow-map-qml "obj"
+ PREFIX
+ "/"
+ BASE
+ "../exampleresources"
+ FILES
+ ${obj_resource_files}
+)
+
+install(TARGETS shadow-map-qml
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/tests/manual/shadow-map-qml/GroundPlane.qml b/tests/manual/shadow-map-qml/GroundPlane.qml
new file mode 100644
index 000000000..278f50432
--- /dev/null
+++ b/tests/manual/shadow-map-qml/GroundPlane.qml
@@ -0,0 +1,29 @@
+// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import Qt3D.Core 2.0
+import Qt3D.Render 2.0
+import Qt3D.Extras 2.0
+
+Entity {
+ id: root
+ property Material material
+
+ PlaneMesh {
+ id: groundMesh
+ width: 50
+ height: width
+ meshResolution: Qt.size(2, 2)
+ }
+
+ Transform {
+ id: groundTransform
+ translation: Qt.vector3d(0, -5, 0)
+ }
+
+ components: [
+ groundMesh,
+ groundTransform,
+ material
+ ]
+}
diff --git a/tests/manual/shadow-map-qml/ShadowMapFrameGraph.qml b/tests/manual/shadow-map-qml/ShadowMapFrameGraph.qml
new file mode 100644
index 000000000..c534ae7d2
--- /dev/null
+++ b/tests/manual/shadow-map-qml/ShadowMapFrameGraph.qml
@@ -0,0 +1,71 @@
+// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick 2.2 as QQ2
+import Qt3D.Core 2.0
+import Qt3D.Render 2.0
+
+RenderSettings {
+ id: root
+
+ property alias viewCamera: viewCameraSelector.camera
+ property alias lightCamera: lightCameraSelector.camera
+ readonly property Texture2D shadowTexture: depthTexture
+
+ activeFrameGraph: Viewport {
+ normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
+
+ RenderSurfaceSelector {
+ RenderPassFilter {
+ matchAny: [ FilterKey { name: "pass"; value: "shadowmap" } ]
+
+ RenderTargetSelector {
+ target: RenderTarget {
+ attachments: [
+ RenderTargetOutput {
+ objectName: "depth"
+ attachmentPoint: RenderTargetOutput.Depth
+ texture: Texture2D {
+ id: depthTexture
+ width: 1024
+ height: 1024
+ format: Texture.DepthFormat
+ generateMipMaps: false
+ magnificationFilter: Texture.Linear
+ minificationFilter: Texture.Linear
+ wrapMode {
+ x: WrapMode.ClampToEdge
+ y: WrapMode.ClampToEdge
+ }
+ comparisonFunction: Texture.CompareLessEqual
+ comparisonMode: Texture.CompareRefToTexture
+ }
+ }
+ ]
+ }
+
+ ClearBuffers {
+ buffers: ClearBuffers.DepthBuffer
+
+ CameraSelector {
+ id: lightCameraSelector
+ }
+ }
+ }
+ }
+
+ RenderPassFilter {
+ matchAny: [ FilterKey { name: "pass"; value: "forward" } ]
+
+ ClearBuffers {
+ clearColor: Qt.rgba(0.0, 0.4, 0.7, 1.0)
+ buffers: ClearBuffers.ColorDepthBuffer
+
+ CameraSelector {
+ id: viewCameraSelector
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/manual/shadow-map-qml/ShadowMapLight.qml b/tests/manual/shadow-map-qml/ShadowMapLight.qml
new file mode 100644
index 000000000..797aeb769
--- /dev/null
+++ b/tests/manual/shadow-map-qml/ShadowMapLight.qml
@@ -0,0 +1,28 @@
+// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import Qt3D.Core 2.0
+import Qt3D.Render 2.0
+
+Entity {
+ id: root
+
+ property vector3d lightPosition: Qt.vector3d(30.0, 30.0, 0.0)
+ property vector3d lightIntensity: Qt.vector3d(1.0, 1.0, 1.0)
+
+ readonly property Camera lightCamera: lightCamera
+ readonly property matrix4x4 lightViewProjection: lightCamera.projectionMatrix.times(lightCamera.viewMatrix)
+
+ Camera {
+ id: lightCamera
+ objectName: "lightCameraLens"
+ projectionType: CameraLens.PerspectiveProjection
+ fieldOfView: 45
+ aspectRatio: 1
+ nearPlane : 0.1
+ farPlane : 200.0
+ position: root.lightPosition
+ viewCenter: Qt.vector3d(0.0, 0.0, 0.0)
+ upVector: Qt.vector3d(0.0, 1.0, 0.0)
+ }
+}
diff --git a/tests/manual/shadow-map-qml/Toyplane.qml b/tests/manual/shadow-map-qml/Toyplane.qml
new file mode 100644
index 000000000..d0ae66a4e
--- /dev/null
+++ b/tests/manual/shadow-map-qml/Toyplane.qml
@@ -0,0 +1,94 @@
+// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick 2.1 as QQ2
+import Qt3D.Core 2.0
+import Qt3D.Render 2.0
+
+Entity {
+ id: root
+ property Material material
+
+ Mesh {
+ id: toyplaneMesh
+ source: "qrc:///assets/obj/toyplane.obj"
+ }
+
+ Transform {
+ id: toyplaneTransform
+
+ property real rollAngle: 0
+ property real pitchAngle: 15
+ property real altitude: 5
+ property real angle: 0
+ property real scaleFactor: 10
+
+ QQ2.Behavior on rollAngle { QQ2.SpringAnimation { spring: 2; damping: 0.2} }
+
+ matrix: {
+ var m = Qt.matrix4x4();
+ m.translate(Qt.vector3d(Math.sin(angle * Math.PI / 180) * scaleFactor,
+ altitude,
+ Math.cos(angle * Math.PI / 180) * scaleFactor));
+ m.rotate(angle, Qt.vector3d(0, 1, 0));
+ m.rotate(pitchAngle, Qt.vector3d(0, 0, 1));
+ m.rotate(rollAngle, Qt.vector3d(1, 0, 0));
+ m.scale(1.0 / toyplaneTransform.scaleFactor);
+ return m;
+ }
+ }
+
+ QQ2.NumberAnimation {
+ target: toyplaneTransform
+
+ running: true
+ loops: QQ2.Animation.Infinite
+
+ property: "angle"
+ duration: 10000
+ from: 0
+ to: 360
+ }
+
+ // Altitude / Pitch animation
+ QQ2.SequentialAnimation {
+ running: true
+ loops: QQ2.Animation.Infinite
+ QQ2.ParallelAnimation {
+ QQ2.SequentialAnimation {
+ QQ2.NumberAnimation { target: toyplaneTransform; property: "pitchAngle"; from: 0; to: 30; duration: 2000; easing.type: QQ2.Easing.OutQuad }
+ QQ2.NumberAnimation { target: toyplaneTransform; property: "pitchAngle"; from: 30; to: 0; duration: 2000; easing.type: QQ2.Easing.OutSine }
+ }
+ QQ2.NumberAnimation { target: toyplaneTransform; property: "altitude"; to: 5; duration: 4000; easing.type: QQ2.Easing.InOutCubic }
+ }
+ QQ2.PauseAnimation { duration: 1500 }
+ QQ2.ParallelAnimation {
+ QQ2.SequentialAnimation {
+ QQ2.NumberAnimation { target: toyplaneTransform; property: "pitchAngle"; from: 0; to: -30; duration: 1000; easing.type: QQ2.Easing.OutQuad }
+ QQ2.NumberAnimation { target: toyplaneTransform; property: "pitchAngle"; from: -30; to: 0; duration: 5000; easing.type: QQ2.Easing.OutSine }
+ }
+ QQ2.NumberAnimation { target: toyplaneTransform; property: "altitude"; to: 0; duration: 6000; easing.type: QQ2.Easing.InOutCubic}
+ }
+ QQ2.PauseAnimation { duration: 1500 }
+ }
+
+ // Roll Animation
+ QQ2.SequentialAnimation {
+ running: true
+ loops: QQ2.Animation.Infinite
+ QQ2.NumberAnimation { target: toyplaneTransform; property: "rollAngle"; to: 360; duration: 1500; easing.type: QQ2.Easing.InOutQuad }
+ QQ2.PauseAnimation { duration: 1000 }
+ QQ2.NumberAnimation { target: toyplaneTransform; property: "rollAngle"; from: 0; to: 30; duration: 1000; easing.type: QQ2.Easing.OutQuart }
+ QQ2.PauseAnimation { duration: 1500 }
+ QQ2.NumberAnimation { target: toyplaneTransform; property: "rollAngle"; from: 30; to: -30; duration: 1000; easing.type: QQ2.Easing.OutQuart }
+ QQ2.PauseAnimation { duration: 1500 }
+ QQ2.NumberAnimation { target: toyplaneTransform; property: "rollAngle"; from: -30; to: 0; duration: 750; easing.type: QQ2.Easing.OutQuart }
+ QQ2.PauseAnimation { duration: 2000 }
+ }
+
+ components: [
+ toyplaneMesh,
+ toyplaneTransform,
+ material
+ ]
+}
diff --git a/tests/manual/shadow-map-qml/Trefoil.qml b/tests/manual/shadow-map-qml/Trefoil.qml
new file mode 100644
index 000000000..338fa0e48
--- /dev/null
+++ b/tests/manual/shadow-map-qml/Trefoil.qml
@@ -0,0 +1,40 @@
+// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick 2.1 as QQ2
+import Qt3D.Core 2.0
+import Qt3D.Render 2.0
+
+Entity {
+ id: root
+ property Material material
+
+ Mesh {
+ id: trefoilMesh
+ source: "qrc:///assets/obj/trefoil.obj"
+ }
+
+ Transform {
+ id: trefoilMeshTransform
+ property real userAngle: 0.0
+ rotation: fromAxisAndAngle(Qt.vector3d(0, 1, 0), userAngle)
+ }
+
+ QQ2.NumberAnimation {
+ target: trefoilMeshTransform
+
+ running: true
+ loops: QQ2.Animation.Infinite
+
+ property: "userAngle"
+ duration: 5000
+ from: 360
+ to: 0
+ }
+
+ components: [
+ trefoilMesh,
+ trefoilMeshTransform,
+ material
+ ]
+}
diff --git a/tests/manual/shadow-map-qml/doc/images/shadowmapping-depth.png b/tests/manual/shadow-map-qml/doc/images/shadowmapping-depth.png
new file mode 100644
index 000000000..d2b501412
--- /dev/null
+++ b/tests/manual/shadow-map-qml/doc/images/shadowmapping-depth.png
Binary files differ
diff --git a/tests/manual/shadow-map-qml/doc/images/shadowmapping-qt3d.png b/tests/manual/shadow-map-qml/doc/images/shadowmapping-qt3d.png
new file mode 100644
index 000000000..bac6ac75c
--- /dev/null
+++ b/tests/manual/shadow-map-qml/doc/images/shadowmapping-qt3d.png
Binary files differ
diff --git a/tests/manual/shadow-map-qml/doc/src/shadow-map-qml.qdoc b/tests/manual/shadow-map-qml/doc/src/shadow-map-qml.qdoc
new file mode 100644
index 000000000..29cb4d391
--- /dev/null
+++ b/tests/manual/shadow-map-qml/doc/src/shadow-map-qml.qdoc
@@ -0,0 +1,252 @@
+// Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \example shadow-map-qml
+ \title Qt 3D: Shadow Map QML Example
+ \ingroup qt3d-examples-qml
+
+ \brief A Qt 3D QML application that illustrates how to render a scene in Qt 3D
+ with shadows.
+
+ \image shadowmapping-qt3d.png
+
+ \e {Qt 3D Shadow Map} illustrates how to configure the renderer in order to
+ accommodate custom rendering techniques. The example application displays a
+ self-shadowed plane and trefoil knot.
+
+ We implement \l{Shadow Mapping}{shadow mapping} using a two pass rendering.
+ In the first pass, we generate the shadow information. In the second pass,
+ we generate the scene using the forward rendering technique with Phong
+ shading, while at the same time using the information gathered in the first
+ pass to draw the shadows.
+
+ The entire rendering is configured using QML, but it is possible to use C++
+ to achieve the very same result.
+
+ \include examples-run.qdocinc
+
+ \section1 Setting Up the Scene
+
+ We set up the entire scene in the \e main.qml file.
+
+ To be able to use the types in the Q3D and Q3D Renderer modules, we must
+ import the modules:
+
+ \quotefromfile shadow-map-qml/main.qml
+ \skipto import Qt3D.Core
+ \printuntil Render 2.0
+
+ The first entities we create are a \l Camera, which represents the camera
+ used for the final rendering, and a \l Configuration, which allows us to
+ control this camera using the keyboard or the mouse:
+
+ \printuntil }
+ \printuntil }
+
+ We then create a Light custom entity, which represents our light. It is a
+ directional spotlight, placed somewhere above the plane and looking down at
+ the scene’s origin:
+
+ \printuntil }
+
+ This light entity is used by our custom frame graph, ShadowMapFrameGraph,
+ and our rendering effect, AdsEffect, whose instances are created just after
+ the light:
+
+ \printuntil ]
+ \printuntil }
+
+ Last, we create three entities for the meshes in the scene: a trefoil knot,
+ a toy plane, and a ground plane. They aggregate a mesh, a transformation,
+ and a material that uses the AdsEffect. The toy plane and the trefoil knot
+ transformations are animated:
+
+ \printuntil /^\}/
+
+ \section1 Specifying the Light
+
+ We specify the Light custom entity in \e ShadowMapLight.qml.
+
+ Again, we import the necessary modules:
+
+ \quotefromfile shadow-map-qml/ShadowMapLight.qml
+ \skipto import Qt3D
+ \printuntil Qt3D.Render
+
+ We then use an \l Entity type as the root element of the custom QML type.
+ The light is a directional spotlight that exposes as properties a position,
+ intensity, and a 4×4 transformation matrix:
+
+ \printuntil matrix4x4
+
+ In the first rendering pass, we use the light as a camera, and therefore we
+ use a \l Camera entity within the light and expose it as a property:
+
+ \printuntil /^\}/
+
+ \section1 Configuring the Framegraph
+
+ In Qt 3D, the frame graph is the data-driven configuration for the rendering.
+ We implement the frame graph in the \e ShadowMapFrameGraph.qml file.
+
+ In addition to the Qt 3D and Qt 3D Render modules, we also import the
+ Qt Quick module:
+
+ \quotefromfile shadow-map-qml/ShadowMapFrameGraph.qml
+ \skipto import QtQuick
+ \printuntil Render 2.0
+
+ The code defines a \l RenderSettings node that has a tree of nodes as the
+ active frame graph:
+
+ \badcode
+ RenderSettings {
+ activeFrameGraph: Viewport {...}
+ }
+ \endcode
+
+ Any path from the leaves of this tree to the root is a viable frame graph
+ configuration. Filter entities can enable or disable such paths, and
+ selector entities can alter the configuration.
+
+ In our case, the tree looks like this:
+
+ \badcode
+ Viewport
+ RenderSurfaceSelector
+ RenderPassFilter
+ RenderTargetSelector
+ ClearBuffers
+ CameraSelector
+ RenderPassFilter
+ ClearBuffers
+ CameraSelector
+ \endcode
+
+ So we have two paths from the topmost \l Viewport entity. Each path
+ corresponds to a pass, or phase, of the shadow map technique. The paths are
+ enabled and disabled using a RenderPassFilter, a node that can filter
+ depending on arbitrary values defined in a given render pass. In this
+ example, it is a string:
+
+ \skipto RenderPassFilter
+ \printuntil ]
+
+ The actual passes are not defined within the frame graph. Instead the
+ available passes are declared in the Materials used in the scene graph. The
+ frame graph is only used to select which passes are used when rendering.
+
+ \section1 Generating the Shadow Map
+
+ In the shadow map generation pass, we must render to an offscreen surface
+ (Framebuffer Object) which has a depth texture attachment. In Qt 3D, it is
+ represented by the RenderTarget entity, which has a number of attachments.
+
+ In this example, we need only a depth attachment. We define it as a
+ RenderAttachment entity using the RenderAttachment.DepthAttachment \c type
+ that stores the depth and a Texture2D entity that actually configures the
+ exture storage used to store the depth information:
+
+ \printuntil ]
+ \printuntil }
+
+ Moreover, in this first pass, we must render using the light’s camera.
+ Therefore, we have a CameraSelector entity that sets the camera to the one
+ exported by the Light:
+
+ \skipto CameraSelector
+ \printuntil }
+
+ The second pass is more straightforward, because we simply render to the
+ screen using the main camera:
+
+ \skipto RenderPassFilter
+ \printuntil }
+ \printuntil }
+ \printuntil }
+ \printuntil }
+
+ \section1 Using Effects
+
+ The bulk of the magic happens in the \e AdsEffect.qml file, where our main
+ \l Effect is defined. It implements the Ambient, Diffuse and Specular
+ (ADS) Lighting Model using Phong shading with the addition of shadow mapping.
+
+ An effect contains the implementation of a particular rendering strategy. In
+ this example, shadow mapping using two passes:
+
+ \quotefromfile shadow-map-qml/AdsEffect.qml
+ \skipto Effect
+ \printuntil Light
+
+ The \c parameters list defines some default values for the effect. The
+ values will get mapped to shader program uniform variables, so that in the
+ shaders we can access their values. In this example, we expose some information from
+ the Light entity (position, intensity, view or projection matrix defined by
+ the internal camera) and the shadow map texture exposed by the frame graph:
+
+ \skipto parameters:
+ \printuntil ]
+
+ It is possible to put such parameters all the way down, from a \l Material,
+ to its \l Effect, to one of the effect’s \l {Technique}{Techniques} and a
+ \l RenderPass within a \l Technique. This allows a \l Material instance to
+ override defaults in an \l Effect, \l Technique or \l RenderPass.
+
+ To adapt the implementation to different hardware or OpenGL versions, we
+ could use one or more \l Technique elements. In this example, only one
+ technique is provided, targeting OpenGL 3.2 Core, or later:
+
+ \quotefromfile shadow-map-qml/AdsEffect.qml
+ \skipto techniques:
+ \printuntil }
+
+ Inside the technique, we finally have the definition of our two rendering
+ passes. We \e tag each pass with a \l FilterKey object, matching the ones
+ we specified in the frame graph configuration, so that each pass will have
+ different rendering settings:
+
+ \printuntil ]
+
+ The first pass is the shadow map generation. We load a suitable set of GLSL
+ shaders, which are actually extremely simple. They do only MVP (Model, View,
+ Projection) to bring meshes from their model space into clip space (and,
+ remember, in this first pass, the light is the camera). The fragment shader
+ is totally empty, because there is no color to be generated, and the depth
+ will be automatically captured for us by OpenGL:
+
+ \printuntil }
+
+ In this first pass, we also set some custom OpenGL state in the form of a
+ polygon offset and depth testing mode:
+
+ \printuntil ]
+
+ \section1 Rendering Using Phong Shading
+
+ The second pass is a normal forward rendering using Phong shading. The code
+ in the effect entity is extremely simple. We simply configure some
+ parameters and load a pair of shaders which will be used when drawing.
+
+ The first part of the shadow mapping happens in the vertex shader defined in
+ \e ads.vert file, where we output towards the fragment shader the
+ coordinates of each vertex in light space:
+
+ \quotefromfile shadow-map-qml/shaders/ads.vert
+ \skipto mat4(
+ \skipto positionInLightSpace
+ \printuntil ;
+
+ Actually, the coordinates get adjusted a little to allow us to easily sample
+ the shadow map texture.
+
+ The second part happens in the fragment shader defined in the \e ads.frag
+ file, where we sample the shadow map. If the currently processed fragment is
+ behind the one closest to the light, then the current fragment is in shadow
+ (and only gets ambient contribution). Otherwise, it gets full Phong shading:
+
+ \quotefromfile shadow-map-qml/shaders/ads.frag
+ \skipto main
+ \printuntil }
+*/
diff --git a/tests/manual/shadow-map-qml/main.cpp b/tests/manual/shadow-map-qml/main.cpp
new file mode 100644
index 000000000..dbdf4610d
--- /dev/null
+++ b/tests/manual/shadow-map-qml/main.cpp
@@ -0,0 +1,22 @@
+// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <Qt3DQuickExtras/qt3dquickwindow.h>
+#include <Qt3DQuick/QQmlAspectEngine>
+#include <QGuiApplication>
+#include <QQmlContext>
+#include <QQmlEngine>
+
+int main(int argc, char* argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ Qt3DExtras::Quick::Qt3DQuickWindow view;
+ view.resize(1600, 800);
+ view.engine()->qmlEngine()->rootContext()->setContextProperty("_window", &view);
+ view.setSource(QUrl("qrc:/main.qml"));
+ view.show();
+
+ return app.exec();
+}
+
diff --git a/tests/manual/shadow-map-qml/main.qml b/tests/manual/shadow-map-qml/main.qml
new file mode 100644
index 000000000..635557b65
--- /dev/null
+++ b/tests/manual/shadow-map-qml/main.qml
@@ -0,0 +1,75 @@
+// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick 2.1 as QQ2
+import Qt3D.Core 2.0
+import Qt3D.Render 2.0
+import Qt3D.Input 2.0
+import Qt3D.Extras 2.0
+
+Entity {
+ id: sceneRoot
+
+ Camera {
+ id: camera
+ projectionType: CameraLens.PerspectiveProjection
+ fieldOfView: 45
+ aspectRatio: _window.width / _window.height
+ nearPlane: 0.1
+ farPlane: 1000.0
+ position: Qt.vector3d(0.0, 10.0, 20.0)
+ viewCenter: Qt.vector3d(0.0, 0.0, 0.0)
+ upVector: Qt.vector3d(0.0, 1.0, 0.0)
+ }
+
+ FirstPersonCameraController { camera: camera }
+
+ ShadowMapLight {
+ id: light
+ }
+
+ components: [
+ ShadowMapFrameGraph {
+ id: framegraph
+ viewCamera: camera
+ lightCamera: light.lightCamera
+ },
+ // Event Source will be set by the Qt3DQuickWindow
+ InputSettings { }
+ ]
+
+
+ AdsEffect {
+ id: shadowMapEffect
+
+ shadowTexture: framegraph.shadowTexture
+ light: light
+ }
+
+
+ // Trefoil knot entity
+ Trefoil {
+ material: AdsMaterial {
+ effect: shadowMapEffect
+ specularColor: Qt.rgba(0.5, 0.5, 0.5, 1.0)
+ }
+ }
+
+ // Toyplane entity
+ Toyplane {
+ material: AdsMaterial {
+ effect: shadowMapEffect
+ diffuseColor: Qt.rgba(0.9, 0.5, 0.3, 1.0)
+ shininess: 75
+ }
+ }
+
+ // Plane entity
+ GroundPlane {
+ material: AdsMaterial {
+ effect: shadowMapEffect
+ diffuseColor: Qt.rgba(0.2, 0.5, 0.3, 1.0)
+ specularColor: Qt.rgba(0, 0, 0, 1.0)
+ }
+ }
+}
diff --git a/tests/manual/shadow-map-qml/shaders/ads.frag b/tests/manual/shadow-map-qml/shaders/ads.frag
new file mode 100644
index 000000000..2d8318282
--- /dev/null
+++ b/tests/manual/shadow-map-qml/shaders/ads.frag
@@ -0,0 +1,60 @@
+// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#version 150 core
+
+uniform mat4 viewMatrix;
+
+uniform vec3 lightPosition;
+uniform vec3 lightIntensity;
+
+uniform vec3 ka; // Ambient reflectivity
+uniform vec3 kd; // Diffuse reflectivity
+uniform vec3 ks; // Specular reflectivity
+uniform float shininess; // Specular shininess factor
+
+uniform sampler2DShadow shadowMapTexture;
+
+in vec4 positionInLightSpace;
+
+in vec3 position;
+in vec3 normal;
+
+out vec4 fragColor;
+
+vec3 dsModel(const in vec3 pos, const in vec3 n)
+{
+ // Calculate the vector from the light to the fragment
+ vec3 s = normalize(vec3(viewMatrix * vec4(lightPosition, 1.0)) - pos);
+
+ // Calculate the vector from the fragment to the eye position
+ // (origin since this is in "eye" or "camera" space)
+ vec3 v = normalize(-pos);
+
+ // Reflect the light beam using the normal at this fragment
+ vec3 r = reflect(-s, n);
+
+ // Calculate the diffuse component
+ float diffuse = max(dot(s, n), 0.0);
+
+ // Calculate the specular component
+ float specular = 0.0;
+ if (dot(s, n) > 0.0)
+ specular = pow(max(dot(r, v), 0.0), shininess);
+
+ // Combine the diffuse and specular contributions (ambient is taken into account by the caller)
+ return lightIntensity * (kd * diffuse + ks * specular);
+}
+
+void main()
+{
+ float shadowMapSample = textureProj(shadowMapTexture, positionInLightSpace);
+
+ vec3 ambient = lightIntensity * ka;
+
+ vec3 result = ambient;
+ if (shadowMapSample > 0)
+ result += dsModel(position, normalize(normal));
+
+ fragColor = vec4(result, 1.0);
+}
diff --git a/tests/manual/shadow-map-qml/shaders/ads.vert b/tests/manual/shadow-map-qml/shaders/ads.vert
new file mode 100644
index 000000000..017fa0082
--- /dev/null
+++ b/tests/manual/shadow-map-qml/shaders/ads.vert
@@ -0,0 +1,33 @@
+// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#version 150 core
+
+in vec3 vertexPosition;
+in vec3 vertexNormal;
+
+out vec4 positionInLightSpace;
+out vec3 position;
+out vec3 normal;
+
+uniform mat4 lightViewProjection;
+uniform mat4 modelMatrix;
+uniform mat4 modelView;
+uniform mat3 modelViewNormal;
+uniform mat4 mvp;
+
+void main()
+{
+ // positionInLightSpace = lightViewProjection * modelMatrix * vec4(vertexPosition, 1.0);
+ const mat4 shadowMatrix = mat4(0.5, 0.0, 0.0, 0.0,
+ 0.0, 0.5, 0.0, 0.0,
+ 0.0, 0.0, 0.5, 0.0,
+ 0.5, 0.5, 0.5, 1.0);
+
+ positionInLightSpace = shadowMatrix * lightViewProjection * modelMatrix * vec4(vertexPosition, 1.0);
+
+ normal = normalize(modelViewNormal * vertexNormal);
+ position = vec3(modelView * vec4(vertexPosition, 1.0));
+
+ gl_Position = mvp * vec4(vertexPosition, 1.0);
+}
diff --git a/tests/manual/shadow-map-qml/shaders/es3/ads.frag b/tests/manual/shadow-map-qml/shaders/es3/ads.frag
new file mode 100644
index 000000000..8a59268ac
--- /dev/null
+++ b/tests/manual/shadow-map-qml/shaders/es3/ads.frag
@@ -0,0 +1,59 @@
+#version 300 es
+
+precision highp float;
+
+uniform mat4 viewMatrix;
+
+uniform vec3 lightPosition;
+uniform vec3 lightIntensity;
+
+uniform vec3 ka; // Ambient reflectivity
+uniform vec3 kd; // Diffuse reflectivity
+uniform vec3 ks; // Specular reflectivity
+uniform float shininess; // Specular shininess factor
+
+uniform highp sampler2DShadow shadowMapTexture;
+
+in vec4 positionInLightSpace;
+
+in vec3 position;
+in vec3 normal;
+
+out vec4 fragColor;
+
+vec3 dsModel(const in vec3 pos, const in vec3 n)
+{
+ // Calculate the vector from the light to the fragment
+ vec3 s = normalize(vec3(viewMatrix * vec4(lightPosition, 1.0)) - pos);
+
+ // Calculate the vector from the fragment to the eye position
+ // (origin since this is in "eye" or "camera" space)
+ vec3 v = normalize(-pos);
+
+ // Reflect the light beam using the normal at this fragment
+ vec3 r = reflect(-s, n);
+
+ // Calculate the diffuse component
+ float diffuse = max(dot(s, n), 0.0);
+
+ // Calculate the specular component
+ float specular = 0.0;
+ if (dot(s, n) > 0.0)
+ specular = pow(max(dot(r, v), 0.0), shininess);
+
+ // Combine the diffuse and specular contributions (ambient is taken into account by the caller)
+ return lightIntensity * (kd * diffuse + ks * specular);
+}
+
+void main()
+{
+ float shadowMapSample = textureProj(shadowMapTexture, positionInLightSpace);
+
+ vec3 ambient = lightIntensity * ka;
+
+ vec3 result = ambient;
+ if (shadowMapSample > 0.0)
+ result += dsModel(position, normalize(normal));
+
+ fragColor = vec4(result, 1.0);
+}
diff --git a/tests/manual/shadow-map-qml/shaders/es3/ads.vert b/tests/manual/shadow-map-qml/shaders/es3/ads.vert
new file mode 100644
index 000000000..9c16eb07d
--- /dev/null
+++ b/tests/manual/shadow-map-qml/shaders/es3/ads.vert
@@ -0,0 +1,30 @@
+#version 300 es
+
+in vec3 vertexPosition;
+in vec3 vertexNormal;
+
+out vec4 positionInLightSpace;
+out vec3 position;
+out vec3 normal;
+
+uniform mat4 lightViewProjection;
+uniform mat4 modelMatrix;
+uniform mat4 modelView;
+uniform mat3 modelViewNormal;
+uniform mat4 mvp;
+
+void main()
+{
+ // positionInLightSpace = lightViewProjection * modelMatrix * vec4(vertexPosition, 1.0);
+ const mat4 shadowMatrix = mat4(0.5, 0.0, 0.0, 0.0,
+ 0.0, 0.5, 0.0, 0.0,
+ 0.0, 0.0, 0.5, 0.0,
+ 0.5, 0.5, 0.5, 1.0);
+
+ positionInLightSpace = shadowMatrix * lightViewProjection * modelMatrix * vec4(vertexPosition, 1.0);
+
+ normal = normalize(modelViewNormal * vertexNormal);
+ position = vec3(modelView * vec4(vertexPosition, 1.0));
+
+ gl_Position = mvp * vec4(vertexPosition, 1.0);
+}
diff --git a/tests/manual/shadow-map-qml/shaders/es3/shadowmap.frag b/tests/manual/shadow-map-qml/shaders/es3/shadowmap.frag
new file mode 100644
index 000000000..93ced265c
--- /dev/null
+++ b/tests/manual/shadow-map-qml/shaders/es3/shadowmap.frag
@@ -0,0 +1,7 @@
+#version 300 es
+
+precision highp float;
+
+void main()
+{
+}
diff --git a/tests/manual/shadow-map-qml/shaders/es3/shadowmap.vert b/tests/manual/shadow-map-qml/shaders/es3/shadowmap.vert
new file mode 100644
index 000000000..4745c7214
--- /dev/null
+++ b/tests/manual/shadow-map-qml/shaders/es3/shadowmap.vert
@@ -0,0 +1,10 @@
+#version 300 es
+
+in vec3 vertexPosition;
+
+uniform mat4 mvp;
+
+void main()
+{
+ gl_Position = mvp * vec4(vertexPosition, 1.0);
+}
diff --git a/tests/manual/shadow-map-qml/shaders/rhi/ads.frag b/tests/manual/shadow-map-qml/shaders/rhi/ads.frag
new file mode 100644
index 000000000..c30b34a78
--- /dev/null
+++ b/tests/manual/shadow-map-qml/shaders/rhi/ads.frag
@@ -0,0 +1,89 @@
+// Copyright (C) 2020 Klaralvdalens Datakonsult AB (KDAB).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#version 450
+
+layout(location = 0) in vec4 positionInLightSpace;
+layout(location = 1) in vec3 position;
+layout(location = 2) in vec3 normal;
+
+layout(location = 0) out vec4 fragColor;
+
+layout(std140, binding = 0) uniform qt3d_render_view_uniforms {
+ mat4 viewMatrix;
+ mat4 projectionMatrix;
+ mat4 viewProjectionMatrix;
+ mat4 inverseViewMatrix;
+ mat4 inverseProjectionMatrix;
+ mat4 inverseViewProjectionMatrix;
+ mat4 viewportMatrix;
+ mat4 inverseViewportMatrix;
+ vec4 textureTransformMatrix;
+ vec3 eyePosition;
+ float aspectRatio;
+ float gamma;
+ float exposure;
+ float time;
+};
+
+layout(std140, binding = 1) uniform qt3d_command_uniforms {
+ mat4 modelMatrix;
+ mat4 inverseModelMatrix;
+ mat4 modelView;
+ mat3 modelNormalMatrix;
+ mat4 inverseModelViewMatrix;
+ mat4 mvp;
+ mat4 inverseModelViewProjectionMatrix;
+ mat3 modelViewNormal;
+};
+
+layout(std140, binding = 2) uniform qt3d_custom_uniforms {
+ mat4 lightViewProjection;
+ vec3 lightPosition;
+ vec3 lightIntensity;
+
+ vec3 ka; // Ambient reflectivity
+ vec3 kd; // Diffuse reflectivity
+ vec3 ks; // Specular reflectivity
+ float shininess; // Specular shininess factor
+};
+
+layout(binding = 3) uniform sampler2DShadow shadowMapTexture;
+
+
+vec3 dsModel(const in vec3 pos, const in vec3 n)
+{
+ // Calculate the vector from the light to the fragment
+ vec3 s = normalize(vec3(viewMatrix * vec4(lightPosition, 1.0)) - pos);
+
+ // Calculate the vector from the fragment to the eye position
+ // (origin since this is in "eye" or "camera" space)
+ vec3 v = normalize(-pos);
+
+ // Reflect the light beam using the normal at this fragment
+ vec3 r = reflect(-s, n);
+
+ // Calculate the diffuse component
+ float diffuse = max(dot(s, n), 0.0);
+
+ // Calculate the specular component
+ float specular = 0.0;
+ if (dot(s, n) > 0.0)
+ specular = pow(max(dot(r, v), 0.0), shininess);
+
+ // Combine the diffuse and specular contributions (ambient is taken into account by the caller)
+ return lightIntensity * (kd * diffuse + ks * specular);
+}
+
+void main()
+{
+ float shadowMapSample = textureProj(shadowMapTexture, positionInLightSpace);
+
+ vec3 ambient = lightIntensity * ka;
+
+ vec3 result = ambient;
+ if (shadowMapSample > 0)
+ result += dsModel(position, normalize(normal));
+
+ fragColor = vec4(result, 1.0);
+}
diff --git a/tests/manual/shadow-map-qml/shaders/rhi/ads.vert b/tests/manual/shadow-map-qml/shaders/rhi/ads.vert
new file mode 100644
index 000000000..c4e484883
--- /dev/null
+++ b/tests/manual/shadow-map-qml/shaders/rhi/ads.vert
@@ -0,0 +1,67 @@
+// Copyright (C) 2020 Klaralvdalens Datakonsult AB (KDAB).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#version 450
+
+layout(location = 0) in vec3 vertexPosition;
+layout(location = 1) in vec3 vertexNormal;
+
+layout(location = 0) out vec4 positionInLightSpace;
+layout(location = 1) out vec3 position;
+layout(location = 2) out vec3 normal;
+
+
+layout(std140, binding = 0) uniform qt3d_render_view_uniforms {
+ mat4 viewMatrix;
+ mat4 projectionMatrix;
+ mat4 viewProjectionMatrix;
+ mat4 inverseViewMatrix;
+ mat4 inverseProjectionMatrix;
+ mat4 inverseViewProjectionMatrix;
+ mat4 viewportMatrix;
+ mat4 inverseViewportMatrix;
+ vec4 textureTransformMatrix;
+ vec3 eyePosition;
+ float aspectRatio;
+ float gamma;
+ float exposure;
+ float time;
+};
+
+layout(std140, binding = 1) uniform qt3d_command_uniforms {
+ mat4 modelMatrix;
+ mat4 inverseModelMatrix;
+ mat4 modelView;
+ mat3 modelNormalMatrix;
+ mat4 inverseModelViewMatrix;
+ mat4 mvp;
+ mat4 inverseModelViewProjectionMatrix;
+ mat3 modelViewNormal;
+};
+
+layout(std140, binding = 2) uniform qt3d_custom_uniforms {
+ mat4 lightViewProjection;
+ vec3 lightPosition;
+ vec3 lightIntensity;
+
+ vec3 ka; // Ambient reflectivity
+ vec3 kd; // Diffuse reflectivity
+ vec3 ks; // Specular reflectivity
+ float shininess; // Specular shininess factor
+};
+
+void main()
+{
+ // positionInLightSpace = lightViewProjection * modelMatrix * vec4(vertexPosition, 1.0);
+ const mat4 shadowMatrix = mat4(0.5, 0.0, 0.0, 0.0,
+ 0.0, 0.5, 0.0, 0.0,
+ 0.0, 0.0, 0.5, 0.0,
+ 0.5, 0.5, 0.5, 1.0);
+
+ positionInLightSpace = shadowMatrix * lightViewProjection * modelMatrix * vec4(vertexPosition, 1.0);
+
+ normal = normalize(modelViewNormal * vertexNormal);
+ position = vec3(modelView * vec4(vertexPosition, 1.0));
+
+ gl_Position = mvp * vec4(vertexPosition, 1.0);
+}
diff --git a/tests/manual/shadow-map-qml/shaders/rhi/shadowmap.frag b/tests/manual/shadow-map-qml/shaders/rhi/shadowmap.frag
new file mode 100644
index 000000000..6e0b8a03a
--- /dev/null
+++ b/tests/manual/shadow-map-qml/shaders/rhi/shadowmap.frag
@@ -0,0 +1,8 @@
+// Copyright (C) 2020 Klaralvdalens Datakonsult AB (KDAB).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#version 450
+
+void main()
+{
+}
diff --git a/tests/manual/shadow-map-qml/shaders/rhi/shadowmap.vert b/tests/manual/shadow-map-qml/shaders/rhi/shadowmap.vert
new file mode 100644
index 000000000..277819aef
--- /dev/null
+++ b/tests/manual/shadow-map-qml/shaders/rhi/shadowmap.vert
@@ -0,0 +1,22 @@
+// Copyright (C) 2020 Klaralvdalens Datakonsult AB (KDAB).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#version 450
+
+layout(location = 0) in vec3 vertexPosition;
+
+layout(std140, binding = 1) uniform qt3d_command_uniforms {
+ mat4 modelMatrix;
+ mat4 inverseModelMatrix;
+ mat4 modelView;
+ mat3 modelNormalMatrix;
+ mat4 inverseModelViewMatrix;
+ mat4 mvp;
+ mat4 inverseModelViewProjectionMatrix;
+ mat3 modelViewNormal;
+};
+
+void main()
+{
+ gl_Position = mvp * vec4(vertexPosition, 1.0);
+}
diff --git a/tests/manual/shadow-map-qml/shaders/shadowmap.frag b/tests/manual/shadow-map-qml/shaders/shadowmap.frag
new file mode 100644
index 000000000..31b39e148
--- /dev/null
+++ b/tests/manual/shadow-map-qml/shaders/shadowmap.frag
@@ -0,0 +1,8 @@
+// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#version 150 core
+
+void main()
+{
+}
diff --git a/tests/manual/shadow-map-qml/shaders/shadowmap.vert b/tests/manual/shadow-map-qml/shaders/shadowmap.vert
new file mode 100644
index 000000000..d245cd127
--- /dev/null
+++ b/tests/manual/shadow-map-qml/shaders/shadowmap.vert
@@ -0,0 +1,13 @@
+// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#version 150 core
+
+in vec3 vertexPosition;
+
+uniform mat4 mvp;
+
+void main()
+{
+ gl_Position = mvp * vec4(vertexPosition, 1.0);
+}
diff --git a/tests/manual/shadow-map-qml/shadow-map-qml.qrc b/tests/manual/shadow-map-qml/shadow-map-qml.qrc
new file mode 100644
index 000000000..838766c4d
--- /dev/null
+++ b/tests/manual/shadow-map-qml/shadow-map-qml.qrc
@@ -0,0 +1,24 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ <file>AdsMaterial.qml</file>
+ <file>AdsEffect.qml</file>
+ <file>ShadowMapLight.qml</file>
+ <file>ShadowMapFrameGraph.qml</file>
+ <file>Trefoil.qml</file>
+ <file>Toyplane.qml</file>
+ <file>GroundPlane.qml</file>
+ <file>shaders/ads.frag</file>
+ <file>shaders/ads.vert</file>
+ <file>shaders/shadowmap.frag</file>
+ <file>shaders/shadowmap.vert</file>
+ <file>shaders/es3/ads.frag</file>
+ <file>shaders/es3/ads.vert</file>
+ <file>shaders/es3/shadowmap.frag</file>
+ <file>shaders/es3/shadowmap.vert</file>
+ <file>shaders/rhi/ads.frag</file>
+ <file>shaders/rhi/ads.vert</file>
+ <file>shaders/rhi/shadowmap.frag</file>
+ <file>shaders/rhi/shadowmap.vert</file>
+ </qresource>
+</RCC>