Qt Quick 3D - Scene Effects Example▲
Sélectionnez
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import
QtCore
import
QtQuick.Window
import
QtQuick.Controls
import
QtQuick.Layouts
import
QtQuick.Dialogs
import
QtQuick3D
import
QtQuick3D.Helpers
import
QtQuick3D.AssetUtils
Window
{
visible
:
true
width
:
1280
height
:
720
property
url
importUrl
SettingsPage {
id
:
settingsPage
camera
:
view3D.camera
sceneEnvironment
:
env
anchors.left
:
parent.left
anchors.top
:
pane.bottom
anchors.bottom
:
parent.bottom
implicitWidth
:
420
color
:
&
quot;lightGray&
quot;
lutTexture
:
lutSourceTexture
}
View3D {
id
:
view3D
anchors.top
:
pane.bottom
anchors.bottom
:
parent.bottom
anchors.left
:
settingsPage.right
anchors.right
:
parent.right
environment
:
ExtendedSceneEnvironment {
id
:
env
backgroundMode
:
SceneEnvironment.SkyBox
lightProbe
:
Texture {
textureData
:
ProceduralSkyTextureData{}
}
InfiniteGrid {
visible
:
helper.gridEnabled
gridInterval
:
helper.gridInterval
}
skyboxBlurAmount
:
0.1
exposure
:
1.0
lensFlareBloomBias
:
2.75
lensFlareApplyDirtTexture
:
true
lensFlareApplyStarburstTexture
:
true
lensFlareCameraDirection
:
view3D.camera.forward
lutTexture
:
lutSourceTexture
Texture {
id
:
lutSourceTexture
source
:
&
quot;qrc
:/
luts/
identity.png&
quot;
}
fog
:
Fog {
}
}
camera
:
helper.orbitControllerEnabled ? orbitCamera :
wasdCamera
DirectionalLight {
eulerRotation.x
:
-
35
eulerRotation.y
:
-
90
castsShadow
:
true
}
Node {
id
:
orbitCameraNode
PerspectiveCamera {
id
:
orbitCamera
}
}
PerspectiveCamera {
id
:
wasdCamera
onPositionChanged
: {
// Near/far logic copied from OrbitController
let distance =
position.length
(
)
if (
distance &
lt;
1
) {
clipNear =
0
.
01
clipFar =
100
}
else if (
distance &
lt;
100
) {
clipNear =
0
.
1
clipFar =
1000
}
else {
clipNear =
1
clipFar =
10000
}
}
}
function
resetView() {
if (
importNode.
status
!==
RuntimeLoader.
Error) {
helper.resetController
(
)
}
}
function
resetModel() {
importUrl =
&
quot;&
quot;
helper.updateBounds
(
defaultModel.
bounds)
resetView
(
)
}
RandomInstancing {
id
:
instancing
instanceCount
:
30
position
:
InstanceRange {
property
alias
boundsDiameter
:
helper.boundsDiameter
from
:
Qt.vector3d(-
3
*
boundsDiameter, -
3
*
boundsDiameter, -
3
*
boundsDiameter);
to
:
Qt.vector3d(3
*
boundsDiameter, 3
*
boundsDiameter, 3
*
boundsDiameter)
}
color
:
InstanceRange {
from
:
&
quot;black&
quot;; to
:
&
quot;white&
quot; }
}
QtObject
{
id
:
helper
property
real
boundsDiameter
:
0
property
vector3d
boundsCenter
property
vector3d
boundsSize
property
bool
orbitControllerEnabled
:
true
property
bool
gridEnabled
:
gridButton.checked
property
real
cameraDistance
:
orbitControllerEnabled ? orbitCamera.z :
wasdCamera.position.length()
property
real
gridInterval
:
Math.pow(10
, Math.round(Math.log10(cameraDistance)) -
1
)
function
updateBounds(bounds) {
boundsSize =
Qt.vector3d
(
bounds.
maximum.
x -
bounds.
minimum.
x,
bounds.
maximum.
y -
bounds.
minimum.
y,
bounds.
maximum.
z -
bounds.
minimum.
z)
boundsDiameter =
Math.max
(
boundsSize.
x,
boundsSize.
y,
boundsSize.
z)
boundsCenter =
Qt.vector3d
((
bounds.
maximum.
x +
bounds.
minimum.
x) /
2
,
(
bounds.
maximum.
y +
bounds.
minimum.
y) /
2
,
(
bounds.
maximum.
z +
bounds.
minimum.
z) /
2
)
wasdController.
speed =
boundsDiameter /
1000
.
0
wasdController.
shiftSpeed =
3
*
wasdController.
speed
wasdCamera.
clipNear =
boundsDiameter /
100
wasdCamera.
clipFar =
boundsDiameter *
10
view3D.resetView
(
)
}
function
resetController() {
orbitCameraNode.
eulerRotation =
Qt.vector3d
(-
5
,
0
,
0
)
orbitCameraNode.
position =
boundsCenter
orbitCamera.
position =
Qt.vector3d
(
0
,
0
,
2
*
helper.
boundsDiameter)
orbitCamera.
eulerRotation =
Qt.vector3d
(
0
,
0
,
0
)
orbitControllerEnabled =
true
}
function
switchController(useOrbitController) {
if (
useOrbitController) {
let wasdOffset =
wasdCamera.
position.minus
(
boundsCenter)
let wasdDistance =
wasdOffset.length
(
)
let wasdDistanceInPlane =
Qt.vector3d
(
wasdOffset.
x,
0
,
wasdOffset.
z).length
(
)
let yAngle =
Math.atan2
(
wasdOffset.
x,
wasdOffset.
z) *
180
/
Math.
PI
let xAngle =
-
Math.atan2
(
wasdOffset.
y,
wasdDistanceInPlane) *
180
/
Math.
PI
orbitCameraNode.
position =
boundsCenter
orbitCameraNode.
eulerRotation =
Qt.vector3d
(
xAngle,
yAngle,
0
)
orbitCamera.
position =
Qt.vector3d
(
0
,
0
,
wasdDistance)
orbitCamera.
eulerRotation =
Qt.vector3d
(
0
,
0
,
0
)
}
else {
wasdCamera.
position =
orbitCamera.
scenePosition
wasdCamera.
rotation =
orbitCamera.
sceneRotation
wasdController.
focus
=
true
}
orbitControllerEnabled =
useOrbitController
}
}
RuntimeLoader {
id
:
importNode
source
:
importUrl
instancing
:
instancingButton.checked ? instancing :
null
onBoundsChanged
:
helper.updateBounds(bounds)
}
Model {
id
:
defaultModel
source
:
&
quot;#Sphere&
quot;
visible
:
importNode.status ===
RuntimeLoader.Empty
instancing
:
instancingButton.checked ? instancing :
null
onBoundsChanged
:
helper.updateBounds(bounds)
materials
:
PrincipledMaterial {
baseColor
:
&
quot;green&
quot;
}
scale
:
Qt.vector3d(helper.boundsSize.x /
100
,
helper.boundsSize.y /
100
,
helper.boundsSize.z /
100
)
}
Model {
parent
:
importNode
source
:
&
quot;#Cube&
quot;
materials
:
PrincipledMaterial {
baseColor
:
&
quot;red&
quot;
}
opacity
:
0.2
visible
:
visualizeButton.checked &
amp;&
amp; importNode.status !==
RuntimeLoader.Error
}
Rectangle
{
id
:
messageBox
visible
:
importNode.status ===
RuntimeLoader.Error
color
:
&
quot;red&
quot;
width
:
parent.width *
0.8
height
:
parent.height *
0.8
anchors.centerIn
:
parent
radius
:
Math.min(width
, height
) /
10
opacity
:
0.6
Text
{
anchors.fill
:
parent
font.pixelSize
:
36
text
:
&
quot;Status
:
&
quot; +
importNode.errorString +
&
quot;\nPress \&
quot;Import...\&
quot; to
import
a model
&
quot;
color
:
&
quot;white&
quot;
wrapMode
:
Text.Wrap
horizontalAlignment
:
Text.AlignHCenter
verticalAlignment
:
Text.AlignVCenter
}
}
}
OrbitCameraController {
id
:
orbitController
origin
:
orbitCameraNode
anchors.fill
:
view3D
camera
:
orbitCamera
enabled
:
helper.orbitControllerEnabled
}
WasdController {
id
:
wasdController
anchors.fill
:
view3D
controlledObject
:
wasdCamera
enabled
:
!
helper.orbitControllerEnabled
}
Rectangle
{
id
:
pane
width
:
parent.width
anchors.top
:
parent.top
height
:
controlsLayout.implicitHeight *
1.20
color
:
&
quot;lightGray&
quot;
RowLayout
{
id
:
controlsLayout
anchors.verticalCenter
:
parent.verticalCenter
Button
{
id
:
importButton
text
:
&
quot;Import...&
quot;
onClicked
:
fileDialog.open()
focusPolicy
:
Qt.NoFocus
}
Button
{
id
:
resetModel
text
:
&
quot;ResetModel&
quot;
onClicked
:
view3D.resetModel()
focusPolicy
:
Qt.NoFocus
}
Button
{
id
:
resetButton
text
:
&
quot;Reset view
&
quot;
onClicked
:
view3D.resetView()
focusPolicy
:
Qt.NoFocus
}
Button
{
id
:
visualizeButton
checkable
:
true
text
:
&
quot;Visualize bounds&
quot;
focusPolicy
:
Qt.NoFocus
}
Button
{
id
:
instancingButton
checkable
:
true
text
:
&
quot;Instancing&
quot;
focusPolicy
:
Qt.NoFocus
}
Button
{
id
:
gridButton
text
:
&
quot;Show grid&
quot;
focusPolicy
:
Qt.NoFocus
checkable
:
true
checked
:
false
}
Button
{
id
:
controllerButton
text
:
helper.orbitControllerEnabled ? &
quot;Orbit&
quot; :
&
quot;WASD&
quot;
onClicked
:
helper.switchController(!
helper.orbitControllerEnabled)
focusPolicy
:
Qt.NoFocus
}
RowLayout
{
Label
{
text
:
&
quot;Material Override&
quot;
}
ComboBox
{
id
:
materialOverrideComboBox
textRole
:
&
quot;text
&
quot;
valueRole
:
&
quot;value
&
quot;
implicitContentWidthPolicy
:
ComboBox.WidestText
onActivated
:
env.debugSettings.materialOverride =
currentValue
Component.onCompleted
:
materialOverrideComboBox.currentIndex =
materialOverrideComboBox.indexOfValue(env.debugSettings.materialOverride)
model
:
[
{
value
:
DebugSettings.None, text
:
&
quot;None&
quot;}
,
{
value
:
DebugSettings.BaseColor, text
:
&
quot;Base Color&
quot;}
,
{
value
:
DebugSettings.Roughness, text
:
&
quot;Roughness&
quot;}
,
{
value
:
DebugSettings.Metalness, text
:
&
quot;Metalness&
quot;}
,
{
value
:
DebugSettings.Diffuse, text
:
&
quot;Diffuse&
quot;}
,
{
value
:
DebugSettings.Specular, text
:
&
quot;Specular&
quot;}
,
{
value
:
DebugSettings.ShadowOcclusion, text
:
&
quot;Shadow Occlusion&
quot;}
,
{
value
:
DebugSettings.Emission, text
:
&
quot;Emission&
quot;}
,
{
value
:
DebugSettings.AmbientOcclusion, text
:
&
quot;Ambient Occlusion&
quot;}
,
{
value
:
DebugSettings.Normals, text
:
&
quot;Normals&
quot;}
,
{
value
:
DebugSettings.Tangents, text
:
&
quot;Tangents&
quot;}
,
{
value
:
DebugSettings.Binormals, text
:
&
quot;Binormals&
quot;}
,
{
value
:
DebugSettings.F0, text
:
&
quot;F0&
quot;}
]
}
}
CheckBox
{
text
:
&
quot;Wireframe&
quot;
checked
:
env.debugSettings.wireframeEnabled
onCheckedChanged
: {
env.
debugSettings.
wireframeEnabled =
checked
}
}
}
}
FileDialog
{
id
:
fileDialog
nameFilters
:
[&
quot;glTF files (*
.gltf *
.glb)&
quot;, &
quot;All files (*
)&
quot;]
onAccepted
:
importUrl =
selectedFile
Settings
{
id
:
fileDialogSettings
category
:
&
quot;QtQuick3D.Examples.RuntimeLoader&
quot;
property
alias
currentFolder
:
fileDialog.currentFolder
}
}
Item
{
width
:
debugViewToggleText.implicitWidth
height
:
debugViewToggleText.implicitHeight
anchors.right
:
parent.right
Label
{
id
:
debugViewToggleText
text
:
&
quot;Click here &
quot; +
(dbg.visible ? &
quot;to
hide DebugView&
quot; :
&
quot;for
DebugView&
quot;)
anchors.right
:
parent.right
anchors.top
:
parent.top
}
MouseArea
{
anchors.fill
:
parent
onClicked
:
dbg.visible =
!
dbg.visible
DebugView {
y
:
debugViewToggleText.height *
2
anchors.right
:
parent.right
source
:
view3D
id
:
dbg
visible
:
false
}
}
}
}