summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Harmer <sean.harmer@kdab.com>2015-06-24 14:05:53 +0200
committerJani Heikkinen <jani.heikkinen@theqtcompany.com>2015-06-25 04:21:23 +0000
commit05e378b2fcbe72725b4736946d65c1290c291d25 (patch)
tree97795821a4bc370074c319414fc693028ded7742
parent1b98284ad0e775c84963385732c93ef0e2d5a0f1 (diff)
Doc: Add some docs for the shadow map example
Change-Id: Iea29c9f654fc57518bf3d428b30fa5955aa1230d Reviewed-by: Sean Harmer <sean.harmer@kdab.com> Reviewed-by: Leena Miettinen <riitta-leena.miettinen@theqtcompany.com>
-rw-r--r--examples/qt3d/shadow-map-qml/doc/images/shadowmapping-depth.pngbin0 -> 23712 bytes
-rw-r--r--examples/qt3d/shadow-map-qml/doc/images/shadowmapping-qt3d.pngbin0 -> 39159 bytes
-rw-r--r--examples/qt3d/shadow-map-qml/doc/src/shadow-map-qml.qdoc240
-rw-r--r--src/core/doc/qt3dcore.qdocconf3
-rw-r--r--src/core/doc/src/qt3d-overview.qdoc86
5 files changed, 324 insertions, 5 deletions
diff --git a/examples/qt3d/shadow-map-qml/doc/images/shadowmapping-depth.png b/examples/qt3d/shadow-map-qml/doc/images/shadowmapping-depth.png
new file mode 100644
index 000000000..d2b501412
--- /dev/null
+++ b/examples/qt3d/shadow-map-qml/doc/images/shadowmapping-depth.png
Binary files differ
diff --git a/examples/qt3d/shadow-map-qml/doc/images/shadowmapping-qt3d.png b/examples/qt3d/shadow-map-qml/doc/images/shadowmapping-qt3d.png
new file mode 100644
index 000000000..bac6ac75c
--- /dev/null
+++ b/examples/qt3d/shadow-map-qml/doc/images/shadowmapping-qt3d.png
Binary files differ
diff --git a/examples/qt3d/shadow-map-qml/doc/src/shadow-map-qml.qdoc b/examples/qt3d/shadow-map-qml/doc/src/shadow-map-qml.qdoc
index 4e55da3b1..fd3377a8b 100644
--- a/examples/qt3d/shadow-map-qml/doc/src/shadow-map-qml.qdoc
+++ b/examples/qt3d/shadow-map-qml/doc/src/shadow-map-qml.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB).
** Contact: http://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
@@ -29,4 +29,242 @@
\example shadow-map-qml
\title Qt3D: Shadow Map QML Example
\ingroup qt3d-examples-qml
+
+ \brief A Qt3D QML application that illustrates how to render a scene in Qt3D
+ with shadows.
+
+ \image shadowmapping-qt3d.png
+
+ \e {Qt3D 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
+ \printuntil Renderer
+
+ 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 framegraph, 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 Light.qml.
+
+ Again, we import the necessary modules:
+
+ \quotefromfile shadow-map-qml/Light.qml
+ \skipto import Qt3D
+ \printuntil Qt3D.Renderer
+
+ 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 Qt3D, the framegraph is the data-driven configuration for the rendering.
+ We implement the framegraph in the \e ShadowMapFrameGraph.qml file.
+
+ In addition to the Qt3D and Qt3D Renderer modules, we also import the
+ Qt Quick module:
+
+ \quotefromfile shadow-map-qml/ShadowMapFrameGraph.qml
+ \skipto import Qt3D
+ \printuntil QtQuick
+
+ The code defines a \l FrameGraph entity that has a tree of entities as the
+ active framegraph:
+
+ \printuntil clearColor
+
+ Any path from the leaves of this tree to the root is a viable framegraph
+ configuration. Filter entities can enable or disable such paths, and
+ selector entities can alter the configuration.
+
+ In our case, the tree looks like this:
+
+ \code
+ Viewport
+ RenderPassFilter
+ RenderTargetSelector
+ ClearBuffer
+ CameraSelector
+ RenderPassFilter
+ ClearBuffer
+ CameraSelector
+ \endcode
+
+ So we have two paths from the topmost \l Viewport entity. Each path
+ corresponds to a pass of the shadow map technique. The paths are enabled and
+ disabled using a RenderPassFilter, an entity that can filter depending on
+ arbitrary values defined in a given render pass. In this example, it is a
+ string:
+
+ \printuntil ]
+
+ The actual passes are not defined here. The framegraph simply modifies its
+ configuration when a given pass is rendered.
+
+ \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 Qt3D, 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.
+
+ \section1 Using Effects
+
+ The bulk of the magic happens in the \e AdsEffect.qml file, where our main
+ \l Effect entity is defined. It implements the Ambient, Diffuse and Specular
+ (ADS) Lightning Model Phong shading with the addition of shadow mapped
+ generated shadows.
+
+ 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 OpenGL shader program uniforms, so that in the
+ shaders we can access them. 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 framegraph:
+
+ \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 Techniques. This allows a
+ \l Material instance to override defaults in an \l Effect or \l Technique.
+ The bindings array provides the same thing, except that it also allows us to
+ rename some parameters. In this example, it renames the \c ambient,
+ \c diffuse, and \c specular values defined in the material to the actual
+ uniform names used by the shader programs:
+
+ \skipto bindings:
+ \printuntil ]
+
+ 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 an \l Annotation entity, matching the ones
+ we specified in the framegraph 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/src/core/doc/qt3dcore.qdocconf b/src/core/doc/qt3dcore.qdocconf
index 28f985029..923cc1345 100644
--- a/src/core/doc/qt3dcore.qdocconf
+++ b/src/core/doc/qt3dcore.qdocconf
@@ -48,7 +48,8 @@ exampledirs += src/snippets
#excludedirs +=
-imagedirs += images
+imagedirs += images \
+ ../../../examples/qt3d/shadow-map-qml/doc/images
Cpp.ignoretokens += QT3DCORE_PRIVATE_EXPORT \
QT3DINPUTSHARED_EXPORT \
diff --git a/src/core/doc/src/qt3d-overview.qdoc b/src/core/doc/src/qt3d-overview.qdoc
index 74a4c2949..133f6fd14 100644
--- a/src/core/doc/src/qt3d-overview.qdoc
+++ b/src/core/doc/src/qt3d-overview.qdoc
@@ -61,14 +61,14 @@
\li 2D and 3D rendering for C++ and Qt Quick applications
\li Meshes
\li \l {Materials}
- \li Shadows
\li \l {Shaders}
+ \li \l {Shadow Mapping}{Shadow mapping}
\li Ambient occlusion
\li High dynamic range
\li Deferred rendering
\li Multitexturing
- \li Instancing
- \li Uniform Buffer Objects
+ \li \l {Instanced Rendering}{Instanced rendering}
+ \li \l {Uniform Buffer Objects}
\endlist
\section2 Materials
@@ -98,6 +98,86 @@
\l {Qt3D: Shadow Map QML Example}, \l{Qt3D: Wireframe QML Example}, and
\l {Qt3D: Wave QML Example}.
+ \section2 Shadow Mapping
+
+ Shadows are not directly supported by OpenGL, but there are countless
+ techniques that can be employed to generate them. Shadow mapping is simple
+ to use for generating good-looking shadows, while having a very small
+ performance cost.
+
+ Shadow mapping is typically implemented using a two pass rendering. In the
+ first pass, the shadow information is generated. In the second pass, the
+ scene is generated using a particular rendering technique, while at the
+ same time using the information gathered in the first pass to draw the
+ shadows.
+
+ The idea behind shadow mapping is that only the closest fragments to the
+ light are lit. Fragments \e behind other fragments are occluded, and
+ therefore in shadow.
+
+ Therefore, in the first pass, the scene is drawn from the point of view of
+ the light. The information that is stored is simply the distance of the
+ closest fragment in this \e {light space}. In OpenGL terms, this corresponds
+ to having a Framebuffer Object, or FBO, with a depth texture attached to it.
+ In fact, the \e {distance from the eye} is the definition of the depth,
+ and the default depth testing done by OpenGL will actually store only the
+ depth for the closest fragment.
+
+ A color texture attachment is not even needed, because there is no need to
+ shade fragments, only to calculate their depth.
+
+ The following image displays a scene with a self-shadowed plane and trefoil
+ knot:
+
+ \image shadowmapping-qt3d.png
+
+ The following image shows an exaggerated shadow map texture of the scene:
+
+ \image shadowmapping-depth.png
+
+ The image indicates the depth stored when rendering the scene from the light
+ point of view. Darker colors represent a shallow depth (that is, closer to
+ the camera). In this scene, the light is placed somewhere above the objects
+ in the scene, on the right side with respect to the main camera (compare
+ this with the first screenshot). This matches with the fact that the toy
+ plane is closer to the camera than the other objects.
+
+ Once the shadow map has been generated, the second rendering pass is done.
+ In this second pass, rendering is done using the normal scene's camera. Any
+ effect can be used here, such as Phong shading. It is important that the
+ shadow map algorithm is applied in the fragment shader. That is, the
+ fragment that is closest to the light is drawn lit, whereas the other
+ fragments are drawn in shadow.
+
+ The shadow map generated in the first pass provides the necessary
+ information about the distance of fragments to light. It then suffices to
+ remap the fragment in light space, thereby calculating its depth from the
+ light point of view, as well as where its coordinates are on the shadow map
+ texture. The shadow map texture can then be sampled at the given coordinates
+ and the fragment's depth can be compared with the result of the sampling. If
+ the fragment is further away, then it is in shadow; otherwise it is lit.
+
+ For example code, see the \l {Qt3D: Shadow Map QML Example}.
+
+ \section2 Instanced Rendering
+
+ \e Instancing is a way of getting the GPU to draw many copies (instances) of
+ a base object that varies in some way for each copy. Often, in position,
+ orientation, color, material properties, scale, and so on. Qt3D provides an
+ API similar to the Qt Quick \l Repeater element. In this case, the delegate
+ is the base object and the model provides the per-instance data. So whereas
+ an entity with a \l Mesh component attached eventually gets transformed into
+ a call to glDrawElements, an entity with a instanced component will be
+ translated into a call to glDrawElementsInstanced.
+
+ Instanced rendering is planned for a future release.
+
+ \section2 Uniform Buffer Objects
+
+ A Uniform Buffer Object (UBO) can be bound to OpenGL shader programs to make
+ large amounts of data readily available. Typical use cases for UBOs are for
+ sets of material or lighting parameters.
+
\section1 Configurable Renderer
To combine support for both C++ and QML APIs with having a fully