Qt例子学习笔记 - Examples/Qt-6.2.0/qt3d/compute-particles

71 篇文章 4 订阅

main.cpp

#include <QGuiApplication>
#include <QQuickView>
#include <Qt3DRender/qt3drender-config.h>

int main(int argc, char* argv[])
{
    QGuiApplication app(argc, argv);

#if !QT_CONFIG(qt3d_rhi_renderer)
    qputenv("QSG_RHI_BACKEND", "opengl");
#endif
    //QQuickView 类提供了一个用于显示 Qt Quick 用户界面的窗口
    //这是 QQuickWindow 的一个方便的子类,
    //当给定主源文件的 URL 时,它将自动加载和显示 QML 场景。
    //或者,您可以使用 QQmlComponent 实例化您自己的对象并将它们放置在手动设置的 QQuickWindow 中。
    //典型用法:
    /*
        int main(int argc,char *argv[])
        {
            QGuiApplication app(argc,argv);

            QQuickView *view = new  QQuickView;
            view->setSource(QUrl::fromLocalFile("myqmlfile.qml"));
            view->show();
            return app.exe();
        }
    */
    //要接收与使用 QQuickView 加载和执行 QML 相关的错误
    //您可以连接到 statusChanged() 信号并监视 QQuickView::Error。
    //错误可通过 QQuickView::errors() 获得。
    //QQuickView 还管理视图和根对象的大小。
    //默认情况下,resizeMode 是 SizeViewToRootObject,
    //它将加载组件并将其调整为视图的大小。
    //或者,可以将 resizeMode 设置为 SizeRootObjectToView,
    //这会将视图大小调整为根对象的大小。
    QQuickView view;

    view.resize(500, 500);
    view.setResizeMode(QQuickView::SizeRootObjectToView);
    view.setSource(QUrl("qrc:/main.qml"));
    view.show();

    return app.exec();
}

main.qml

import QtQuick 2.0
import QtQuick.Scene3D 2.0
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.1

//一个基本的可视化 QML 类型
//Item 类型是 Qt Quick 中所有可视项的基本类型。
//Qt Quick 中的所有可视项都继承自 Item。
//尽管 Item 对象没有视觉外观,但它定义了所有视觉项的通用属性,
//例如 x 和 y 位置、宽度和高度、锚定和关键处理支持。
//Item 类型可用于将多个项目分组到单个根视觉项目下。 例如:
/*
    import QtQuick 2.0
    Item
    {
        Image
        {
            source: "tile.png"
        }
        Image
        {
            x:80
            width:100
            height:100
            source:"tile.png"
        }
        Image
        {
            x:190
            width:100
            height:100
            fillMode:Image.Tile
            source:"tile.png"
        }
    }
*/
//事件处理
//所有基于 Item 的视觉类型都可以使用 Input Handlers 来处理传入的输入事件(QInputEvent 的子类)
//,例如鼠标、触摸和按键事件。 这是处理事件的首选声明方式。
//处理触摸事件的另一种方法是继承 QQuickItem,
//在构造函数中调用 setAcceptTouchEvents() 并覆盖 touchEvent()。
//接受整个事件以停止向下面的项目交付,并专门抓取所有事件的接触点。
//使用 QPointerEvent::setExclusiveGrabber() 仅抓取某些接触点,并允许进一步传递事件。
//同样,QQuickItem 子类可以调用 setAcceptedMouseButtons() 注册接收鼠标按钮事件
//setAcceptHoverEvents() 接收悬停事件(没有按下按钮时的鼠标移动),
//并覆盖虚拟函数 mousePressEvent()、mouseMoveEvent() 和 mouseReleaseEvent ()。
//那些也可以接受事件以防止进一步交付并同时获得隐式抓取;
//或显式获取 QMouseEvent 携带的单个 QEventPoint。
//通过 Keys 附加属性,所有基于 Item 的视觉类型都可以使用键处理。
//Keys 附加属性提供基本信号,例如按下和释放,以及特定键的信号,例如 spacePressed。
//下面的示例将键盘焦点分配给项目并通过通用 onPressed 处理程序处理左键,
//并通过 onReturnPressed 处理程序处理返回键:
/*
    import QtQuick 2.0
    Item
    {
        focus:true
        Keys.onPressed:(event)=>{
            if(event.key == Qt.Key_Left)
            {
                console.log("move left");
                event.accepted = true;
            }
        }
        Keys.onReturnPressed: console.log("Pressed return");
    }
*/
//有关详细文档,请参阅 Keys 附加属性。
//布局镜像
//可以使用 LayoutMirroring 附加属性来镜像项目布局。
//这会导致锚点水平反转,也会导致布置或定位其子项(例如 ListView 或 Row)的项目水平反转其布局的方向。
//有关更多详细信息,请参阅 LayoutMirroring。
//项目层
//一个 Item 通常会直接渲染到它所属的窗口中
//。 但是,通过设置 layer.enabled,可以将项目及其整个子树委托到offscreen surface。
//只有offscreen surface,一个纹理,才会被绘制到窗口中。
//如果需要与项目的纹理大小不同的纹理大小,可以使用 layer.textureSize。
//要仅将项目的一部分渲染到纹理中,请使用 layer.sourceRect。
//也可以指定 layer.sourceRect 使其超出项目的边界。
//在这种情况下,外部将填充透明像素。
//如果 layer.smooth 设置为 true,
//该项目将使用线性插值进行缩放
//如果 layer.mipmap 设置为 true,则该项目将使用 mipmap 进行下采样。
//Mipmapping 可以提高缩小项目的视觉质量
//对于单个 Image 项的 mipmapping,首选 Image::mipmap。
//图层不透明度与项目不透明度
//将不透明度应用于项目层次结构时,不透明度将单独应用于每个项目。
//当不透明度应用于子树时,这可能会导致不希望的视觉结果。
//考虑以下示例:
/*
    //不分层不透明度
    Item
    {
        id:nonLayered
        opacity:0.5

        width:100
        height:100

        Rectangle{ width:80; height:80;border.width:1}
        Rectangle{ x:20;y:20;width:80;height:80;border.width:1}
    }
    显示透明
*/

//以根项目的不透明度为 1 渲染图层,然后在绘制时将根项目的不透明度应用于纹理。
//这意味着可以在大型项目层次结构中从透明淡化到不透明
//反之亦然,可以在没有正常项目逐项目 alpha 混合所具有的重叠伪影的情况下完成。
//这是启用图层的相同示例:
/*
    分层不透明度
    Item
    {
        id: layered
        opacity:0.5
        layer.enabled:true

        width:100
        height:100

        Rectangle { width:80;height:80;border.width:1}
        Rectangle { x:20;y:20;width:80;height:80;border.width:1}
    }
    显示不透明
*/
//Combined with ShaderEffects
//将 layer.enabled 设置为 true 会将项目转换为纹理提供程序
//,从而可以将项目直接用作纹理,例如与 ShaderEffect 类型结合使用。
//可以在运行时使用 layer.effect 对图层应用效果:
/*
    Item
    {
        id:layerRoot
        layer.enabled = true
        layer.effect:ShaderEffect
        {
            fragmentShader:"effect.frag.qsb"
        }
    }
*/
//有关使用效果的更多信息,请参见 ShaderEffect。
//注意: layer.enabled 实际上只是一种更方便的使用 ShaderEffectSource 的方式。

//内存和性能
//当项目的层被启用时,场景图将在 GPU 中分配等于宽 x 高 x 4 的内存。在内存受限的配置中,应谨慎使用大层。
//在 QPainter / QWidget 世界中,有时在像素图、图像或纹理中缓存复杂内容是有利的。
//在 Qt Quick 中,由于场景图渲染器已经应用了这些技术,因此在大多数情况下并非如此。
//由于批处理已经减少了过多的绘制调用,并且在大多数情况下,缓存最终会混合比原始内容更多的像素。
//因此,渲染到屏幕外的开销以及绘制结果纹理所涉及的混合通常比简单地让项目及其子项正常绘制成本更高。
//此外,在渲染过程中无法对使用图层的项目进行批处理。
//这意味着具有许多分层项目的场景可能存在性能问题。
//分层对于视觉效果来说非常方便和有用
//但在大多数情况下应该在效果的持续时间内启用并在之后禁用。
//Property Documentation

//implicitHeight : real
//implicitWidth : real

//如果未指定宽度或高度,则定义项目的自然宽度或高度。
//大多数项目的默认隐式大小为 0x0,但是有些项目具有无法覆盖的固有隐式大小,例如,图像和文本。
//设置隐式大小对于根据内容定义具有首选大小的组件很有用,例如:
/*
    //Label.qml
    import QtQuick 2.0
    Item
    {
        property alias icon:Image.source
        property alias label:text.text
        implicitWidth: text.implicitWidth + image.implicitWidth
        implicitHeight:Math.max(text.implicitHeight,image.implicitHeight)
        Image{id:image}
        Text
        {
            id:text
            wrapMode:Text.Wrap
            anchors.left:image.right;anchors.right:parent.right
            anchors.verticalCenter:parent.varticalCenter
        }
    }
*/

//注意:使用implicitWidth of Text 或TextEdit 并显式设置宽度会导致性能损失,因为文本必须布局两次

//height : real
//width : real
//x : real
//y : real

//定义项目的位置和大小。 默认值为 0。
//(x,y) 位置是相对于父级的。
//Item{x:100;y:100;width:100;height:100}

//children : list<Item>
//resources : list<Object>
//children 属性包含此项的可视子项列表。 
//resources 属性包含要按名称引用的非可视资源。

//添加子项或资源时通常不需要引用这些属性
//因为默认数据属性会根据需要自动将子对象分配给子项和资源属性。

//aciveFocus:bool

//此只读属性指示项目是否具有活动焦点。
//如果 activeFocus 为 true,则此项要么是当前接收键盘输入的项
//要么是当前接收键盘输入的项的 FocusScope 祖先。
//通常,通过将焦点设置在一个项目及其封闭的 FocusScope 对象上来获得 activeFocus。
//在以下示例中, input 和 focusScope 对象将具有活动焦点,而根矩形对象则没有。

/*
    import QtQuick 2.0
    Rectangle
    {
        width:100;height:100
        FocusScore
        {
            id:focusScope
            focus:true

            TextInput
            {
                id:input
                focus:true
            }
        }
    }
*/

//activeFocusOnTab : bool

//此属性保存项目是否要位于选项卡焦点链中。 默认情况下,这设置为 false。
//选项卡焦点链通过首先访问父元素,然后按照它们在 children 属性中出现的顺序访问其子元素来遍历元素。
//在选项卡焦点链中的项目上按下选项卡键会将键盘焦点移动到链中的下一个项目。
//按 BackTab(通常是 Shift+Tab)会将焦点移到上一项。
//要设置手动选项卡焦点链,请参阅 KeyNavigation。
//Keys 或 KeyNavigation 使用的 Tab 键事件优先于焦点链行为;
//忽略其他键处理程序中的事件以允许它传播。


//anchors group
//anchors.alignWhenCentered : bool
//anchors.baseline : AnchorLine
//anchors.baselineOffset : real
//anchors.bottom : AnchorLine
//anchors.bottomMargin : real
//anchors.centerIn : Item
//anchors.fill : Item
//anchors.horizontalCenter : AnchorLine
//anchors.horizontalCenterOffset : real
//anchors.left : AnchorLine
//anchors.leftMargin : real
//anchors.margins : real
//anchors.right : AnchorLine
//anchors.rightMargin : real
//anchors.top : AnchorLine
//anchors.topMargin : real
//anchors.verticalCenter : AnchorLine
//anchors.verticalCenterOffset : real

//锚点提供了一种通过指定项目与其他项目的关系来定位项目的方法。
//边距适用于顶部、底部、左侧、右侧和填充锚点。
//anchors.margins 属性可用于一次将所有不同的边距设置为相同的值。
//它不会覆盖先前设置的特定边距;
//清除显式边距将其值设置为未定义。
//请注意,边距是特定于锚点的,如果项目不使用锚点,则不会应用边距。
//偏移适用于水平中心、垂直中心和基线锚点。


//文本锚定到图像,水平居中,垂直下方,有边距。
/*
Item
{
    Image
    {
        id:pic
        //...
    }
    Text
    {
        id:label
        anchors.horizontalCenter:pic.horizontalCenter
        anchors.top:pic.bottom
        anchors.topMargin:5
        //...
    }
}
*/

//文本的左侧锚定在图像的右侧,有一个边距。 两者的 y 属性默认为 0。
/*
Item
{
    Image
    {
        id:pic
        //..
    }
    Text
    {
        id:label
        anchors.left:pic.right
        anchors.leftMargin:5
        //...
    }
}
*/

//anchors.fill 为一个 item 与另一个 item 具有相同的几何形状提供
//了一种方便的方式,相当于连接了所有四个定向锚点。
//要清除锚值,请将其设置为undefined。
//anchors.alignWhenCentered(默认为true)强制居中的anchors与整个像素对齐;
//如果居中的项目具有奇数的宽度或高度,则项目将定位在整个像素上,而不是放置在半个像素上。
//这确保了该项目被清晰显示。
//在某些情况下这是不可取的,例如当旋转项目时,由于中心是圆形的,抖动可能很明显。
//注意:您只能将项目锚定到兄弟姐妹或父项。

//antialiasing : bool

//由视觉元素用来决定项目是否应该使用抗锯齿。
//在某些情况下,具有抗锯齿功能的项目需要更多内存,并且渲染速度可能较慢(有关更多详细信息,请参阅抗锯齿)。
//默认值为 false,但可能会被派生元素覆盖。

//baselineOffset : int
//指定项目基线在本地坐标中的位置。
//文本项的基线是文本所在的假想线。 包含文本的控件通常将其基线设置为其文本的基线
//对于非文本项目,使用默认基线偏移量 0。

childrenRect group


//[read-only] childrenRect.height : real
//[read-only] childrenRect.width : real
//[read-only] childrenRect.x : real
//[read-only] childrenRect.y : real

//此只读属性保存项目子项的集体位置和大小
//如果您需要访问项的子项的集合几何以正确调整项的大小,则此属性很有用。
//返回的几何图形是项目本地的。 例如:
/*
item
{
    x:50
    y:100

    //prints:QRectF(-10,-20,30,40)
    Component.onCompleted:print(childrenRect)

    Item
    {
        x:-10
        y:-20
        width:30
        height:40
    }
}
*/

//clip : bool

//此属性保存是否启用剪辑。 默认剪辑值为 false。
//如果启用了裁剪,则项目会将其自己的绘画以及其子项的绘画裁剪到其边界矩形。

//[since 5.11] containmentMask : QObject*
//该属性为在 QtQuick::Item::contains() 方法中使用的 Item 持有一个可选掩码。
//它目前的主要用途是确定pointer event是否已进入项目。
//默认情况下,对于 Item 边界框中的任何点, contains 方法都将返回 true。
//containsMask 允许更细粒度的控制。
//例如,如果使用具有专用 contains() 方法的自定义 C++ QQuickItem 子类作为 containsMask:

//Item{id:item;containmentMask:AnotherItem{id:anotherItem}}

//只有当 anotherItem 的 contains() 实现返回 true 时,item 的 contains 方法才会返回 true。
//Shape 可用作遮罩,使项目仅对非矩形区域内的指针事件做出反应:
/*
Rectangle
{
    width:90;height:100
    color:hoverHandler.hovered?"wheat":"lightgray"
    containmentMask:shape

    HoverHandle{id: hoverHandler}

    Shape
    {
        id:shape
        containsMode:Shape.fillContains

        ShapePath
        {
            fillColor:"lightsteelblue"
            startX:10;startY:20
            PathArc
            {
                x:10;y:80
                radiusX:40;radiusY:40
                useLargeArc:true
            }
            PathLine
            {
                x:10;y:20
            }
        }
    }
}
*/

//也可以在 QML 中定义 contains 方法。 例如,要创建一个仅响应其实际范围内的事件的循环项:
/*
Rectangle
{
    id:circle
    width:100;height:width
    radius:width/2
    color:tapHandler.pressed?"tomato":hoverHandle.hovered?"darkgray":"lightgray"
    TapHandle{id:tapHandler}
    HoverHandler{id:hoverHandler}

    containmentMask:QtObject
    {
        property alias radius:circle.radius
        function contains(point:point):bool
        {
            return(Math.pow(point.x - radius,2) + Math.pow(point.y - radius,2)) < Math.pow(radius,2)
        }
    }
}
*/

//[default] data : list<Object>


//data 属性允许您在项目中自由混合可视子项和资源。
//如果您将可视项分配给数据列表,它将成为子项,如果您分配任何其他对象类型,则将其添加为 resource。
//所以你可以写:
/*
Item
{
    Text{}
    Rectangle{}
    Timer{}
}

*/
//代替:
/*
Item
{
    children
    [
        Text{},
        Rectangle{}
    ]
    resources:
    [
        Timer{}
    ]

}
*/

//通常不需要引用 data 属性,因为它是 Item 的默认属性,因此所有子项都会自动分配给此属性。

//enabled:bool

//此属性保存项目是否接收鼠标和键盘事件。 默认情况下这是真的。
//设置此属性直接影响子项的启用值。
//设置为 false 时,所有子项的启用值也变为 false。
//当设置为 true 时,子项的启用值将返回为 true,除非它们已明确设置为 false。
//将此属性设置为 false 会自动导致 activeFocus 设置为 false,并且此项将不再接收键盘事件。


//focus : bool
//此属性保存该项目是否在封闭的 FocusScope 内具有焦点。
//如果为 true,则当封闭的 FocusScope 获得活动焦点时,此项将获得活动焦点。
//在以下示例中,当示波器获得活动焦点时,输入将被给予活动焦点:
/*
    import QtQuick 2.0
    Rectangle
    {
        width:100;height:100

        FocusScope
        {
            id:scope
            TextInput
            {
                id:input
                focus:true
            }
        }
    }
*/

//出于此属性的目的,假设整个场景就像一个焦点范围。
//在实践层面,这意味着以下 QML 将积极关注启动时的输入。

/*
    Rectangle
    {
        width:100;height:100
        TextInput
        {
            id:input
            focus:true
        }
    }
*/

//layer.effect : Component
//保持应用于该层的效果。
//该效果通常是一个 ShaderEffect 组件,尽管可以分配任何 Item 组件。
//该效果应具有名称与 layer.samplerName 匹配的源纹理属性。

//layer.enabled : bool

//保持项目是否分层。 默认情况下禁用分层。
//分层项目被渲染到屏幕外表面并缓存,直到它被更改。
//为复杂的 QML 项层次结构启用分层有时可能是一种优化。
//当图层被禁用时,其他图层属性都没有任何影响。

//layer.format : enumeration
//该属性定义了纹理的内部格式。
//当还指定了 layer.effect 时,修改此属性最有意义。
//根据 OpenGL 实现,此属性可能允许您节省一些纹理内存。

//ShaderEffectSource.Alpha - GL_ALPHA;
//ShaderEffectSource.RGB - GL_RGB
//ShaderEffectSource.RGBA - GL_RGBA

//注意:ShaderEffectSource.RGB 和 ShaderEffectSource.Alpha 应谨慎使用,因为底层硬件和驱动程序通常不支持这些格式。

//layer.mipmap : bool
//如果此属性为 true,则为纹理生成 mipmap。
//注意:某些 OpenGL ES 2 实现不支持非 2 次幂纹理的 mipmapping。


//layer.samplerName : string
//保存效果的源纹理属性的名称。
//此值必须与效果的源纹理属性的名称匹配,以便项目可以正确地将图层的屏幕外表面传递给效果。

//[since 5.10] layer.samples : enumeration
//此属性允许在图层中请求多采样渲染。
//默认情况下,只要为整个窗口启用多重采样,就会启用多重采样,假设正在使用的场景图渲染器和底层图形 API 支持这一点。

//通过将该值设置为 2、4 等,可以为场景的一部分请求多重采样渲染,而无需为整个场景启用多重采样。
//通过这种方式,多重采样仅应用于给定的子树,由于多重采样未应用于场景的其他部分,因此可以显着提高性能。

//注意:无论层的大小如何,启用多重采样都可能很昂贵,因为它会导致硬件和驱动程序相关的性能和内存成本。

//注意:此属性仅在支持多采样渲染缓冲区和帧缓冲区 blit 时有效。 否则,该值将被静默忽略。

//layer.smooth : bool

//保持图层是否平滑变换。启用后,使用线性插值对图层的纹理进行采样,而非平滑会使用最近的过滤模式。


//layer.sourceRect : rect


//该属性定义了应该渲染到纹理中的项目的矩形区域。源矩形可以大于项目本身。
//如果矩形为空(这是默认值),则整个项目将渲染到纹理。

//[since 5.6] layer.textureMirroring : enumeration


//这个属性定义了生成的纹理应该如何被镜像。默认值为 ShaderEffectSource.MirrorVertically。
//如果自定义着色器(例如 ShaderEffect 指定的着色器)直接访问生成的纹理,则自定义镜像会很有用。
//如果没有为分层项目指定效果,则镜像对项目的 UI 表示没有影响。
//ShaderEffectSource.NoMirroring - 无镜像
//ShaderEffectSource.MirrorHorizontally - 生成的纹理沿 X 轴翻转。
//ShaderEffectSource.MirrorVertically - 生成的纹理沿 Y 轴翻转。


//layer.textureSize : size


//此属性保存图层纹理的请求像素大小。 如果它为空,这是默认值,则使用项目的大小。
//注意:某些平台对帧缓冲区对象的大小有限制,这意味着实际纹理大小可能大于请求的大小。

//layer.wrapMode : enumeration

//此属性定义与纹理关联的环绕模式。 当指定 layer.effect 时,修改此属性最有意义。

//ShaderEffectSource.ClampToEdge - GL_CLAMP_TO_EDGE 水平和垂直
//ShaderEffectSource.RepeatHorizontally - 水平方向 GL_REPEAT,垂直方向 GL_CLAMP_TO_EDGE
//ShaderEffectSource.RepeatVertically - GL_CLAMP_TO_EDGE 水平,GL_REPEAT 垂直
//ShaderEffectSource.Repeat - GL_REPEAT 水平和垂直

//opacity : real
//此属性保存项目的不透明度。 不透明度指定为介于 0.0(完全透明)和 1.0(完全不透明)之间的数字。 默认值为 1.0。

//设置此属性后,指定的不透明度也会单独应用于子项。
//在某些情况下,这可能会产生意想不到的影响。
//例如,在下面的第二组矩形中,红色矩形指定的不透明度为 0.5,这会影响其蓝色子矩形的不透明度,即使子矩形未指定不透明度。

/*
    Item
    {
        Rectangle
        {
            color:"red"
            width:100;height:100
            Rectangle
            {
                color:"blue"
                x:50;y:50;width:100;height:100
            }
        }
    }
*/

/*
    Item
    {
        Rectangle
        {
            opacity:0.5
            coloc:"red"
            width:100;height:100
            Rectangle
            {
                color:"blue"
                x:50;y:50;width:100;height:100
            }
        }
    }
*

//更改项目的不透明度不会影响项目是否接收用户输入事件。
//(相反,将可见属性设置为 false 会停止鼠标事件,将 enabled 属性设置为 false 会停止鼠标和键盘事件,并且还会从项目中移除活动焦点。)

//[since 6.0] palette : Palette

//此属性保存当前为项目设置的调色板。
//此属性描述项目请求的调色板。
//调色板在呈现所有控件时由项目的样式使用,可用作确保自定义控件可以与本机平台的本机外观保持一致的一种方式。
//不同的平台或不同的样式为应用程序定义不同的调色板是很常见的。

//默认调色板取决于系统环境。
//ApplicationWindow 维护一个系统/主题调色板,作为所有控件的默认设置。
//某些类型的控件也可能有特殊的调色板默认值。
//您还可以通过以下任一方式设置控件的默认调色板:
//在加载任何 QML 之前,将自定义调色板传递给 QGuiApplication::setPalette();
//或者
在 qtquickcontrols2.conf 文件中指定颜色。
//项目将显式调色板属性从父级传播到子级。
//如果更改项目调色板上的特定属性,该属性将传播到该项目的所有子项,覆盖该属性的任何系统默认值。

/*
    Item
    {
        palette
        {
            buttonText:"maroon"
            button:"lavender"
        }

        Button
        {
            text:"Click Me"
        }
    }
*/

//parent : Item

//此属性保存项目的视觉父级。
//注意:visual parent 的概念与 QObject parent 的概念不同。
//项目的视觉父级不一定与其对象父级相同。
//有关更多详细信息,请参阅概念 - Qt Quick 中的可视化父级。

//rotation : real

//此属性保存项目绕其 transformOrigin 顺时针旋转的度数。默认值为 0 度(即不旋转)。
/*
    Rectangle
    {
        color:"blue"
        width:100;height:100
        Rectangle
        {
            color:"red"
            x:25; y:25;width:50;height:50
            rotation:30
        }
    }
*/
//红色矩形顺时针旋转了30度

//scale : real

//此属性保存此项目的比例因子。
//小于 1.0 的比例会使项目以较小的尺寸呈现,而大于 1.0 的比例会使项目以较大的尺寸呈现。
//负比例会导致项目在渲染时被镜像。
//默认值为 1.0。

/*
import QtQuick 2.0
Rectangle
{
    color:"blue"
    width:100;height:100

    Rectangle
    {
        color:"green"
        width:25;height:25
    }

    Rectangle
    {
        color:"red"
        x:25;y:25;width:50;height:50
        scale:1.4
        transformOrigin:Item.TopLeft
    }
}
*/

//smooth : bool

//主要用于基于图像的项目,以决定项目是否应使用平滑采样。
//使用线性插值执行平滑采样,而使用最近邻执行非平滑采样。
//在 Qt Quick 2.0 中,此属性对性能的影响最小。
//默认情况下,此属性设置为 true。


//state : string
//此属性保存项目当前状态的名称。
//如果该项处于默认状态,即未设置显式状态,则此属性为空字符串。
//同样,您可以通过将此属性设置为空字符串来将项目返回到其默认状态



//states : list<State>
//此属性包含此项目的可能状态列表。
//要更改此项目的状态,请将 state 属性设置为这些状态之一,
//或将 state 属性设置为空字符串以将项目恢复为其默认状态。

//此属性被指定为 State 对象的列表。 例如,下面是一个带有“red_color”和“blue_color”状态的项目:

/*
    import QtQuick 2.0
    Rectangle
    {
        id:root
        width:100;height:100

        states
        [
            State
            {
                name:"red_color"
                PropertyChanges{target:root;color:"red"}
            },
            State
            {
                name:"blue_color"
                PropertyChanges{target:root;color:"blue"}
            }
        ]
    }
*/

//transform : list<Transform>

//此属性包含要应用的转换列表。

//transformOrigin : enumeration
//此属性保存缩放和旋转变换所围绕的原点。
//有九个变换原点可用,如下图所示。 默认变换原点是 Item.Center。
//TopLeft
//Top
//TopRight
//Left 
//Center
//Right
//BottomLeft
//Bottom
//BottomRight

//本示例围绕其右下角旋转图像。
/*
Image
{
    source: "myimage.png"
    transformOrigin:Item.BottomRight
    rotation:45
}
*/

//要设置任意变换原点,请使用带有变换的缩放或旋转变换类型。

//transitions : list<Transition>

//此属性保存此项目的转换列表。这些定义了当项目改变其状态时要应用于项目的转换。
//此属性被指定为 Transition 对象的列表。 例如:
/*
import QtQuick 2.0
Item
{
    transitions:
    [
        Transition{
        ...
        },
        Transition{
        //....
        }
    ]
}
*/

//visible : bool
//此属性保存项目是否可见。默认情况下这是真的。
//设置此属性直接影响子项的可见值。
//设置为 false 时,所有子项的可见值也变为 false。
//当设置为 true 时,子项的可见值将返回为 true,除非它们已明确设置为 false。
//(由于这种流动行为,如果属性绑定只应响应显式属性更改,则使用可见属性可能不会达到预期效果。在这种情况下,最好使用不透明度属性。)

//如果此属性设置为 false,则该项目将不再接收鼠标事件,但会继续接收按键事件,并且如果已设置,则将保留键盘焦点。 (相反,将 enabled 属性设置为 false 会停止鼠标和键盘事件,并且还会从项目中移除焦点。)

//visibleChildren : list<Item>

//此只读属性列出了当前可见的所有项的子项。
//请注意,子项的可见性可能已显式更改,或者因为此(它的父项)或另一个祖父项的可见性已更改。

//z : real
//设置同级项的堆叠顺序。 默认情况下,堆叠顺序为 0。
//具有较高堆叠值的项目绘制在具有较低堆叠顺序的同级项之上。
//具有相同堆叠值的项目按照它们出现的顺序自下而上绘制。
//具有负堆叠值的项目将绘制在其父项的内容下。
//以下示例显示了堆叠顺序的各种效果。
//相同的 z - 较早的孩子之上的较晚的孩子
/*
    Item
    {
        Rectangle
        {
            color:"red"
            width:100
            height:100
        }
        Rectangle
        {
            color:"blue"
            x:50;y:50;width:100;height:100
        }
    }
    //蓝色在红色的上面
*/

//顶部 z 值较高
/*
Item
{
    Rectangle
    {
        z:1
        color:"red"
        width:100
        height:100
    }
    Rectangle
    {
        color:"blue"
        x:50;y:50;width:100;height:100
    }
    //红色在蓝色的上面
}
*/

//相同的 z - 父母之上的孩子:
/*
    Item
    {
        Rectangle
        {
            color:"red"
            width:100;height:100
            Rectangle
            {
                color:"blue"
                x:50;y:50;width:100;height:100
            }
        }
    }
    //蓝色在红色上面
*/

//下面的低 z
/*
    Item
    {
        Rectangle
        {
            color:"red"
            width:100;height:100
            Rectangle
            {
                z:-1
                color:"blue"
                x:50;y:50;width:100;height:100
            }
        }
        //红色在蓝色上面
    }
*/

//Method Documentation



//object mapToItem(Item item, point p)
//object mapToItem(Item item, real x, real y)
//object mapToItem(Item item, real x, real y, real width, real height)
//object mapToItem(Item item, rect r)

//将此项坐标系中的点 (x, y) 或 rect (x, y, width, height) 映射到 item 的坐标系,并返回与映射坐标匹配的点或矩形。
//映射中使用了项目的以下属性:x、y、缩放、旋转、transformOrigin 和变换。
//如果 item 为空值,则将点或矩形映射到根 QML 视图的坐标系。
//接受 point 和 rect 的版本是从 Qt 5.15 开始的。

//将 item 坐标系中的点 (x, y) 或 rect (x, y, width, height) 映射到该 item 的坐标系,并返回与映射坐标匹配的点或矩形。

//映射中使用了项目的以下属性:x、y、缩放、旋转、transformOrigin 和变换。
//如果 item 为空值,则从根 QML 视图的坐标系映射点或矩形。
//接受 point 和 rect 的版本是从 Qt 5.15 开始的。


//childAt(real x, real y)
//返回在此项的坐标系内的点 (x, y) 处找到的第一个可见子项。
如果没有这样的项目,则返回 null//bool contains(point point)
//如果此项包含点,则返回true,该点位于本地坐标中;
//否则返回 false。 这与在事件传递期间用于对 QEventPoint 进行命中测试的检查相同,并且如果设置了containmentMask(),则会受到影响。

//[since 5.1] forceActiveFocus(Qt::FocusReason reason)

//这是一个重载函数
//使用给定的原因强制将注意力集中在项目上。
//此方法将焦点设置在项目上,并确保对象层次结构中的所有祖先 FocusScope 对象也获得焦点。

//forceActiveFocus()
//强制主动关注该项目。
//此方法将焦点设置在项目上,并确保对象层次结构中的所有祖先 FocusScope 对象也获得焦点。
//焦点更改的原因是 Qt::OtherFocusReason。 使用重载方法指定焦点原因,以便更好地处理焦点更改。

//bool grabToImage(callback, targetSize)

//将项目抓取到内存中的图像中。
//抓取是异步发生的,抓取完成后会调用 JavaScript 函数回调。 回调接受一个参数,即抓取操作的结果; 一个 ItemGrabResult 对象。
//使用 targetSize 指定目标图像的大小。 默认情况下,结果将与项目具有相同的大小。
//如果无法启动抓取,则该函数返回 false。
//以下代码段显示了如何抓取项目并将结果存储到文件中。
/*
    Rectangle
    {
        id:source
        width:100
        height:100
        gradient:Gradient
        {
            GradientStop{position:0;color:"steelblue"}
            GradientStop{position:1;color:"black"}
        }
    }
    //..
    source.grabToImage(function(result){
        result.saveToFile("something.png")
    });
*/

//以下代码段展示了如何抓取一个项目并在另一个图像元素中使用结果。

/*
    Image
    {
        id:image
    }
    //...
    source.grabToImage(function(result){
        image.source = result.url;
    },
    Qt.size(50,50));
*/

//注意:此函数会将项目渲染到屏幕外的表面,并将该表面从 GPU 的内存复制到 CPU 的内存中,这可能会非常昂贵。
//对于“实时”预览,请使用图层或 ShaderEffectSource。

//[since 5.7] object mapFromGlobal(real x, real y)

//将全局坐标系中的点 (x, y) 映射到项目的坐标系,并返回与映射坐标匹配的点。
//映射中使用了项目的以下属性:x、y、缩放、旋转、transformOrigin 和变换。
//这个方法是在 Qt 5.7 中引入的。

//[since 5.7] object mapToGlobal(real x, real y)
//将此项坐标系中的点 (x, y) 映射到全局坐标系,并返回与映射坐标匹配的点。
//映射中使用了项目的以下属性:x、y、缩放、旋转、transformOrigin 和变换。

//[since 5.1] nextItemInFocusChain(bool forward)
//返回焦点链中此项目旁边的项目。 如果 forward 为真,或未提供,则它是前进方向的下一项。 如果 forward 为 false,则它是向后方向的下一项。





Item {
    //Scene3D 类型用于将 Qt3D 场景集成到 QtQuick 2 场景中。
    //Scene3D 类型将实体提供的 Qt3D 场景渲染到多采样帧缓冲对象中。
    //此对象稍后被 blit 为非多重采样的 Framebuffer 对象,然后使用预乘 alpha 进行渲染。
    //如果不需要多重采样,可以通过将 multisample 属性设置为 false 来避免。
    //在这种情况下,Scene3D 将直接渲染到非多重采样的 Framebuffer 对象中。
    //如果要渲染的场景包含非不透明材质,您可能需要使用自定义混合参数修改这些材质,以便正确渲染它们。
    //例如,如果使用 PhongAlphaMaterial 和具有不透明透明颜色的场景,您可能需要添加:
    /*
        sourceAlphaArg:BlendEquationArguments.Zero
        destinatiionAlphaArg: BlendEquationArguments.one
    */
    //到那个材料。
    //不建议为每个应用程序实例化多个 Scene3D 实例。
    //这样做的原因是 Scene3D 实例实例化了场景下的整个 Qt 3D 引擎
    //(内存管理器、线程池、渲染...)。

    Scene3D {
        anchors.fill: parent
        //应为 3D 场景注册的方面列表。
        aspects: "input"
        //ParticlesScene.qml
        ParticlesScene {
            id: scene
            particleStep: stepSlider.value
            finalCollisionFactor: collisionSlider.value
        }
    }
    //与 GridLayout 相同,但只有一列。    
    ColumnLayout {
        id: colorLayout
        anchors.left: parent.left
        anchors.leftMargin: 35
        anchors.right: parent.right
        anchors.rightMargin: 35
        anchors.bottom: parent.bottom
        anchors.bottomMargin: 35
        //此属性保存每个单元格之间的间距。 默认值为 5。
        spacing: 15
        //与 GridLayout 相同,但只有一行
        RowLayout {
            Text {
                text: "Particles Step:"
                color: "white"
            }
            //用于通过沿轨道滑动手柄来选择值
            Slider {
                height: 35
                id: stepSlider
                Layout.fillWidth: true
                from: 0.0
                to: 2
                value: 0.4
            }
        }
        RowLayout {
            Text {
                text: "Particles Collision:"
                color: "white"
            }
            Slider {
                height: 35
                id: collisionSlider
                Layout.fillWidth: true
                from: 0.0
                to: 2
                value: 0.2
            }
        }
        RowLayout {
            Button {
                text: "Reset Particles"
               onClicked: scene.reset()
            }
        }
        RowLayout {
            Text {
                text: "Particles Shape:"
                color: "white"
            }
            //互斥的一组可检查按钮
            ButtonGroup {
                exclusive: true
                id: particlesTypeGroup
            }
            //可以打开或关闭的检查按钮
            //CheckBox 提供了一个选项按钮,
            //可以打开(选中)或关闭(未选中)。
            //复选框通常用于从一组选项中选择一个或多个选项。
            //对于更大的选项集,例如列表中的选项,请考虑改用 CheckDelegate。
            //CheckBox 从 AbstractButton 继承其 API。 例如,可以使用checked 属性设置复选框的状态。
            //除了选中和未选中状态之外,还有第三种状态:部分选中。
            //可以使用 tristate 属性启用部分检查状态。
            //此状态表示无法确定常规选中/未选中状态;
            //通常是因为其他影响复选框的状态。
            //如,当在树视图中选择了多个子节点时,此状态很有用。
            /*
                ColumnLayout
                {
                    CheckBox
                    {
                        checked:true
                        text:qsTr("First")
                    }
                    CheckBox
                    {
                        text:qsTr("Second")
                    }
                    CheckBox
                    {
                        checked:true
                        text:qsTr("Third")
                    }
                }
            */

            //可以使用非独占的 ButtonGroup 管理分层复选框组。
            //以下示例说明了如何将子项的组合检查状态绑定到父复选框的检查状态:
            /*
                Column
                {
                    ButtonGroup
                    {
                        id:childGroup
                        exclusive:false
                        checkState:parentBox.checkState
                    }

                    CheckBox
                    {
                        id:parentBox
                        text:qsTr("parent")
                        checkState:childGroup.checkState
                    }

                    CheckBox
                    {
                        checked:true
                        text:qsTr("Child 1")
                        leftPadding:indicator.width
                        ButtonGroup.group:childGroup
                    }

                    CheckBox
                    {
                        text:qsTr("Child 2")
                        leftPadding:indicator.width
                        ButtonGroup.group:childGroup
                    }
                }
            */

            CheckBox {
                text: "Sphere"
                //
                checked: true
                //互斥的一组可检查按钮。
                //ButtonGroup 是一组不可见的、互斥的按钮。 
                //它与 RadioButton 等控件一起使用,其中一次只能选择一个选项。
                
                /*
                    ButtonGroup
                    {
                        buttons:colum.children
                    }
                    Column
                    {
                        id:column
                        RadioButton
                        {
                            checked:true
                            text:qsTr("DAB")
                        }
                        RadioButton
                        {
                            text:qsTr("FM")
                        }
                        RadioButton
                        {
                            text:qsTr("AM")
                        }
                    }
                */
                //互斥按钮并不总是共享同一个父项,
                //或者父布局有时可能包含不应包含在按钮组中的项。
                //这种情况最好使用组附加属性来处理。
                /*
                    ButtonGroup{id:radioGroup}
                    Column
                    {
                        Label
                        {
                            text:qsTr("Radio:")
                        }
                        RadioButton
                        {
                            checked:true
                            text:qsTr("DAB")
                            ButtonGroup.group:radioGroup
                        }
                        RadioButton
                        {
                            text:qsTr("FM")
                            ButtonGroup.group:radioGroup
                        }
                        RadioButton
                        {
                            text:qsTr("AM")
                            ButtonGroup.group:radioGroup
                        }
                    }
                */
                //可以使用 addButton() 和 removeButton() 方法处理更高级的用例。
                ButtonGroup.group: particlesTypeGroup
                onClicked: scene.particlesShape = scene._SPHERE
            }
            CheckBox
            { text: "Cube"
                checked: false
                ButtonGroup.group: particlesTypeGroup
                onClicked: scene.particlesShape = scene._CUBE
            }
            CheckBox {
                text: "Cylinder"
                checked: false
                ButtonGroup.group: particlesTypeGroup
                onClicked: scene.particlesShape = scene._CYLINDER
            }
            CheckBox {
                text: "Torus"
                checked: false
                ButtonGroup.group: particlesTypeGroup
                onClicked: scene.particlesShape = scene._TORUS
            }
        }
    }
}

ComputeFrameGraph.qml

import Qt3D.Core 2.0
import Qt3D.Render 2.9
//Qt3D 场景上的视口
Viewport {
    property alias camera: selector.camera
    //提供一种指定渲染表面的方法
    //RenderSurfaceSelector 可用于选择表面,Qt3D 在此渲染内容。 表面可以是窗口表面或屏幕外表面。
    //externalRenderTargetSize 用于在使用离屏表面时指定渲染目标的实际大小。
    //当系统使用 DPI 缩放时,鼠标事件使用的逻辑表面大小和表面的实际“物理”大小可能不同。
    //surfacePixelRatio 是将逻辑大小转换为物理大小的因子。

    RenderSurfaceSelector {
        id: surfaceSelector

        // 清除缓冲区
        ClearBuffers {
            buffers: ClearBuffers.ColorDepthBuffer
            NoDraw {}
        }

        // Compute Pass
        //FrameGraph 节点为 GPU 上的计算着色器发出工作
        //DispatchCompute 允许为计算着色器发出工作以在 GPU 上运行。
        //workGroupX、workGroupY 和 workGroupZ 属性指定计算着色器调用的工作组大小。
        //ComputeCommand 组件需要添加到实体中,以指示 Qt3D 从实体中选择材料和几何体以进行计算调用。
        //着色器调用的工作组大小将是 DispatchCompute 和 ComputeCommand 中指定的工作组大小的最大值。
        DispatchCompute {
            workGroupX: 50; workGroupY: 1; workGroupZ: 1
            //一个 FrameGraphNode 用于选择使用的技术。
            //TechniqueFilter 指定 FrameGraph 在呈现实体时使用哪些Technique。
            //TechniqueFilter 指定了 FilterKey 对象和 Parameter 对象的列表。
            //当 FrameGraph 中存在 TechniqueFilter 时,仅使用与列表中的键匹配的技术进行渲染。
            //列表中的参数可用于设置着色器参数的值。
            //echniqueFilter 中的参数会覆盖 Material、Effect、Technique 和 RenderPass 中的参数,但会被 RenderPassFilter 中的参数覆盖。

            TechniqueFilter {
                matchAll: [
                    FilterKey { name: "type"; value: "compute"}
                ]
            }
        }

        // 从 Compute Pass 中计算的缓冲区中绘制粒子
        CameraSelector {
            id: selector
            TechniqueFilter {
                //放置内存屏障的类。
                //MemoryBarrier FrameGraph 节点用于在渲染的特定时间放置特定的内存屏障。
                //这是在 GPU 上正确同步绘图和计算命令所必需的。
                //屏障定义了先前命令发出的内存操作的顺序。
                //这意味着如果 command1 正在操作一个缓冲区,
                //该缓冲区将在后面的 command2 中用作顶点属性缓冲区,
                //那么内存屏障应该放在 command1 之后,并为顶点属性缓冲区设置适当的屏障类型。
                //当在 FrameGraph 分支中找到 QMemoryBarrier 节点时,
                //障碍将在任何绘制或计算命令之前强制执行,即使这些在分支中定义得更深。
                //对于 OpenGL 渲染,此页面提供了有关内存模型的更多信息
                
                MemoryBarrier { waitFor: MemoryBarrier.VertexAttributeArray }
                matchAll: [
                    FilterKey { name: "type"; value: "draw"}
                ]
            }
        }
    }
}

ComputeMaterial.qml

import Qt3D.Core 2.0
import Qt3D.Render 2.0
//Material 提供了一种指定实体渲染的方法。
//任何方面都可以定义自己的 Material 子类型,以便 Material 可以用来描述视觉元素;
//例如,声音从元素反射的方式、表面温度等。
//就其本身而言,材质不做任何事情。
//只有当它引用一个 Effect 节点时,材质才会变得有用。
//在实践中,一个 Effect 经常被多个 Material 组件引用。
//这允许只创建一次效果、技术、传递和着色器,同时允许通过添加参数实例来指定材质。
//在材质上定义的参数会覆盖在效果、、技术和 RenderPass 中定义的参数(同名),但会被 RenderPassFilter 和 TechniqueFilter 中的参数覆盖。
/*
Effect
{
    id:effect
    technique:
    {
        Technique
        {
            id:gl3Technique
            graphicsApiFilter
            {
                api:GraphicsApiFilter.OpenGL
                profile:GraphicsApiFilter.CoreProfile
                majorVersion:3
                minorVersion:1
            }
            renderPasses:
            [
                RenderPass
                {
                    id:gl3Pass
                    shaderProgram:ShaderProgram
                    {
                        ...
                    }
                }
            ]
        }
    }
}

Material
{
    id:materiall
    parameters:
    [
        Parameter{name:"color";value:"green"}
    ]
}

Material
{
    id:material2
    parameters:
    [
        Parameter{name:"color";value:"white"}
    ]
}
*/

Material {
    property Buffer dataBuffer;
    property real particleStep: 0.4
    property real finalCollisionFactor: 0.2

    parameters: [
        Parameter { name: "particleStep"; value: particleStep },
        Parameter { name: "finalCollisionFactor"; value: finalCollisionFactor }
    ]
    
    //Effect Qt 3D 场景中效果的基类
    //效果类型结合了一组技术和这些技术使用的参数来为材质产生渲染效果。
    //一个 Effect 实例应该在可能的情况下在多个 Material 实例之间共享。
    //在 Effect 上定义的参数会覆盖在 Technique 和 RenderPass 中定义的参数(同名)
    //但会被 RenderPassFilter、TechniqueFilter 和 Material 中的参数覆盖。
    //注意:效果节点不能被禁用。
    /*
        Effect
        {
            id:effect
            technique
            {
                id:gl3Technique
                graphicsApiFilter
                {
                    api:GraphicsApiFilter.OpenGL
                    profile:GraphicsApiFilter.CoreProfile
                    majorVersion:3
                    minorVersion:1
                }
                renderPasses:[
                    RenderPass{
                    id:gl3Pass
                    shaderProgram:ShaderProgram
                    {
                        ...
                    }
                    }
                ]
            }
        }
    */

    //Technique 指定了一组 RenderPass 对象、FilterKey 对象、Parameter 对象和一个 GraphicsApiFilter,
    //它们共同定义了给定图形 API 可以呈现的呈现技术。
    //TechniqueFilter 使用过滤器键来选择 FrameGraph 特定部分的特定技术。
    //在 Technique 上定义的参数会覆盖 RenderPass 中定义的参数(同名),但会被
    //RenderPassFilter、TechniqueFilter、Material 和 Effect 中的参数覆盖。
    //在创建以图形 API 的多个版本为目标的 Effect 时,
    //创建多个 Technique 节点很有用,
    //每个节点都设置了 graphicsApiFilter 以匹配目标版本之一。
    //在运行时,Qt3D 渲染器将根据支持的图形 API 版本和(如果指定)
    //满足 FrameGraph 中给定 TechniqueFilter 的 FilterKey 节点来选择最合适的 Technique。
    //注意:当使用 OpenGL 作为图形 API 进行渲染时,
    //Qt3D 依赖于 QSurfaceFormat::defaultFormat() 在运行时返回的
    //QSurfaceFormat 来决定什么是最合适的可用 GL 版本。
    //如果您需要自定义 QSurfaceFormat,请不要忘记使用QSurfaceFormat::setDefaultFormat() 来应用它。
    //在视图上设置 QSurfaceFormat 可能对 Qt3D 相关渲染没有影响。
    //注意:技术节点不能被禁用。
    /*
        Technique
        {
            id:gl3Technique
            parameters:
            [
                Parameters{name:"color";value:"orange"}
            ]
            filterKeys:
            [
                FilterKey{name:"renderingStyle";value:"forward"}
            ]
            graphicsApiFilter:
            {
                api:GraphicsApiFilter.OpenGL
                profile:GraphicsApiFilter.CorePerofile
                majorVersion:3
                minorVersion:1
            }
            renderPasses:
            [
                RenderPass{
                    id:firstPass
                    shaderProgram:ShaderProgram
                    {

                        //...
                    }
                }
            ]
        }
    */
    //RenderPass 指定技术使用的渲染通道
    //RenderPass 指定单个渲染通道 - 着色器程序执行的实例
    //由 Technique 使用。
    //渲染通道由一个 ShaderProgram 和一个 FilterKey 对象列表、一个 RenderState 对象列表和一个 Parameter 对象列表组成。
    //当至少一个被引用的 FilterKey 节点与 RenderPassFilter 中的任何 FilterKey 节点匹配或当 FrameGraph 中不存在
    //RenderPassFilter 时,RenderPass 使用给定的 RenderState 和 Parameter 节点执行 ShaderProgram。

    //如果 RenderPass 定义了一个 Parameter,
    //并且它在运行时存在于与该 pass 相关联的 Technique、Effect、Material、
    //TechniqueFilter、RenderPassFilter 中的任何一个中,则它将被具有相同名称的 Parameter 覆盖。
    //这对于定义合理的默认值仍然很有用。
    //在渲染时,对于 FrameGraph 的每个叶节点,通过累积由 FrameGraph 分支中的所有 RenderStateSet 节点定义的状态来记录基本渲染状态。
    //每个 RenderPass 都可以通过指定自己的 RenderState 节点来重载此基本渲染状态。

    /*
        Technique
        {
            filterKeys:
            [
                FilterKey{name:"renderingStyle";value:"forward"}
            ]

            graphicsApiFilter:
            {
                api:GraphicsApiFilter.OpengGL
                profile:GraphicsApiFilter.CoreProfile
                majorVersion:3
                minorVersion:1
            }

            renderPasses:
            [
                RenderPass
                {
                    id:pass
                    shaderProgram: ShaderProgram
                    {
                        //...
                    }
                    parameters:
                    [
                        Parameter{name:"Color";value:"red"}
                    ]
                    renderStates:
                    [
                        DepthTest{}
                    ]
                }
            ]
        }
    */

    //ShaderProgram 类封装了一个着色器程序。
    //一个着色器程序由几个不同的着色器组成,
    //例如顶点着色器和片段着色器。
    //Uniform 关联的 Qt3D 参数名称 GLSL声明
    //ModelMatrix模型矩阵 modelMatrix uniform mat4 modelMatrix;
    //ViewMatrix视图矩阵 viewMatrix uniform mat4 viewMatrix
    //ProjectionMatrix投影矩阵 projectionMatrix uniform mat4 projectionMatrix;
    //ModelViewMatrix模型视图矩阵 modelView  uniform mat4 modelView
    //ViewProjectionMatrix视图投影矩阵 viewProjectionMatrix uniform mat4 viewProjectionMatrix;
    //ModelViewProjectionMatrix模型视图投影矩阵  modelViewProjection mvp uniform mat4 modelViewProjection; 
 uniform mat4 mvp;
    //InverseModelMatrix逆模型矩阵   inverseModelMatrix uniform mat4 inverseModelMatrix;
    //InverseViewMatrix逆视矩阵 inverseViewMatrix   uniform mat4 inverseViewMatrix;
    //InverseProjectionMatrix逆投影矩阵  uniform mat4 inverseProjectionMatrix;
    //InverseModelViewMatrix逆模型视图矩阵 inverseModelView    uniform mat4 inverseModelView;
    //InverseViewProjectionMatrix逆视投影矩阵 inverseViewProjectionMatrix uniform mat4 inverseViewProjectionMatrix;
    //InverseModelViewProjectionMatrix  逆模型视图投影矩阵   uniform mat4 inverseModelViewProjection;
    //ModelNormalMatrix模型法向量矩阵 modelNormalMatrix    uniform mat3 modelNormalMatrix;
    //ModelViewNormalMatrix模型视图法线矩阵 modelViewNormal uniform mat3 modelViewNormal;
    //ViewportMatrix视口矩阵    viewportMatrix uniform mat4 viewportMatrix;
    //InverseViewportMatrix逆视口矩阵    inverseViewportMatrix uniform mat4 inverseViewportMatrix;
    //AspectRatio(surface width / surface height)纵横比    aspectRatio uniform float aspectRatio;
    //Exposure  exposure uniform float exposure;
    //Gamma Gamma   uniform float gamma;
    //Time(in nano seconds) time    uniform float time;
    //EyePosition   eyePosition uniform vec3 eyePosition;
    //SkinningPalette蒙皮调色板  skinningPalette[0]  const int maxJoints = 100; 
 uniform mat4 skinningPalette[maxJoints];

    //RHI 支持
    //在编写 GLSL 450 着色器代码以与 Qt 3D 的 RHI 后端一起使用时,默认统一将作为 2 个统一缓冲区对象提供。
    //这些的绑定位置设置为 RenderView 制服的绑定 0 和命令制服的 1。
    /*
        #version 450 core
        layout(location = 0) in vec3 vertexPosition;
        layout(std140,binding = 0) uniform qt3d_render_view_uniforms{
            mat4 viewMatix;
            mat4 projectionMatrix
            mat4 uncorrectedProjectionMatrix 未修正投影矩阵
            mat4 clipCorrectionMatrix;
            mat4 viewProjectionMatrix;
            mat4 inverseViewMatrix;
            mat4 inverseProjectionMatrix;
            mat4 inverseViewProjectionMatrix;
            mat4 viewportMatrix;
            mat4 inverseViewportMatrix;
            vec4 textureTransformMatrix;
            vec3 eyePosition;
            float aspectRatio;
            float gamma;
            float time;
            float yUpInNDC;
            float yUpInFBO;
        };

        layout(std140,binding = 1) uniform qt3d_command_uniforms
        {
            mat4 modelMatrix;
            mat4 inverseModelMatrix;
            mat4 modelViewMatrix;
            mat3 modelNormalMatrix;
            mat4 inverseModelViewMatrix;
            mat4 modelViewProjection;
            mat4 inverseModelViewProjectionMatrix;
        };

        void main()
        {
            gl_Position = (projectionMatrix * viewMatrix*modelMatrix*vertexPosition);
        }
    */

//对于用户定义的统一缓冲区对象,使用从 2 开始的绑定或自动让 Qt 3D 自动计算绑定。
//确保在不同着色器阶段之间保持一致。
/*
    #version 450 core
    layout(std140,binding = auto) uniform my_uniforms{
        vec4 myColor;
    };
    layout(location = 0) out vec4 fragColor;
    void main()
    {
        fragColor = myColor;
    }
*/
    //对于上面的示例,可以通过以下方式设置 myColor:
    //Parameter{name:"myColor";value:"blue"}

    //纹理仍然必须定义为独立的uniforms。
    /*
        #version 450 core
        layout(binding = 0) uniform sampler2D source;
        layout(location = 0) out vec4 fragColor;

        void main()
        {
            fragColor = texture(source,vec2(0.5,0.5))
        }
    */

    effect: Effect {
        techniques: [
            Technique {
                renderPasses: [
                    RenderPass {
                        shaderProgram: ShaderProgram {
                            //computeShaderCode保存此着色器程序使用的计算着色器代码。 
                            computeShaderCode: loadSource("qrc:/shaders/gl43/particles.comp")
                        }
                        //我们将缓冲区设置为参数数据
                        parameters: [
                            Parameter { name: "Particles"; value: dataBuffer }
                        ]
                    }
                ]
                //指定启用此技术的过滤器键列表
                filterKeys: [
                    FilterKey { name: "type"; value: "compute" }
                ]
                graphicsApiFilter {
                    api: GraphicsApiFilter.OpenGL
                    profile: GraphicsApiFilter.CoreProfile
                    majorVersion: 4
                    minorVersion: 3
                }
            },
            Technique {
                renderPasses: [
                    RenderPass {
                        shaderProgram: ShaderProgram {
                            vertexShaderCode: loadSource("qrc:/shaders/gl43/particles.vert")
                            fragmentShaderCode: loadSource("qrc:/shaders/gl43/particles.frag")
                        }
                        // We assume the mesh to be drawn will also receive
                        // Vertex buffers attributes that will be used to position and color
                    }
                ]
                filterKeys: [
                    FilterKey { name: "type"; value: "draw" }
                ]
                graphicsApiFilter {
                    api: GraphicsApiFilter.OpenGL
                    profile: GraphicsApiFilter.CoreProfile
                    majorVersion: 4
                    minorVersion: 3
                }
            },
            Technique {
                renderPasses: [
                    RenderPass {
                        shaderProgram: ShaderProgram {
                            computeShaderCode: loadSource("qrc:/shaders/gl45/particles.comp")
                        }
                        // We set the buffer as the parameter data
                        parameters: [
                            Parameter { name: "Particles"; value: dataBuffer }
                        ]
                    }
                ]
                filterKeys: [
                    FilterKey { name: "type"; value: "compute" }
                ]
                graphicsApiFilter {
                    api: GraphicsApiFilter.RHI
                    profile: GraphicsApiFilter.NoProfile
                    majorVersion: 1
                    minorVersion: 0
                }
            },
            Technique {
                renderPasses: [
                    RenderPass {
                        shaderProgram: ShaderProgram {
                            vertexShaderCode: loadSource("qrc:/shaders/gl45/particles.vert")
                            fragmentShaderCode: loadSource("qrc:/shaders/gl45/particles.frag")
                        }
                        // We assume the mesh to be drawn will also receive
                        // Vertex buffers attributes that will be used to position and color
                    }
                ]
                filterKeys: [
                    FilterKey { name: "type"; value: "draw" }
                ]
                graphicsApiFilter {
                    api: GraphicsApiFilter.RHI
                    profile: GraphicsApiFilter.NoProfile
                    majorVersion: 1
                    minorVersion: 0
                }
            }
        ] // techniques
    }
}

ParticlesScene.qml

import Qt3D.Core 2.0
import Qt3D.Render 2.0
import Qt3D.Extras 2.0

Entity {
    property alias particleStep: computeMaterial.particleStep
    property alias finalCollisionFactor: computeMaterial.finalCollisionFactor

    readonly property int _SPHERE: 0
    readonly property int _CUBE: 1
    readonly property int _CYLINDER: 2
    readonly property int _TORUS: 3

    property int particlesShape: _SPHERE

    signal reset()

    components: [
    //RenderSettings 类型保存与渲染过程相关的设置并托管活动的 FrameGraph
    //RenderSettings 组件必须设置为场景根实体的组件。 它指定渲染策略和拾取设置,以及托管活动的 FrameGraph。
        RenderSettings {
            ComputeFrameGraph {
                camera: sceneCamera
            }
           // 将 RenderingPolicy 显式设置为 AlwaysRender,
           // 因为场景中的更改不会反射在实际的 Qt 场景图更改中(由于 GPU 计算调用)
           //渲染策略
           //Qt3DRender::QRenderSettings::OnDemand 0
           //FrameGraph 仅在发生变化时呈现。
           //Qt3DRender::QRenderSettings::Always
           //即使没有任何变化,FrameGraph 也会连续呈现。
            renderPolicy: RenderSettings.Always
        }
    ]
    //FirstPersonCameraController 允许从第一人称视角控制场景相机
    FirstPersonCameraController 
    { 
        //保存当前控制的摄像机。
        camera: sceneCamera 
    } 

    Camera {
        id: sceneCamera
        //保存相机投影的类型。 默认值为 CameraLens.PerspectiveProjection。
        projectionType: CameraLens.PerspectiveProjection
        viewCenter: Qt.vector3d(0, 0, 0)
        position: Qt.vector3d(0, 0, -800)
        nearPlane: 0.1
        farPlane: 1000
        //以度为单位保持相机的当前垂直视野。
        //与 aspectRatio 一起,此属性确定了相机可见的场景的多少。
        //在这方面,您可能会认为它类似于选择广角(宽水平视野)或长焦(窄水平视野)镜头,具体取决于您想要捕捉多少场景。
        fieldOfView: 25
        //保持相机的当前纵横比。
        aspectRatio: 1.33
    }

    property int particlesCount: 50 * 1024
    readonly property int floatSize: 4

    function buildParticlesBuffer() {
        var byteSizeOfParticleData = 12;
        var bufferData = new Float32Array(particlesCount * byteSizeOfParticleData);
        var factor = 500.0;
        for (var i = 0; i < particlesCount; ++i) {
            var positionIdx = i * byteSizeOfParticleData;
            var velocityIdx = i * byteSizeOfParticleData + 4;
            var colorIdx = i * byteSizeOfParticleData + 8;

            for (var j = 0; j < 3; ++j) {
                bufferData[positionIdx + j] = (Math.random() - 0.5) * factor;
                bufferData[velocityIdx + j] = Math.random() * 2.0;
                bufferData[colorIdx + j] = 0.75 + Math.sin(((i / 1024.0) + j * 0.333) * 6.0) * 0.25;
            }

            bufferData[positionIdx + 3] = 1.0;
            bufferData[velocityIdx + 3] = 0.0;
            bufferData[colorIdx + 3] = 1.0;
        }
        return bufferData
    }
    //为原始数据提供数据存储,以便稍后用作顶点或uniform
    Buffer {
        id: particleBuffer
        //        struct ParticleData
        //        {
        //            vec3 position;      // Aligned to 4 floats
        //            vec3 velocity;      // Aligned to 4 floats
        //            vec3 color;         // Aligned to 4 floats
        //        };
        data: buildParticlesBuffer()
    }

    onReset : {
        particleBuffer.data = buildParticlesBuffer()
    }
    //定义一个属性以及如何从 Buffet 中读取数据
    Attribute {
        id: particlePositionDataAttribute
        name: "particlePosition"
        attributeType: Attribute.VertexAttribute
        vertexBaseType: Attribute.Float
        vertexSize: 3
        divisor: 1
        byteStride: 12 * floatSize
        buffer: particleBuffer
    }

    Attribute {
        id: particleColorDataAttribute
        name: "particleColor"
        attributeType: Attribute.VertexAttribute
        vertexBaseType: Attribute.Float
        vertexSize: 3
        divisor: 1
        byteOffset: 8 * floatSize
        byteStride: 12 * floatSize
        buffer: particleBuffer
    }

    ComputeMaterial {
        id: computeMaterial
        dataBuffer: particleBuffer
    }

    Entity {
        id: particleComputeEntity
        readonly property ComputeCommand particlesComputeJob: ComputeCommand {}
        components: [
            particlesComputeJob,
            computeMaterial
        ]
    }
    //SphereGeometry 类型最常在 SphereMesh 类型内部使用,但也可用于自定义 GeometryRenderer 类型。
    SphereGeometry {
        id: sphereGeometry
        rings: 10
        slices: 10
        radius: 1
        // Additional Attributes
        attributes: [
            particlePositionDataAttribute,
            particleColorDataAttribute
        ]
    }

    CuboidGeometry {
        id: cubeGeometry
        yzMeshResolution: Qt.size(2, 2)
        xzMeshResolution: Qt.size(2, 2)
        xyMeshResolution: Qt.size(2, 2)
        // Additional Attributes
        attributes: [
            particlePositionDataAttribute,
            particleColorDataAttribute
        ]
    }

    CylinderGeometry {
        id: cylinderGeometry
        rings: 10
        slices: 10
        radius: 1
        length: 1.5
        // Additional Attributes
        attributes: [
            particlePositionDataAttribute,
            particleColorDataAttribute
        ]
    }

    TorusGeometry {
        id: torusGeometry
        rings: 10
        slices: 10
        radius: 1
        minorRadius: 0.5
        // Additional Attributes
        attributes: [
            particlePositionDataAttribute,
            particleColorDataAttribute
        ]
    }

    Entity {
        id: particleRenderEntity
        readonly property GeometryRenderer particlesRenderer: GeometryRenderer {
            instanceCount: particlesCount
            indexOffset: 0
            firstInstance: 0
            primitiveType: GeometryRenderer.Triangles
            geometry:  {
                switch (particlesShape) {
                case _SPHERE:
                    return sphereGeometry;
                case _CUBE:
                    return cubeGeometry;
                case _CYLINDER:
                    return cylinderGeometry;
                case _TORUS:
                    return torusGeometry;
                }
            }
        }

        components: [
            particlesRenderer,
            computeMaterial
        ]
    }
}

particles.comp

#version 430 core

uniform float particleStep;
uniform float finalCollisionFactor;

layout (local_size_x = 1024) in;

struct ParticleData
{
    vec4 position;
    vec4 direction;
    vec4 color;
};

// Particles from previouse frame
layout (std430, binding = 0) coherent buffer Particles
{
    ParticleData particles[];
} data;

void main(void)
{
    uint globalId = gl_GlobalInvocationID.x;

    // 从前一帧中检索当前粒子
    ParticleData currentParticle = data.particles[globalId];

    // 新位置 = 旧位置 + 跨步持续时间
    currentParticle.position = currentParticle.position + currentParticle.direction * particleStep;

    // 使加速度或多或少指向场景的中心
    vec4 acceleration =  normalize(vec4(0.0) - currentParticle.position) * finalCollisionFactor;

    // 新速度 = 旧速度 + 跨步持续时间的加速度
    currentParticle.direction = currentParticle.direction + acceleration * particleStep;

    // 保存更新的粒子
    data.particles[globalId] = currentParticle;
}

particles.vert

#version 430 core

in vec3 vertexPosition;
in vec3 vertexNormal;

in vec3 particlePosition;
in vec3 particleColor;

out VertexBlock
{
    flat vec3 color;
    vec3 pos;
    vec3 normal;
} v_out;

uniform mat4 mvp;
uniform mat3 modelViewNormal;
uniform mat4 modelView;

void main(void)
{
    vec4 pos = vec4(vertexPosition.xyz, 1.0) + vec4(particlePosition, 0.0);
    gl_Position = mvp * pos;
    v_out.pos = vec4(modelView * pos).xyz;
    v_out.normal = normalize(modelViewNormal * vertexNormal);
    v_out.color = mix(particleColor * 0.2, particleColor, smoothstep(0.5, 0.8, abs(v_out.normal).z));
}

particles.frag

#version 430 core

out vec4 color;

in VertexBlock
{
    flat vec3 color;
    vec3 pos;
    vec3 normal;
} frag_in;

const vec4 lightPosition = vec4(0.0, 0.0, 0.0, 0.0);
const vec3 lightIntensity = vec3(1.0, 1.0, 1.0);
const vec3 ka = vec3(0.1, 0.1, 0.1);
const vec3 ks = vec3(0.8, 0.8, 0.8);
const float shininess = 50.0;

vec3 ads()
{
   vec3 n = normalize( frag_in.normal);
   vec3 s = normalize( vec3(lightPosition) - frag_in.pos );
   vec3 v = normalize( -frag_in.pos );
   vec3 h = normalize( v + s );
   return lightIntensity * (ka +
                            frag_in.color * max( dot(s, frag_in.normal ), 0.0 ) +
                            ks * pow( max( dot( h, n ), 0.0 ), shininess ) );
}


void main(void)
{
    color = vec4(ads(), 1.0);
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值