diff --git a/graphic/ArkGraphics3D/.gitignore b/graphic/ArkGraphics3D/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..ea27eaff8c3ecef3e9ebe6399a5f9073cd962a7b
--- /dev/null
+++ b/graphic/ArkGraphics3D/.gitignore
@@ -0,0 +1,13 @@
+/node_modules
+/oh_modules
+/local.properties
+/.idea
+**/build
+/.hvigor
+.cxx
+/.clangd
+/.clang-format
+/.clang-tidy
+**/.test
+/.appanalyzer
+oh-package-lock.json5
\ No newline at end of file
diff --git a/graphic/ArkGraphics3D/AppScope/app.json5 b/graphic/ArkGraphics3D/AppScope/app.json5
new file mode 100644
index 0000000000000000000000000000000000000000..2a2fc64855bea3030a8066d67f3bec55e500e921
--- /dev/null
+++ b/graphic/ArkGraphics3D/AppScope/app.json5
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "app": {
+ "bundleName": "com.samples.ArkGraphics3D",
+ "vendor": "example",
+ "versionCode": 1000000,
+ "versionName": "1.0.0",
+ "icon": "$media:app_icon",
+ "label": "$string:app_name"
+ }
+}
diff --git a/graphic/ArkGraphics3D/AppScope/resources/base/element/string.json b/graphic/ArkGraphics3D/AppScope/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..64d50a205bd8227bb17db7c6805f2e86f81e658f
--- /dev/null
+++ b/graphic/ArkGraphics3D/AppScope/resources/base/element/string.json
@@ -0,0 +1,8 @@
+{
+ "string": [
+ {
+ "name": "app_name",
+ "value": "com.samples.ArkGraphics3D"
+ }
+ ]
+}
diff --git a/graphic/ArkGraphics3D/AppScope/resources/base/media/app_icon.png b/graphic/ArkGraphics3D/AppScope/resources/base/media/app_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..a39445dc87828b76fed6d2ec470dd455c45319e3
Binary files /dev/null and b/graphic/ArkGraphics3D/AppScope/resources/base/media/app_icon.png differ
diff --git a/graphic/ArkGraphics3D/README.md b/graphic/ArkGraphics3D/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..5f94084f7e2904c4a66a0f5809359e03c59d8f12
--- /dev/null
+++ b/graphic/ArkGraphics3D/README.md
@@ -0,0 +1,133 @@
+# ArkGraphics 3D
+
+## 介绍
+
+本示例通过 ArkGraphics 3D 的接口,利用轻量级的 3D 引擎和渲染管线,实现了 3D 场景创建、3D 场景资源创建和 3D 动画创建。
+
+本示例主要展现了如何利用 ArkGraphics 3D 来实现 3D 图像的渲染,其中利用 Scene、Camera 和 Light 来创建基础的场景,使用 Material、Shader、Image 和Environment 来实现场景资源,采用 Animation 的各种方法来播放 3D 动画。
+
+## 效果预览
+
+| Index | Scene | Resource | Animation |
+| :-----------------------------------------------: | :-----------------------------------------------: | :--------------------------------------------------: | :---------------------------------------------------: |
+|
|
|
|
|
+
+**使用方法:**
+
+1. 在 Index 页面点击 ` BUilding and Managing ArkGraphics 3D Scenes` 按钮,跳转至 Scene 页面;
+ - 在 Scene 页面点击 `Model Loading and Display` 按钮,页面跳转至 Model 页面,显现 3D 头盔图像。点击 `Back` 按钮,返回至 Scene 页面;
+ - 在 Scene 页面点击 `Creating and Managing a Camera` 按钮,页面跳转至 Camera 页面,显现几何体图像。通过调节 `X-axis`、`Y-axis` 和 `Z-axis` 滑动条,即可分别修改相机的 X 轴,Y 轴和 Z 轴。点击 `Back` 按钮,返回至 Scene 页面;
+ - 在 Scene 页面点击 `Creating and Managing Light` 按钮,页面跳转至 Light 页面,显现几何体图像。通过调节 `Red`、`Green` 和 `Blue` 滑动条,即可分别调节光线的红、绿和蓝的颜色通道。点击 `Back` 按钮,返回至 Scene 页面;
+ - 在 Scene 页面点击 `Back` 按钮,返回至 `Index` 页面;
+2. 在 Index 页面点击 `Creating and using ArkGraphics 3D Resources` 按钮,跳转至 Resource 页面。点击 `Replace with a blank material` 按钮,几何体图像的材质被空白材质替换。点击 `Replace with a Shader material` 按钮,几何体图像的材质被着色器材质替换。点击 `Replace with a Image material`,几何体材质被图像材质替换。点击 `Add to Environment` 按钮,给几何体图像添加背景。点击 `Back` 按钮,返回至 Index 页面;
+3. 在 Index 页面点击 `Controlling and Managing ArkGraphics 3D Scene Animations` 按钮,跳转至 Animation 页面。点击 `start` 按钮,播放动画。点击 `pause` 按钮,中止动画。点击 `stop` 按钮,暂停动画。点击 `finish` 按钮,结束动画。点击 `restart` 按钮,重新播放动画。点击 `seek to 30% progress` 按钮,动画从 30% 进度开始播放。点击 `Back` 按钮,返回至 Index 页面;
+
+## 工程目录
+
+```
+|--entry/src/main
+│ |--ets // ets代码区
+│ │ |--entryability
+│ │ │ |--EntryAbility.ts // 程序入口类
+| | | |--EntryAbility.ets
+| | |--arkGraphic
+│ │ │ |--animation.ets // 动画
+| | | |--resource.ets // 场景资源
+| | | |--scene.ets // 场景搭建
+| | |--scene
+| | | |--camera.ets // 相机
+| | | |--init.ets // 模型加载
+| | | |--light.ets // 光线
+│ │ |--pages // 页面文件
+│ │ | |--Index.ets // 初始页面
+│ │ |--utils // 工具类
+| |--resources // 资源文件目录
+```
+
+## 具体实现
+
+1. 创建场景:一个 3D 场景通常由模型、相机和光源三个关键部分组成。其中先加载模型,再生成相机和光源。等 3D 图像加载完毕,可以使 Component3D 组件将渲染好的图像传递给用户。
+
+ - | 接口名 | 描述 |
+ | ------------------------------------------------------ | -------- |
+ | `Scene.load(): Promise` | 加载模型 |
+ | `SceneResourceFactory.createCamera(): Promise` | 创建相机 |
+ | `SceneResourceFactory.createLight(): Promise` | 创建光源 |
+
+ - | SceneOption 参数 | 描述 |
+ | -------------------- | ------------------------------------------------------------ |
+ | scene: Scene | 3D模型资源文件或场景对象,默认值为undefined。
**说明:目前仅支持GLTF格式资源。** |
+ | modelType: ModelType | 3D场景显示合成方式。
**说明:**
一般开发者可以使用默认值而无需关心此项设置。 |
+
+2. 创建场景资源:3D 场景中主要有以下常见资源:
+
+ - 材质(Material):材质是对场景中物体的光学物理性质的数学建模。在渲染计算的过程中,利用这些物理性质计算与光的相互作用,得到渲染的颜色。ArkGraphics 3D 提供的材质类型基于 PBR 渲染,支持用户参照 PBR 渲染材质类型创建材质资源,得到预期的渲染结果。
+
+ - 图片(Image): 图片本质上是上一个储存信息的二维内存块(buffer),用于储存 3D 渲染计算过程需要的相关信息,比如基础色、法线等等。ArkGraphics 3D 提供基于 PNG、JPG、KTX格式创建 Image 资源的能力,支持用户自定义需要的 Image 资源。
+
+ - 着色器(Shader): 着色器是 GPU 上可以执行的一段程序,可以控制 GPU 执行哪些并行计算操作。AGP 引擎提供的默认着色器实现了 PBR 渲染,开发者只需要指定对应的参数就可以完成不同的 PBR 渲染。ArkGraphics 3D 支持开发者创建自定义的着色器,开发者可以通过自定义着色器自定义渲染计算过程,完全控制渲染计算流程,比如控制某物体不受某光源的影响等。
+
+ - 环境(Environment): 环境是 3D 场景背景的一种描述,可以基于图片进行创建。通过将一张图片进行正方体或者球体的映射处理,将图片贴在正方体或者球体上,在 3D 场景中模拟真实的环境。ArkGraphics 3D 支持用户创建环境资源,定义 3D 场景的背景。
+
+ - | 接口名 | 描述 |
+ | ------------------------------------------------------------ | ---------- |
+ | `SceneResourceFactory.createMaterial(): Promise` | 创建材质 |
+ | `SceneResourceFactory.createImage(): Promise` | 创建图片 |
+ | `SceneResourceFactory.createShader(): Promise` | 创建着色器 |
+ | `SceneResourceFactory.createEnvironment(): Promise` | 创建环境 |
+
+ - 尤其需要注意:在 ArkGraphics 3D 中需要将材质(Material)给与子网格(SubMesh)才能成功替换材质。
+
+ - | SubMesh 属性 | 说明 |
+ | ---------------------- | ------------------------ |
+ | name: string | 名称,没有特殊格式要求。 |
+ | **material: Material** | 材质。 |
+ | aabb: Aabb | 轴对齐边界盒。 |
+
+3. 创建动画:动画是3D场景中重要的资源类型,用于控制场景中各种元素的运动。
+
+ - 调用 `start` 方法控制动画开启;
+
+ - 调用 `pause` 方法控制动画暂停;
+
+ - 调用 `stop` 方法控制动画停止,并将动画状态设置为开头;
+
+ - 调用`finish` 方法控制动画结束,并将动画状态设置为结尾;
+
+ - 调用 `restart` 方法控制动画从头开始;
+
+ - 调用 `seek` 方法控制动画设置到指定状态;
+
+ - `onStarted` 方法在动画开始时执行传入的回调;
+
+ - `onFinished` 方法在动画结束时执行传入的回调。
+
+## 相关权限
+
+不涉及。
+
+## 依赖
+
+不涉及。
+
+## 约束与限制
+
+1. 本示例仅支持标准系统上运行,支持设备:华为手机。
+
+2. HarmonyOS系统:HarmonyOS 5.0.2 Release及以上。
+
+3. DevEco Studio版本:DevEco Studio 5.0.2 Release及以上。
+
+4. HarmonyOS SDK版本:HarmonyOS 5.0.2 Release及以上。
+
+## 下载
+
+如需单独下载本工程,执行如下命令:
+
+```
+git init
+git config core.sparsecheckout true
+echo code/DocsSample/graphic/Arkgraphics3D/ > .git/info/sparse-checkout
+git remote add origin https://gitcode.com/openharmony/applications_app_samples.git
+git pull origin master
+```
\ No newline at end of file
diff --git a/graphic/ArkGraphics3D/build-profile.json5 b/graphic/ArkGraphics3D/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..9beb54e97334358d1dc01477101aa0a0aa5e103d
--- /dev/null
+++ b/graphic/ArkGraphics3D/build-profile.json5
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "app": {
+ "products": [
+ {
+ "name": "default",
+ "signingConfig": "default",
+ "compatibleSdkVersion": "5.0.2(14)",
+ "targetSdkVersion": "5.0.2(14)",
+ "runtimeOS": "HarmonyOS"
+ }
+ ],
+ "buildModeSet": [
+ {
+ "name": "debug"
+ },
+ {
+ "name": "release"
+ }
+ ],
+ },
+ "modules": [
+ {
+ "name": "entry",
+ "srcPath": "./entry",
+ "targets": [
+ {
+ "name": "default",
+ "applyToProducts": [
+ "default"
+ ]
+ }
+ ],
+ }
+ ]
+}
\ No newline at end of file
diff --git a/graphic/ArkGraphics3D/code-linter.json5 b/graphic/ArkGraphics3D/code-linter.json5
new file mode 100644
index 0000000000000000000000000000000000000000..28586467ee7a761c737d8654a73aed6fddbc3c71
--- /dev/null
+++ b/graphic/ArkGraphics3D/code-linter.json5
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "files": [
+ "**/*.ets"
+ ],
+ "ignore": [
+ "**/src/ohosTest/**/*",
+ "**/src/test/**/*",
+ "**/src/mock/**/*",
+ "**/node_modules/**/*",
+ "**/oh_modules/**/*",
+ "**/build/**/*",
+ "**/.preview/**/*"
+ ],
+ "ruleSet": [
+ "plugin:@performance/recommended",
+ "plugin:@typescript-eslint/recommended"
+ ],
+ "rules": {
+ }
+}
\ No newline at end of file
diff --git a/graphic/ArkGraphics3D/entry/.gitignore b/graphic/ArkGraphics3D/entry/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/.gitignore
@@ -0,0 +1,6 @@
+/node_modules
+/oh_modules
+/.preview
+/build
+/.cxx
+/.test
\ No newline at end of file
diff --git a/graphic/ArkGraphics3D/entry/build-profile.json5 b/graphic/ArkGraphics3D/entry/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..ad1d4aa712abae906cc8f085863ca3eea087e13a
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/build-profile.json5
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "apiType": "stageMode",
+ "buildOption": {
+ },
+ "buildOptionSet": [
+ {
+ "name": "release",
+ "arkOptions": {
+ "obfuscation": {
+ "ruleOptions": {
+ "enable": false,
+ "files": [
+ "./obfuscation-rules.txt"
+ ]
+ }
+ }
+ }
+ },
+ ],
+ "targets": [
+ {
+ "name": "default"
+ },
+ {
+ "name": "ohosTest",
+ }
+ ],
+}
\ No newline at end of file
diff --git a/graphic/ArkGraphics3D/entry/hvigorfile.ts b/graphic/ArkGraphics3D/entry/hvigorfile.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e4f43d54667f8327c367c8096bd08bb8c75aff54
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/hvigorfile.ts
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { hapTasks } from '@ohos/hvigor-ohos-plugin';
+
+export default {
+ system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
+ plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
+}
diff --git a/graphic/ArkGraphics3D/entry/obfuscation-rules.txt b/graphic/ArkGraphics3D/entry/obfuscation-rules.txt
new file mode 100644
index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/obfuscation-rules.txt
@@ -0,0 +1,23 @@
+# Define project specific obfuscation rules here.
+# You can include the obfuscation configuration files in the current module's build-profile.json5.
+#
+# For more details, see
+# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5
+
+# Obfuscation options:
+# -disable-obfuscation: disable all obfuscations
+# -enable-property-obfuscation: obfuscate the property names
+# -enable-toplevel-obfuscation: obfuscate the names in the global scope
+# -compact: remove unnecessary blank spaces and all line feeds
+# -remove-log: remove all console.* statements
+# -print-namecache: print the name cache that contains the mapping from the old names to new names
+# -apply-namecache: reuse the given cache file
+
+# Keep options:
+# -keep-property-name: specifies property names that you want to keep
+# -keep-global-name: specifies names that you want to keep in the global scope
+
+-enable-property-obfuscation
+-enable-toplevel-obfuscation
+-enable-filename-obfuscation
+-enable-export-obfuscation
\ No newline at end of file
diff --git a/graphic/ArkGraphics3D/entry/oh-package.json5 b/graphic/ArkGraphics3D/entry/oh-package.json5
new file mode 100644
index 0000000000000000000000000000000000000000..c9cb6c8174858277c9b0d465a51547dcab16d5ff
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/oh-package.json5
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "name": "entry",
+ "version": "1.0.0",
+ "description": "Please describe the basic information.",
+ "main": "",
+ "author": "",
+ "license": "",
+ "dependencies": {}
+}
+
diff --git a/graphic/ArkGraphics3D/entry/src/main/ets/arkgraphic/animation.ets b/graphic/ArkGraphics3D/entry/src/main/ets/arkgraphic/animation.ets
new file mode 100644
index 0000000000000000000000000000000000000000..f35cfaf6882202f41f210cda3af91826a10ea926
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/main/ets/arkgraphic/animation.ets
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Animation, Camera, Scene, SceneResourceFactory } from '@kit.ArkGraphics3D';
+import { router } from '@kit.ArkUI';
+import logger from '../utils/Logger';
+
+@Entry
+@Component
+struct sceneAnimation {
+ scene: Scene | null = null;
+ @State sceneOpt: SceneOptions | null = null;
+ cam: Camera | null = null;
+ anim: Animation | null = null;
+ @State animationCallbackInvoked: string = 'no invoked callback';
+
+ onPageShow(): void {
+ this.init();
+ }
+
+ onPageHide(): void {
+ if (this.scene) {
+ this.scene.destroy();
+ }
+ this.scene = null;
+ this.sceneOpt = null;
+ this.cam = null;
+ this.anim = null;
+ }
+
+ init(): void {
+ if (this.scene == null) {
+ // Loading scene.
+ // Switched from .gltf to .glb; same content, different format
+ Scene.load($rawfile('gltf/BrainStem/glTF/BrainStem.glb'))
+ .then(async (result: Scene) => {
+ this.scene = result;
+ let rf: SceneResourceFactory = this.scene.getResourceFactory();
+
+ // Get animation resources
+ this.anim = this.scene.animations[0];
+ if (this.anim) {
+ this.anim.enabled = true;
+ // Register callback function
+ this.anim.onStarted(() => {
+ console.info('onStarted');
+ this.animationCallbackInvoked = 'animation on start';
+ });
+
+ this.anim.onFinished(() => {
+ console.info('onFinished');
+ this.animationCallbackInvoked = 'animation on finish';
+ });
+
+ logger.info('ready to create a new animation.');
+ } else {
+ logger.error('No animation found in scene.');
+ }
+
+ // create a new camera.
+ this.cam = await rf.createCamera({ 'name': 'Camera' });
+ // set the camera.
+ this.cam.enabled = true;
+ this.cam.position.z = 5;
+
+ this.sceneOpt = { scene: this.scene, modelType: ModelType.SURFACE } as SceneOptions;
+ }).catch((err: string) => {
+ logger.error(err);
+ });
+ }
+ }
+
+ build() {
+ Row() {
+ Column() {
+ Column() {
+ if (this.sceneOpt) {
+ Component3D(this.sceneOpt)
+ .renderWidth('60%')
+ .renderHeight('60%');
+ } else {
+ Text('Loading···');
+ }
+ }
+ .height('30%');
+
+ Text('animation invoked callback:' + this.animationCallbackInvoked)
+ .fontSize(16)
+ .fontWeight(500);
+
+ Button('start')
+ .id('start')
+ .margin({ top: 50, left: 6 })
+ .width('30%')
+ .height(40)
+ .onClick(async () => {
+ if (!this.scene || !this.scene.animations[0]) {
+ return;
+ }
+ this.anim = this.scene.animations[0];
+ this.anim.start();
+ });
+
+ Button('pause')
+ .id('pause')
+ .margin({ top: 10, left: 6 })
+ .width('30%')
+ .height(40)
+ .onClick(async () => {
+ if (!this.scene || !this.scene.animations[0]) {
+ return;
+ }
+ this.anim = this.scene.animations[0];
+ this.anim.pause();
+ });
+
+ Button('stop')
+ .id('stop')
+ .margin({ top: 10, left: 6 })
+ .width('30%')
+ .height(40)
+ .onClick(async () => {
+ if (!this.scene || !this.scene.animations[0]) {
+ return;
+ }
+ this.anim = this.scene.animations[0];
+ this.anim.stop();
+ });
+
+ Button('finish')
+ .margin({ top: 10, left: 6 })
+ .width('30%')
+ .height(40)
+ .onClick(async () => {
+ if (!this.scene || !this.scene.animations[0]) {
+ return;
+ }
+ this.anim = this.scene.animations[0];
+ this.anim.finish();
+ })
+ .id('finish');
+
+ Button('restart')
+ .margin({ top: 10, left: 6 })
+ .width('30%')
+ .height(40)
+ .onClick(async () => {
+ if (!this.scene || !this.scene.animations[0]) {
+ return;
+ }
+ this.anim = this.scene.animations[0];
+ this.anim.restart();
+ })
+ .id('restart');
+
+ Button('seek to 30% progress')
+ .margin({ top: 10, left: 6 })
+ .width('30%')
+ .height(40)
+ .onClick(async () => {
+ if (!this.scene || !this.scene.animations[0]) {
+ return;
+ }
+ this.anim = this.scene.animations[0];
+ // seek to 30%
+ this.anim.seek(0.3);
+ })
+ .id('seek');
+
+ Button('back')
+ .margin({ top: 10, left: 6 })
+ .width('30%')
+ .height(40)
+ .onClick(() => {
+ router.back();
+ })
+ .id('back');
+ }
+ .width('100%');
+ }
+ .height('100%');
+ }
+}
\ No newline at end of file
diff --git a/graphic/ArkGraphics3D/entry/src/main/ets/arkgraphic/resource.ets b/graphic/ArkGraphics3D/entry/src/main/ets/arkgraphic/resource.ets
new file mode 100644
index 0000000000000000000000000000000000000000..a7b6cd5e34f4cc4292e3f4e0cc8c50d98774b92a
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/main/ets/arkgraphic/resource.ets
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {
+ Camera,
+ Environment,
+ Geometry,
+ Image,
+ Material,
+ MaterialType,
+ Scene,
+ SceneResourceFactory,
+ SceneResourceParameters,
+ Shader,
+ ShaderMaterial,
+ EnvironmentBackgroundType
+} from '@kit.ArkGraphics3D';
+import { router } from '@kit.ArkUI';
+import logger from '../utils/Logger';
+
+let globalScene: Scene | null = null;
+
+function createMaterialPromise(): Promise {
+ return new Promise((resolve, reject) => {
+ // Ensure the scene is loaded before accessing sceneFactory
+ if (globalScene) {
+ let sceneFactory: SceneResourceFactory = globalScene.getResourceFactory();
+ let sceneMaterialParameter: SceneResourceParameters = { name: 'material' };
+ // Create Material
+ let material: Promise = sceneFactory.createMaterial(sceneMaterialParameter, MaterialType.SHADER);
+ material.then(resolve)
+ .catch((err: string) => {
+ logger.error('Blank material create failed: ' + err);
+ reject(err);
+ });
+ } else {
+ reject('Scene is not loaded yet.');
+ }
+ });
+}
+
+function createShaderPromise(): Promise {
+ return new Promise((resolve, reject) => {
+ // Ensure the scene is loaded before accessing sceneFactory
+ if (globalScene) {
+ let sceneFactory: SceneResourceFactory = globalScene.getResourceFactory();
+
+ // Create a SceneResourceParameters object and use it to create a shader
+ let sceneResourceParameter: SceneResourceParameters = {
+ name: 'shaderResource',
+ uri: $rawfile('shaders/custom_shader/custom_material_sample.shader')
+ };
+ let shader: Promise = sceneFactory.createShader(sceneResourceParameter);
+ shader.then(async (shaderEntity: Shader) => {
+ let sceneMaterialParameter: SceneResourceParameters = { name: 'material' };
+ // Create material
+ let material: Promise = sceneFactory.createMaterial(sceneMaterialParameter, MaterialType.SHADER);
+ material.then(async (materialEntity: ShaderMaterial) => {
+ // Bind material with shader
+ materialEntity.colorShader = shaderEntity;
+ resolve(shaderEntity);
+ }).catch((err: string) => {
+ logger.error('Custom ShaderMaterial create failed: ' + err + '.');
+ reject(err);
+ });
+ }).catch((err: string) => {
+ logger.error('Shader load failed: ' + err + '.');
+ reject(err);
+ });
+ } else {
+ reject('Scene is not loaded yet.');
+ }
+ });
+}
+
+function createImagePromise(): Promise {
+ return new Promise((resolve, reject) => {
+ // Ensure the scene is loaded before accessing sceneFactory
+ if (globalScene) {
+ let sceneFactory: SceneResourceFactory = globalScene.getResourceFactory();
+ let sceneImageParameter: SceneResourceParameters = { name: 'image', uri: $rawfile('image/Cube_BaseColor.png') };
+ // Create image
+ let image: Promise = sceneFactory.createImage(sceneImageParameter);
+ image.then(async (imageEntity: Image) => {
+ let sceneMaterialParameter: SceneResourceParameters = { name: 'material' };
+ // Create material
+ let material: Promise = sceneFactory.createMaterial(sceneMaterialParameter, MaterialType.SHADER);
+ material.then(async (materialEntity: ShaderMaterial) => {
+ // Use the created image resource to set texture property
+ if (materialEntity && materialEntity.colorShader) {
+ materialEntity.colorShader.inputs['BASE_COLOR_Image'] = imageEntity;
+ }
+ resolve(imageEntity);
+ }).catch((err: string) => {
+ logger.error('Shader material of image texture create failed: ' + err + '.');
+ reject(err);
+ });
+ }).catch((err: string) => {
+ logger.error('ImageTexture load failed: ' + err + '.');
+ reject(err);
+ });
+ } else {
+ reject('Scene is not loaded yet.');
+ }
+ });
+}
+
+function createEnvironmentPromise() : Promise {
+ return new Promise((resolve, reject) => {
+ // Ensure the scene is loaded before accessing sceneFactory
+ if (globalScene) {
+ let sceneFactory: SceneResourceFactory = globalScene.getResourceFactory();
+
+ // Manually load environment maps (.ktx/.jpg/.png etc.)
+ let sceneImageParameter: SceneResourceParameters = { name: 'image', uri: $rawfile('image/Cube_BaseColor.png') };
+ let image: Promise = sceneFactory.createImage(sceneImageParameter);
+ image.then(async (imageEntity: Image) => {
+ // Create Environment
+ let sceneEnvironmentParameter: SceneResourceParameters = { name: 'env' };
+ let env: Promise = sceneFactory.createEnvironment(sceneEnvironmentParameter);
+ env.then(async (envEntity: Environment) => {
+ envEntity.backgroundType = EnvironmentBackgroundType.BACKGROUND_EQUIRECTANGULAR;
+ envEntity.environmentImage = imageEntity;
+ // Set environment related properties
+ envEntity.indirectDiffuseFactor.x = 1;
+ envEntity.indirectDiffuseFactor.y = 1;
+ envEntity.indirectDiffuseFactor.z = 1;
+ envEntity.indirectDiffuseFactor.w = 1;
+ resolve(envEntity);
+ }).catch((err: string) => {
+ logger.error('Environment mapping material create failed: ' + err + '.');
+ reject(err);
+ });
+ }).catch((err: string) => {
+ logger.error('Image load failed: ' + err);
+ reject(err);
+ });
+ } else {
+ reject('Scene is not loaded yet.');
+ }
+ });
+}
+
+@Entry
+@Component
+struct materialPage {
+ scene: Scene | null = null;
+ @State sceneOpt: SceneOptions | null = null;
+ rf: SceneResourceFactory | null = null;
+ cam: Camera | null = null;
+ shader: Shader | null = null;
+ material: ShaderMaterial | null = null;
+ geom: Geometry | null = null;
+ image: Image | null = null;
+ originalMat: ShaderMaterial | null = null;
+ blankMat: Material | null = null;
+ shaderMat: ShaderMaterial | null = null;
+ imageMat: ShaderMaterial | null = null;
+ env: Environment | null = null;
+
+ onPageShow(): void {
+ this.init();
+ }
+
+ onPageHide(): void {
+ if (this.scene) {
+ this.scene.destroy();
+ }
+ this.scene = null;
+ this.sceneOpt = null;
+ this.rf = null;
+ this.cam = null;
+ this.shader = null;
+ this.material = null;
+ this.geom = null;
+ this.image = null;
+ this.originalMat = null;
+ this.blankMat = null;
+ this.shaderMat = null;
+ this.imageMat = null;
+ this.env = null;
+ globalScene = null;
+ }
+
+ init(): void {
+ if (this.scene === null) {
+ // Switched from .gltf to .glb; same content, different format
+ Scene.load($rawfile('gltf/CubeWithFloor/glTF/AnimatedCube.glb'))
+ .then(async (result: Scene) => {
+ // Assign loaded scene to globalScene for unified resource creation
+ globalScene = result;
+ this.scene = result;
+ this.sceneOpt = { scene: this.scene, modelType: ModelType.SURFACE } as SceneOptions;
+ this.rf = this.scene.getResourceFactory();
+ this.cam = await this.rf.createCamera({ 'name': 'Camera1' });
+ this.cam.enabled = true;
+ this.cam.position.z = 5;
+
+ // create a geometry
+ this.geom = this.scene.getNodeByPath('rootNode_/Unnamed Node 1/AnimatedCube') as Geometry;
+
+ // record original material
+ this.originalMat = this.geom.mesh.subMeshes[0].material;
+ })
+ .catch((error: string) => {
+ logger.error('init error: ' + error + '.');
+ });
+ }
+ }
+
+ build() {
+ Row() {
+ Column() {
+ Column() {
+ if (this.sceneOpt) {
+ Component3D(this.sceneOpt);
+ } else {
+ Text('Loading···');
+ }
+ }
+ .height('30%');
+
+ Button('Replace with a blank material')
+ .id('material')
+ .margin({ top: 80, left: 6 })
+ .width('60%')
+ .height(40)
+ .onClick(async (): Promise => {
+ logger.info('Start to replace with a blank material');
+
+ if (!this.blankMat) {
+ this.blankMat = await createMaterialPromise();
+ }
+
+ if (!this.scene || !this.rf) {
+ return;
+ }
+
+ this.geom = this.scene.getNodeByPath('rootNode_/Unnamed Node 1/AnimatedCube') as Geometry;
+
+ this.geom.mesh.materialOverride = undefined;
+ if (this.blankMat) {
+ this.geom.mesh.subMeshes[0].material = this.blankMat;
+ }
+
+ });
+
+ Button('Replace with a Shader material')
+ .id('shader')
+ .margin({ top: 20, left: 6 })
+ .width('60%')
+ .height(40)
+ .onClick(async (): Promise => {
+ logger.info('Start to replace with a shader material');
+
+ if (!this.shader) {
+ this.shader = await createShaderPromise();
+ }
+
+ if (!this.scene || !this.rf) {
+ return;
+ }
+
+ if (!this.shaderMat) {
+ let rf = this.scene.getResourceFactory();
+ this.shaderMat = await rf.createMaterial({ name: 'shaderMat' }, MaterialType.SHADER);
+ }
+
+ if (this.shader) {
+ this.shaderMat.colorShader = this.shader;
+ }
+
+ this.geom = this.scene.getNodeByPath('rootNode_/Unnamed Node 1/AnimatedCube') as Geometry;
+
+ this.geom.mesh.materialOverride = undefined;
+
+ if (this.shaderMat) {
+ this.geom.mesh.subMeshes[0].material = this.shaderMat;
+ }
+ })
+
+ Button('Replace with a Image material')
+ .id('image')
+ .margin({ top: 20, left: 6 })
+ .width('60%')
+ .height(40)
+ .onClick(async (): Promise => {
+ logger.info('Start to replace with a material of image');
+
+ if (!this.scene || !this.cam || !this.rf) {
+ return;
+ }
+
+ // create shader
+ this.shader = await this.rf.createShader({
+ name: 'shaderResource',
+ uri: $rawfile('shaders/custom_shader/custom_material_sample.shader')
+ });
+
+ // create imageMat
+ this.imageMat = await this.rf.createMaterial({ name: 'imageMat' }, MaterialType.SHADER) as ShaderMaterial;
+
+ // bind between shader and imageMat
+ this.imageMat.colorShader = this.shader;
+ let createdImage = await createImagePromise();
+ if (createdImage) {
+ this.imageMat.colorShader.inputs['BASE_COLOR_Image'] = createdImage;
+ }
+
+ this.geom = this.scene.getNodeByPath('rootNode_/Unnamed Node 1/AnimatedCube') as Geometry;
+
+ this.geom.mesh.materialOverride = undefined;
+ this.geom.mesh.subMeshes[0].material = this.imageMat;
+ })
+
+ Button('Add to Environment')
+ .id('env')
+ .margin({ top: 20, left: 6 })
+ .width('60%')
+ .height(40)
+ .onClick(async (): Promise => {
+ logger.info('Start to replace with a material of image');
+
+ if (!this.scene || !this.cam) {
+ return;
+ }
+
+ this.env = await createEnvironmentPromise();
+ if (this.env) {
+ this.scene.environment = this.env;
+ }
+ });
+
+ Button('back')
+ .id('back')
+ .margin({ top: 20, left: 6 })
+ .width('60%')
+ .height(40)
+ .onClick(() => {
+ router.back();
+ })
+ }
+ .width('100%');
+ }
+ .height('100%');
+ }
+}
\ No newline at end of file
diff --git a/graphic/ArkGraphics3D/entry/src/main/ets/arkgraphic/scene.ets b/graphic/ArkGraphics3D/entry/src/main/ets/arkgraphic/scene.ets
new file mode 100644
index 0000000000000000000000000000000000000000..005b2cdcbe73c8a6f64346ce56d41397e23493d6
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/main/ets/arkgraphic/scene.ets
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { router } from '@kit.ArkUI';
+import logger from '../utils/Logger';
+
+@Entry
+@Component
+struct scenePage {
+ build() {
+ Column({ space: 20 }) {
+ Button('Model Loading and Display')
+ .id('init')
+ .fontSize(16)
+ .fontWeight(500)
+ .margin({ top: 200, left: 6 })
+ .onClick((): void => {
+ router.pushUrl({
+ url: 'scene/init'
+ }, router.RouterMode.Standard, (err) => {
+ if (err) {
+ logger.error('Invoke replaceUrl failed, code is %{public}s, message is %{public}s');
+ return;
+ }
+ logger.info('Invoke replaceUrl succeeded.');
+ });
+ })
+ .width('80%')
+ .height(40);
+
+ Button('Creating and Managing a Camera')
+ .id('camera')
+ .fontSize(16)
+ .fontWeight(500)
+ .margin({ top: 20, left: 6 })
+ .onClick((): void => {
+ router.pushUrl({
+ url: 'scene/camera'
+ }, router.RouterMode.Standard, (err) => {
+ if (err) {
+ logger.error('Invoke replaceUrl failed, code is %{public}s, message is %{public}s');
+ return;
+ }
+ logger.info('Invoke replaceUrl succeeded.');
+ });
+ })
+ .width('80%')
+ .height(40)
+
+ Button('Creating and Managing Light')
+ .id('light')
+ .fontSize(16)
+ .fontWeight(500)
+ .margin({ top: 20, left: 6 })
+ .onClick((): void => {
+ router.pushUrl({
+ url: 'scene/light'
+ }, router.RouterMode.Standard, (err) => {
+ if (err) {
+ logger.error('Invoke replaceUrl failed, code is %{public}s, message is %{public}s');
+ return;
+ }
+ logger.info('Invoke replaceUrl succeeded.');
+ });
+ })
+ .width('80%')
+ .height(40)
+
+ Button('back')
+ .id('back')
+ .fontSize(16)
+ .fontWeight(500)
+ .margin({ top: 20, left: 6 })
+ .onClick(() => {
+ router.back();
+ })
+ .width('80%')
+ .height(40);
+ }
+ .width('100%');
+ }
+}
\ No newline at end of file
diff --git a/graphic/ArkGraphics3D/entry/src/main/ets/entryability/EntryAbility.ets b/graphic/ArkGraphics3D/entry/src/main/ets/entryability/EntryAbility.ets
new file mode 100644
index 0000000000000000000000000000000000000000..edc2839f203ba057c186e19b0cbbbf80c8faa8b3
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/main/ets/entryability/EntryAbility.ets
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit';
+import { hilog } from '@kit.PerformanceAnalysisKit';
+import { window } from '@kit.ArkUI';
+
+export default class EntryAbility extends UIAbility {
+ onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
+ this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
+ }
+
+ onDestroy(): void {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
+ }
+
+ onWindowStageCreate(windowStage: window.WindowStage): void {
+ // Main window is created, set main page for this ability
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
+
+ windowStage.loadContent('pages/Index', (err) => {
+ if (err.code) {
+ hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
+ return;
+ }
+ hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');
+ });
+ }
+
+ onWindowStageDestroy(): void {
+ // Main window is destroyed, release UI related resources
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
+ }
+
+ onForeground(): void {
+ // Ability has brought to foreground
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
+ }
+
+ onBackground(): void {
+ // Ability has back to background
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
+ }
+}
\ No newline at end of file
diff --git a/graphic/ArkGraphics3D/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/graphic/ArkGraphics3D/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets
new file mode 100644
index 0000000000000000000000000000000000000000..b1e212947256c5533c7b06285a597c94f840a6e3
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { hilog } from '@kit.PerformanceAnalysisKit';
+import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit';
+
+export default class EntryBackupAbility extends BackupExtensionAbility {
+ async onBackup() {
+ hilog.info(0x0000, 'testTag', 'onBackup ok');
+ }
+
+ async onRestore(bundleVersion: BundleVersion) {
+ hilog.info(0x0000, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion));
+ }
+}
\ No newline at end of file
diff --git a/graphic/ArkGraphics3D/entry/src/main/ets/pages/Index.ets b/graphic/ArkGraphics3D/entry/src/main/ets/pages/Index.ets
new file mode 100644
index 0000000000000000000000000000000000000000..c1ce392bc104598fd9058b7ec82a7dc1a9a166fa
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/main/ets/pages/Index.ets
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { router } from '@kit.ArkUI';
+import logger from '../utils/Logger';
+
+@Entry
+@Component
+struct Index {
+ build() {
+ Column({ space: 20 }) {
+ Button('Building and Managing ArkGraphics 3D Scenes')
+ .id('scene')
+ .fontWeight(500)
+ .margin({ top: 200, left: 6 })
+ .width('80%')
+ .height(40)
+ .onClick((): void => {
+ router.pushUrl(
+ { url: 'arkgraphic/scene' },
+ router.RouterMode.Standard,
+ (err) => {
+ if (err) {
+ logger.error('Invoke replaceUrl failed, code is ' + err.code + ', message is ' + err.message);
+ return;
+ }
+ logger.info('Invoke replaceUrl succeeded.');
+ }
+ );
+ })
+
+ Button('Creating and Using ArkGraphics 3D Resources')
+ .id('resource')
+ .fontWeight(500)
+ .margin({ top: 20, left: 6 })
+ .width('80%')
+ .height(40)
+ .onClick((): void => {
+ router.pushUrl(
+ { url: 'arkgraphic/resource' },
+ router.RouterMode.Standard,
+ (err) => {
+ if (err) {
+ logger.error('Invoke replaceUrl failed, code is ' + err.code + ', message is ' + err.message);
+ return;
+ }
+ logger.info('Invoke replaceUrl succeeded.');
+ }
+ );
+ })
+
+ Button('Controlling and Managing ArkGraphics 3D Scene Animations')
+ .id('animation')
+ .fontWeight(500)
+ .margin({ top: 20, left: 6 })
+ .width('80%')
+ .height(40)
+ .onClick((): void => {
+ router.pushUrl({ url: 'arkgraphic/animation' },
+ router.RouterMode.Single,
+ (err) => {
+ if (err) {
+ logger.error('Invoke replaceUrl failed, code is ' + err.code + ', message is ' + err.message);
+ return;
+ }
+ logger.info('Invoke replaceUrl succeeded.');
+ }
+ );
+ })
+ }
+ .width('100%');
+ }
+}
+
diff --git a/graphic/ArkGraphics3D/entry/src/main/ets/scene/camera.ets b/graphic/ArkGraphics3D/entry/src/main/ets/scene/camera.ets
new file mode 100644
index 0000000000000000000000000000000000000000..03cd0ffae1c5912b4cdc97576a8df06a7e0ec4a8
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/main/ets/scene/camera.ets
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Camera, Scene, SceneNodeParameters, SceneResourceFactory } from '@kit.ArkGraphics3D';
+import { router } from '@kit.ArkUI';
+import logger from '../utils/Logger';
+
+let globalScene: Scene | null = null;
+
+function createCameraPromise(): Promise {
+ return new Promise((resolve, reject) => {
+ // Switched from .gltf to .glb; same content, different format
+ let scene: Promise = Scene.load($rawfile('gltf/CubeWithFloor/glTF/AnimatedCube.glb'));
+ scene.then(async (result: Scene) => {
+ // Save loaded scene globally for reuse (e.g., in CameraPage)
+ globalScene = result;
+ let sceneFactory: SceneResourceFactory = result.getResourceFactory();
+ let sceneCameraParameter: SceneNodeParameters = { name: 'camera' };
+ // Create a Camera.
+ let camera: Promise = sceneFactory.createCamera(sceneCameraParameter);
+ camera.then(async (cameraEntity: Camera) => {
+ // Enable the camera node.
+ cameraEntity.enabled = true;
+
+ // Set the camera position.
+ cameraEntity.position.z = 5;
+
+ // Set the FoV.
+ cameraEntity.fov = 60 * Math.PI / 180;
+
+ // Set other camera parameters.
+ // ...
+ resolve(cameraEntity);
+ }).catch((error: string) => {
+ logger.error('Camera create failed: ' + error + '.');
+ reject(error);
+ });
+ }).catch((error: string) => {
+ logger.error('Scene load failed: ' + error);
+ reject(error);
+ });
+ });
+}
+
+@Entry
+@Component
+struct CameraPage {
+ scene: Scene | null = null;
+ @State sceneOpt: SceneOptions | null = null;
+ camera: Camera | null = null;
+ @State positionX: number = 0;
+ @State positionY: number = 0;
+ @State positionZ: number = 5;
+
+ onPageShow(): void {
+ this.init();
+ }
+
+ onPageHide(): void {
+ if (this.scene) {
+ this.scene.destroy();
+ }
+ this.scene = null;
+ this.sceneOpt = null;
+ this.camera = null;
+ globalScene = null;
+ }
+
+ async init(): Promise {
+ this.camera = await createCameraPromise();
+ if (globalScene && this.camera) {
+ this.scene = globalScene;
+ this.positionX = this.camera.position.x;
+ this.positionY = this.camera.position.y;
+ this.positionZ = this.camera.position.z;
+ this.sceneOpt = { scene: globalScene, modelType: ModelType.SURFACE } as SceneOptions;
+ }
+ }
+
+ build() {
+ Row() {
+ Column() {
+ Column() {
+ if (this.sceneOpt) {
+ // Use Component3D to display the 3D scenario.
+ Component3D(this.sceneOpt);
+ } else {
+ Text('Loading···');
+ }
+ }
+
+ Column() {
+ Text('X-axis: ' + this.positionX.toFixed(1)).fontSize(12);
+ Slider({
+ value: this.positionX,
+ min: 0,
+ max: 5,
+ step: 0.1,
+ style: SliderStyle.OutSet
+ })
+ .id('xAxis')
+ .showTips(false)
+ .onChange((value: number, mode: SliderChangeMode) => {
+ this.positionX = value;
+ if (mode === SliderChangeMode.End) {
+ if (!this.scene || !this.camera) {
+ return;
+ }
+ this.camera.position.x = value;
+ }
+ })
+ .width('100%')
+ }
+ .width('100%')
+
+ Column() {
+ Text('Y-axis: ' + this.positionY.toFixed(1)).fontSize(12);
+ Slider({
+ value: this.positionY,
+ min: 0,
+ max: 5,
+ step: 0.1,
+ style: SliderStyle.OutSet
+ })
+ .showTips(false)
+ .onChange((value: number, mode: SliderChangeMode) => {
+ this.positionY = value;
+ if (mode === SliderChangeMode.End) {
+ if (!this.scene || !this.camera) {
+ return;
+ }
+ this.camera.position.y = value;
+ }
+ })
+ .width('100%')
+ }
+ .width('100%')
+
+ Column() {
+ Text('Z-axis: ' + this.positionZ.toFixed(1)).fontSize(12)
+ Slider({
+ value: this.positionZ,
+ min: 5,
+ max: 10,
+ step: 0.1,
+ style: SliderStyle.OutSet
+ })
+ .showTips(false)
+ .onChange((value: number, mode: SliderChangeMode) => {
+ this.positionZ = value;
+ if (mode === SliderChangeMode.End) {
+ if (!this.scene || !this.camera) {
+ return;
+ }
+ this.camera.position.z = value;
+ }
+ })
+ .width('100%')
+ }
+ .width('100%')
+
+ Button('back')
+ .id('back')
+ .fontSize(16)
+ .fontWeight(500)
+ .margin({ top: 20, left: 6 })
+ .onClick(() => {
+ router.back();
+ })
+ .width('80%')
+ .height(40)
+ }
+ }.height('60%')
+ }
+}
diff --git a/graphic/ArkGraphics3D/entry/src/main/ets/scene/init.ets b/graphic/ArkGraphics3D/entry/src/main/ets/scene/init.ets
new file mode 100644
index 0000000000000000000000000000000000000000..1f80003f476516547818cbdc94338ec838739cb4
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/main/ets/scene/init.ets
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Camera, Scene, SceneResourceFactory } from '@kit.ArkGraphics3D';
+import { router } from '@kit.ArkUI';
+import logger from '../utils/Logger';
+
+@Entry
+@Component
+struct Model {
+ scene: Scene | null = null;
+ @State sceneOpt: SceneOptions | null = null;
+ cam: Camera | null = null;
+
+ onPageShow(): void {
+ this.init();
+ }
+
+ onPageHide(): void {
+ if (this.scene) {
+ this.scene.destroy();
+ }
+ this.scene = null;
+ this.sceneOpt = null;
+ this.cam = null;
+ }
+
+ init(): void {
+ if (this.scene == null) {
+ // Load the model and place the gltf file in the related path. Use the actual path during loading.
+ // Switched from .gltf to .glb; same content, different format
+ Scene.load($rawfile('gltf/DamagedHelmet/glTF/DamagedHelmet.glb'))
+ .then(async (result: Scene) => {
+ this.scene = result;
+ let rf: SceneResourceFactory = this.scene.getResourceFactory();
+ // Create a Camera.
+ this.cam = await rf.createCamera({ 'name': 'Camera' });
+ // Set proper camera parameters.
+ this.cam.enabled = true;
+ this.cam.position.z = 5;
+
+ this.sceneOpt = { scene: this.scene, modelType: ModelType.SURFACE } as SceneOptions;
+ logger.info('initialization completely.');
+ })
+ .catch((reason: string) => {
+ console.log(reason);
+ });
+ }
+ }
+
+ build() {
+ Row() {
+ Column() {
+ if (this.sceneOpt) {
+ // Use Component3D to display the 3D scenario.
+ Component3D(this.sceneOpt);
+ } else {
+ Text('Loading···');
+ }
+
+ Button('back')
+ .id('back')
+ .fontSize(16)
+ .fontWeight(500)
+ .margin({ top: 20, left: 6 })
+ .onClick(() => {
+ router.back();
+ })
+ .width('80%')
+ .height(40)
+ }.width('100%')
+ }.height('60%')
+ }
+}
diff --git a/graphic/ArkGraphics3D/entry/src/main/ets/scene/light.ets b/graphic/ArkGraphics3D/entry/src/main/ets/scene/light.ets
new file mode 100644
index 0000000000000000000000000000000000000000..0a7482a83645a352f1b1af955fc7cd680ec93437
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/main/ets/scene/light.ets
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Camera, Light, LightType, Scene, SceneNodeParameters, SceneResourceFactory } from '@kit.ArkGraphics3D';
+import { router } from '@kit.ArkUI';
+import logger from '../utils/Logger';
+
+let globalScene: Scene | null = null;
+
+function createLightPromise(): Promise {
+ return new Promise((resolve, reject) => {
+ // Switched from .gltf to .glb; same content, different format
+ let scene: Promise = Scene.load($rawfile('gltf/CubeWithFloor/glTF/AnimatedCube.glb'));
+ scene.then(async (result: Scene) => {
+ // Save loaded scene globally for reuse (e.g., in LightPage)
+ globalScene = result;
+ let sceneFactory: SceneResourceFactory = result.getResourceFactory();
+ let lightParameter: SceneNodeParameters = { name: 'light' };
+ // Create directional light.
+ let light: Promise = sceneFactory.createLight(lightParameter, LightType.DIRECTIONAL);
+ light.then(async (lightEntity: Light) => {
+ // Set the color of the directional light.
+ lightEntity.color = { r: 0.8, g: 0.1, b: 0.2, a: 1.0 };
+
+ // Set other light parameters.
+ // ...
+ resolve(lightEntity);
+ }).catch((err: string) => {
+ logger.error('Light create failed: ' + err + '.');
+ reject(err);
+ });
+ }).catch((error: string) => {
+ logger.error('Scene load failed: ' + error);
+ reject(error);
+ });
+ });
+}
+
+@Entry
+@Component
+struct LightPage {
+ scene: Scene | null = null;
+ @State sceneOpt: SceneOptions | null = null;
+ cam: Camera | null = null;
+ light: Light | null = null;
+ rf: SceneResourceFactory | null = null;
+ @State red: number = 0;
+ @State green: number = 0;
+ @State blue: number = 0;
+
+ onPageShow(): void {
+ this.init();
+ }
+
+ onPageHide(): void {
+ if (this.scene) {
+ this.scene.destroy();
+ }
+ this.scene = null;
+ this.sceneOpt = null;
+ this.cam = null;
+ this.light = null;
+ this.rf = null;
+ globalScene = null;
+ }
+
+ async init(): Promise {
+ this.light = await createLightPromise();
+ if (globalScene && this.light) {
+ this.scene = globalScene;
+ this.sceneOpt = { scene: globalScene, modelType: ModelType.SURFACE } as SceneOptions;
+ this.rf = this.scene.getResourceFactory();
+ this.cam = await this.rf.createCamera({ 'name': 'Camera1' });
+ this.cam.enabled = true;
+ this.cam.position.z = 5;
+ // Initialize color value
+ this.red = this.light.color.r;
+ this.green = this.light.color.g;
+ this.blue = this.light.color.b;
+ }
+ }
+
+ build() {
+ Row() {
+ Column() {
+ if (this.sceneOpt) {
+ Component3D(this.sceneOpt);
+ } else {
+ Text('Loading···');
+ }
+
+ Column() {
+ Text('Red: ' + this.red.toFixed(1)).fontSize(12);
+ Slider({
+ value: this.red,
+ min: 0,
+ max: 1,
+ step: 0.01,
+ style: SliderStyle.OutSet
+ })
+ .showTips(false)
+ .onChange((value: number, mode: SliderChangeMode) => {
+ this.red = value;
+ if (mode === SliderChangeMode.End) {
+ if (!this.scene || !this.light) {
+ return;
+ }
+ this.light.color = {
+ r: this.red,
+ g: this.green,
+ b: this.blue,
+ a: 1.0
+ }
+ }
+ })
+ .width('100%')
+ }
+ .width('100%')
+
+ Column() {
+ Text('Green: ' + this.green.toFixed(1)).fontSize(12)
+ Slider({
+ value: this.green,
+ min: 0,
+ max: 1,
+ step: 0.01,
+ style: SliderStyle.OutSet
+ })
+ .showTips(false)
+ .onChange((value: number, mode: SliderChangeMode) => {
+ this.green = value;
+ if (mode === SliderChangeMode.End) {
+ if (!this.scene || !this.light) {
+ return;
+ }
+
+ this.light.color = {
+ r: this.red,
+ g: this.green,
+ b: this.blue,
+ a: 1.0
+ }
+ }
+ })
+ .width('100%')
+ }
+ .width('100%')
+
+ Column() {
+ Text('Blue: ' + this.blue.toFixed(1)).fontSize(12)
+ Slider({
+ value: this.blue,
+ min: 0,
+ max: 1,
+ step: 0.01,
+ style: SliderStyle.OutSet
+ })
+ .showTips(false)
+ .onChange((value: number, mode: SliderChangeMode) => {
+ this.blue = value;
+ if (mode === SliderChangeMode.End) {
+ if (!this.scene || !this.light) {
+ return;
+ }
+
+ this.light.color = {
+ r: this.red,
+ g: this.green,
+ b: this.blue,
+ a: 1.0
+ }
+ }
+ })
+ .width('100%')
+ }
+ .width('100%')
+
+ Button('back')
+ .id('back')
+ .fontSize(16)
+ .fontWeight(500)
+ .margin({ top: 20, left: 6 })
+ .onClick(() => {
+ router.back();
+ })
+ .width('80%')
+ .height(40)
+ }
+ .width('100%')
+ }
+ .height('60%')
+ }
+}
diff --git a/graphic/ArkGraphics3D/entry/src/main/ets/utils/Logger.ets b/graphic/ArkGraphics3D/entry/src/main/ets/utils/Logger.ets
new file mode 100644
index 0000000000000000000000000000000000000000..6ae0f3425a43a6501455d3a6020793ed1168b177
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/main/ets/utils/Logger.ets
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { hilog } from '@kit.PerformanceAnalysisKit';
+
+class Logger {
+ private domain: number;
+ private prefix: string;
+ private format: string = '%{public}s';
+
+ constructor(prefix: string) {
+ this.prefix = prefix;
+ this.domain = 0xFF00;
+ }
+
+ debug(...args: string[]) {
+ hilog.debug(this.domain, this.prefix, this.format, args);
+ }
+
+ info(...args: string[]) {
+ hilog.info(this.domain, this.prefix, this.format, args);
+ }
+
+ warn(...args: string[]) {
+ hilog.warn(this.domain, this.prefix, this.format, args);
+ }
+
+ error(...args: string[]) {
+ hilog.error(this.domain, this.prefix, this.format, args);
+ }
+}
+
+export default new Logger('[Sample_ArkGraphics3D]');
\ No newline at end of file
diff --git a/graphic/ArkGraphics3D/entry/src/main/module.json5 b/graphic/ArkGraphics3D/entry/src/main/module.json5
new file mode 100644
index 0000000000000000000000000000000000000000..4144486d1af4c03b0d767cce1cda86fc0d697f91
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/main/module.json5
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "module": {
+ "name": "entry",
+ "type": "entry",
+ "description": "$string:module_desc",
+ "mainElement": "EntryAbility",
+ "deviceTypes": [
+ "default",
+ "tablet"
+ ],
+ "deliveryWithInstall": true,
+ "installationFree": false,
+ "pages": "$profile:main_pages",
+ "abilities": [
+ {
+ "name": "EntryAbility",
+ "srcEntry": "./ets/entryability/EntryAbility.ets",
+ "description": "$string:EntryAbility_desc",
+ "icon": "$media:layered_image",
+ "label": "$string:EntryAbility_label",
+ "startWindowIcon": "$media:startIcon",
+ "startWindowBackground": "$color:start_window_background",
+ "exported": true,
+ "skills": [
+ {
+ "entities": [
+ "entity.system.home"
+ ],
+ "actions": [
+ "action.system.home"
+ ]
+ }
+ ]
+ }
+ ],
+ "extensionAbilities": [
+ {
+ "name": "EntryBackupAbility",
+ "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets",
+ "type": "backup",
+ "exported": false,
+ "metadata": [
+ {
+ "name": "ohos.extension.backup",
+ "resource": "$profile:backup_config"
+ }
+ ]
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/base/element/color.json b/graphic/ArkGraphics3D/entry/src/main/resources/base/element/color.json
new file mode 100644
index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/main/resources/base/element/color.json
@@ -0,0 +1,8 @@
+{
+ "color": [
+ {
+ "name": "start_window_background",
+ "value": "#FFFFFF"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/base/element/string.json b/graphic/ArkGraphics3D/entry/src/main/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..22d70eec8727bed9ab34886858eb3fb30c773fd5
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/main/resources/base/element/string.json
@@ -0,0 +1,16 @@
+{
+ "string": [
+ {
+ "name": "module_desc",
+ "value": "module description"
+ },
+ {
+ "name": "EntryAbility_desc",
+ "value": "description"
+ },
+ {
+ "name": "EntryAbility_label",
+ "value": "ArkGraphics3D"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/base/media/background.png b/graphic/ArkGraphics3D/entry/src/main/resources/base/media/background.png
new file mode 100644
index 0000000000000000000000000000000000000000..f939c9fa8cc8914832e602198745f592a0dfa34d
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/base/media/background.png differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/base/media/foreground.png b/graphic/ArkGraphics3D/entry/src/main/resources/base/media/foreground.png
new file mode 100644
index 0000000000000000000000000000000000000000..4483ddad1f079e1089d685bd204ee1cfe1d01902
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/base/media/foreground.png differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/base/media/layered_image.json b/graphic/ArkGraphics3D/entry/src/main/resources/base/media/layered_image.json
new file mode 100644
index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/main/resources/base/media/layered_image.json
@@ -0,0 +1,7 @@
+{
+ "layered-image":
+ {
+ "background" : "$media:background",
+ "foreground" : "$media:foreground"
+ }
+}
\ No newline at end of file
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/base/media/startIcon.png b/graphic/ArkGraphics3D/entry/src/main/resources/base/media/startIcon.png
new file mode 100644
index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/base/media/startIcon.png differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/base/profile/backup_config.json b/graphic/ArkGraphics3D/entry/src/main/resources/base/profile/backup_config.json
new file mode 100644
index 0000000000000000000000000000000000000000..78f40ae7c494d71e2482278f359ec790ca73471a
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/main/resources/base/profile/backup_config.json
@@ -0,0 +1,3 @@
+{
+ "allowToBackupRestore": true
+}
\ No newline at end of file
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/base/profile/main_pages.json b/graphic/ArkGraphics3D/entry/src/main/resources/base/profile/main_pages.json
new file mode 100644
index 0000000000000000000000000000000000000000..4158b4f8ebadd84491400b286ba8b526df17a5f6
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/main/resources/base/profile/main_pages.json
@@ -0,0 +1,11 @@
+{
+ "src": [
+ "pages/Index",
+ "arkgraphic/scene",
+ "arkgraphic/resource",
+ "arkgraphic/animation",
+ "scene/init",
+ "scene/camera",
+ "scene/light"
+ ]
+}
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/dark/element/color.json b/graphic/ArkGraphics3D/entry/src/main/resources/dark/element/color.json
new file mode 100644
index 0000000000000000000000000000000000000000..79b11c2747aec33e710fd3a7b2b3c94dd9965499
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/main/resources/dark/element/color.json
@@ -0,0 +1,8 @@
+{
+ "color": [
+ {
+ "name": "start_window_background",
+ "value": "#000000"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/KTX/quarry_02_2k_radiance.ktx b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/KTX/quarry_02_2k_radiance.ktx
new file mode 100644
index 0000000000000000000000000000000000000000..250942b8b36600420116f48a6c85def90efaf0a4
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/KTX/quarry_02_2k_radiance.ktx differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Binary/BrainStem.glb b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Binary/BrainStem.glb
new file mode 100644
index 0000000000000000000000000000000000000000..88fe89569bedb74926a35b460b8b29ff8b609d01
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Binary/BrainStem.glb differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Draco/BrainStem.glb b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Draco/BrainStem.glb
new file mode 100644
index 0000000000000000000000000000000000000000..c72536ca3be25984c17c30ef662c3983b0c9ba05
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Draco/BrainStem.glb differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Draco/BrainStem0.bin b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Draco/BrainStem0.bin
new file mode 100644
index 0000000000000000000000000000000000000000..96c3c805156e57c05b37a10db54a5709f9cf47fd
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Draco/BrainStem0.bin differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Embedded/BrainStem.glb b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Embedded/BrainStem.glb
new file mode 100644
index 0000000000000000000000000000000000000000..fb2fbe95ad93346218092f02a3b725d697db8504
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Embedded/BrainStem.glb differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Meshopt/BrainStem.bin b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Meshopt/BrainStem.bin
new file mode 100644
index 0000000000000000000000000000000000000000..5f85d43cc9a5ff51a05650692a22024c9379390c
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Meshopt/BrainStem.bin differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Meshopt/BrainStem.glb b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Meshopt/BrainStem.glb
new file mode 100644
index 0000000000000000000000000000000000000000..c600aeb2fa4df27b6537fe3960d589d82a290a36
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF-Meshopt/BrainStem.glb differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF/BrainStem.glb b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF/BrainStem.glb
new file mode 100644
index 0000000000000000000000000000000000000000..fb2fbe95ad93346218092f02a3b725d697db8504
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF/BrainStem.glb differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF/BrainStem0.bin b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF/BrainStem0.bin
new file mode 100644
index 0000000000000000000000000000000000000000..a684a8f3ea96953630e64babe15c93c75c3035cf
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/BrainStem/glTF/BrainStem0.bin differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/CubeWithFloor/glTF/AnimatedCube.bin b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/CubeWithFloor/glTF/AnimatedCube.bin
new file mode 100644
index 0000000000000000000000000000000000000000..72f7d2d52ad79f8cb5a71f1640e51bd91ddd4a08
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/CubeWithFloor/glTF/AnimatedCube.bin differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/CubeWithFloor/glTF/AnimatedCube.glb b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/CubeWithFloor/glTF/AnimatedCube.glb
new file mode 100644
index 0000000000000000000000000000000000000000..ff0f71c3156997419e45c91bfe9bc75c23318596
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/CubeWithFloor/glTF/AnimatedCube.glb differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/CubeWithFloor/glTF/AnimatedCube_BaseColor.png b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/CubeWithFloor/glTF/AnimatedCube_BaseColor.png
new file mode 100644
index 0000000000000000000000000000000000000000..5e5cb2068fa85aec944bd75c981fa6420c1cea87
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/CubeWithFloor/glTF/AnimatedCube_BaseColor.png differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/CubeWithFloor/glTF/AnimatedCube_MetallicRoughness.png b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/CubeWithFloor/glTF/AnimatedCube_MetallicRoughness.png
new file mode 100644
index 0000000000000000000000000000000000000000..efd20260218a92d097c4005a8167dcdf08180664
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/CubeWithFloor/glTF/AnimatedCube_MetallicRoughness.png differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/DamagedHelmet.bin b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/DamagedHelmet.bin
new file mode 100644
index 0000000000000000000000000000000000000000..662eacc1da580cdcbc08572d5535b3ed484b1579
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/DamagedHelmet.bin differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/DamagedHelmet.glb b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/DamagedHelmet.glb
new file mode 100644
index 0000000000000000000000000000000000000000..2cee76d76a752c92458a8a8294ff3658fdc9d6c7
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/DamagedHelmet.glb differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_AO.jpg b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_AO.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..419f62840ad0eff2bc2482ada01e55ed02fb87e3
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_AO.jpg differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_albedo.jpg b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_albedo.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..15d64855c732130451cfd511d61ffb07b2d97e1f
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_albedo.jpg differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_emissive.jpg b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_emissive.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..2de59e897bbfb1a664053bc5ba3cab0cd21accf0
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_emissive.jpg differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_metalRoughness.jpg b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_metalRoughness.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..04874cb6e9aba270a2c5d3b41f487c0dcc7b481d
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_metalRoughness.jpg differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_normal.jpg b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_normal.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..94ca20a2d131d5aa70f93f040707a80987cc4904
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/gltf/DamagedHelmet/glTF/Default_normal.jpg differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/image/Cube_BaseColor.png b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/image/Cube_BaseColor.png
new file mode 100644
index 0000000000000000000000000000000000000000..5e5cb2068fa85aec944bd75c981fa6420c1cea87
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/image/Cube_BaseColor.png differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag
new file mode 100644
index 0000000000000000000000000000000000000000..97d939730b439961cb3dd709c063c29eaddda15f
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#version 460 core
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shading_language_420pack : enable
+
+// includes
+
+#include "render/shaders/common/render_compatibility_common.h"
+
+#include "render/shaders/common/render_color_conversion_common.h"
+#include "render/shaders/common/render_post_process_common.h"
+#include "render/shaders/common/render_tonemap_common.h"
+
+#include "3d/shaders/common/3d_dm_structures_common.h"
+
+// sets and specializations
+
+#include "3d/shaders/common/3d_dm_frag_layout_common.h"
+#include "3d/shaders/common/3d_dm_lighting_common.h"
+
+// custom user set
+struct MyMaterialSampleStruct {
+ vec4 vec_1;
+ float time;
+ bool dof;
+ bool motionBlur;
+};
+layout(set = 1, binding = 4, std140) uniform uMyBuffer0
+{
+ MyMaterialSampleStruct uMyData;
+};
+
+
+#define CORE3D_DM_FW_FRAG_INPUT 1
+#include "3d/shaders/common/3d_dm_inout_common.h"
+#include "3d/shaders/common/3d_dm_inplace_sampling_common.h"
+#include "3d/shaders/common/3d_dm_inplace_post_process.h"
+
+// in / out
+
+layout(location = 0) out vec4 outColor;
+
+
+// Corrected normal vector.
+
+#define hash(x) fract(sin(x)*5723.2622)
+const float pi = acos(-1.);
+const float pi2 = acos(-1.)*2.;
+
+// If you have a strong PC, make it bigger.
+const int nS = 2; // Number of samples.
+
+const float w = .03; // Width of the fiber.
+
+// Rotation matrix in two dimensions.
+mat2 rot(float a) {
+ float s = sin(a), c = cos(a);
+ return mat2(c, s, -s, c);
+}
+
+float hash12(vec2 p) {
+ float v = dot(p, vec2(1.8672, 1.3723));
+ return hash(v);
+}
+
+// 1D perlin noise.
+float perlin1d(float x) {
+ float i = floor(x);
+ float f = fract(x);
+ float u = f*f*(3.-2.*f);
+
+ return mix(f*(hash(i)*2.-1.), (f-1.)*(hash(i+1.)*2.-1.), u); // from -0.5 to 0.5
+}
+
+float fiberShape(float x, float time) {
+ float s = .03;
+ float curve = smoothstep(.25-s, .25+s, abs(fract(time*.11) - .5));
+ return perlin1d(x) * (1. - w * 2.) * curve;
+}
+
+// Smooth stair-like noise.
+float stepNoise(float x, float n) {
+ float i = floor(x);
+ float s = .1;
+ float u = smoothstep(.5-s, .5+s, fract(x));
+
+ return mix(floor(hash(i)*n), floor(hash(i+1.)*n), u);
+}
+
+
+
+void main(void)
+{
+ vec2 uv = (inUv.xy-vec2(0.5,0.5))*2.0f;
+ vec2 fragCoord = inUv.xy;
+
+ vec3 col = vec3(0);
+
+ vec3 ac = vec3(0);
+
+
+ for(float j=0.; j 0. && abs(p.x) < w) {
+ q = p;
+ hit = true;
+ break;
+ }
+ }
+
+ if(hit) { // Ray hit a fiber.
+ vec3 add = vec3(1);
+
+ vec3 lightDir = normalize(vec3(-5, 2, -2));
+ vec3 normal = normalize(vec3(q.x, sqrt(w*w - q.x*q.x), 0));
+
+ float e = 1e-4;
+ float grad = (fiberShape(q.y + e, time) - fiberShape(q.y - e, time)) / (e*2.);
+ float a = atan(grad);
+ normal.xz *= rot(-id.x*2. + a);
+
+ // Shading
+ float diff = max(dot(normal, lightDir), 0.);
+ float spec = pow(max(dot(reflect(lightDir, normal), rds), 0.), 20.);
+ float m = .5;
+ float lp = 3.;
+ add *= diff * (1.-m) * lp + spec * m * lp + .2;
+
+ // Streaming light.
+ q.y = fract(q.y * .03 - time * .2) - .5;
+ add += smoothstep(.01, 0., abs(q.y)) * 3.;
+
+ // Flickering light.
+ float T = time + hash12(id);
+ add += step(hash12(id*1.1 + floor(T)), .05) * step(fract(T*3.), .8) * 3.;
+
+ add *= exp(-t*t*.1 -id.x*id.x*.001);
+
+ ac += add;
+ }
+ }
+
+ col += ac / float(nS);
+
+ float a= uMyData.vec_1.w;
+
+ col*=uMyData.vec_1.xyz;
+
+ col = pow(col, vec3(1./2.2)); // Gamma correction.
+
+ CORE_RELAXEDP vec4 baseColor = GetBaseColorSample(inUv);
+
+ col*=baseColor.xyz;
+
+ outColor = vec4(col,a);
+}
+
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv
new file mode 100644
index 0000000000000000000000000000000000000000..534bdb3ca4c0ed704d84f6d2d27162e5d2fc4ac6
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv.gl b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv.gl
new file mode 100644
index 0000000000000000000000000000000000000000..3a703d3a60b377450fb36391e722d743459d2c28
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv.gl
@@ -0,0 +1,234 @@
+#version 450
+
+struct DefaultMaterialSingleMaterialStruct
+{
+ vec4 factors[15];
+ uvec4 indices;
+};
+
+struct DefaultMaterialMaterialStruct
+{
+ DefaultMaterialSingleMaterialStruct material[64];
+};
+
+#ifndef SPIRV_CROSS_CONSTANT_ID_1
+#define SPIRV_CROSS_CONSTANT_ID_1 0u
+#endif
+const uint CORE_MATERIAL_FLAGS = SPIRV_CROSS_CONSTANT_ID_1;
+const uint _162 = (CORE_MATERIAL_FLAGS & 8u);
+const bool _163 = (_162 == 8u);
+
+struct DefaultMaterialTransformSingleMaterialStruct
+{
+ uvec4 _packed[15];
+ uvec4 indices;
+};
+
+struct DefaultMaterialTransformMaterialStruct
+{
+ DefaultMaterialTransformSingleMaterialStruct material[64];
+};
+
+struct MyMaterialSampleStruct
+{
+ vec4 vec_1;
+ float time;
+ uint dof;
+ uint motionBlur;
+};
+
+layout(std140) uniform s1_b2
+{
+ DefaultMaterialMaterialStruct uMaterialData;
+} _s1_b2;
+
+layout(std140) uniform s1_b3
+{
+ DefaultMaterialTransformMaterialStruct uMaterialTransformData;
+} _s1_b3;
+
+layout(std140) uniform s1_b4
+{
+ MyMaterialSampleStruct uMyData;
+} _s1_b4;
+
+uniform sampler2D s2_b0;
+
+layout(location = 4) in vec4 inUv;
+layout(location = 0) out vec4 outColor;
+
+vec2 _1444;
+float _1477;
+float _1562;
+
+void main()
+{
+ vec2 _336 = (inUv.xy - vec2(0.5)) * 2.0;
+ vec3 _1434;
+ vec2 _1462;
+ vec2 _1470;
+ _1470 = _1444;
+ _1462 = _1444;
+ _1434 = vec3(0.0);
+ vec2 _1466;
+ float _1472;
+ vec3 _1490;
+ vec2 _1516;
+ float _1476;
+ for (float _1433 = 0.0; _1433 < 2.0; _1476 = _1472, _1470 = _1466, _1462 = _1516, _1434 = _1490, _1433 += 1.0)
+ {
+ vec2 _372 = (inUv.xy + vec2(fract(_s1_b4.uMyData.time) * 500.0)) + vec2(_1433 * 31.3528308868408203125);
+ float _1448;
+ if (_s1_b4.uMyData.motionBlur != 0u)
+ {
+ _1448 = fma(fract(sin(dot(_372, vec2(1.86720001697540283203125, 1.37230002880096435546875))) * 5723.26220703125), 0.0500000007450580596923828125, _s1_b4.uMyData.time);
+ }
+ else
+ {
+ _1448 = _s1_b4.uMyData.time;
+ }
+ float _389 = -_1448;
+ float _912 = floor(_389);
+ vec3 _1368 = vec3(0.0, 1.0, _389);
+ _1368.x = (mix(floor(fract(sin(_912) * 5723.26220703125) * 5.0), floor(fract(sin(_912 + 1.0) * 5723.26220703125) * 5.0), smoothstep(0.4000000059604644775390625, 0.60000002384185791015625, fract(_389))) - 2.0) * 0.5;
+ float _411 = (-500.0) - _1448;
+ float _943 = floor(_411);
+ vec3 _1372 = _1368;
+ _1372.y = fma(mix(floor(fract(sin(_943) * 5723.26220703125) * 5.0), floor(fract(sin(_943 + 1.0) * 5723.26220703125) * 5.0), smoothstep(0.4000000059604644775390625, 0.60000002384185791015625, fract(_411))), 0.5, 1.0);
+ vec3 _423 = vec3(0.0, -0.5, (-0.5) - _1448) - _1372;
+ vec3 _424 = normalize(_423);
+ vec3 _429 = normalize(cross(_424, vec3(0.0, 1.0, 0.0)));
+ float _440 = (-1000.0) - _1448;
+ float _974 = floor(_440);
+ float _475 = length(_423);
+ vec3 _1449;
+ if (_s1_b4.uMyData.dof != 0u)
+ {
+ float _504 = fract(sin(dot(_372 * 1.2000000476837158203125, vec2(1.86720001697540283203125, 1.37230002880096435546875))) * 5723.26220703125) * 6.283185482025146484375;
+ vec2 _518 = _1372.xy + (((vec2(cos(_504), sin(_504)) * sqrt(fract(sin(dot(_372 * 1.10000002384185791015625, vec2(1.86720001697540283203125, 1.37230002880096435546875))) * 5723.26220703125))) * _475) * 0.02500000037252902984619140625);
+ vec3 _1377 = _1372;
+ _1377.x = _518.x;
+ vec3 _1379 = _1377;
+ _1379.y = _518.y;
+ _1449 = _1379;
+ }
+ else
+ {
+ _1449 = _1372;
+ }
+ vec3 _527 = normalize((_1372 + (normalize(((_429 * _336.x) + (normalize(cross(_429, _424)) * _336.y)) + (_424 / vec3(tan(fma(fma(mix(floor(fract(sin(_974) * 5723.26220703125) * 2.0), floor(fract(sin(_974 + 1.0) * 5723.26220703125) * 2.0), smoothstep(0.4000000059604644775390625, 0.60000002384185791015625, fract(_440))), 2.0, -1.0), 20.0, 40.0) * 0.00872664712369441986083984375)))) * _475)) - _1449);
+ vec2 _1467;
+ _1467 = _1470;
+ float _548;
+ vec2 _577;
+ bool _1455;
+ vec2 _1458;
+ float _1450 = 0.0;
+ float _1473 = _1476;
+ for (;;)
+ {
+ if (_1450 < 50.0)
+ {
+ _548 = (-fma(_1450, 0.0500000007450580596923828125, _1449.y)) / _527.y;
+ vec2 _556 = _1449.xz + (_527.xz * _548);
+ vec2 _1384 = _556;
+ _1384.x = fma(fract(sin(_1450) * 5723.26220703125), 500.0, _556.x);
+ float _567 = _1450 * 2.0;
+ float _1023 = sin(_567);
+ float _1025 = cos(_567);
+ vec2 _571 = _1384 * mat2(vec2(_1025, _1023), vec2(-_1023, _1025));
+ float _575 = _571.x;
+ _577 = vec2(_1450, floor(_575));
+ float _581 = fract(_575) - 0.5;
+ float _589 = fma(fract(sin(dot(_577, vec2(1.86720001697540283203125, 1.37230002880096435546875))) * 5723.26220703125), 500.0, _571.y);
+ float _1069 = floor(_589);
+ float _1071 = fract(_589);
+ float _599 = fma(mix(_1071 * fma(fract(sin(_1069) * 5723.26220703125), 2.0, -1.0), (_1071 - 1.0) * fma(fract(sin(_1069 + 1.0) * 5723.26220703125), 2.0, -1.0), (_1071 * _1071) * fma(-2.0, _1071, 3.0)) * (-0.939999997615814208984375), smoothstep(0.2199999988079071044921875, 0.2800000011920928955078125, abs(fract(_1448 * 0.10999999940395355224609375) - 0.5)), _581);
+ vec2 _1395 = vec2(_581, _589);
+ _1395.x = _599;
+ bool _602 = _548 > 0.0;
+ bool _609;
+ if (_602)
+ {
+ _609 = abs(_599) < 0.02999999932944774627685546875;
+ }
+ else
+ {
+ _609 = _602;
+ }
+ if (_609)
+ {
+ _1472 = _548;
+ _1466 = _577;
+ _1458 = _1395;
+ _1455 = true;
+ break;
+ }
+ _1450 += 1.0;
+ _1473 = _548;
+ _1467 = _577;
+ continue;
+ }
+ else
+ {
+ _1472 = _1473;
+ _1466 = _1467;
+ _1458 = _1462;
+ _1455 = false;
+ break;
+ }
+ }
+ if (_1455)
+ {
+ vec3 _640 = normalize(vec3(_1458.x, sqrt(fma(-_1458.x, _1458.x, 0.000899999984540045261383056640625)), 0.0));
+ float _647 = _1458.y + 9.9999997473787516355514526367188e-05;
+ float _1113 = smoothstep(0.2199999988079071044921875, 0.2800000011920928955078125, abs(fract(_1448 * 0.10999999940395355224609375) - 0.5));
+ float _1125 = floor(_647);
+ float _1127 = fract(_647);
+ float _655 = _1458.y - 9.9999997473787516355514526367188e-05;
+ float _1181 = floor(_655);
+ float _1183 = fract(_655);
+ float _672 = fma(_1466.x, -2.0, atan(fma(mix(_1127 * fma(fract(sin(_1125) * 5723.26220703125), 2.0, -1.0), (_1127 - 1.0) * fma(fract(sin(_1125 + 1.0) * 5723.26220703125), 2.0, -1.0), (_1127 * _1127) * fma(-2.0, _1127, 3.0)) * 0.939999997615814208984375, _1113, -((mix(_1183 * fma(fract(sin(_1181) * 5723.26220703125), 2.0, -1.0), (_1183 - 1.0) * fma(fract(sin(_1181 + 1.0) * 5723.26220703125), 2.0, -1.0), (_1183 * _1183) * fma(-2.0, _1183, 3.0)) * 0.939999997615814208984375) * _1113)) * 5000.0));
+ float _1216 = sin(_672);
+ float _1218 = cos(_672);
+ vec2 _677 = _640.xz * mat2(vec2(_1218, _1216), vec2(-_1216, _1218));
+ vec3 _1404 = _640;
+ _1404.x = _677.x;
+ vec3 _1406 = _1404;
+ _1406.z = _677.y;
+ float _720 = fract(fma(_1458.y, 0.02999999932944774627685546875, _1448 * (-0.20000000298023223876953125))) - 0.5;
+ vec2 _1409 = _1458;
+ _1409.y = _720;
+ float _736 = _1448 + fract(sin(dot(_1466, vec2(1.86720001697540283203125, 1.37230002880096435546875))) * 5723.26220703125);
+ _1516 = _1409;
+ _1490 = _1434 + ((((vec3(1.0) * fma(1.5, max(dot(_1406, vec3(-0.8703882694244384765625, 0.348155319690704345703125, -0.348155319690704345703125)), 0.0) + pow(max(dot(reflect(vec3(-0.8703882694244384765625, 0.348155319690704345703125, -0.348155319690704345703125), _1406), _527), 0.0), 20.0), 0.20000000298023223876953125)) + vec3(smoothstep(0.00999999977648258209228515625, 0.0, abs(_720)) * 3.0)) + vec3((step(fract(sin(dot((_1466 * 1.10000002384185791015625) + vec2(floor(_736)), vec2(1.86720001697540283203125, 1.37230002880096435546875))) * 5723.26220703125), 0.0500000007450580596923828125) * step(fract(_736 * 3.0), 0.800000011920928955078125)) * 3.0)) * exp(fma((-_1472) * _1472, 0.100000001490116119384765625, (_1466.x * _1466.x) * (-0.001000000047497451305389404296875))));
+ }
+ else
+ {
+ _1516 = _1458;
+ _1490 = _1434;
+ }
+ }
+ uint _1301 = floatBitsToUint(_s1_b2.uMaterialData.material[0].factors[11].y);
+ vec2 _1436;
+ if (((_1301 >> uint(16)) & 1u) == 1u)
+ {
+ _1436 = inUv.zw;
+ }
+ else
+ {
+ _1436 = inUv.xy;
+ }
+ vec2 _1445;
+ if (_163 && (((_1301 & 65535u) & 1u) == 1u))
+ {
+ vec4 _1531 = vec4(unpackHalf2x16(_s1_b3.uMaterialTransformData.material[0]._packed[0u].x), unpackHalf2x16(_s1_b3.uMaterialTransformData.material[0]._packed[0u].y));
+ _1445 = vec2(dot(_1531.xy, _1436), dot(_1531.zw, _1436)) + vec4(unpackHalf2x16(_s1_b3.uMaterialTransformData.material[0]._packed[0u].z), _1562, _1562).xy;
+ }
+ else
+ {
+ _1445 = _1436;
+ }
+ outColor = vec4(pow((_1434 * vec3(0.5)) * _s1_b4.uMyData.vec_1.xyz, vec3(0.4545454680919647216796875)) * texture(s2_b0, _1445).xyz, _s1_b4.uMyData.vec_1.w);
+}
+
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv.gles b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv.gles
new file mode 100644
index 0000000000000000000000000000000000000000..1a0fbb10c1ce24c15566a2eedf398db642c32afc
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv.gles
@@ -0,0 +1,236 @@
+#version 320 es
+precision highp float;
+precision highp int;
+
+struct DefaultMaterialSingleMaterialStruct
+{
+ vec4 factors[15];
+ uvec4 indices;
+};
+
+struct DefaultMaterialMaterialStruct
+{
+ DefaultMaterialSingleMaterialStruct material[64];
+};
+
+#ifndef SPIRV_CROSS_CONSTANT_ID_1
+#define SPIRV_CROSS_CONSTANT_ID_1 0u
+#endif
+const uint CORE_MATERIAL_FLAGS = SPIRV_CROSS_CONSTANT_ID_1;
+const uint _162 = (CORE_MATERIAL_FLAGS & 8u);
+const bool _163 = (_162 == 8u);
+
+struct DefaultMaterialTransformSingleMaterialStruct
+{
+ uvec4 _packed[15];
+ uvec4 indices;
+};
+
+struct DefaultMaterialTransformMaterialStruct
+{
+ DefaultMaterialTransformSingleMaterialStruct material[64];
+};
+
+struct MyMaterialSampleStruct
+{
+ vec4 vec_1;
+ float time;
+ uint dof;
+ uint motionBlur;
+};
+
+layout(std140) uniform s1_b2
+{
+ DefaultMaterialMaterialStruct uMaterialData;
+} _s1_b2;
+
+layout(std140) uniform s1_b3
+{
+ DefaultMaterialTransformMaterialStruct uMaterialTransformData;
+} _s1_b3;
+
+layout(std140) uniform s1_b4
+{
+ MyMaterialSampleStruct uMyData;
+} _s1_b4;
+
+uniform mediump sampler2D s2_b0;
+
+layout(location = 4) in vec4 inUv;
+layout(location = 0) out vec4 outColor;
+
+vec2 _1444;
+float _1477;
+float _1562;
+
+void main()
+{
+ vec2 _336 = (inUv.xy - vec2(0.5)) * 2.0;
+ vec3 _1434;
+ vec2 _1462;
+ vec2 _1470;
+ _1470 = _1444;
+ _1462 = _1444;
+ _1434 = vec3(0.0);
+ vec2 _1466;
+ float _1472;
+ vec3 _1490;
+ vec2 _1516;
+ float _1476;
+ for (float _1433 = 0.0; _1433 < 2.0; _1476 = _1472, _1470 = _1466, _1462 = _1516, _1434 = _1490, _1433 += 1.0)
+ {
+ vec2 _372 = (inUv.xy + vec2(fract(_s1_b4.uMyData.time) * 500.0)) + vec2(_1433 * 31.3528308868408203125);
+ float _1448;
+ if (_s1_b4.uMyData.motionBlur != 0u)
+ {
+ _1448 = fma(fract(sin(dot(_372, vec2(1.86720001697540283203125, 1.37230002880096435546875))) * 5723.26220703125), 0.0500000007450580596923828125, _s1_b4.uMyData.time);
+ }
+ else
+ {
+ _1448 = _s1_b4.uMyData.time;
+ }
+ float _389 = -_1448;
+ float _912 = floor(_389);
+ vec3 _1368 = vec3(0.0, 1.0, _389);
+ _1368.x = (mix(floor(fract(sin(_912) * 5723.26220703125) * 5.0), floor(fract(sin(_912 + 1.0) * 5723.26220703125) * 5.0), smoothstep(0.4000000059604644775390625, 0.60000002384185791015625, fract(_389))) - 2.0) * 0.5;
+ float _411 = (-500.0) - _1448;
+ float _943 = floor(_411);
+ vec3 _1372 = _1368;
+ _1372.y = fma(mix(floor(fract(sin(_943) * 5723.26220703125) * 5.0), floor(fract(sin(_943 + 1.0) * 5723.26220703125) * 5.0), smoothstep(0.4000000059604644775390625, 0.60000002384185791015625, fract(_411))), 0.5, 1.0);
+ vec3 _423 = vec3(0.0, -0.5, (-0.5) - _1448) - _1372;
+ vec3 _424 = normalize(_423);
+ vec3 _429 = normalize(cross(_424, vec3(0.0, 1.0, 0.0)));
+ float _440 = (-1000.0) - _1448;
+ float _974 = floor(_440);
+ float _475 = length(_423);
+ vec3 _1449;
+ if (_s1_b4.uMyData.dof != 0u)
+ {
+ float _504 = fract(sin(dot(_372 * 1.2000000476837158203125, vec2(1.86720001697540283203125, 1.37230002880096435546875))) * 5723.26220703125) * 6.283185482025146484375;
+ vec2 _518 = _1372.xy + (((vec2(cos(_504), sin(_504)) * sqrt(fract(sin(dot(_372 * 1.10000002384185791015625, vec2(1.86720001697540283203125, 1.37230002880096435546875))) * 5723.26220703125))) * _475) * 0.02500000037252902984619140625);
+ vec3 _1377 = _1372;
+ _1377.x = _518.x;
+ vec3 _1379 = _1377;
+ _1379.y = _518.y;
+ _1449 = _1379;
+ }
+ else
+ {
+ _1449 = _1372;
+ }
+ vec3 _527 = normalize((_1372 + (normalize(((_429 * _336.x) + (normalize(cross(_429, _424)) * _336.y)) + (_424 / vec3(tan(fma(fma(mix(floor(fract(sin(_974) * 5723.26220703125) * 2.0), floor(fract(sin(_974 + 1.0) * 5723.26220703125) * 2.0), smoothstep(0.4000000059604644775390625, 0.60000002384185791015625, fract(_440))), 2.0, -1.0), 20.0, 40.0) * 0.00872664712369441986083984375)))) * _475)) - _1449);
+ vec2 _1467;
+ _1467 = _1470;
+ float _548;
+ vec2 _577;
+ bool _1455;
+ vec2 _1458;
+ float _1450 = 0.0;
+ float _1473 = _1476;
+ for (;;)
+ {
+ if (_1450 < 50.0)
+ {
+ _548 = (-fma(_1450, 0.0500000007450580596923828125, _1449.y)) / _527.y;
+ vec2 _556 = _1449.xz + (_527.xz * _548);
+ vec2 _1384 = _556;
+ _1384.x = fma(fract(sin(_1450) * 5723.26220703125), 500.0, _556.x);
+ float _567 = _1450 * 2.0;
+ float _1023 = sin(_567);
+ float _1025 = cos(_567);
+ vec2 _571 = _1384 * mat2(vec2(_1025, _1023), vec2(-_1023, _1025));
+ float _575 = _571.x;
+ _577 = vec2(_1450, floor(_575));
+ float _581 = fract(_575) - 0.5;
+ float _589 = fma(fract(sin(dot(_577, vec2(1.86720001697540283203125, 1.37230002880096435546875))) * 5723.26220703125), 500.0, _571.y);
+ float _1069 = floor(_589);
+ float _1071 = fract(_589);
+ float _599 = fma(mix(_1071 * fma(fract(sin(_1069) * 5723.26220703125), 2.0, -1.0), (_1071 - 1.0) * fma(fract(sin(_1069 + 1.0) * 5723.26220703125), 2.0, -1.0), (_1071 * _1071) * fma(-2.0, _1071, 3.0)) * (-0.939999997615814208984375), smoothstep(0.2199999988079071044921875, 0.2800000011920928955078125, abs(fract(_1448 * 0.10999999940395355224609375) - 0.5)), _581);
+ vec2 _1395 = vec2(_581, _589);
+ _1395.x = _599;
+ bool _602 = _548 > 0.0;
+ bool _609;
+ if (_602)
+ {
+ _609 = abs(_599) < 0.02999999932944774627685546875;
+ }
+ else
+ {
+ _609 = _602;
+ }
+ if (_609)
+ {
+ _1472 = _548;
+ _1466 = _577;
+ _1458 = _1395;
+ _1455 = true;
+ break;
+ }
+ _1450 += 1.0;
+ _1473 = _548;
+ _1467 = _577;
+ continue;
+ }
+ else
+ {
+ _1472 = _1473;
+ _1466 = _1467;
+ _1458 = _1462;
+ _1455 = false;
+ break;
+ }
+ }
+ if (_1455)
+ {
+ vec3 _640 = normalize(vec3(_1458.x, sqrt(fma(-_1458.x, _1458.x, 0.000899999984540045261383056640625)), 0.0));
+ float _647 = _1458.y + 9.9999997473787516355514526367188e-05;
+ float _1113 = smoothstep(0.2199999988079071044921875, 0.2800000011920928955078125, abs(fract(_1448 * 0.10999999940395355224609375) - 0.5));
+ float _1125 = floor(_647);
+ float _1127 = fract(_647);
+ float _655 = _1458.y - 9.9999997473787516355514526367188e-05;
+ float _1181 = floor(_655);
+ float _1183 = fract(_655);
+ float _672 = fma(_1466.x, -2.0, atan(fma(mix(_1127 * fma(fract(sin(_1125) * 5723.26220703125), 2.0, -1.0), (_1127 - 1.0) * fma(fract(sin(_1125 + 1.0) * 5723.26220703125), 2.0, -1.0), (_1127 * _1127) * fma(-2.0, _1127, 3.0)) * 0.939999997615814208984375, _1113, -((mix(_1183 * fma(fract(sin(_1181) * 5723.26220703125), 2.0, -1.0), (_1183 - 1.0) * fma(fract(sin(_1181 + 1.0) * 5723.26220703125), 2.0, -1.0), (_1183 * _1183) * fma(-2.0, _1183, 3.0)) * 0.939999997615814208984375) * _1113)) * 5000.0));
+ float _1216 = sin(_672);
+ float _1218 = cos(_672);
+ vec2 _677 = _640.xz * mat2(vec2(_1218, _1216), vec2(-_1216, _1218));
+ vec3 _1404 = _640;
+ _1404.x = _677.x;
+ vec3 _1406 = _1404;
+ _1406.z = _677.y;
+ float _720 = fract(fma(_1458.y, 0.02999999932944774627685546875, _1448 * (-0.20000000298023223876953125))) - 0.5;
+ vec2 _1409 = _1458;
+ _1409.y = _720;
+ float _736 = _1448 + fract(sin(dot(_1466, vec2(1.86720001697540283203125, 1.37230002880096435546875))) * 5723.26220703125);
+ _1516 = _1409;
+ _1490 = _1434 + ((((vec3(1.0) * fma(1.5, max(dot(_1406, vec3(-0.8703882694244384765625, 0.348155319690704345703125, -0.348155319690704345703125)), 0.0) + pow(max(dot(reflect(vec3(-0.8703882694244384765625, 0.348155319690704345703125, -0.348155319690704345703125), _1406), _527), 0.0), 20.0), 0.20000000298023223876953125)) + vec3(smoothstep(0.00999999977648258209228515625, 0.0, abs(_720)) * 3.0)) + vec3((step(fract(sin(dot((_1466 * 1.10000002384185791015625) + vec2(floor(_736)), vec2(1.86720001697540283203125, 1.37230002880096435546875))) * 5723.26220703125), 0.0500000007450580596923828125) * step(fract(_736 * 3.0), 0.800000011920928955078125)) * 3.0)) * exp(fma((-_1472) * _1472, 0.100000001490116119384765625, (_1466.x * _1466.x) * (-0.001000000047497451305389404296875))));
+ }
+ else
+ {
+ _1516 = _1458;
+ _1490 = _1434;
+ }
+ }
+ uint _1301 = floatBitsToUint(_s1_b2.uMaterialData.material[0].factors[11].y);
+ vec2 _1436;
+ if (((_1301 >> uint(16)) & 1u) == 1u)
+ {
+ _1436 = inUv.zw;
+ }
+ else
+ {
+ _1436 = inUv.xy;
+ }
+ vec2 _1445;
+ if (_163 && (((_1301 & 65535u) & 1u) == 1u))
+ {
+ vec4 _1531 = vec4(unpackHalf2x16(_s1_b3.uMaterialTransformData.material[0]._packed[0u].x), unpackHalf2x16(_s1_b3.uMaterialTransformData.material[0]._packed[0u].y));
+ _1445 = vec2(dot(_1531.xy, _1436), dot(_1531.zw, _1436)) + vec4(unpackHalf2x16(_s1_b3.uMaterialTransformData.material[0]._packed[0u].z), _1562, _1562).xy;
+ }
+ else
+ {
+ _1445 = _1436;
+ }
+ outColor = vec4(pow((_1434 * vec3(0.5)) * _s1_b4.uMyData.vec_1.xyz, vec3(0.4545454680919647216796875)) * texture(s2_b0, _1445).xyz, _s1_b4.uMyData.vec_1.w);
+}
+
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv.lsb b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv.lsb
new file mode 100644
index 0000000000000000000000000000000000000000..7a6b95bcf11cef0aea50d0634c2a3471381a2201
Binary files /dev/null and b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv.lsb differ
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv.pre b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv.pre
new file mode 100644
index 0000000000000000000000000000000000000000..18078b919e3173acdac1ad428476c8c8f3d38d22
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.frag.spv.pre
@@ -0,0 +1,5758 @@
+#version 460 core
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shading_language_420pack : enable
+
+
+
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_compatibility_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+precision highp float;
+precision highp int;
+
+
+
+
+
+layout(constant_id = 256) const uint CORE_BACKEND_TYPE = 0;
+
+
+
+
+layout(constant_id = 257) const float CORE_FLIP_NDC = 1.0;
+
+
+
+
+
+
+
+
+
+
+vec2 GetFragCoordUv(vec2 fragCoord, vec2 inverseTexelSize)
+{
+ vec2 uv = fragCoord * inverseTexelSize;
+ if (CORE_FLIP_NDC < 0.0) {
+ uv = vec2(uv.x, 1.0 - uv.y);
+ }
+ return uv;
+}
+
+
+
+
+
+
+
+#line 8 "shader/custom_materiaL_sample.frag"
+
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_color_conversion_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_compatibility_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 24 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_color_conversion_common.h"
+
+
+
+
+float CalcLuma(const vec3 color)
+{
+
+ return 0.299 * color.r + 0.587 * color.g + 0.114 * color.b;
+}
+
+
+
+
+float CalcLumaFxaa(const vec3 color)
+{
+
+ return color.g * (0.587 / 0.299) + color.r;
+}
+
+
+
+
+float LumaWeight(const float luma)
+{
+ return(1.0 / (1.0 + luma));
+}
+
+
+
+
+vec3 TonemapLuma(const vec3 color, const float luma, const float range)
+{
+ return color / (1.0 + luma / range);
+}
+
+
+
+
+vec3 TonemapLumaInv(const vec3 color, const float luma, const float range)
+{
+ return color / (1.0 - luma / range);
+}
+
+
+
+
+
+vec3 SrgbToLinear(const vec3 srgb)
+{
+ const float mlow = 1.0f / 12.92f;
+ const float mhigh = 1.0f / 1.055f;
+
+ const vec3 high = pow( (srgb + 0.055f) * mhigh, vec3(2.4f));
+ const vec3 low = srgb * mlow;
+ const bvec3 cutoff = lessThan(srgb, vec3(0.04045f));
+ return mix(high, low, cutoff);
+}
+
+
+
+
+
+vec3 LinearToSrgb(const vec3 linear)
+{
+ const float mlow = 12.92f;
+ const float mhigh = 1.055f;
+
+ const vec3 high = pow(linear, vec3(0.416f)) * mhigh - 0.055f;
+ const vec3 low = linear * mlow;
+ const bvec3 cutoff = lessThan(linear, vec3(0.0031308f));
+ return mix(high, low, cutoff);
+}
+
+
+
+
+
+vec3 rgbToYCoCg(const vec3 rgb)
+{
+ const float y = dot(rgb, vec3(0.25, 0.5, 0.25));
+ const float co = dot(rgb, vec3(0.5, 0.0, - 0.5));
+ const float cg = dot(rgb, vec3(- 0.25, 0.5, - 0.25));
+ return vec3(y, co, cg);
+}
+
+
+
+
+
+vec3 yCoCgToRgb(const vec3 ycocg)
+{
+ const float y = ycocg.r;
+ const float co = ycocg.g;
+ const float cg = ycocg.b;
+ return vec3(y + co - cg, y + cg, y - co - cg);
+}
+
+
+#line 10 "shader/custom_materiaL_sample.frag"
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_post_process_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_post_process_structs_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_compatibility_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 20 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_post_process_structs_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct GlobalPostProcessStruct {
+
+ uvec4 flags;
+
+ vec4 renderTimings;
+
+
+ vec4 factors[14];
+
+
+ vec4 userFactors[16];
+};
+
+
+
+
+struct LocalPostProcessStruct {
+
+ vec4 factors[16];
+};
+
+struct LocalPostProcessPushConstantStruct {
+
+ vec4 viewportSizeInvSize;
+
+ vec4 factor;
+};
+
+struct PostProcessTonemapStruct {
+ vec4 texSizeInvTexSize;
+
+ uvec4 flags;
+
+ vec4 tonemap;
+ vec4 vignette;
+ vec4 colorFringe;
+ vec4 dither;
+
+ vec4 bloomParameters;
+};
+
+
+#line 20 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_post_process_common.h"
+
+
+
+
+
+
+float getVignetteCoeff(const vec2 uv, mediump const float coeff, mediump const float power)
+{
+ vec2 uvVal = uv.xy * (vec2(1.0) - uv.yx);
+ float vignette = uvVal.x * uvVal.y * coeff;
+ vignette = pow(vignette, power);
+ return clamp(vignette, 0.0, 1.0);
+}
+
+
+
+
+float getChromaCoeff(const vec2 uv, mediump const float chromaCoefficient)
+{
+
+ vec2 distUv = (uv - 0.5) * 2.0;
+ return dot(distUv, distUv) * chromaCoefficient;
+}
+
+
+
+
+float RandomDither(vec2 st)
+{
+ return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453);
+}
+
+
+
+
+#line 11 "shader/custom_materiaL_sample.frag"
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_tonemap_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_post_process_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 20 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_tonemap_common.h"
+
+
+
+
+
+vec3 TonemapAces(vec3 x)
+{
+ const float a = 2.51f;
+ const float b = 0.03f;
+ const float c = 2.43f;
+ const float d = 0.59f;
+ const float e = 0.14f;
+ return(x * (a * x + b)) / (x * (c * x + d) + e);
+}
+
+
+
+
+
+vec3 TonemapAcesFilmRec2020(vec3 x)
+{
+ float a = 15.8f;
+ float b = 2.12f;
+ float c = 1.2f;
+ float d = 5.92f;
+ float e = 1.9f;
+ return(x * (a * x + b)) / (x * (c * x + d) + e);
+}
+
+
+
+
+
+float TonemapFilmic(float x)
+{
+ const float a = 0.15f;
+ const float b = 0.50f;
+ const float c = 0.10f;
+ const float d = 0.20f;
+ const float e = 0.02f;
+ const float f = 0.30f;
+ return( (x * (a * x + c * b) + d * e) / (x * (a * x + b) + d * f)) - e / f;
+}
+vec3 TonemapFilmic(vec3 x)
+{
+ const float a = 0.15f;
+ const float b = 0.50f;
+ const float c = 0.10f;
+ const float d = 0.20f;
+ const float e = 0.02f;
+ const float f = 0.30f;
+ const float w = 11.2f;
+ const vec3 curr = ( (x * (a * x + c * b) + d * e) / (x * (a * x + b) + d * f)) - e / f;
+ const float whiteScale = 1.0 / TonemapFilmic(w);
+ return curr * vec3(whiteScale);
+}
+
+
+#line 12 "shader/custom_materiaL_sample.frag"
+
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_structures_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_compatibility_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 20 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_structures_common.h"
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_packing_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+uvec2 PackVec4Half2x16(const vec4 up)
+{
+ uvec2 packed;
+ packed.x = packHalf2x16(up.xy);
+ packed.y = packHalf2x16(up.zw);
+ return packed;
+}
+
+vec4 UnpackVec4Half2x16(const uvec2 packed)
+{
+ vec4 up;
+ up.xy = unpackHalf2x16(packed.x);
+ up.zw = unpackHalf2x16(packed.y);
+ return up;
+}
+
+uvec4 Pack2Vec4Half2x16(const vec4 up0, const vec4 up1)
+{
+ uvec4 packed;
+ packed.x = packHalf2x16(up0.xy);
+ packed.y = packHalf2x16(up0.zw);
+ packed.z = packHalf2x16(up1.xy);
+ packed.w = packHalf2x16(up1.zw);
+ return packed;
+}
+
+void UnpackVec42Half2x16(const uvec4 packed, inout vec4 up0, inout vec4 up1)
+{
+ up0.xy = unpackHalf2x16(packed.x);
+ up0.zw = unpackHalf2x16(packed.y);
+ up1.xy = unpackHalf2x16(packed.z);
+ up1.zw = unpackHalf2x16(packed.w);
+}
+
+
+
+
+#line 21 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_structures_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct DefaultMaterialSingleMeshStruct {
+
+
+ mat4 world;
+ mat4 normalWorld;
+ mat4 prevWorld;
+
+
+ uvec4 indices;
+
+ uvec4 layers;
+
+ uvec4 customData[2];
+};
+
+struct DefaultMaterialMeshStruct {
+ DefaultMaterialSingleMeshStruct mesh[64];
+};
+
+struct DefaultMaterialSingleMaterialStruct {
+ vec4 factors[15];
+ uvec4 indices;
+};
+
+struct DefaultMaterialMaterialStruct {
+ DefaultMaterialSingleMaterialStruct material[64];
+};
+
+struct DefaultMaterialTransformSingleMaterialStruct {
+ uvec4 packed[15];
+ uvec4 indices;
+};
+
+struct DefaultMaterialTransformMaterialStruct {
+ DefaultMaterialTransformSingleMaterialStruct material[64];
+};
+
+struct DefaultMaterialSingleUserMaterialStruct {
+ uvec4 userData[16u];
+};
+
+struct DefaultMaterialUserMaterialStruct {
+ DefaultMaterialSingleUserMaterialStruct material[64];
+};
+
+struct DefaultMaterialSingleLightStruct {
+ vec4 pos;
+
+ vec4 dir;
+
+ vec4 color;
+
+ vec4 spotLightParams;
+
+ vec4 shadowFactors;
+
+ vec4 additionalFactor;
+
+
+ uvec4 flags;
+
+ uvec4 indices;
+};
+
+struct DefaultMaterialLightStruct {
+ uint directionalLightBeginIndex;
+ uint directionalLightCount;
+
+ uint pointLightBeginIndex;
+ uint pointLightCount;
+
+ uint spotLightBeginIndex;
+ uint spotLightCount;
+
+ uint pad0;
+ uint pad1;
+
+ uvec4 clusterSizes;
+ vec4 clusterFactors;
+
+ vec4 atlasSizeInvSize;
+ vec4 additionalFactors;
+
+ DefaultMaterialSingleLightStruct lights[64];
+};
+
+struct DefaultMaterialSkinStruct {
+
+ mat4 jointMatrices[256u];
+};
+
+
+struct DefaultMaterialGeneralDataStruct {
+
+ uvec4 indices;
+
+ vec4 viewportSizeInvViewportSize;
+
+ vec4 sceneTimingData;
+};
+
+
+struct DefaultMaterialEnvironmentStruct {
+
+ vec4 indirectSpecularColorFactor;
+
+ vec4 indirectDiffuseColorFactor;
+
+ vec4 envMapColorFactor;
+
+ vec4 values;
+
+ vec4 blendFactor;
+
+
+ mat4 envRotation;
+
+
+ uvec4 indices;
+
+
+ vec4 shIndirectCoefficients[9];
+
+
+ vec4 pad0;
+};
+
+struct DefaultMaterialFogStruct {
+
+ uvec4 indices;
+
+
+ vec4 firstLayer;
+
+ vec4 secondLayer;
+
+
+ vec4 baseFactors;
+
+ vec4 inscatteringColor;
+
+ vec4 envMapFactor;
+
+
+ vec4 additionalFactor;
+};
+
+
+struct DefaultCameraMatrixStruct {
+ mat4 view;
+ mat4 proj;
+ mat4 viewProj;
+
+ mat4 viewInv;
+ mat4 projInv;
+ mat4 viewProjInv;
+
+ mat4 viewPrevFrame;
+ mat4 projPrevFrame;
+ mat4 viewProjPrevFrame;
+
+ mat4 shadowViewProj;
+ mat4 shadowViewProjInv;
+
+
+ vec4 jitter;
+ vec4 jitterPrevFrame;
+
+
+ uvec4 indices;
+
+ uvec4 multiViewIndices;
+
+ vec4 frustumPlanes[6];
+
+
+ uvec4 counts;
+
+ uvec4 pad0;
+ mat4 matPad0;
+ mat4 matPad1;
+};
+
+
+
+
+
+struct DefaultMaterialUnpackedSceneTimingStruct {
+
+ float sceneDeltaTime;
+
+ float tickDeltaTime;
+
+ float tickTotalTime;
+
+ uint frameIndex;
+};
+
+struct DefaultMaterialUnpackedPostProcessStruct {
+ float tonemapExposure;
+ float vignetteCoeff;
+ float vignettePower;
+};
+
+uint GetPackFlatIndices(const uint cameraIdx, const uint instanceIdx)
+{
+ return( (instanceIdx << 16) | (cameraIdx & 0xffff));
+}
+
+void GetUnpackFlatIndices(in uint indices, out uint cameraIdx, out uint instanceIdx)
+{
+ cameraIdx = indices & 0xffff;
+ instanceIdx = indices >> 16;
+}
+
+uint GetUnpackFlatIndicesInstanceIdx(in uint indices)
+{
+ return(indices >> 16);
+}
+
+uint GetUnpackFlatIndicesCameraIdx(in uint indices)
+{
+ return(indices & 0xffff);
+}
+
+uint GetUnpackCameraIndex(const DefaultMaterialGeneralDataStruct dmgds)
+{
+ return dmgds.indices.x;
+}
+
+DefaultMaterialUnpackedSceneTimingStruct GetUnpackSceneTiming(const DefaultMaterialGeneralDataStruct dmgds)
+{
+ DefaultMaterialUnpackedSceneTimingStruct dm;
+ dm.sceneDeltaTime = dmgds.sceneTimingData.x;
+ dm.tickDeltaTime = dmgds.sceneTimingData.y;
+ dm.tickTotalTime = dmgds.sceneTimingData.z;
+ dm.frameIndex = floatBitsToUint(dmgds.sceneTimingData.w);
+ return dm;
+}
+
+vec4 GetUnpackViewport(const DefaultMaterialGeneralDataStruct dmgds)
+{
+ return dmgds.viewportSizeInvViewportSize;
+}
+
+
+
+struct DefaultMaterialUnpackedTexTransformStruct {
+ vec4 rotateScale;
+ vec2 translate;
+};
+
+DefaultMaterialUnpackedTexTransformStruct GetUnpackTextureTransform(const uvec4 packedTexTransform)
+{
+ DefaultMaterialUnpackedTexTransformStruct dm;
+ dm.rotateScale = UnpackVec4Half2x16(packedTexTransform.xy);
+ dm.translate = UnpackVec4Half2x16(packedTexTransform.zw).xy;
+ return dm;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 14 "shader/custom_materiaL_sample.frag"
+
+
+
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_frag_layout_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_structures_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 20 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_frag_layout_common.h"
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_compatibility_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 21 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_frag_layout_common.h"
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_post_process_structs_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 22 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_frag_layout_common.h"
+
+
+
+
+
+
+
+layout(set = 0, binding = 0, std140) uniform uCameraMatrices
+{
+ DefaultCameraMatrixStruct uCameras[16];
+};
+layout(set = 0, binding = 1, std140) uniform uGeneralStructData
+{
+ DefaultMaterialGeneralDataStruct uGeneralData;
+};
+layout(set = 0, binding = 2, std140) uniform uEnvironmentStructData
+{
+ DefaultMaterialEnvironmentStruct uEnvironmentData;
+};
+layout(set = 0, binding = 3, std140) uniform uFogStructData
+{
+ DefaultMaterialFogStruct uFogData;
+};
+layout(set = 0, binding = 4, std140) uniform uLightStructData
+{
+ DefaultMaterialLightStruct uLightData;
+};
+layout(set = 0, binding = 5, std140) uniform uPostProcessStructData
+{
+ GlobalPostProcessStruct uPostProcessData;
+};
+layout(set = 0, binding = 6, std430) buffer uLightClusterIndexData
+{
+ uint uLightClusterData;
+};
+layout(set = 0, binding = 7) uniform mediump sampler2D uSampColorPrePass;
+layout(set = 0, binding = 8) uniform sampler2D uSampColorShadow;
+layout(set = 0, binding = 9) uniform sampler2DShadow uSampDepthShadow;
+layout(set = 0, binding = 10) uniform samplerCube uSampRadiance;
+
+
+
+layout(set = 1, binding = 0, std140) uniform uMeshStructData
+{
+ DefaultMaterialMeshStruct uMeshMatrix;
+};
+layout(set = 1, binding = 1, std140) uniform uObjectSkinStructData
+{
+ DefaultMaterialSkinStruct uSkinData;
+};
+layout(set = 1, binding = 2, std140) uniform uMaterialStructData
+{
+ DefaultMaterialMaterialStruct uMaterialData;
+};
+
+layout(set = 1, binding = 3, std140) uniform uMaterialTransformStructData
+{
+ DefaultMaterialTransformMaterialStruct uMaterialTransformData;
+};
+layout(set = 1, binding = 4, std140) uniform uMaterialUserStructData
+{
+ DefaultMaterialUserMaterialStruct uMaterialUserData;
+};
+
+
+layout(set = 2, binding = 0) uniform mediump sampler2D uSampTextureBase;
+layout(set = 2, binding = 1) uniform mediump sampler2D uSampTextures[10];
+
+layout(constant_id = 0) const uint CORE_MATERIAL_TYPE = 0;
+layout(constant_id = 1) const uint CORE_MATERIAL_FLAGS = 0;
+layout(constant_id = 2) const uint CORE_LIGHTING_FLAGS = 0;
+layout(constant_id = 3) const uint CORE_POST_PROCESS_FLAGS = 0;
+layout(constant_id = 4) const uint CORE_CAMERA_FLAGS = 0;
+
+
+
+
+
+
+#line 18 "shader/custom_materiaL_sample.frag"
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_lighting_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_brdf_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+float dLambert()
+{
+ return(1.0 / 3.14159265359);
+}
+
+
+
+float EnvSpecularAo(float ao, float NoV, float roughness)
+{
+ return clamp(pow(NoV + ao, exp2(- 16.0 * roughness - 1.0)) - 1.0 + ao, 0.0, 1.0);
+}
+
+float SpecularHorizonOcclusion(vec3 R, vec3 N)
+{
+ const float horizon = min(1.0 + dot(R, N), 1.0);
+ return horizon * horizon;
+}
+
+float dAshikhmin(float roughness, float NoH)
+{
+ const float r2 = roughness * roughness;
+ const float cos2h = NoH * NoH;
+ const float sin2h = 1.0 - cos2h;
+ const float sin4h = sin2h * sin2h;
+ return(sin4h + 4.0 * exp(- cos2h / (sin2h * r2))) / (3.14159265359 * (1.0 + 4.0 * r2) * sin4h);
+}
+
+
+float vAshikhmin(float NoV, float NoL)
+{
+ return 1.0 / (4.0 * (NoL + NoV - NoL * NoL));
+}
+
+float dCharlie(float roughness, float NoH)
+{
+ const float invR = 1.0 / roughness;
+ const float cos2h = NoH * NoH;
+ const float sin2h = 1.0 - cos2h;
+ return(2.0 + invR) * pow(sin2h, invR * 0.5) / (2.0 * 3.14159265359);
+}
+
+
+vec3 f0ClearcoatToSurface(const vec3 f0)
+{
+
+ return clamp(f0 * (f0 * 0.526868 + 0.529324) - 0.0482256, 0.0, 1.0);
+}
+
+
+float EnvBRDFApproxSheen(float NoV, float alpha)
+{
+ const float c = 1.0 - NoV;
+ const float c3 = c * c * c;
+ return 0.6558446 * c3 + 1.0 / (4.1652655 + exp(- 7.9729136 * alpha + 6.3351689));
+}
+
+vec3 fSchlick(vec3 f0, float VoH)
+{
+
+ const float p = pow(1.0 - VoH, 5.0);
+ return p + f0 * (1.0 - p);
+}
+
+float fSchlickSingle(float f0, float VoH)
+{
+ const float p = pow(1.0 - VoH, 5.0);
+ return p + f0 * (1.0 - p);
+}
+
+
+vec3 fSchlick(vec4 f0, float VoH)
+{
+ const float p = pow(1.0 - VoH, 5.0);
+ return(f0.w * p) + f0.xyz * (1.0 - p);
+}
+
+
+float dGGX(float alpha2, float NoH)
+{
+ const float f = (NoH * alpha2 - NoH) * NoH + 1.0;
+ return alpha2 / (3.14159265359 * (f * f));
+}
+
+
+float dGGXAnisotropic(float at, float ab, float NoH, float ToH, float BoH, float anisotropy)
+{
+ float a2 = at * ab;
+ vec3 d = vec3(ab * ToH, at * BoH, a2 * NoH);
+ float d2 = dot(d, d);
+ if (d2 == 0) {
+ return 0.0;
+ }
+ float w2 = a2 / d2;
+ return a2 * w2 * w2 * (1.0 / 3.14159265359);
+}
+
+
+float vGGXWithCombinedDenominator(float alpha2, float NoV, float NoL)
+{
+ const float gv = NoV + sqrt( (NoV - NoV * alpha2) * NoV + alpha2);
+ const float gl = NoL + sqrt( (NoL - NoL * alpha2) * NoL + alpha2);
+ return min(1.0 / (gv * gl), 64512.0);
+}
+
+
+
+float vKelemen(float LoH)
+{
+ return min(0.25 / (LoH * LoH), 64512.0);
+}
+
+float vGGXAnisotropic(
+ float at, float ab, float NoL, float NoV, float ToL, float ToV, float BoL, float BoV, float anisotropy)
+{
+ float gv = NoL * length(vec3(at * ToV, ab * BoV, NoV));
+ float gl = NoV * length(vec3(at * ToL, ab * BoL, NoL));
+ float v = 0.5 / (gv + gl);
+ return clamp(v, 0.0, 1.0);
+}
+
+vec3 microfacedSpecularBrdf(vec3 f0, float alpha2, float NoL, float NoV, float NoH, float VoH)
+{
+
+ float D = dGGX(alpha2, NoH);
+ float G = vGGXWithCombinedDenominator(alpha2, NoV, NoL);
+ vec3 F = fSchlick(f0, VoH);
+ return F * (D * G);
+}
+
+float microfacedSpecularBrdfClearcoat(
+ float f0, float alpha2, float NoL, float NoH, float VoH, float clearcoat, out float fcc)
+{
+
+ float D = dGGX(alpha2, NoH);
+ float G = vKelemen(NoH);
+ float F = fSchlickSingle(f0, VoH) * clearcoat;
+ fcc = F;
+ return F * D * G;
+}
+
+vec3 microfacedSpecularBrdfAnisotropic(vec3 f0, float alpha, float NoL, float NoV, float NoH, float VoH, float ToL,
+ float ToV, float ToH, float BoL, float BoV, float BoH, float anisotropy)
+{
+ const float at = max(alpha * (1.0 + anisotropy), 0.0001);
+ const float ab = max(alpha * (1.0 - anisotropy), 0.0001);
+
+ float D = dGGXAnisotropic(at, ab, NoH, ToH, BoH, anisotropy);
+ float V = vGGXAnisotropic(at, ab, NoL, NoV, BoV, ToV, ToL, BoL, anisotropy);
+ vec3 F = fSchlick(f0, VoH);
+ return F * (V * D);
+}
+
+float diffuseCoeff()
+{
+ return dLambert();
+}
+
+
+#line 20 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_lighting_common.h"
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_indirect_lighting_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_structures_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 20 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_indirect_lighting_common.h"
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_compatibility_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 21 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_indirect_lighting_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+vec3 unpackEnvMap(vec4 envColorRgbd)
+{
+ return envColorRgbd.xyz * (1.0 / envColorRgbd.a);
+}
+
+
+vec3 unpackIblRadiance(vec4 envColorRgbd)
+{
+ return envColorRgbd.xyz * (1.0 / envColorRgbd.a);
+}
+
+
+vec3 unpackIblIrradianceSH(vec3 n, vec4 sh[9])
+{
+
+ return max(vec3(0.0), sh[0].xyz
+
+ + sh[1].xyz * n.y + sh[2].xyz * n.z + sh[3].xyz * n.x
+
+ + sh[4].xyz * (n.x * n.y) + sh[5].xyz * (n.z * n.y) +
+ sh[6].xyz * ( (3.0 * n.z * n.z) - 1.0) + sh[7].xyz * (n.x * n.z) +
+ sh[8].xyz * (n.x * n.x - n.y * n.y));
+}
+
+
+
+vec3 EnvBRDFApprox(vec3 f0, float roughness, float NoV)
+{
+ const vec4 c0 = vec4(- 1.0, - 0.0275, - 0.572, 0.022);
+ const vec4 c1 = vec4(1.0, 0.0425, 1.04, - 0.04);
+ vec4 r = roughness * c0 + c1;
+ float a004 = min(r.x * r.x, exp2(- 9.28 * NoV)) * r.x + r.y;
+ vec2 ab = vec2(- 1.04, 1.04) * a004 + r.zw;
+
+
+ const float f90 = clamp(50.0 * max(f0.x, max(f0.y, f0.z)), 0.0, 1.0);
+ return f0 * ab.x + ab.y * f90;
+}
+
+
+
+float EnvBRDFApproxNonmetal(float Roughness, float NoV)
+{
+
+ const vec2 c0 = { - 1, - 0.0275 };
+ const vec2 c1 = { 1, 0.0425 };
+ vec2 r = Roughness * c0 + c1;
+ return min(r.x * r.x, exp2(- 9.28 * NoV)) * r.x + r.y;
+}
+
+
+
+
+#line 21 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_lighting_common.h"
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_shadowing_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_compatibility_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 20 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_shadowing_common.h"
+
+
+
+
+
+
+
+vec2 ComputeReceiverPlaneDepthBias(const vec3 uvDdx, const vec3 uvDdy)
+{
+ vec2 uvBias;
+ uvBias.x = uvDdy.y * uvDdx.z - uvDdx.y * uvDdy.z;
+ uvBias.y = uvDdx.x * uvDdy.z - uvDdy.x * uvDdx.z;
+ uvBias *= 1.0f / ( (uvDdx.x * uvDdy.y) - (uvDdx.y * uvDdy.x));
+ return uvBias;
+}
+
+float GetPcfSample(sampler2DShadow shadow, const vec2 baseUv, const vec2 offset, const float compareDepth,
+ const vec2 texelSize, const vec2 receiverPlaneDepthBias)
+{
+ const vec2 uvOffset = offset * texelSize;
+
+
+
+ const float compZ = compareDepth;
+
+ return texture(shadow, vec3(baseUv + uvOffset, compZ)).x;
+}
+
+bool ValidShadowRange(const vec3 shadowCoord, float stepSize, float shadowIdx)
+{
+ const float xMin = stepSize * shadowIdx;
+ const float xMax = xMin + stepSize;
+ return( (shadowCoord.z > 0.0) && (shadowCoord.x > xMin) && (shadowCoord.x < xMax));
+}
+
+
+
+float CalcPcfShadow(
+ sampler2DShadow shadow, vec4 inShadowCoord, float NoL, vec4 shadowFactor, vec4 atlasSizeInvSize, uvec2 shadowFlags)
+{
+
+ const vec3 shadowCoord = inShadowCoord.xyz / inShadowCoord.w;
+
+ mediump float light = 1.0;
+ if (ValidShadowRange(shadowCoord, shadowFactor.w, float(shadowFlags.x))) {
+ const vec2 textureSize = atlasSizeInvSize.xy;
+ const vec2 texelSize = atlasSizeInvSize.zw;
+ const float normalBias = shadowFactor.z;
+ const float depthBias = shadowFactor.y;
+ const float bias = max(normalBias * (1.0 - NoL), depthBias);
+
+ const vec2 offset = vec2(0.5);
+ const vec2 uv = (shadowCoord.xy * textureSize) + offset;
+ vec2 baseUv = (floor(uv) - offset) * texelSize;
+ const float fracS = fract(uv.x);
+ const float fracT = fract(uv.y);
+
+
+
+
+
+
+
+
+
+
+
+
+ const vec2 receiverPlaneDepthBias = vec2(shadowFactor.y, shadowFactor.y);
+ const float compareDepth = shadowCoord.z - bias;
+
+
+ const float uw0 = 4.0 - 3.0 * fracS;
+ const float uw1 = 7.0;
+ const float uw2 = 1.0 + 3.0 * fracS;
+
+ const float u0 = (3.0 - 2.0 * fracS) / uw0 - 2.0;
+ const float u1 = (3.0 + fracS) / uw1;
+ const float u2 = fracS / uw2 + 2.0;
+
+ const float vw0 = 4.0 - 3.0 * fracT;
+ const float vw1 = 7.0;
+ const float vw2 = 1.0 + 3.0 * fracT;
+
+ const float v0 = (3.0 - 2.0 * fracT) / vw0 - 2.0;
+ const float v1 = (3.0 + fracT) / vw1;
+ const float v2 = fracT / vw2 + 2.0;
+
+ mediump float sum = 0;
+
+ sum += uw0 * vw0 * GetPcfSample(shadow, baseUv, vec2(u0, v0), compareDepth, texelSize, receiverPlaneDepthBias);
+ sum += uw1 * vw0 * GetPcfSample(shadow, baseUv, vec2(u1, v0), compareDepth, texelSize, receiverPlaneDepthBias);
+ sum += uw2 * vw0 * GetPcfSample(shadow, baseUv, vec2(u2, v0), compareDepth, texelSize, receiverPlaneDepthBias);
+
+ sum += uw0 * vw1 * GetPcfSample(shadow, baseUv, vec2(u0, v1), compareDepth, texelSize, receiverPlaneDepthBias);
+ sum += uw1 * vw1 * GetPcfSample(shadow, baseUv, vec2(u1, v1), compareDepth, texelSize, receiverPlaneDepthBias);
+ sum += uw2 * vw1 * GetPcfSample(shadow, baseUv, vec2(u2, v1), compareDepth, texelSize, receiverPlaneDepthBias);
+
+ sum += uw0 * vw2 * GetPcfSample(shadow, baseUv, vec2(u0, v2), compareDepth, texelSize, receiverPlaneDepthBias);
+ sum += uw1 * vw2 * GetPcfSample(shadow, baseUv, vec2(u1, v2), compareDepth, texelSize, receiverPlaneDepthBias);
+ sum += uw2 * vw2 * GetPcfSample(shadow, baseUv, vec2(u2, v2), compareDepth, texelSize, receiverPlaneDepthBias);
+
+ sum *= 1.0f / 144.0f;
+
+ light = 1.0 - (sum * shadowFactor.x);
+ }
+
+ return light;
+}
+float CalcPcfShadowMed(
+ sampler2DShadow shadow, vec4 inShadowCoord, float NoL, vec4 shadowFactor, vec4 atlasSizeInvSize, uvec2 shadowFlags)
+{
+
+ const vec3 shadowCoord = inShadowCoord.xyz / inShadowCoord.w;
+
+ mediump float light = 1.0;
+ if (ValidShadowRange(shadowCoord, shadowFactor.w, float(shadowFlags.x))) {
+ const vec2 textureSize = vec2(textureSize(shadow, 0).xy);
+ const vec2 texelSize = 1.0 / textureSize;
+ const float normalBias = shadowFactor.z;
+ const float depthBias = shadowFactor.y;
+ const float bias = max(normalBias * (1.0 - NoL), depthBias);
+
+ const vec2 offset = vec2(0.5);
+ const vec2 uv = (shadowCoord.xy * textureSize) + offset;
+ vec2 baseUv = (floor(uv) - offset) * texelSize;
+ const float fracS = fract(uv.x);
+ const float fracT = fract(uv.y);
+
+
+
+
+
+
+
+
+
+
+
+
+ const vec2 receiverPlaneDepthBias = vec2(shadowFactor.y, shadowFactor.y);
+ const float compareDepth = shadowCoord.z - bias;
+
+
+ const float uw0 = (3 - 2 * fracS);
+ const float uw1 = (1 + 2 * fracS);
+
+ const float u0 = (2 - fracS) / uw0 - 1;
+ const float u1 = fracS / uw1 + 1;
+
+ const float vw0 = (3 - 2 * fracT);
+ const float vw1 = (1 + 2 * fracT);
+
+ float v0 = (2 - fracT) / vw0 - 1;
+ float v1 = fracT / vw1 + 1;
+
+ mediump float sum = 0;
+
+ sum += uw0 * vw0 * GetPcfSample(shadow, baseUv, vec2(u0, v0), compareDepth, texelSize, receiverPlaneDepthBias);
+ sum += uw1 * vw0 * GetPcfSample(shadow, baseUv, vec2(u1, v0), compareDepth, texelSize, receiverPlaneDepthBias);
+
+ sum += uw0 * vw1 * GetPcfSample(shadow, baseUv, vec2(u0, v1), compareDepth, texelSize, receiverPlaneDepthBias);
+ sum += uw1 * vw1 * GetPcfSample(shadow, baseUv, vec2(u1, v1), compareDepth, texelSize, receiverPlaneDepthBias);
+
+ sum *= (1.0f / 16.0f);
+
+ light = 1.0 - (sum * shadowFactor.x);
+ }
+
+ return light;
+}
+
+float CalcPcfShadowSimpleSample(
+ sampler2DShadow shadow, vec4 inShadowCoord, vec4 shadowFactor, vec4 atlasSizeInvSize, uvec2 shadowFlags)
+{
+
+ const vec3 shadowCoord = inShadowCoord.xyz / inShadowCoord.w;
+
+ mediump float light = 1.0;
+ if (ValidShadowRange(shadowCoord, shadowFactor.w, float(shadowFlags.x))) {
+ const float bias = 0.002;
+ const vec2 baseUv = shadowCoord.xy;
+ const float compareDepth = shadowCoord.z - bias;
+ const mediump float sum = texture(shadow, vec3(baseUv, compareDepth)).x;
+
+ light = 1.0 - (sum * shadowFactor.x);
+ }
+
+ return light;
+}
+
+
+
+float LinstepVsm(float minVal, float maxVal, float v)
+{
+ return clamp( (v - minVal) / (maxVal - minVal), 0.0, 1.0);
+}
+float ReduceLightBleedingVsm(float pMax, float amount)
+{
+
+ return LinstepVsm(amount, 1.0, pMax);
+}
+
+float CalcVsmShadow(
+ sampler2D shadow, vec4 inShadowCoord, float NoL, vec4 shadowFactors, vec4 atlasSizeInvSize, uvec2 shadowFlags)
+{
+
+ const vec3 shadowCoord = inShadowCoord.xyz / inShadowCoord.w;
+
+ mediump float light = 1.0;
+ if (ValidShadowRange(shadowCoord, shadowFactors.w, float(shadowFlags.x))) {
+ const vec2 moments = texture(shadow, shadowCoord.xy).xy;
+ if (shadowCoord.z > moments.x) {
+ float variance = moments.y - (moments.x * moments.x);
+ const float evaluatedMinValue = 0.00001;
+ variance = max(variance, evaluatedMinValue);
+
+ const float d = shadowCoord.z - moments.x;
+ light = variance / (variance + d * d);
+ const float evaluatedLightBleedingVal = 0.2;
+ light = ReduceLightBleedingVsm(light, evaluatedLightBleedingVal);
+ light = 1.0 - (1.0 - light) * shadowFactors.x;
+ }
+ }
+
+ return light;
+}
+
+float CalcVsmShadowSimpleSample(
+ sampler2D shadow, vec4 inShadowCoord, vec4 shadowFactors, vec4 atlasSizeInvSize, uvec2 shadowFlags)
+{
+
+ const vec3 shadowCoord = inShadowCoord.xyz / inShadowCoord.w;
+
+ mediump float light = 1.0;
+ if (ValidShadowRange(shadowCoord, shadowFactors.w, float(shadowFlags.x))) {
+ const vec2 moments = texture(shadow, shadowCoord.xy).xy;
+ if (shadowCoord.z > moments.x) {
+ float variance = moments.y - (moments.x * moments.x);
+ const float evaluatedMinValue = 0.00001;
+ variance = max(variance, evaluatedMinValue);
+
+ const float d = shadowCoord.z - moments.x;
+ light = variance / (variance + d * d);
+ const float evaluatedLightBleedingVal = 0.2;
+ light = ReduceLightBleedingVsm(light, evaluatedLightBleedingVal);
+ light = 1.0 - (1.0 - light) * shadowFactors.x;
+ }
+ }
+
+ return light;
+}
+
+
+#line 22 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_lighting_common.h"
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_compatibility_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 23 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_lighting_common.h"
+
+
+
+
+
+
+
+
+
+struct InputBrdfData {
+ vec4 f0;
+ vec3 diffuseColor;
+ float roughness;
+ float alpha2;
+};
+
+struct ShadingData {
+ vec3 pos;
+ vec3 N;
+ float NoV;
+ vec3 V;
+ float alpha2;
+ vec4 f0;
+ vec3 diffuseColor;
+};
+
+struct ShadingDataInplace {
+ vec3 pos;
+ vec3 N;
+ float NoV;
+ vec3 V;
+ float alpha2;
+ vec4 f0;
+ vec3 diffuseColor;
+ uint materialFlags;
+ uvec2 layers;
+};
+
+struct ClearcoatShadingVariables {
+ vec3 ccNormal;
+ float cc;
+ mediump float ccRoughness;
+ float ccAlpha2;
+};
+
+struct SheenShadingVariables {
+ mediump vec3 sheenColor;
+ mediump float sheenRoughness;
+ mediump float sheenColorMax;
+ mediump float sheenBRDFApprox;
+};
+
+struct AnisotropicShadingVariables {
+ float roughness;
+ float alpha;
+ float anisotropy;
+ float ToV;
+ float BoV;
+ vec3 anisotropicT;
+ vec3 anisotropicB;
+};
+
+struct SubsurfaceScatterShadingVariables {
+ vec3 scatterColor;
+ float scatterDistance;
+ float thickness;
+};
+
+
+
+void GetFinalCorrectedRoughness(mediump in vec3 polygonNormal, mediump inout float roughness)
+{
+
+
+ const mediump vec3 normalDFdx = dFdx(polygonNormal);
+ const mediump vec3 normalDdFdy = dFdy(polygonNormal);
+ const mediump float geometricRoughness =
+ pow(clamp(max(dot(normalDFdx, normalDFdx), dot(normalDdFdy, normalDdFdy)), 0.0, 1.0), 0.333);
+ roughness = max(roughness, geometricRoughness);
+
+ roughness = clamp(roughness, 0.089, 1.0);
+}
+
+void AppendIndirectSheen(in SheenShadingVariables ssv, in mediump vec3 radianceSample,
+ in mediump float alpha, inout mediump vec3 irradiance, inout mediump vec3 radiance)
+{
+ const vec3 sheenF = ssv.sheenColor * ssv.sheenBRDFApprox;
+ const float sheenAttenuation = 1.0 - (ssv.sheenColorMax * ssv.sheenBRDFApprox);
+
+ irradiance *= sheenAttenuation;
+ radiance *= sheenAttenuation;
+
+ radiance += sheenF * radianceSample;
+}
+
+void AppendIndirectClearcoat(in ClearcoatShadingVariables ccsv, in mediump vec3 radianceSample,
+ in mediump float alpha, in vec3 V, inout mediump vec3 irradiance, inout mediump vec3 radiance)
+{
+ const float ccNoV = clamp(dot(ccsv.ccNormal, V), 0.0001, 1.0);
+
+ GetFinalCorrectedRoughness(ccsv.ccNormal, ccsv.ccAlpha2);
+
+ float ccRadianceFactor = EnvBRDFApproxNonmetal(ccsv.ccAlpha2, ccNoV);
+ float ccAttenuation = 1.0 - ccRadianceFactor;
+
+
+ irradiance *= ccAttenuation;
+ radiance *= ccAttenuation;
+
+
+ radiance += radianceSample * ccRadianceFactor;
+}
+
+void AppendIndirectTransmission(in mediump vec3 radianceSample, in mediump vec3 baseColor,
+ in mediump float transmission, inout mediump vec3 irradiance)
+{
+
+ const mediump vec3 Ft = radianceSample * baseColor.rgb;
+ irradiance *= (1.0 - transmission);
+ irradiance = mix(irradiance, Ft, transmission);
+}
+
+void GetFinalSampledBrdfGeometricCorrection(in vec3 polygonNormal, inout InputBrdfData ibd)
+{
+
+ mediump float roughness = ibd.roughness;
+ GetFinalCorrectedRoughness(polygonNormal, roughness);
+
+ const mediump float alpha = roughness * roughness;
+ ibd.alpha2 = alpha * alpha;
+ ibd.roughness = roughness;
+}
+
+void GetFinalSampledBrdfGeometricCorrection(inout InputBrdfData ibd)
+{
+ const mediump float roughness = ibd.roughness;
+ const mediump float alpha = roughness * roughness;
+ ibd.alpha2 = alpha * alpha;
+}
+
+InputBrdfData CalcBRDFMetallicRoughness(mediump vec4 baseColor, vec3 polygonNormal, mediump vec4 material)
+{
+ InputBrdfData bd;
+ {
+ const mediump float metallic = clamp(material.b, 0.0, 1.0);
+ bd.f0.xyz = mix(vec3(material.a), baseColor.rgb, metallic);
+ bd.f0.w = 1.0;
+
+ bd.diffuseColor = mix(baseColor.rgb * (1.0 - bd.f0.xyz), vec3(0.0), vec3(metallic));
+ bd.roughness = material.g;
+ }
+
+ GetFinalSampledBrdfGeometricCorrection(polygonNormal, bd);
+
+ return bd;
+}
+
+InputBrdfData CalcBRDFMetallicRoughness(mediump vec4 baseColor, mediump vec4 material)
+{
+ InputBrdfData bd;
+ {
+ const mediump float metallic = clamp(material.b, 0.0, 1.0);
+ bd.f0.xyz = mix(vec3(material.a), baseColor.rgb, metallic);
+ bd.f0.w = 1.0;
+
+ bd.diffuseColor = mix(baseColor.rgb * (1.0 - bd.f0.xyz), vec3(0.0), vec3(metallic));
+ bd.roughness = material.g;
+ }
+
+ GetFinalSampledBrdfGeometricCorrection(bd);
+
+ return bd;
+}
+
+InputBrdfData CalcBRDFSpecularGlossiness(mediump vec4 baseColor, vec3 polygonNormal, mediump vec4 material)
+{
+ InputBrdfData bd;
+ {
+ bd.f0.xyz = material.xyz;
+ bd.f0.w = 1.0;
+ bd.diffuseColor = baseColor.rgb * (1.0 - max(bd.f0.x, max(bd.f0.y, bd.f0.z)));
+ bd.roughness = 1.0 - clamp(material.a, 0.0, 1.0);
+ }
+
+ GetFinalSampledBrdfGeometricCorrection(polygonNormal, bd);
+
+ return bd;
+}
+
+InputBrdfData CalcBRDFSpecular(
+ mediump vec4 baseColor, vec3 polygonNormal, mediump vec4 material, mediump vec4 specular)
+{
+ InputBrdfData bd;
+ {
+ const mediump float metallic = clamp(material.b, 0.0, 1.0);
+
+ bd.f0.xyz = mix(vec3(material.a), baseColor.rgb, metallic);
+
+
+ bd.f0.xyz = min(bd.f0.xyz * specular.rgb, vec3(1.0)) * specular.a;
+
+
+ bd.diffuseColor = mix(baseColor.rgb * (1.0 - max(bd.f0.x, max(bd.f0.y, bd.f0.z))), vec3(0.0), vec3(metallic));
+
+
+ bd.f0.xyz = mix(bd.f0.xyz, baseColor.rgb, metallic);
+ bd.f0.w = mix(specular.a, 1.0, metallic);
+ bd.roughness = material.g;
+ }
+
+ GetFinalSampledBrdfGeometricCorrection(polygonNormal, bd);
+
+ return bd;
+}
+
+mat3 CalcTbnMatrix(in vec3 polygonNormal, in vec4 tangentW)
+{
+ const vec3 tangent = normalize(tangentW.xyz);
+ const vec3 bitangent = cross(polygonNormal, tangent.xyz) * tangentW.w;
+ return mat3(tangent.xyz, bitangent.xyz, polygonNormal);
+}
+
+vec3 CalcFinalNormal(in mat3 tbn, in vec3 normal, in float normalScale)
+{
+ vec3 n = normalize( (2.0 * normal - 1.0) * vec3(normalScale, normalScale, 1.0f));
+ return normalize(tbn * n);
+}
+
+vec3 GetAnistropicReflectionVector(const vec3 V, const vec3 N, AnisotropicShadingVariables asv)
+{
+
+ const vec3 anisoDir = asv.anisotropy >= 0.0 ? asv.anisotropicB : asv.anisotropicT;
+ const vec3 anisoTangent = cross(anisoDir, V);
+ const vec3 anisoNormal = cross(anisoTangent, anisoDir);
+
+ const float bendFactor = abs(asv.anisotropy) * clamp(asv.roughness * 5.0, 0.0, 1.0);
+ const vec3 bentNormal = normalize(mix(N, anisoNormal, bendFactor));
+
+ return reflect(- V, bentNormal);
+}
+
+mat4 GetShadowMatrix(const uint shadowCamIdx)
+{
+
+ return uCameras[shadowCamIdx].shadowViewProj;
+}
+
+vec3 CalculateLight(
+ uint currLightIdx, vec3 materialDiffuseBRDF, vec3 L, float NoL, ShadingData sd, const uint materialFlags)
+{
+ const vec3 H = normalize(L + sd.V);
+ const float VoH = clamp(dot(sd.V, H), 0.0, 1.0);
+ const float NoH = clamp(dot(sd.N, H), 0.0, 1.0);
+
+ float extAttenuation = 1.0;
+ vec3 calculatedColor = vec3(0.0);
+ const float D = dGGX(sd.alpha2, NoH);
+ const float G = vGGXWithCombinedDenominator(sd.alpha2, sd.NoV, NoL);
+ const vec3 F = fSchlick(sd.f0, VoH);
+ const vec3 specContrib = F * (D * G);
+
+
+
+ const vec3 diffuseContrib = (1.0 - F.xyz) * materialDiffuseBRDF;
+ calculatedColor += (diffuseContrib + specContrib * extAttenuation) * extAttenuation * NoL;
+ calculatedColor *= uLightData.lights[currLightIdx].color.xyz;
+ return calculatedColor;
+}
+
+vec3 CalculateLight(uint currLightIdx, vec3 materialDiffuseBRDF, vec3 L, float NoL, ShadingData sd,
+ ClearcoatShadingVariables ccsv, SheenShadingVariables ssv, const uint materialFlags)
+{
+ const vec3 H = normalize(L + sd.V);
+ const float VoH = clamp(dot(sd.V, H), 0.0, 1.0);
+ const float NoH = clamp(dot(sd.N, H), 0.0, 1.0);
+
+ float extAttenuation = 1.0;
+ vec3 calculatedColor = vec3(0.0);
+ if ( (materialFlags & (1 << 6)) == (1 << 6)) {
+ const float sheenD = dCharlie(ssv.sheenRoughness, NoH);
+ const float sheenV = vAshikhmin(sd.NoV, NoL);
+ const vec3 sheenSpec = ssv.sheenColor * (sheenD * sheenV);
+
+ extAttenuation *= (1.0 - (ssv.sheenColorMax * ssv.sheenBRDFApprox));
+ calculatedColor += (sheenSpec * NoL);
+ }
+ if ( (materialFlags & (1 << 4)) == (1 << 4)) {
+ const float ccNoL = clamp(dot(ccsv.ccNormal, L), 0.0001, 1.0);
+ const float ccNoH = clamp(dot(ccsv.ccNormal, H), 0.0001, 1.0);
+ const float ccLoH = clamp(dot(L, H), 0.0001, 1.0);
+ const float ccNoV = clamp(dot(ccsv.ccNormal, sd.V), 0.0001, 1.0);
+ const float ccf0 = 0.04;
+
+ const float ccD = dGGX(ccsv.ccAlpha2, ccNoH);
+ const float ccG = vKelemen(ccLoH);
+ const float ccF = fSchlickSingle(ccf0, ccNoV) * ccsv.cc;
+ const float ccSpec = ccF * ccD * ccG;
+
+ extAttenuation *= (1.0 - ccF);
+ calculatedColor += vec3(ccSpec * ccNoL);
+ }
+ const float D = dGGX(sd.alpha2, NoH);
+ const float G = vGGXWithCombinedDenominator(sd.alpha2, sd.NoV, NoL);
+ const vec3 F = fSchlick(sd.f0, VoH);
+ const vec3 specContrib = F * (D * G);
+
+
+
+ const vec3 diffuseContrib = (1.0 - F.xyz) * materialDiffuseBRDF;
+ calculatedColor += (diffuseContrib + specContrib * extAttenuation) * extAttenuation * NoL;
+ calculatedColor *= uLightData.lights[currLightIdx].color.xyz;
+ return calculatedColor;
+}
+
+vec3 CalculateLighting(ShadingData sd, const uint materialFlags)
+{
+ const vec3 materialDiffuseBRDF = sd.diffuseColor * diffuseCoeff();
+ vec3 color = vec3(0.0);
+ const uint directionalLightCount = uLightData.directionalLightCount;
+ const uint directionalLightBeginIndex = uLightData.directionalLightBeginIndex;
+ const vec4 atlasSizeInvSize = uLightData.atlasSizeInvSize;
+ for (uint lightIdx = 0; lightIdx < directionalLightCount; ++ lightIdx) {
+ const uint currLightIdx = directionalLightBeginIndex + lightIdx;
+ const vec3 L = - uLightData.lights[currLightIdx].dir.xyz;
+ const float NoL = clamp(dot(sd.N, L), 0.0, 1.0);
+
+ mediump float shadowCoeff = 1.0;
+ if ( (materialFlags & (1 << 0)) == (1 << 0)) {
+ const uvec4 lightFlags = uLightData.lights[currLightIdx].flags;
+ if ( (lightFlags.x & (1 << 3)) == (1 << 3)) {
+ const vec4 shadowCoord = GetShadowMatrix(lightFlags.y) * vec4(sd.pos.xyz, 1.0);
+ const vec4 shadowFactors = uLightData.lights[currLightIdx].shadowFactors;
+ if ( (CORE_LIGHTING_FLAGS & (1 << 0)) == (1 << 0)) {
+ shadowCoeff = CalcVsmShadow(
+ uSampColorShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw);
+ } else {
+ shadowCoeff = CalcPcfShadow(
+ uSampDepthShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw);
+ }
+ }
+ }
+ color += CalculateLight(currLightIdx, materialDiffuseBRDF, L, NoL, sd, materialFlags) * shadowCoeff;
+ }
+
+ if ( (CORE_LIGHTING_FLAGS & (1 << 2)) == (1 << 2)) {
+ const uint spotLightCount = uLightData.spotLightCount;
+ const uint spotLightLightBeginIndex = uLightData.spotLightBeginIndex;
+ for (uint spotIdx = 0; spotIdx < spotLightCount; ++ spotIdx) {
+ const uint currLightIdx = spotLightLightBeginIndex + spotIdx;
+
+ const vec3 pointToLight = uLightData.lights[currLightIdx].pos.xyz - sd.pos.xyz;
+ const float dist = length(pointToLight);
+ const vec3 L = pointToLight / dist;
+ const float NoL = clamp(dot(sd.N, L), 0.0, 1.0);
+
+ mediump float shadowCoeff = 1.0;
+ if ( (materialFlags & (1 << 0)) == (1 << 0)) {
+ const uvec4 lightFlags = uLightData.lights[currLightIdx].flags;
+ if ( (lightFlags.x & (1 << 3)) == (1 << 3)) {
+ const vec4 shadowCoord = GetShadowMatrix(lightFlags.y) * vec4(sd.pos.xyz, 1.0);
+ const vec4 shadowFactors = uLightData.lights[currLightIdx].shadowFactors;
+ if ( (CORE_LIGHTING_FLAGS & (1 << 0)) ==
+ (1 << 0)) {
+ shadowCoeff = CalcVsmShadow(
+ uSampColorShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw);
+ } else {
+ shadowCoeff = CalcPcfShadow(
+ uSampDepthShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw);
+ }
+ }
+ }
+
+ const float lightAngleScale = uLightData.lights[currLightIdx].spotLightParams.x;
+ const float lightAngleOffset = uLightData.lights[currLightIdx].spotLightParams.y;
+
+ const float cd = dot(uLightData.lights[currLightIdx].dir.xyz, - L);
+ const float angularAttenuation = clamp(cd * lightAngleScale + lightAngleOffset, 0.0, 1.0);
+
+ const float range = uLightData.lights[currLightIdx].dir.w;
+ const float attenuation = max(min(1.0 - pow(dist / range, 4.0), 1.0), 0.0) / (dist * dist);
+ color += CalculateLight(currLightIdx, materialDiffuseBRDF, L, NoL, sd, materialFlags) *
+ (angularAttenuation * angularAttenuation * attenuation) * shadowCoeff;
+ }
+ }
+
+ if ( (CORE_LIGHTING_FLAGS & (1 << 1)) == (1 << 1)) {
+ const uint pointLightCount = uLightData.pointLightCount;
+ const uint pointLightBeginIndex = uLightData.pointLightBeginIndex;
+ for (uint pointIdx = 0; pointIdx < pointLightCount; ++ pointIdx) {
+ const uint currLightIdx = pointLightBeginIndex + pointIdx;
+
+ const vec3 pointToLight = uLightData.lights[currLightIdx].pos.xyz - sd.pos.xyz;
+ const float dist = length(pointToLight);
+ const vec3 L = pointToLight / dist;
+ const float NoL = clamp(dot(sd.N, L), 0.0, 1.0);
+ const float range = uLightData.lights[currLightIdx].dir.w;
+ const float attenuation = max(min(1.0 - pow(dist / range, 4.0), 1.0), 0.0) / (dist * dist);
+
+ color += CalculateLight(currLightIdx, materialDiffuseBRDF, L, NoL, sd, materialFlags) * attenuation;
+ }
+ }
+
+ return color;
+}
+
+vec3 CalculateLighting(
+ ShadingData sd, ClearcoatShadingVariables ccsv, SheenShadingVariables ssv, const uint materialFlags)
+{
+ const vec3 materialDiffuseBRDF = sd.diffuseColor * diffuseCoeff();
+ vec3 color = vec3(0.0);
+ const uint directionalLightCount = uLightData.directionalLightCount;
+ const uint directionalLightBeginIndex = uLightData.directionalLightBeginIndex;
+ const vec4 atlasSizeInvSize = uLightData.atlasSizeInvSize;
+ for (uint lightIdx = 0; lightIdx < directionalLightCount; ++ lightIdx) {
+ const uint currLightIdx = directionalLightBeginIndex + lightIdx;
+ const vec3 L = - uLightData.lights[currLightIdx].dir.xyz;
+ const float NoL = clamp(dot(sd.N, L), 0.0, 1.0);
+
+ mediump float shadowCoeff = 1.0;
+ if ( (materialFlags & (1 << 0)) == (1 << 0)) {
+ const uvec4 lightFlags = uLightData.lights[currLightIdx].flags;
+ if ( (lightFlags.x & (1 << 3)) == (1 << 3)) {
+ const vec4 shadowCoord = GetShadowMatrix(lightFlags.y) * vec4(sd.pos.xyz, 1.0);
+ const vec4 shadowFactors = uLightData.lights[currLightIdx].shadowFactors;
+ if ( (CORE_LIGHTING_FLAGS & (1 << 0)) == (1 << 0)) {
+ shadowCoeff = CalcVsmShadow(
+ uSampColorShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw);
+ } else {
+ shadowCoeff = CalcPcfShadow(
+ uSampDepthShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw);
+ }
+ }
+ }
+ color += CalculateLight(currLightIdx, materialDiffuseBRDF, L, NoL, sd, ccsv, ssv, materialFlags) * shadowCoeff;
+ }
+
+ if ( (CORE_LIGHTING_FLAGS & (1 << 2)) == (1 << 2)) {
+ const uint spotLightCount = uLightData.spotLightCount;
+ const uint spotLightLightBeginIndex = uLightData.spotLightBeginIndex;
+ for (uint spotIdx = 0; spotIdx < spotLightCount; ++ spotIdx) {
+ const uint currLightIdx = spotLightLightBeginIndex + spotIdx;
+
+ const vec3 pointToLight = uLightData.lights[currLightIdx].pos.xyz - sd.pos.xyz;
+ const float dist = length(pointToLight);
+ const vec3 L = pointToLight / dist;
+ const float NoL = clamp(dot(sd.N, L), 0.0, 1.0);
+
+ mediump float shadowCoeff = 1.0;
+ if ( (materialFlags & (1 << 0)) == (1 << 0)) {
+ const uvec4 lightFlags = uLightData.lights[currLightIdx].flags;
+ if ( (lightFlags.x & (1 << 3)) == (1 << 3)) {
+ const vec4 shadowCoord = GetShadowMatrix(lightFlags.y) * vec4(sd.pos.xyz, 1.0);
+ const vec4 shadowFactors = uLightData.lights[currLightIdx].shadowFactors;
+ if ( (CORE_LIGHTING_FLAGS & (1 << 0)) ==
+ (1 << 0)) {
+ shadowCoeff = CalcVsmShadow(
+ uSampColorShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw);
+ } else {
+ shadowCoeff = CalcPcfShadow(
+ uSampDepthShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw);
+ }
+ }
+ }
+
+ const float lightAngleScale = uLightData.lights[currLightIdx].spotLightParams.x;
+ const float lightAngleOffset = uLightData.lights[currLightIdx].spotLightParams.y;
+
+ const float cd = dot(uLightData.lights[currLightIdx].dir.xyz, - L);
+ const float angularAttenuation = clamp(cd * lightAngleScale + lightAngleOffset, 0.0, 1.0);
+
+ const float range = uLightData.lights[currLightIdx].dir.w;
+ const float attenuation = max(min(1.0 - pow(dist / range, 4.0), 1.0), 0.0) / (dist * dist);
+ color += CalculateLight(currLightIdx, materialDiffuseBRDF, L, NoL, sd, ccsv, ssv, materialFlags) *
+ (angularAttenuation * angularAttenuation * attenuation) * shadowCoeff;
+ }
+ }
+ if ( (CORE_LIGHTING_FLAGS & (1 << 1)) == (1 << 1)) {
+ const uint pointLightCount = uLightData.pointLightCount;
+ const uint pointLightBeginIndex = uLightData.pointLightBeginIndex;
+ for (uint pointIdx = 0; pointIdx < pointLightCount; ++ pointIdx) {
+ const uint currLightIdx = pointLightBeginIndex + pointIdx;
+
+ const vec3 pointToLight = uLightData.lights[currLightIdx].pos.xyz - sd.pos.xyz;
+ const float dist = length(pointToLight);
+ const vec3 L = pointToLight / dist;
+ const float NoL = clamp(dot(sd.N, L), 0.0, 1.0);
+ const float range = uLightData.lights[currLightIdx].dir.w;
+ const float attenuation = max(min(1.0 - pow(dist / range, 4.0), 1.0), 0.0) / (dist * dist);
+
+ color +=
+ CalculateLight(currLightIdx, materialDiffuseBRDF, L, NoL, sd, ccsv, ssv, materialFlags) * attenuation;
+ }
+ }
+
+ return color;
+}
+
+vec3 CalculateLight(uint currLightIdx, vec3 materialDiffuseBRDF, vec3 L, float NoL, ShadingData sd,
+ AnisotropicShadingVariables asv, ClearcoatShadingVariables ccsv, SheenShadingVariables ssv,
+ const uint materialFlags)
+{
+ const vec3 H = normalize(L + sd.V);
+ const float VoH = dot(sd.V, H);
+ const float NoH = dot(sd.N, H);
+
+ vec3 calculatedColor = vec3(0.0);
+ float extAttenuation = 1.0;
+ if ( (materialFlags & (1 << 6)) == (1 << 6)) {
+ const float sheenD = dCharlie(ssv.sheenRoughness, NoH);
+ const float sheenV = vAshikhmin(sd.NoV, NoL);
+ const vec3 sheenSpec = ssv.sheenColor * (sheenD * sheenV);
+
+ extAttenuation *= (1.0 - (ssv.sheenColorMax * ssv.sheenBRDFApprox));
+ calculatedColor += (sheenSpec * NoL);
+ }
+ if ( (materialFlags & (1 << 4)) == (1 << 4)) {
+ const float ccNoL = clamp(dot(ccsv.ccNormal, L), 0.0001, 1.0);
+ const float ccNoH = clamp(dot(ccsv.ccNormal, H), 0.0, 1.0);
+ const float ccf0 = 0.04;
+
+ const float ccD = dGGX(ccsv.ccAlpha2, ccNoH);
+ const float ccG = vKelemen(ccNoH);
+ const float ccF = fSchlickSingle(ccf0, VoH) * ccsv.cc;
+ const float ccSpec = ccF * ccD * ccG;
+
+ extAttenuation *= (1.0 - ccF);
+ calculatedColor += vec3(ccSpec * ccNoL);
+ }
+
+ const float ToL = dot(asv.anisotropicT, L);
+ const float ToH = dot(asv.anisotropicT, H);
+ const float BoL = dot(asv.anisotropicB, L);
+ const float BoH = dot(asv.anisotropicB, H);
+ const float at = max(asv.alpha * (1.0 + asv.anisotropy), 0.0001);
+ const float ab = max(asv.alpha * (1.0 - asv.anisotropy), 0.0001);
+
+ const float D = dGGXAnisotropic(at, ab, NoH, ToH, BoH, asv.anisotropy);
+ const float G = vGGXAnisotropic(at, ab, NoL, sd.NoV, ToL, asv.ToV, BoL, asv.BoV, asv.anisotropy);
+ const vec3 F = fSchlick(sd.f0, VoH);
+ const vec3 specContrib = F * (D * G);
+
+
+
+ const vec3 diffuseContrib = (1.0 - F.xyz) * materialDiffuseBRDF;
+ calculatedColor += (diffuseContrib + specContrib * extAttenuation) * extAttenuation * NoL;
+ calculatedColor *= uLightData.lights[currLightIdx].color.xyz;
+ return calculatedColor;
+}
+
+vec3 CalculateLighting(ShadingData sd, AnisotropicShadingVariables asv, ClearcoatShadingVariables ccsv,
+ SheenShadingVariables ssv, const uint materialFlags)
+{
+ const vec3 materialDiffuseBRDF = sd.diffuseColor * diffuseCoeff();
+ vec3 color = vec3(0.0);
+ const uint directionalLightCount = uLightData.directionalLightCount;
+ const uint directionalLightBeginIndex = uLightData.directionalLightBeginIndex;
+ const vec4 atlasSizeInvSize = uLightData.atlasSizeInvSize;
+ for (uint lightIdx = 0; lightIdx < directionalLightCount; ++ lightIdx) {
+ const uint currLightIdx = directionalLightBeginIndex + lightIdx;
+ const vec3 L = - uLightData.lights[currLightIdx].dir.xyz;
+ const float NoL = clamp(dot(sd.N, L), 0.0, 1.0);
+
+ mediump float shadowCoeff = 1.0;
+ if ( (materialFlags & (1 << 0)) == (1 << 0)) {
+ const uvec4 lightFlags = uLightData.lights[currLightIdx].flags;
+ if ( (lightFlags.x & (1 << 3)) == (1 << 3)) {
+ const vec4 shadowCoord = GetShadowMatrix(lightFlags.y) * vec4(sd.pos.xyz, 1.0);
+ const vec4 shadowFactors = uLightData.lights[currLightIdx].shadowFactors;
+ if ( (CORE_LIGHTING_FLAGS & (1 << 0)) == (1 << 0)) {
+ shadowCoeff = CalcVsmShadow(
+ uSampColorShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw);
+ } else {
+ shadowCoeff = CalcPcfShadow(
+ uSampDepthShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw);
+ }
+ }
+ }
+ color +=
+ CalculateLight(currLightIdx, materialDiffuseBRDF, L, NoL, sd, asv, ccsv, ssv, materialFlags) * shadowCoeff;
+ }
+
+ if ( (CORE_LIGHTING_FLAGS & (1 << 2)) == (1 << 2)) {
+ const uint spotLightCount = uLightData.spotLightCount;
+ const uint spotLightLightBeginIndex = uLightData.spotLightBeginIndex;
+ for (uint spotIdx = 0; spotIdx < spotLightCount; ++ spotIdx) {
+ const uint currLightIdx = spotLightLightBeginIndex + spotIdx;
+
+ const vec3 pointToLight = uLightData.lights[currLightIdx].pos.xyz - sd.pos.xyz;
+ const float dist = length(pointToLight);
+ const vec3 L = pointToLight / dist;
+ const float NoL = clamp(dot(sd.N, L), 0.0, 1.0);
+
+ mediump float shadowCoeff = 1.0;
+ if ( (materialFlags & (1 << 0)) == (1 << 0)) {
+ const uvec4 lightFlags = uLightData.lights[currLightIdx].flags;
+ if ( (lightFlags.x & (1 << 3)) == (1 << 3)) {
+ const vec4 shadowCoord = GetShadowMatrix(lightFlags.y) * vec4(sd.pos.xyz, 1.0);
+ const vec4 shadowFactors = uLightData.lights[currLightIdx].shadowFactors;
+ if ( (CORE_LIGHTING_FLAGS & (1 << 0)) ==
+ (1 << 0)) {
+ shadowCoeff = CalcVsmShadow(
+ uSampColorShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw);
+ } else {
+ shadowCoeff = CalcPcfShadow(
+ uSampDepthShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw);
+ }
+ }
+ }
+
+ const float lightAngleScale = uLightData.lights[currLightIdx].spotLightParams.x;
+ const float lightAngleOffset = uLightData.lights[currLightIdx].spotLightParams.y;
+
+ const float cd = dot(uLightData.lights[currLightIdx].dir.xyz, - L);
+ const float angularAttenuation = clamp(cd * lightAngleScale + lightAngleOffset, 0.0, 1.0);
+
+ const float range = uLightData.lights[currLightIdx].dir.w;
+ const float attenuation = max(min(1.0 - pow(dist / range, 4.0), 1.0), 0.0) / (dist * dist);
+ color += CalculateLight(currLightIdx, materialDiffuseBRDF, L, NoL, sd, asv, ccsv, ssv, materialFlags) *
+ (angularAttenuation * angularAttenuation * attenuation) * shadowCoeff;
+ }
+ }
+ if ( (CORE_LIGHTING_FLAGS & (1 << 1)) == (1 << 1)) {
+ const uint pointLightCount = uLightData.pointLightCount;
+ const uint pointLightBeginIndex = uLightData.pointLightBeginIndex;
+ for (uint pointIdx = 0; pointIdx < pointLightCount; ++ pointIdx) {
+ const uint currLightIdx = pointLightBeginIndex + pointIdx;
+
+ const vec3 pointToLight = uLightData.lights[currLightIdx].pos.xyz - sd.pos.xyz;
+ const float dist = length(pointToLight);
+ const vec3 L = pointToLight / dist;
+ const float NoL = clamp(dot(sd.N, L), 0.0, 1.0);
+ const float range = uLightData.lights[currLightIdx].dir.w;
+ const float attenuation = max(min(1.0 - pow(dist / range, 4.0), 1.0), 0.0) / (dist * dist);
+
+ color += CalculateLight(currLightIdx, materialDiffuseBRDF, L, NoL, sd, asv, ccsv, ssv, materialFlags) *
+ attenuation;
+ }
+ }
+
+ return color;
+}
+
+vec3 CalculateLight(uint currLightIdx, vec3 materialDiffuseBRDF, vec3 L, float NoL, ShadingData sd,
+ SubsurfaceScatterShadingVariables ssssv, const uint materialFlags)
+{
+ const vec3 H = normalize(L + sd.V);
+ const float VoH = clamp(dot(sd.V, H), 0.0, 1.0);
+ const float NoH = clamp(dot(sd.N, H), 0.0, 1.0);
+
+ float extAttenuation = 1.0;
+ vec3 calculatedColor = vec3(0.0);
+ const float D = dGGX(sd.alpha2, NoH);
+ const float G = vGGXWithCombinedDenominator(sd.alpha2, sd.NoV, NoL);
+ const vec3 F = fSchlick(sd.f0, VoH);
+ const vec3 specContrib = F * (D * G);
+
+ const vec3 diffuseContrib = (1.0 - F.xyz) * materialDiffuseBRDF;
+ calculatedColor += (diffuseContrib + specContrib * extAttenuation) * extAttenuation * NoL;
+
+
+
+
+ float scatterVoH = clamp(dot(sd.V, - L), 0.0, 1.0);
+
+ float sharpness = 10000.0 - 10000.0 * ssssv.scatterDistance;
+ float forwardScatter = exp2(scatterVoH * sharpness - sharpness);
+ float backScatter = clamp(NoL * ssssv.thickness + (1.0 - ssssv.thickness), 0.0, 1.0) * 0.5;
+ float subsurface = mix(backScatter, 1.0, forwardScatter) * (1.0 - ssssv.thickness);
+ calculatedColor += ssssv.scatterColor * (subsurface * dLambert());
+
+
+ return(calculatedColor * uLightData.lights[currLightIdx].color.rgb);
+}
+
+vec3 CalculateLighting(ShadingData sd, SubsurfaceScatterShadingVariables sssv, const uint materialFlags)
+{
+ const vec3 materialDiffuseBRDF = sd.diffuseColor * diffuseCoeff();
+ vec3 color = vec3(0.0);
+ const uint directionalLightCount = uLightData.directionalLightCount;
+ const uint directionalLightBeginIndex = uLightData.directionalLightBeginIndex;
+ const vec4 atlasSizeInvSize = uLightData.atlasSizeInvSize;
+ for (uint lightIdx = 0; lightIdx < directionalLightCount; ++ lightIdx) {
+ const uint currLightIdx = directionalLightBeginIndex + lightIdx;
+ const vec3 L = - uLightData.lights[currLightIdx].dir.xyz;
+ const float NoL = clamp(dot(sd.N, L), 0.0, 1.0);
+
+ mediump float shadowCoeff = 1.0;
+ if ( (materialFlags & (1 << 0)) == (1 << 0)) {
+ const uvec4 lightFlags = uLightData.lights[currLightIdx].flags;
+ if ( (lightFlags.x & (1 << 3)) == (1 << 3)) {
+ const vec4 shadowCoord = GetShadowMatrix(lightFlags.y) * vec4(sd.pos.xyz, 1.0);
+ const vec4 shadowFactors = uLightData.lights[currLightIdx].shadowFactors;
+ if ( (CORE_LIGHTING_FLAGS & (1 << 0)) == (1 << 0)) {
+ shadowCoeff = CalcVsmShadow(
+ uSampColorShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw);
+ } else {
+ shadowCoeff = CalcPcfShadow(
+ uSampDepthShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw);
+ }
+ }
+ }
+ color += CalculateLight(currLightIdx, materialDiffuseBRDF, L, NoL, sd, sssv, materialFlags) * shadowCoeff;
+ }
+
+ if ( (CORE_LIGHTING_FLAGS & (1 << 2)) == (1 << 2)) {
+ const uint spotLightCount = uLightData.spotLightCount;
+ const uint spotLightLightBeginIndex = uLightData.spotLightBeginIndex;
+ for (uint spotIdx = 0; spotIdx < spotLightCount; ++ spotIdx) {
+ const uint currLightIdx = spotLightLightBeginIndex + spotIdx;
+
+ const vec3 pointToLight = uLightData.lights[currLightIdx].pos.xyz - sd.pos.xyz;
+ const float dist = length(pointToLight);
+ const vec3 L = pointToLight / dist;
+ const float NoL = clamp(dot(sd.N, L), 0.0, 1.0);
+
+ mediump float shadowCoeff = 1.0;
+ if ( (materialFlags & (1 << 0)) == (1 << 0)) {
+ const uvec4 lightFlags = uLightData.lights[currLightIdx].flags;
+ if ( (lightFlags.x & (1 << 3)) == (1 << 3)) {
+ const vec4 shadowCoord = GetShadowMatrix(lightFlags.y) * vec4(sd.pos.xyz, 1.0);
+ const vec4 shadowFactors = uLightData.lights[currLightIdx].shadowFactors;
+ if ( (CORE_LIGHTING_FLAGS & (1 << 0)) ==
+ (1 << 0)) {
+ shadowCoeff = CalcVsmShadow(
+ uSampColorShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw);
+ } else {
+ shadowCoeff = CalcPcfShadow(
+ uSampDepthShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw);
+ }
+ }
+ }
+
+ const float lightAngleScale = uLightData.lights[currLightIdx].spotLightParams.x;
+ const float lightAngleOffset = uLightData.lights[currLightIdx].spotLightParams.y;
+
+ const float cd = dot(uLightData.lights[currLightIdx].dir.xyz, - L);
+ const float angularAttenuation = clamp(cd * lightAngleScale + lightAngleOffset, 0.0, 1.0);
+
+ const float range = uLightData.lights[currLightIdx].dir.w;
+ const float attenuation = max(min(1.0 - pow(dist / range, 4.0), 1.0), 0.0) / (dist * dist);
+ color += CalculateLight(currLightIdx, materialDiffuseBRDF, L, NoL, sd, sssv, materialFlags) *
+ (angularAttenuation * angularAttenuation * attenuation) * shadowCoeff;
+ }
+ }
+ if ( (CORE_LIGHTING_FLAGS & (1 << 1)) == (1 << 1)) {
+ const uint pointLightCount = uLightData.pointLightCount;
+ const uint pointLightBeginIndex = uLightData.pointLightBeginIndex;
+ for (uint pointIdx = 0; pointIdx < pointLightCount; ++ pointIdx) {
+ const uint currLightIdx = pointLightBeginIndex + pointIdx;
+
+ const vec3 pointToLight = uLightData.lights[currLightIdx].pos.xyz - sd.pos.xyz;
+ const float dist = length(pointToLight);
+ const vec3 L = pointToLight / dist;
+ const float NoL = clamp(dot(sd.N, L), 0.0, 1.0);
+ const float range = uLightData.lights[currLightIdx].dir.w;
+ const float attenuation = max(min(1.0 - pow(dist / range, 4.0), 1.0), 0.0) / (dist * dist);
+
+ color += CalculateLight(currLightIdx, materialDiffuseBRDF, L, NoL, sd, sssv, materialFlags) * attenuation;
+ }
+ }
+
+ return color;
+}
+
+
+#line 19 "shader/custom_materiaL_sample.frag"
+
+
+struct MyMaterialSampleStruct {
+ vec4 vec_1;
+ float time;
+ bool dof;
+ bool motionBlur;
+};
+layout(set = 1, binding = 4, std140) uniform uMyBuffer0
+{
+ MyMaterialSampleStruct uMyData;
+};
+
+
+
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_inout_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_compatibility_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 20 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_inout_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+layout(location = 0) in vec3 inPos;
+layout(location = 1) in vec3 inNormal;
+layout(location = 2) in vec4 inTangentW;
+layout(location = 3) in vec4 inPrevPosI;
+layout(location = 4) in vec4 inUv;
+layout(location = 5) in mediump vec4 inColor;
+layout(location = 6) in flat uint inIndices;
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 35 "shader/custom_materiaL_sample.frag"
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_inplace_sampling_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+vec2 GetTransformedUV(const DefaultMaterialUnpackedTexTransformStruct texTransform, const vec2 uvInput)
+{
+ vec2 uv;
+ uv.x = dot(texTransform.rotateScale.xy, uvInput);
+ uv.y = dot(texTransform.rotateScale.zw, uvInput);
+ uv += texTransform.translate.xy;
+ return uv;
+}
+
+
+
+uint GetUnpackTexCoordInfo()
+{
+ return floatBitsToUint(uMaterialData.material[0].factors[11].y);
+}
+uint GetUnpackTexCoordInfo(uint instanceIdx)
+{
+ return floatBitsToUint(uMaterialData.material[instanceIdx].factors[11].y);
+}
+
+vec2 GetFinalSamplingUV(vec4 inputUv, uint texCoordInfoBit, uint texCoordIdx)
+{
+ const uint texCoordInfo = GetUnpackTexCoordInfo();
+ vec2 uv = ( ( (texCoordInfo >> 16) & texCoordInfoBit) == texCoordInfoBit) ? inputUv.zw
+ : inputUv.xy;
+ const bool doTrans = ( ( (texCoordInfo & 0xffff) & texCoordInfoBit) == texCoordInfoBit);
+ if ( ( (CORE_MATERIAL_FLAGS & (1 << 3)) == (1 << 3)) &&
+ doTrans) {
+ DefaultMaterialUnpackedTexTransformStruct texTransform =
+ GetUnpackTextureTransform(uMaterialTransformData.material[0].packed[texCoordIdx]);
+ uv = GetTransformedUV(texTransform, uv);
+ }
+ return uv;
+}
+vec2 GetFinalSamplingUV(vec4 inputUv, uint texCoordInfoBit, uint texCoordIdx, uint instanceIdx)
+{
+ const uint texCoordInfo = GetUnpackTexCoordInfo(instanceIdx);
+ vec2 uv = ( ( (texCoordInfo >> 16) & texCoordInfoBit) == texCoordInfoBit) ? inputUv.zw
+ : inputUv.xy;
+ const bool doTrans = ( ( (texCoordInfo & 0xffff) & texCoordInfoBit) == texCoordInfoBit);
+ if ( ( (CORE_MATERIAL_FLAGS & (1 << 3)) == (1 << 3)) &&
+ doTrans) {
+ DefaultMaterialUnpackedTexTransformStruct texTransform =
+ GetUnpackTextureTransform(uMaterialTransformData.material[instanceIdx].packed[texCoordIdx]);
+ uv = GetTransformedUV(texTransform, uv);
+ }
+ return uv;
+}
+
+vec4 GetBaseColorSample(const vec4 uvInput)
+{
+ const vec2 uv =
+ GetFinalSamplingUV(uvInput, (1 << 0), 0);
+ return texture(uSampTextureBase, uv);
+}
+vec4 GetBaseColorSample(const vec4 uvInput, const uint instanceIdx)
+{
+ const vec2 uv = GetFinalSamplingUV(
+ uvInput, (1 << 0), 0, instanceIdx);
+ return texture(uSampTextureBase, uv);
+}
+
+vec3 GetNormalSample(const vec4 uvInput)
+{
+ const vec2 uv =
+ GetFinalSamplingUV(uvInput, (1 << 1), 1);
+ return texture(uSampTextures[0], uv).xyz;
+}
+vec3 GetNormalSample(const vec4 uvInput, const uint instanceIdx)
+{
+ const vec2 uv = GetFinalSamplingUV(
+ uvInput, (1 << 1), 1, instanceIdx);
+ return texture(uSampTextures[0], uv).xyz;
+}
+
+vec4 GetMaterialSample(const vec4 uvInput)
+{
+ const vec2 uv =
+ GetFinalSamplingUV(uvInput, (1 << 2), 2);
+ return texture(uSampTextures[1], uv);
+}
+vec4 GetMaterialSample(const vec4 uvInput, const uint instanceIdx)
+{
+ const vec2 uv = GetFinalSamplingUV(
+ uvInput, (1 << 2), 2, instanceIdx);
+ return texture(uSampTextures[1], uv);
+}
+
+vec3 GetEmissiveSample(const vec4 uvInput)
+{
+ const vec2 uv =
+ GetFinalSamplingUV(uvInput, (1 << 3), 3);
+ return texture(uSampTextures[2], uv).xyz;
+}
+vec3 GetEmissiveSample(const vec4 uvInput, const uint instanceIdx)
+{
+ const vec2 uv = GetFinalSamplingUV(
+ uvInput, (1 << 3), 3, instanceIdx);
+ return texture(uSampTextures[2], uv).xyz;
+}
+
+float GetAOSample(const vec4 uvInput)
+{
+ const vec2 uv = GetFinalSamplingUV(uvInput, (1 << 4), 4);
+ return texture(uSampTextures[3], uv).x;
+}
+float GetAOSample(const vec4 uvInput, const uint instanceIdx)
+{
+ const vec2 uv =
+ GetFinalSamplingUV(uvInput, (1 << 4), 4, instanceIdx);
+ return texture(uSampTextures[3], uv).x;
+}
+
+float GetClearcoatSample(const vec4 uvInput)
+{
+ const vec2 uv =
+ GetFinalSamplingUV(uvInput, (1 << 5), 5);
+ return texture(uSampTextures[4], uv).x;
+}
+float GetClearcoatSample(const vec4 uvInput, const uint instanceIdx)
+{
+ const vec2 uv = GetFinalSamplingUV(
+ uvInput, (1 << 5), 5, instanceIdx);
+ return texture(uSampTextures[4], uv).x;
+}
+
+float GetClearcoatRoughnessSample(const vec4 uvInput)
+{
+ const vec2 uv = GetFinalSamplingUV(uvInput, (1 << 6),
+ 6);
+ return texture(uSampTextures[5], uv).y;
+}
+float GetClearcoatRoughnessSample(const vec4 uvInput, const uint instanceIdx)
+{
+ const vec2 uv = GetFinalSamplingUV(uvInput, (1 << 6),
+ 6, instanceIdx);
+ return texture(uSampTextures[5], uv).y;
+}
+
+vec3 GetClearcoatNormalSample(const vec4 uvInput)
+{
+ const vec2 uv = GetFinalSamplingUV(
+ uvInput, (1 << 7), 7);
+ return texture(uSampTextures[6], uv).xyz;
+}
+vec3 GetClearcoatNormalSample(const vec4 uvInput, const uint instanceIdx)
+{
+ const vec2 uv = GetFinalSamplingUV(uvInput, (1 << 7),
+ 7, instanceIdx);
+ return texture(uSampTextures[6], uv).xyz;
+}
+
+vec3 GetSheenSample(const vec4 uvInput)
+{
+ const vec2 uv =
+ GetFinalSamplingUV(uvInput, (1 << 8), 8);
+ return texture(uSampTextures[7], uv).xyz;
+}
+vec3 GetSheenSample(const vec4 uvInput, const uint instanceIdx)
+{
+ const vec2 uv = GetFinalSamplingUV(
+ uvInput, (1 << 8), 8, instanceIdx);
+ return texture(uSampTextures[7], uv).xyz;
+}
+
+
+float GetSheenRoughnessSample(const vec4 uvInput)
+{
+ const vec2 uv =
+ GetFinalSamplingUV(uvInput, (1 << 8), 8);
+ return texture(uSampTextures[7], uv).a;
+}
+float GetSheenRoughnessSample(const vec4 uvInput, const uint instanceIdx)
+{
+ const vec2 uv = GetFinalSamplingUV(
+ uvInput, (1 << 8), 8, instanceIdx);
+ return texture(uSampTextures[7], uv).a;
+}
+
+float GetTransmissionSample(const vec4 uvInput)
+{
+ const vec2 uv = GetFinalSamplingUV(
+ uvInput, (1 << 9), 9);
+ return texture(uSampTextures[8], uv).r;
+}
+float GetTransmissionSample(const vec4 uvInput, const uint instanceIdx)
+{
+ const vec2 uv = GetFinalSamplingUV(
+ uvInput, (1 << 9), 9, instanceIdx);
+ return texture(uSampTextures[8], uv).r;
+}
+
+vec4 GetSpecularSample(const vec4 uvInput)
+{
+ const vec2 uv =
+ GetFinalSamplingUV(uvInput, (1 << 10), 10);
+ return texture(uSampTextures[9], uv);
+}
+vec4 GetSpecularSample(const vec4 uvInput, const uint instanceIdx)
+{
+ const vec2 uv = GetFinalSamplingUV(
+ uvInput, (1 << 10), 10, instanceIdx);
+ return texture(uSampTextures[9], uv);
+}
+
+
+
+
+
+uint GetUnpackCameraIndex()
+{
+ return uGeneralData.indices.x;
+}
+
+vec4 GetUnpackViewport()
+{
+ return uGeneralData.viewportSizeInvViewportSize;
+}
+
+vec4 GetUnpackBaseColor(const uint instanceIdx)
+{
+ return uMaterialData.material[instanceIdx].factors[0];
+}
+
+vec4 GetUnpackMaterial(const uint instanceIdx)
+{
+ return uMaterialData.material[instanceIdx].factors[2];
+}
+
+float GetUnpackAO(const uint instanceIdx)
+{
+ return uMaterialData.material[instanceIdx].factors[4].x;
+}
+
+float GetUnpackClearcoat(const uint instanceIdx)
+{
+ return uMaterialData.material[instanceIdx].factors[5].x;
+}
+
+
+float GetUnpackClearcoatRoughness(const uint instanceIdx)
+{
+ return uMaterialData.material[instanceIdx].factors[6].y;
+}
+
+float GetUnpackClearcoatNormalScale(const uint instanceIdx)
+{
+ return uMaterialData.material[instanceIdx].factors[7].x;
+}
+
+
+vec4 GetUnpackSheen(const uint instanceIdx)
+{
+ return uMaterialData.material[instanceIdx].factors[8];
+}
+
+float GetUnpackTransmission(const uint instanceIdx)
+{
+ return uMaterialData.material[instanceIdx].factors[9].x;
+}
+
+
+vec4 GetUnpackSpecular(const uint instanceIdx)
+{
+ return uMaterialData.material[instanceIdx].factors[10];
+}
+
+vec3 GetUnpackEmissiveColor(const uint instanceIdx)
+{
+ const vec4 emissive = uMaterialData.material[instanceIdx].factors[3];
+ return emissive.rgb * emissive.a;
+}
+
+float GetUnpackNormalScale(const uint instanceIdx)
+{
+ return uMaterialData.material[instanceIdx].factors[1].x;
+}
+
+float GetUnpackAlphaCutoff(const uint instanceIdx)
+{
+ return uMaterialData.material[instanceIdx].factors[11].x;
+}
+
+vec4 GetUnpackMaterialTextureInfoSlotFactor(const uint materialIndexSlot, const uint instanceIdx)
+{
+ const uint maxIndex = min(materialIndexSlot, 15 - 1);
+ return uMaterialData.material[instanceIdx].factors[maxIndex].xyzw;
+}
+
+vec4 Unpremultiply(in vec4 color)
+{
+ if (color.a == 0.0) {
+ return vec4(0);
+ }
+ return vec4(color.rgb / color.a, color.a);
+}
+
+ mediump vec4 GetUnpackBaseColorFinalValue(in mediump vec4 color, in vec4 uv, in uint instanceIdx)
+{
+
+ mediump vec4 baseColor = GetBaseColorSample(uv, instanceIdx) * GetUnpackBaseColor(instanceIdx) * color;
+ baseColor.a = clamp(baseColor.a, 0.0, 1.0);
+ if ( (CORE_MATERIAL_FLAGS & (1 << 7)) ==
+ (1 << 7)) {
+ if (baseColor.a < GetUnpackAlphaCutoff(instanceIdx)) {
+ discard;
+ }
+ }
+ if ( (CORE_MATERIAL_FLAGS & (1 << 8)) == (1 << 8)) {
+ baseColor.a = 1.0;
+ } else {
+ baseColor = Unpremultiply(baseColor);
+ }
+ return baseColor;
+}
+
+
+vec2 GetFinalCalculatedVelocity(in vec3 pos, in vec3 prevPos)
+{
+
+
+
+ const uint cameraIdx = GetUnpackCameraIndex();
+ const vec4 projPos = uCameras[cameraIdx].viewProj * vec4(pos.xyz, 1.0);
+ const vec4 projPosPrev = uCameras[cameraIdx].viewProjPrevFrame * vec4(prevPos.xyz, 1.0);
+
+ const vec2 uvPos = (projPos.xy / projPos.w) * 0.5 + 0.5;
+ const vec2 oldUvPos = (projPosPrev.xy / projPosPrev.w) * 0.5 + 0.5;
+
+ return(uvPos - oldUvPos) * uGeneralData.viewportSizeInvViewportSize.xy;
+}
+
+vec2 GetFinalCalculatedVelocity(in vec3 pos, in vec3 prevPos, in uint cameraIdx)
+{
+
+
+
+ const vec4 projPos = uCameras[cameraIdx].viewProj * vec4(pos.xyz, 1.0);
+ const vec4 projPosPrev = uCameras[cameraIdx].viewProjPrevFrame * vec4(prevPos.xyz, 1.0);
+
+ const vec2 uvPos = (projPos.xy / projPos.w) * 0.5 + 0.5;
+ const vec2 oldUvPos = (projPosPrev.xy / projPosPrev.w) * 0.5 + 0.5;
+
+ return(uvPos - oldUvPos) * uGeneralData.viewportSizeInvViewportSize.xy;
+}
+
+#line 36 "shader/custom_materiaL_sample.frag"
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_inplace_post_process.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_post_process_blocks.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_color_conversion_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 20 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_post_process_blocks.h"
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_post_process_structs_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 21 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_post_process_blocks.h"
+#line 1 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_tonemap_common.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 22 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/LumeRender/api/render/shaders/common/render_post_process_blocks.h"
+
+
+
+
+
+
+void PostProcessTonemapBlock(in uint postProcessFlags, in vec4 tonemapFactor, in vec3 inCol, out vec3 outCol)
+{
+ outCol = inCol;
+ if ( (postProcessFlags & (1 << 0)) == (1 << 0)) {
+ const float exposure = tonemapFactor.x;
+ const vec3 x = outCol * exposure;
+ const uint tonemapType = uint(tonemapFactor.w);
+ if (tonemapType == 0) {
+ outCol = TonemapAces(x);
+ } else if (tonemapType == 1) {
+ outCol = TonemapAcesFilmRec2020(x);
+ } else if (tonemapType == 2) {
+ const float exposureEstimate = 6.0f;
+ outCol = TonemapFilmic(x * exposureEstimate);
+ }
+ }
+}
+
+
+
+
+void PostProcessVignetteBlock(
+ in uint postProcessFlags, in vec4 vignetteFactor, in vec2 uv, in vec3 inCol, out vec3 outCol)
+{
+ outCol = inCol;
+ if ( (postProcessFlags & (1 << 1)) == (1 << 1)) {
+ const vec2 uvVal = uv.xy * (vec2(1.0) - uv.yx);
+ mediump float vignette = uvVal.x * uvVal.y * vignetteFactor.x * 40.0;
+ vignette = clamp(pow(vignette, vignetteFactor.y), 0.0, 1.0);
+ outCol.rgb *= vignette;
+ }
+}
+
+
+
+
+void PostProcessColorFringeBlock(in uint postProcessFlags, in vec4 chromaFactor, in vec2 uv, in vec2 uvSize,
+ in sampler2D imgSampler, in vec3 inCol, out vec3 outCol)
+{
+ outCol = inCol;
+ if ( (postProcessFlags & (1 << 4)) ==
+ (1 << 4)) {
+
+ const vec2 distUv = (uv - 0.5) * 2.0;
+ const mediump float chroma = dot(distUv, distUv) * chromaFactor.y * chromaFactor.x;
+
+ const vec2 uvDistToImageCenter = chroma * uvSize;
+ const mediump float chromaRed =
+ textureLod(imgSampler, uv - vec2(uvDistToImageCenter.x, uvDistToImageCenter.y), 0).x;
+ const mediump float chromaBlue =
+ textureLod(imgSampler, uv + vec2(uvDistToImageCenter.x, uvDistToImageCenter.y), 0).z;
+
+ outCol.r = chromaRed;
+ outCol.b = chromaBlue;
+ }
+}
+
+
+
+
+void PostProcessDitherBlock(in uint postProcessFlags, in vec4 ditherFactor, in vec2 uv, in vec3 inCol, out vec3 outCol)
+{
+ outCol = inCol;
+ if ( (postProcessFlags & (1 << 2)) == (1 << 2)) {
+ const vec2 random01Range = vec2(uv.x * ditherFactor.y, uv.y * ditherFactor.z);
+ outCol += fract(sin(dot(random01Range.xy, vec2(12.9898, 78.233))) * 43758.5453) * ditherFactor.x;
+ }
+}
+
+
+
+
+void PostProcessColorConversionBlock(
+ in uint postProcessFlags, in vec4 colorConversionFactor, in vec3 inCol, out vec3 outCol)
+{
+ outCol = inCol;
+ if ( (postProcessFlags & (1 << 3)) ==
+ (1 << 3)) {
+ const uint conversionType = uint(colorConversionFactor.w);
+ if (conversionType == 1) {
+ outCol.rgb = LinearToSrgb(outCol.rgb);
+ }
+ }
+}
+
+
+
+
+void PostProcessBloomCombineBlock(in uint postProcessFlags, in vec4 bloomFactor, in vec2 uv, in sampler2D imgSampler,
+ in sampler2D dirtImgSampler, in vec3 inCol, out vec3 outCol)
+{
+ outCol = inCol;
+ if ( (postProcessFlags & (1 << 9)) == (1 << 9)) {
+
+ const vec3 bloomColor = textureLod(imgSampler, uv, 0).rgb * bloomFactor.z;
+ const vec3 dirtColor = textureLod(dirtImgSampler, uv, 0).rgb * bloomFactor.w;
+ const vec3 bloomCombine = outCol + bloomColor + dirtColor * max(bloomColor.x, max(bloomColor.y, bloomColor.z));
+ outCol.rgb = min(bloomCombine, 64512.0);
+ }
+}
+
+
+#line 21 "/home/huxiaoming/upload_gitee/foundation/graphic/graphic_3d/lume/Lume_3D/api/3d/shaders/common/3d_dm_inplace_post_process.h"
+
+
+
+
+
+void InplacePostProcess(in vec2 fragUv, inout vec4 color)
+{
+
+ PostProcessTonemapBlock(
+ uPostProcessData.flags.x, uPostProcessData.factors[0], color.rgb, color.rgb);
+
+ const float tickDelta = uPostProcessData.renderTimings.y;
+ const vec2 vecCoeffs = fragUv.xy * tickDelta;
+ PostProcessDitherBlock(
+ uPostProcessData.flags.x, uPostProcessData.factors[2], vecCoeffs, color.rgb, color.rgb);
+ PostProcessVignetteBlock(
+ uPostProcessData.flags.x, uPostProcessData.factors[1], fragUv, color.rgb, color.rgb);
+ PostProcessColorConversionBlock(
+ uPostProcessData.flags.x, uPostProcessData.factors[3], color.rgb, color.rgb);
+}
+
+
+
+
+#line 37 "shader/custom_materiaL_sample.frag"
+
+
+
+layout(location = 0) out vec4 outColor;
+
+
+
+
+
+const float pi = acos(- 1.);
+const float pi2 = acos(- 1.) * 2.;
+
+
+const int nS = 2;
+
+const float w = .03;
+
+
+mat2 rot(float a) {
+ float s = sin(a), c = cos(a);
+ return mat2(c, s, - s, c);
+}
+
+float hash12(vec2 p) {
+ float v = dot(p, vec2(1.8672, 1.3723));
+ return fract(sin(v) * 5723.2622);
+}
+
+
+float perlin1d(float x) {
+ float i = floor(x);
+ float f = fract(x);
+ float u = f * f * (3. - 2. * f);
+
+ return mix(f * (fract(sin(i) * 5723.2622) * 2. - 1.), (f - 1.) * (fract(sin(i + 1.) * 5723.2622) * 2. - 1.), u);
+}
+
+float fiberShape(float x, float time) {
+ float s = .03;
+ float curve = smoothstep(.25 - s, .25 + s, abs(fract(time * .11) - .5));
+ return perlin1d(x) * (1. - w * 2.) * curve;
+}
+
+
+float stepNoise(float x, float n) {
+ float i = floor(x);
+ float s = .1;
+ float u = smoothstep(.5 - s, .5 + s, fract(x));
+
+ return mix(floor(fract(sin(i) * 5723.2622) * n), floor(fract(sin(i + 1.) * 5723.2622) * n), u);
+}
+
+
+
+void main(void)
+{
+ vec2 uv = (inUv.xy - vec2(0.5, 0.5)) * 2.0f;
+ vec2 fragCoord = inUv.xy;
+
+ vec3 col = vec3(0);
+
+ vec3 ac = vec3(0);
+
+
+ for (float j = 0.; j < float(nS); j ++) {
+ float time = uMyData.time;
+ vec2 seed = fragCoord.xy + fract(time) * 500. + j * sqrt(983.);
+
+
+ if (uMyData.motionBlur) {
+ time += hash12(seed) * .05;
+ }
+
+ vec3 ro = vec3(0, 1, - time);
+ vec3 ta = vec3(0, - .5, - time - .5);
+
+
+ ro.x += (stepNoise(ro.z, 5.) - 2.) * .5;
+ ro.y += stepNoise(ro.z - 500., 5.) * .5;
+
+ vec3 dir = normalize(ta - ro);
+ vec3 side = normalize(cross(dir, vec3(0, 1, 0)));
+ vec3 up = normalize(cross(side, dir));
+
+ float fov = 40.;
+ fov += (stepNoise(ro.z - 1000., 2.) * 2. - 1.) * 20.;
+ vec3 rd = normalize(uv.x * side + uv.y * up + dir / tan(fov / 360. * pi));
+ float L = length(ta - ro);
+ vec3 fp = ro + rd * L;
+
+
+ vec3 ros = ro;
+ if (uMyData.dof) {
+ float r = sqrt(hash12(seed * 1.1));
+ float theta = hash12(seed * 1.2) * pi2;
+ ros.xy += r * vec2(cos(theta), sin(theta)) * L * .025;
+ }
+ vec3 rds = normalize(fp - ros);
+
+ bool hit = false;
+ float t;
+ vec2 id, q;
+
+ for (float i = 0.; i < 50.; i ++) {
+ t = - (ros.y + i * .05) / rds.y;
+ vec2 p = ros.xz + t * rds.xz;
+ p.x += fract(sin(i) * 5723.2622) * 500.;
+ p *= rot(i * 2.);
+
+ id = vec2(i, floor(p.x));
+
+ p.x = fract(p.x) - .5;
+ p.y += hash12(id) * 500.;
+ p.x -= fiberShape(p.y, time);
+
+ if (t > 0. && abs(p.x) < w) {
+ q = p;
+ hit = true;
+ break;
+ }
+ }
+
+ if (hit) {
+ vec3 add = vec3(1);
+
+ vec3 lightDir = normalize(vec3(- 5, 2, - 2));
+ vec3 normal = normalize(vec3(q.x, sqrt(w * w - q.x * q.x), 0));
+
+ float e = 1e-4;
+ float grad = (fiberShape(q.y + e, time) - fiberShape(q.y - e, time)) / (e * 2.);
+ float a = atan(grad);
+ normal.xz *= rot(- id.x * 2. + a);
+
+
+ float diff = max(dot(normal, lightDir), 0.);
+ float spec = pow(max(dot(reflect(lightDir, normal), rds), 0.), 20.);
+ float m = .5;
+ float lp = 3.;
+ add *= diff * (1. - m) * lp + spec * m * lp + .2;
+
+
+ q.y = fract(q.y * .03 - time * .2) - .5;
+ add += smoothstep(.01, 0., abs(q.y)) * 3.;
+
+
+ float T = time + hash12(id);
+ add += step(hash12(id * 1.1 + floor(T)), .05) * step(fract(T * 3.), .8) * 3.;
+
+ add *= exp(- t * t * .1 - id.x * id.x * .001);
+
+ ac += add;
+ }
+ }
+
+ col += ac / float(nS);
+
+ float a = uMyData.vec_1.w;
+
+ col *= uMyData.vec_1.xyz;
+
+ col = pow(col, vec3(1. / 2.2));
+
+ mediump vec4 baseColor = GetBaseColorSample(inUv);
+
+ col *= baseColor.xyz;
+
+ outColor = vec4(col, a);
+}
diff --git a/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.shader b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.shader
new file mode 100644
index 0000000000000000000000000000000000000000..a5cfb9a650d0216c02e9979c6a97783dd7da324d
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/main/resources/rawfile/shaders/custom_shader/custom_material_sample.shader
@@ -0,0 +1,72 @@
+{
+ "compatibility_info" : { "version" : "22.00", "type" : "shader" },
+ "vert": "3dshaders://shader/core3d_dm_fw.vert.spv",
+ "frag": "appshaders://custom_shader/custom_material_sample.frag.spv",
+ "vertexInputDeclaration": "3dvertexinputdeclarations://core3d_dm_fw.shadervid",
+ "state": {
+ "rasterizationState": {
+ "enableDepthClamp": true,
+ "enableDepthBias": true,
+ "enableRasterizerDiscard": true,
+ "polygonMode": "line",
+ "cullModeFlags": "back",
+ "frontFace": "counter_clockwise"
+ },
+ "depthStencilState": {
+ "enableDepthTest": true,
+ "enableDepthWrite": true,
+ "enableDepthBoundsTest": false,
+ "enableStencilTest": false,
+ "depthCompareOp": "less_or_equal"
+ },
+ "colorBlendState": {
+ "colorAttachments": [
+ {
+ "enableBlend": true,
+ "colorWriteMask": "g_bit|b_bit",
+ "srcColorBlendFactor": "one",
+ "dstColorBlendFactor": "one_minus_src_alpha",
+ "colorBlendOp": "add",
+ "srcAlphaBlendFactor": "one",
+ "dstAlphaBlendFactor": "one_minus_src_alpha",
+ "alphaBlendOp": "add"
+ }
+ ]
+ }
+ },
+ "materialMetadata": [
+ {
+ "name": "MaterialComponent",
+ "customProperties": [
+ {
+ "data": [
+ {
+ "name": "vec_1",
+ "displayName": "Color",
+ "type": "vec4",
+ "value" : [1.0,1.0,1.0,1.0]
+ },
+ {
+ "name": "time",
+ "displayName": "Time",
+ "type": "float",
+ "value": 0.0
+ },
+ {
+ "name": "dof",
+ "displayName": "Dof",
+ "type": "int",
+ "value": 1
+ },
+ {
+ "name": "motionblur",
+ "displayName": "MotionBlur",
+ "type": "int",
+ "value": 1
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/graphic/ArkGraphics3D/entry/src/ohosTest/ets/test/Ability.test.ets b/graphic/ArkGraphics3D/entry/src/ohosTest/ets/test/Ability.test.ets
new file mode 100644
index 0000000000000000000000000000000000000000..9d824a856741e821689a087273851e7ea2b8a90a
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/ohosTest/ets/test/Ability.test.ets
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { describe, expect, it } from '@ohos/hypium';
+import { abilityDelegatorRegistry, Driver, ON } from '@kit.TestKit';
+import Logger from '../utils/Logger';
+
+const TAG = '[Sample_Graphics3D]';
+const BUNDLE = 'MyApp_';
+const DELAYMS_1S = 1000;
+const DELAYMS_2S = 2000;
+
+const bundleName = abilityDelegatorRegistry.getArguments().bundleName;
+
+
+export default function abilityTest() {
+ describe('abilityTest', () => {
+ // Test to verify starting the EntryAbility within a specific bundle.
+ // Logs test start/end and any startup errors. Signals completion.
+ it(BUNDLE + 'StartAbility_001, begin', 0, async (done: Function) => {
+ Logger.info(TAG, BUNDLE + 'StartAbility_001');
+ let abilityDelegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator();
+ try {
+ await abilityDelegator.startAbility({
+ bundleName: bundleName,
+ abilityName: 'EntryAbility'
+ });
+ } catch (err) {
+ Logger.info(TAG, `beforeAll exception = ${JSON.stringify(err)}`);
+ }
+
+ Logger.info(TAG, BUNDLE + 'StartAbility_001, end');
+ done();
+ });
+
+ // Test to verify navigation through a series of UI components within a scene.
+ // Interacts with various buttons and checks for their existence. Logs test entry.
+ // In case of failure, marks the test as failed. Signals completion on success.
+ it(BUNDLE + 'Scene_001', 0, async (done: Function) => {
+ try {
+ Logger.info(TAG, BUNDLE + 'Scene_001' + 'in');
+ let driver = Driver.create();
+ await driver.delayMs(DELAYMS_2S);
+
+ await driver.assertComponentExist(ON.id('scene'));
+ let sceneButton = await driver.findComponent(ON.id('scene'));
+ await sceneButton.click();
+ await driver.delayMs(DELAYMS_1S);
+
+ await driver.assertComponentExist(ON.id('init'));
+ let initButton = await driver.findComponent(ON.id('init'));
+ await initButton.click();
+ await driver.delayMs(DELAYMS_1S);
+
+ await driver.assertComponentExist(ON.id('back'));
+ let backButton = await driver.findComponent(ON.id('back'));
+ await backButton.click();
+ await driver.delayMs(DELAYMS_1S);
+
+ await driver.assertComponentExist(ON.id('camera'));
+ let cameraButton = await driver.findComponent(ON.id('camera'));
+ await cameraButton.click();
+ await driver.delayMs(DELAYMS_1S);
+
+ await driver.assertComponentExist(ON.id('back'));
+ backButton = await driver.findComponent(ON.id('back'));
+ await backButton.click();
+ await driver.delayMs(DELAYMS_1S);
+
+ await driver.assertComponentExist(ON.id('light'));
+ let lightButton = await driver.findComponent(ON.id('light'));
+ await lightButton.click();
+ await driver.delayMs(DELAYMS_1S);
+
+ await driver.assertComponentExist(ON.id('back'));
+ backButton = await driver.findComponent(ON.id('back'));
+ await backButton.click();
+ await driver.delayMs(DELAYMS_1S);
+
+ await driver.assertComponentExist(ON.id('back'));
+ backButton = await driver.findComponent(ON.id('back'));
+ await backButton.click();
+ await driver.delayMs(DELAYMS_1S);
+
+ done();
+ } catch {
+ expect().assertFail();
+ }
+ })
+
+ // Test to verify the navigation and interaction with resource-related UI components.
+ // Logs test entry, checks for the existence of resource buttons, and interacts with them.
+ // Interacts with resource, material, shader, image, env, and back buttons in sequence.
+ // In case of failure, marks the test as failed. Signals completion on success.
+ it(BUNDLE + 'Resource_001', 0, async (done: Function) => {
+ try {
+ Logger.info(TAG, BUNDLE + 'Resource_001' + 'in');
+ let driver = Driver.create();
+ await driver.delayMs(DELAYMS_2S);
+
+ await driver.assertComponentExist(ON.id('resource'));
+ let resourceButton = await driver.findComponent(ON.id('resource'));
+ await resourceButton.click();
+ await driver.delayMs(DELAYMS_1S);
+
+ await driver.assertComponentExist(ON.id('material'));
+ let materialButton = await driver.findComponent(ON.id('material'));
+ await materialButton.click();
+ await driver.delayMs(DELAYMS_1S);
+
+ await driver.assertComponentExist(ON.id('shader'));
+ let shaderButton = await driver.findComponent(ON.id('shader'));
+ await shaderButton.click();
+ await driver.delayMs(DELAYMS_1S);
+
+ await driver.assertComponentExist(ON.id('image'));
+ let imageButton = await driver.findComponent(ON.id('image'));
+ await imageButton.click();
+ await driver.delayMs(DELAYMS_1S);
+
+ await driver.assertComponentExist(ON.id('env'));
+ let envButton = await driver.findComponent(ON.id('env'));
+ await envButton.click();
+ await driver.delayMs(DELAYMS_1S);
+
+ await driver.assertComponentExist(ON.id('back'));
+ let backButton = await driver.findComponent(ON.id('back'));
+ await backButton.click();
+ await driver.delayMs(DELAYMS_1S);
+
+ done();
+ } catch {
+ expect().assertFail();
+ }
+ })
+
+ // Test to verify the functionality of animation controls within an application.
+ // Logs test entry and checks for the existence of various animation control buttons.
+ // Interacts with the animation, start, pause, stop, finish, restart, seek, and back buttons in sequence.
+ // In case of failure, marks the test as failed. Signals completion on success.
+ it(BUNDLE + 'Animation_001', 0, async (done: Function) => {
+ try {
+ Logger.info(TAG, BUNDLE + 'Animation_001' + 'in');
+ let driver = Driver.create();
+ await driver.delayMs(DELAYMS_1S);
+
+ await driver.assertComponentExist(ON.id('animation'));
+ let animationButton = await driver.findComponent(ON.id('animation'));
+ await animationButton.click();
+ await driver.delayMs(DELAYMS_1S);
+
+ await driver.assertComponentExist(ON.id('start'));
+ let startButton = await driver.findComponent(ON.id('start'));
+ await startButton.click();
+ await driver.delayMs(DELAYMS_1S);
+
+ await driver.assertComponentExist(ON.id('pause'));
+ let pauseButton = await driver.findComponent(ON.id('pause'));
+ await pauseButton.click();
+ await driver.delayMs(DELAYMS_1S);
+
+ await driver.assertComponentExist(ON.id('stop'));
+ let stopButton = await driver.findComponent(ON.id('stop'));
+ await stopButton.click();
+ await driver.delayMs(DELAYMS_1S);
+
+ await driver.assertComponentExist(ON.id('finish'));
+ let finishButton = await driver.findComponent(ON.id('finish'));
+ await finishButton.click();
+ await driver.delayMs(DELAYMS_1S);
+
+ await driver.assertComponentExist(ON.id('restart'));
+ let restartButton = await driver.findComponent(ON.id('restart'));
+ await restartButton.click();
+ await driver.delayMs(DELAYMS_1S);
+
+ await driver.assertComponentExist(ON.id('seek'));
+ let seekButton = await driver.findComponent(ON.id('seek'));
+ await seekButton.click();
+ await driver.delayMs(DELAYMS_1S);
+
+ await driver.assertComponentExist(ON.id('back'));
+ let backButton = await driver.findComponent(ON.id('back'));
+ await backButton.click();
+ await driver.delayMs(DELAYMS_1S);
+
+ done();
+ } catch {
+ expect().assertFail();
+ }
+ })
+ });
+}
\ No newline at end of file
diff --git a/graphic/ArkGraphics3D/entry/src/ohosTest/ets/test/List.test.ets b/graphic/ArkGraphics3D/entry/src/ohosTest/ets/test/List.test.ets
new file mode 100644
index 0000000000000000000000000000000000000000..f645b15b2d03979e7ec326b478de4d06b2ee506b
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/ohosTest/ets/test/List.test.ets
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import abilityTest from './Ability.test';
+
+export default function testsuite() {
+ abilityTest();
+}
\ No newline at end of file
diff --git a/graphic/ArkGraphics3D/entry/src/ohosTest/ets/utils/Logger.ets b/graphic/ArkGraphics3D/entry/src/ohosTest/ets/utils/Logger.ets
new file mode 100644
index 0000000000000000000000000000000000000000..41b9aead45571dd477832871577e6e8ba6315558
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/ohosTest/ets/utils/Logger.ets
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { hilog } from '@kit.PerformanceAnalysisKit';
+
+class Logger {
+ private domain: number;
+ private prefix: string;
+ private format: string = '%{public}s';
+
+ constructor(prefix: string) {
+ this.prefix = prefix;
+ this.domain = 0xF811;
+ }
+
+ debug(...args: string[]) {
+ hilog.debug(this.domain, this.prefix, this.format, args);
+ }
+
+ info(...args: string[]) {
+ hilog.info(this.domain, this.prefix, this.format, args);
+ }
+
+ warn(...args: string[]) {
+ hilog.warn(this.domain, this.prefix, this.format, args);
+ }
+
+ error(...args: string[]) {
+ hilog.error(this.domain, this.prefix, this.format, args);
+ }
+}
+
+export default new Logger('[Sample_ArkGraphics3D]');
\ No newline at end of file
diff --git a/graphic/ArkGraphics3D/entry/src/ohosTest/module.json5 b/graphic/ArkGraphics3D/entry/src/ohosTest/module.json5
new file mode 100644
index 0000000000000000000000000000000000000000..c3fd9dda3040d888d9d8b0b62bcb5d3b6fbeb614
--- /dev/null
+++ b/graphic/ArkGraphics3D/entry/src/ohosTest/module.json5
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "module": {
+ "name": "entry_test",
+ "type": "feature",
+ "deviceTypes": [
+ "default",
+ "tablet"
+ ],
+ "deliveryWithInstall": true,
+ "installationFree": false
+ }
+}
diff --git a/graphic/ArkGraphics3D/hvigor/hvigor-config.json5 b/graphic/ArkGraphics3D/hvigor/hvigor-config.json5
new file mode 100644
index 0000000000000000000000000000000000000000..d584c19c247db9a7caee4b606bb931aa9279c637
--- /dev/null
+++ b/graphic/ArkGraphics3D/hvigor/hvigor-config.json5
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "modelVersion": "5.0.1",
+ "dependencies": {
+ },
+ "execution": {
+ // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | false ]. Default: "normal" */
+ // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */
+ // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */
+ // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */
+ // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */
+ },
+ "logging": {
+ // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */
+ },
+ "debugging": {
+ // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */
+ },
+ "nodeOptions": {
+ // "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/
+ // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/
+ }
+}
diff --git a/graphic/ArkGraphics3D/hvigorfile.ts b/graphic/ArkGraphics3D/hvigorfile.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2a5e543f190732c159beb574dfc9fa37bc94e156
--- /dev/null
+++ b/graphic/ArkGraphics3D/hvigorfile.ts
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { appTasks } from '@ohos/hvigor-ohos-plugin';
+
+export default {
+ system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
+ plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
+}
diff --git a/graphic/ArkGraphics3D/oh-package.json5 b/graphic/ArkGraphics3D/oh-package.json5
new file mode 100644
index 0000000000000000000000000000000000000000..e41bae026aab3b50d0abb42fece08ba43b4a772b
--- /dev/null
+++ b/graphic/ArkGraphics3D/oh-package.json5
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "modelVersion": "5.0.1",
+ "description": "Please describe the basic information.",
+ "dependencies": {
+ },
+ "devDependencies": {
+ "@ohos/hypium": "1.0.19",
+ "@ohos/hamock": "1.0.0"
+ }
+}
diff --git a/graphic/ArkGraphics3D/ohosTest.md b/graphic/ArkGraphics3D/ohosTest.md
new file mode 100644
index 0000000000000000000000000000000000000000..280dbe74c4e1e68fdc32d7d2aab71374a791f532
--- /dev/null
+++ b/graphic/ArkGraphics3D/ohosTest.md
@@ -0,0 +1,26 @@
+| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 |
+|:-------:|:------------:|:--------------:|:---------------------:|:----:|:----:|
+| 拉起应用 | 设备正常运行 | | 成功拉起应用 | 是 | Pass |
+| 主页展示 | 设备正常运行 | | 展示 Building and Managing ArkGraphics 3D Scenes、Creating and Using ArkGraphics 3D Resources 和 Controlling and Managing ArkGraphics 3D Scene Animations 三种按钮 | 是 | Pass |
+| 主页按钮点击 | 位于主页 | 点击 Building and Managing ArkGraphics 3D Scenes 按钮 | 跳转 Scene 页面 | 是 | Pass |
+| Scene 页面按钮点击 | 位于 Scene 页面 | 点击 Model Loading and Display 按钮 | 跳转至 Model 页面,显现头盔 | 是 | Pass |
+| Model 页面按钮点击 | 位于 Model 页面 | 点击 Back 按钮 | 返回 Scene 页面 | 是 | Pass |
+| Scene 页面按钮点击 | 位于 Scene 页面 | 点击 Creating and Managing a Camera 按钮 | 跳转至 Camera 页面,显现几何体 | 是 | Pass |
+| Camera 页面按钮点击 | 位于 Camera 页面 | 点击 Back 按钮 | 返回 Scene 页面 | 是 | Pass |
+| Scene 页面 按钮点击 | 位于 Scene 页面 | 点击 Creating and Managing Light 按钮 | 跳转至 Light 页面 | 是 | Pass |
+| Light 页面按钮点击 | 位于 Light 页面 | 点击 Back 按钮 | 返回 Scene 页面 | 是 | Pass |
+| Scene 页面 按钮点击 | 位于 Scene 页面 | 点击 Back 按钮 | 返回主页 | 是 | Pass |
+| 主页按钮点击 | 位于主页 | 点击 Creating and Using ArkGraphics 3D Resources 按钮 | 跳转至 Resource 页面,显现几何体 | 是 | Pass |
+| Resource 页面按钮点击 | 位于 Resource 页面 | 点击 Replace with a blank material 按钮 | 用空白材质替换原有的材质 | 是 | Pass |
+| Resource 页面按钮点击 | 位于 Resource 页面 | 点击 Replace with a image material 按钮 | 用图像材质替换原有的材质 | 是 | Pass |
+| Resource 页面按钮点击 | 位于 Resource 页面 | 点击 Replace with a shader material 按钮 | 用着色器材质替换原有的材质 | 是 | Pass |
+| Resource 页面按钮点击 | 位于 Resource 页面 | 点击 Add to Environment 按钮 | 添加场景 | 是 | Pass |
+| Resource 页面按钮点击 | 位于 Resource 页面 | 点击 Back 按钮 | 返回主页 | 是 | Pass |
+| 主页按钮点击 | 位于主页 | 点击 Controlling and Managing ArkGraphics 3D Scene Animations按钮 | 跳转至 Animation 页面 | 是 | Pass |
+| Animation 页面按钮点击 | 位于 Animation 页面 | 点击 Start 按钮 | 开始播放动画 | 是 | Pass |
+| Animation 页面按钮点击 | 位于 Animation 页面 | 点击 Pause 按钮 | 暂停播放动画 | 是 | Pass |
+| Animation 页面按钮点击 | 位于 Animation 页面 | 点击 Stop 按钮 | 停止播放动画 | 是 | Pass |
+| Animation 页面按钮点击 | 位于 Animation 页面 | 点击 Finish 按钮 | 结束播放动画 | 是 | Pass |
+| Animation 页面按钮点击 | 位于 Animation 页面 | 点击 Restart 按钮 | 重新播放动画 | 是 | Pass |
+| Animation 页面按钮点击 | 位于 Animation 页面 | 点击 seek to 30% progress 按钮 | 从 30% 开始播放动画 | 是 | Pass |
+| Animation 页面按钮点击 | 位于 Animation 页面 | 点击 Back 按钮 | 返回主页 | 是 | Pass |
\ No newline at end of file
diff --git a/graphic/ArkGraphics3D/screenshots/animation.png b/graphic/ArkGraphics3D/screenshots/animation.png
new file mode 100644
index 0000000000000000000000000000000000000000..ff89c70716cd8a74676396047fe8aa8e8edd3767
Binary files /dev/null and b/graphic/ArkGraphics3D/screenshots/animation.png differ
diff --git a/graphic/ArkGraphics3D/screenshots/index.png b/graphic/ArkGraphics3D/screenshots/index.png
new file mode 100644
index 0000000000000000000000000000000000000000..daa0ee795bfe1b6899cfd0134f23f5fe1ed73c58
Binary files /dev/null and b/graphic/ArkGraphics3D/screenshots/index.png differ
diff --git a/graphic/ArkGraphics3D/screenshots/resource.png b/graphic/ArkGraphics3D/screenshots/resource.png
new file mode 100644
index 0000000000000000000000000000000000000000..08a6d2a4e8779de06ca4b44d10dc48589c3544fb
Binary files /dev/null and b/graphic/ArkGraphics3D/screenshots/resource.png differ
diff --git a/graphic/ArkGraphics3D/screenshots/scene.png b/graphic/ArkGraphics3D/screenshots/scene.png
new file mode 100644
index 0000000000000000000000000000000000000000..391f0b8f5f1ad67ebafa0fbdc15f2a44f598c66f
Binary files /dev/null and b/graphic/ArkGraphics3D/screenshots/scene.png differ
diff --git a/graphic/DisplaySoloist/.gitignore b/graphic/DisplaySoloist/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..ea27eaff8c3ecef3e9ebe6399a5f9073cd962a7b
--- /dev/null
+++ b/graphic/DisplaySoloist/.gitignore
@@ -0,0 +1,13 @@
+/node_modules
+/oh_modules
+/local.properties
+/.idea
+**/build
+/.hvigor
+.cxx
+/.clangd
+/.clang-format
+/.clang-tidy
+**/.test
+/.appanalyzer
+oh-package-lock.json5
\ No newline at end of file
diff --git a/graphic/DisplaySoloist/AppScope/app.json5 b/graphic/DisplaySoloist/AppScope/app.json5
new file mode 100644
index 0000000000000000000000000000000000000000..4059b8b3a87a512b8eb3d79b91c1707159a40ff1
--- /dev/null
+++ b/graphic/DisplaySoloist/AppScope/app.json5
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+{
+ "app": {
+ "bundleName": "com.samples.Displaysoloist",
+ "vendor": "example",
+ "versionCode": 1000000,
+ "versionName": "1.0.0",
+ "icon": "$media:app_icon",
+ "label": "$string:app_name"
+ }
+}
diff --git a/graphic/DisplaySoloist/AppScope/resources/base/element/string.json b/graphic/DisplaySoloist/AppScope/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..8f27bbd6363b153e19eb343ee29e37f4a2813c8e
--- /dev/null
+++ b/graphic/DisplaySoloist/AppScope/resources/base/element/string.json
@@ -0,0 +1,8 @@
+{
+ "string": [
+ {
+ "name": "app_name",
+ "value": "DisplaySoloist"
+ }
+ ]
+}
diff --git a/graphic/DisplaySoloist/AppScope/resources/base/media/app_icon.png b/graphic/DisplaySoloist/AppScope/resources/base/media/app_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..a39445dc87828b76fed6d2ec470dd455c45319e3
Binary files /dev/null and b/graphic/DisplaySoloist/AppScope/resources/base/media/app_icon.png differ
diff --git a/graphic/DisplaySoloist/README.md b/graphic/DisplaySoloist/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..7f2a5ac46b5b60e564f17e5bcd878625fb1d50ca
--- /dev/null
+++ b/graphic/DisplaySoloist/README.md
@@ -0,0 +1,85 @@
+# DisplaySoloist分级管控
+
+### 介绍
+
+本示例通过 DisplaySoloist 系列功能,使用 UI 外的线程对 XComponent 的绘制内容,设置开发者所期望的帧率。使用 [NativeDisplaySoloist](https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/graphics/displaysoloist-native-guidelines.md) 和 [Drawing](https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/graphics/drawing-guidelines.md) 来实现图像绘制和显示。
+
+### 效果预览
+
+| XComponent |
+| :------------------------------------------------------: |
+|
|
+
+使用说明
+
+1.进入 XComponent 页面,依次点击“**Start**”,三个方块分别按照 30Hz、60Hz、120Hz 移动;点击“**Stop**”动画停止。
+
+### 工程目录
+
+```
+├──entry/src/main
+│ ├──cpp // C++代码区
+│ │ ├──CMakeLists.txt // CMake配置文件
+│ │ ├──napi_init.cpp // Napi模块注册
+│ │ ├──common
+│ │ │ └──log_common.h // 日志封装定义文件
+│ │ ├──plugin // 生命周期管理模块
+│ │ │ ├──plugin_manager.cpp
+│ │ │ └──plugin_manager.h
+│ │ ├──samples // samples渲染模块
+│ │ │ ├──sample_xcomponent.cpp
+│ │ │ └──sample_xcomponent.h
+│ ├──ets // ets代码区
+│ │ ├──entryability
+│ │ │ ├──EntryAbility.ts // 程序入口类
+| | | └──EntryAbility.ets
+| | ├──interface
+│ │ │ └──XComponentContext.ts // XComponentContext
+│ │ ├──pages // 页面文件
+│ │ | └──Index.ets // XComponent页面
+│ │ ├──utils // 工具类
+| ├──resources // 资源文件目录
+```
+
+### 具体实现
+
+* XComponent:通过在 IDE 中的 Native C++ 工程,在 TS 侧中声明对外接口为 register、unregister 以及 destroy;在 C++ 侧调用 NativeDisplaySoloist 分级管控接口,并在使用 drawing 来绘制期望帧率图像。
+
+ | 接口名 | 描述 |
+ | ------------------------------------------- | --------------------------------------------------- |
+ | OH_DisplaySoloist_Create | 创建一个OH_DisplaySoloist实例 |
+ | OH_DisplaySoloist_Destroy | 销毁一个OH_DisplaySoloist实例 |
+ | OH_DisplaySoloist_Start | 设置每帧回调函数,每次vsync信号到来时启动每帧回调 |
+ | OH_DisplaySoloist_Stop | 停止请求下一次vsync信号,并停止调用回调函数callback |
+ | OH_DisplaySoloist_SetExpectedFrameRateRange | 设置期望帧率范围 |
+
+
+### 相关权限
+
+不涉及。
+
+### 依赖
+
+不涉及。
+
+### 约束与限制
+
+1. 本示例仅支持标准系统上运行,支持设备:华为手机。
+
+2. HarmonyOS系统:HarmonyOS 5.0.2 Release及以上。
+
+3. DevEco Studio版本:DevEco Studio 5.0.2 Release及以上。
+
+4. HarmonyOS SDK版本:HarmonyOS 5.0.2 Release及以上。
+
+### 下载
+
+如需单独下载本工程,执行如下命令:
+
+```
+git init
+git config core.sparsecheckout true
+echo code/DocsSample/graphic/DisplaySoloist/ > .git/info/sparse-checkout
+git remote add origin https://gitcode.com/openharmony/applications_app_samples.git
+git pull origin master
+```
\ No newline at end of file
diff --git a/graphic/DisplaySoloist/build-profile.json5 b/graphic/DisplaySoloist/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..590145ac3d80c83b0197ada84ece1e876571e1f7
--- /dev/null
+++ b/graphic/DisplaySoloist/build-profile.json5
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+{
+ "app": {
+ "products": [
+ {
+ "name": "default",
+ "signingConfig": "default",
+ "compatibleSdkVersion": "5.0.2(14)",
+ "targetSdkVersion": "5.0.2(14)",
+ "runtimeOS": "HarmonyOS",
+ "buildOption": {
+ "externalNativeOptions": {
+ "abiFilters": [
+ "arm64-v8a",
+ "x86_64"
+ ]
+ }
+ }
+ }
+ ],
+ "buildModeSet": [
+ {
+ "name": "debug"
+ },
+ {
+ "name": "release"
+ }
+ ],
+ },
+ "modules": [
+ {
+ "name": "entry",
+ "srcPath": "./entry",
+ "targets": [
+ {
+ "name": "default",
+ "applyToProducts": [
+ "default"
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/graphic/DisplaySoloist/code-linter.json5 b/graphic/DisplaySoloist/code-linter.json5
new file mode 100644
index 0000000000000000000000000000000000000000..3311c9280cd317b17b4b2745922184ac805051d8
--- /dev/null
+++ b/graphic/DisplaySoloist/code-linter.json5
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+{
+ "files": [
+ "**/*.ets"
+ ],
+ "ignore": [
+ "**/src/ohosTest/**/*",
+ "**/src/test/**/*",
+ "**/src/mock/**/*",
+ "**/node_modules/**/*",
+ "**/oh_modules/**/*",
+ "**/build/**/*",
+ "**/.preview/**/*"
+ ],
+ "ruleSet": [
+ "plugin:@performance/recommended",
+ "plugin:@typescript-eslint/recommended"
+ ],
+ "rules": {
+ }
+}
\ No newline at end of file
diff --git a/graphic/DisplaySoloist/entry/.gitignore b/graphic/DisplaySoloist/entry/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..eadab4e1522296628f32a70228b2c758ecab4759
--- /dev/null
+++ b/graphic/DisplaySoloist/entry/.gitignore
@@ -0,0 +1,7 @@
+/node_modules
+/oh_modules
+/.preview
+/build
+/.cxx
+/.test
+/oh-package-lock.json5
\ No newline at end of file
diff --git a/graphic/DisplaySoloist/entry/build-profile.json5 b/graphic/DisplaySoloist/entry/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..13781d517fa6d16ad7a8348345c632ce2d2d1d61
--- /dev/null
+++ b/graphic/DisplaySoloist/entry/build-profile.json5
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+{
+ "apiType": "stageMode",
+ "buildOption": {
+ "externalNativeOptions": {
+ "path": "./src/main/cpp/CMakeLists.txt",
+ "arguments": "",
+ "cppFlags": "",
+ }
+ },
+ "buildOptionSet": [
+ {
+ "name": "release",
+ "arkOptions": {
+ "obfuscation": {
+ "ruleOptions": {
+ "enable": false,
+ "files": [
+ "./obfuscation-rules.txt"
+ ]
+ }
+ }
+ },
+ "nativeLib": {
+ "debugSymbol": {
+ "strip": true,
+ "exclude": []
+ }
+ }
+ },
+ ],
+ "targets": [
+ {
+ "name": "default"
+ },
+ {
+ "name": "ohosTest",
+ }
+ ]
+}
\ No newline at end of file
diff --git a/graphic/DisplaySoloist/entry/hvigorfile.ts b/graphic/DisplaySoloist/entry/hvigorfile.ts
new file mode 100644
index 0000000000000000000000000000000000000000..03701040981658f09c62d2c71567bc38dda4d37e
--- /dev/null
+++ b/graphic/DisplaySoloist/entry/hvigorfile.ts
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { hapTasks } from '@ohos/hvigor-ohos-plugin';
+
+export default {
+ system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
+ plugins: [] /* Custom plugin to extend the functionality of Hvigor. */
+}
diff --git a/graphic/DisplaySoloist/entry/obfuscation-rules.txt b/graphic/DisplaySoloist/entry/obfuscation-rules.txt
new file mode 100644
index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b
--- /dev/null
+++ b/graphic/DisplaySoloist/entry/obfuscation-rules.txt
@@ -0,0 +1,23 @@
+# Define project specific obfuscation rules here.
+# You can include the obfuscation configuration files in the current module's build-profile.json5.
+#
+# For more details, see
+# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5
+
+# Obfuscation options:
+# -disable-obfuscation: disable all obfuscations
+# -enable-property-obfuscation: obfuscate the property names
+# -enable-toplevel-obfuscation: obfuscate the names in the global scope
+# -compact: remove unnecessary blank spaces and all line feeds
+# -remove-log: remove all console.* statements
+# -print-namecache: print the name cache that contains the mapping from the old names to new names
+# -apply-namecache: reuse the given cache file
+
+# Keep options:
+# -keep-property-name: specifies property names that you want to keep
+# -keep-global-name: specifies names that you want to keep in the global scope
+
+-enable-property-obfuscation
+-enable-toplevel-obfuscation
+-enable-filename-obfuscation
+-enable-export-obfuscation
\ No newline at end of file
diff --git a/graphic/DisplaySoloist/entry/oh-package.json5 b/graphic/DisplaySoloist/entry/oh-package.json5
new file mode 100644
index 0000000000000000000000000000000000000000..1182eecc31bffd54beb78b9aee733f9df9aa735f
--- /dev/null
+++ b/graphic/DisplaySoloist/entry/oh-package.json5
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+{
+ "name": "entry",
+ "version": "1.0.0",
+ "description": "Please describe the basic information.",
+ "main": "",
+ "author": "",
+ "license": "",
+ "dependencies": {
+ "libentry.so": "file:./src/main/cpp/types/libentry"
+ }
+}
\ No newline at end of file
diff --git a/graphic/DisplaySoloist/entry/src/main/cpp/CMakeLists.txt b/graphic/DisplaySoloist/entry/src/main/cpp/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0e5253594a889deea00f2e32cdc8cff59ca626a7
--- /dev/null
+++ b/graphic/DisplaySoloist/entry/src/main/cpp/CMakeLists.txt
@@ -0,0 +1,23 @@
+# the minimum version of CMake.
+cmake_minimum_required(VERSION 3.5.0)
+project(drawing_test)
+
+set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
+
+include_directories(${NATIVERENDER_ROOT_PATH}
+ ${NATIVERENDER_ROOT_PATH}/include)
+
+add_library(entry SHARED
+ napi_init.cpp
+ samples/sample_xcomponent.cpp
+ plugin/plugin_manager.cpp
+)
+find_library(
+ # Sets the name of the path variable.
+ hilog-lib
+ # Specifies the name of the NDK library that
+ # you want CMake to locate.
+ hilog_ndk.z
+)
+target_link_libraries(entry PUBLIC ${hilog-lib})
+target_link_libraries(entry PUBLIC libace_napi.z.so libnative_drawing.so libnative_window.so libace_ndk.z.so libnative_display_soloist.so)
\ No newline at end of file
diff --git a/graphic/DisplaySoloist/entry/src/main/cpp/common/log_common.h b/graphic/DisplaySoloist/entry/src/main/cpp/common/log_common.h
new file mode 100644
index 0000000000000000000000000000000000000000..fb896663b06a89bf20001789d1ac15b5864979fe
--- /dev/null
+++ b/graphic/DisplaySoloist/entry/src/main/cpp/common/log_common.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef LOG_COMMON_H
+#define LOG_COMMON_H
+#include
+#define LOG_PRINT_DOMAIN 0xFF00
+#define APP_LOG_DOMAIN 0x0001
+constexpr const char *APP_LOG_TAG = "DisplaySoloistSample";
+#define SAMPLE_LOGI(...) ((void)OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__))
+#define SAMPLE_LOGD(...) ((void)OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__))
+#define SAMPLE_LOGW(...) ((void)OH_LOG_Print(LOG_APP, LOG_WARN, LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__))
+#define SAMPLE_LOGE(...) ((void)OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__))
+
+#endif // LOG_COMMON_H
diff --git a/graphic/DisplaySoloist/entry/src/main/cpp/napi_init.cpp b/graphic/DisplaySoloist/entry/src/main/cpp/napi_init.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8e3c41842597dbd9332193f106963ef0b5ce4743
--- /dev/null
+++ b/graphic/DisplaySoloist/entry/src/main/cpp/napi_init.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include
+#include "napi/native_api.h"
+#include "common/log_common.h"
+#include "plugin/plugin_manager.h"
+
+EXTERN_C_START
+static napi_value Init(napi_env env, napi_value exports)
+{
+ SAMPLE_LOGI("napi init");
+ PluginManager::GetInstance()->Export(env, exports);
+ return exports;
+}
+EXTERN_C_END
+
+static napi_module demoModule = {
+ .nm_version = 1,
+ .nm_flags = 0,
+ .nm_filename = nullptr,
+ .nm_register_func = Init,
+ .nm_modname = "entry",
+ .nm_priv = ((void *)0),
+ .reserved = {0},
+};
+
+extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
diff --git a/graphic/DisplaySoloist/entry/src/main/cpp/plugin/plugin_manager.cpp b/graphic/DisplaySoloist/entry/src/main/cpp/plugin/plugin_manager.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3e27aa378dffd585e69b5c6fffee391bc8d3ba26
--- /dev/null
+++ b/graphic/DisplaySoloist/entry/src/main/cpp/plugin/plugin_manager.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include
+#include
+#include
+#include
+#include "common/log_common.h"
+#include "plugin_manager.h"
+
+PluginManager *PluginManager::GetInstance()
+{
+ static PluginManager pluginManager;
+ return &pluginManager;
+}
+
+PluginManager::~PluginManager()
+{
+ SAMPLE_LOGI("~PluginManager");
+ for (auto iter = nativeXComponentMap_.begin(); iter != nativeXComponentMap_.end(); ++iter) {
+ if (iter->second != nullptr) {
+ delete iter->second;
+ iter->second = nullptr;
+ }
+ }
+ nativeXComponentMap_.clear();
+
+ for (auto iter = pluginRenderMap_.begin(); iter != pluginRenderMap_.end(); ++iter) {
+ if (iter->second != nullptr) {
+ delete iter->second;
+ iter->second = nullptr;
+ }
+ }
+ pluginRenderMap_.clear();
+}
+
+// [Start display_soloist_export_api]
+void PluginManager::Export(napi_env env, napi_value exports)
+{
+ nativeXComponentMap_.clear();
+ pluginRenderMap_.clear();
+ if ((env == nullptr) || (exports == nullptr)) {
+ SAMPLE_LOGE("Export: env or exports is null");
+ return;
+ }
+
+ napi_value exportInstance = nullptr;
+ if (napi_get_named_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) {
+ SAMPLE_LOGE("Export: napi_get_named_property fail");
+ return;
+ }
+
+ OH_NativeXComponent *nativeXComponent = nullptr;
+ if (napi_unwrap(env, exportInstance, reinterpret_cast(&nativeXComponent)) != napi_ok) {
+ SAMPLE_LOGE("Export: napi_unwrap fail");
+ return;
+ }
+
+ char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
+ uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
+ if (OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
+ SAMPLE_LOGE("Export: OH_NativeXComponent_GetXComponentId fail");
+ return;
+ }
+
+ std::string id(idStr);
+ auto context = PluginManager::GetInstance();
+ if ((context != nullptr) && (nativeXComponent != nullptr)) {
+ context->SetNativeXComponent(id, nativeXComponent);
+ auto render = context->GetRender(id);
+ if (render != nullptr) {
+ render->RegisterCallback(nativeXComponent);
+ render->Export(env, exports);
+ } else {
+ SAMPLE_LOGE("render is nullptr");
+ }
+ }
+}
+// [End display_soloist_export_api]
+
+void PluginManager::SetNativeXComponent(std::string &id, OH_NativeXComponent *nativeXComponent)
+{
+ SAMPLE_LOGI("set native xComponent, ID = %{public}s.", id.c_str());
+ if (nativeXComponent == nullptr) {
+ SAMPLE_LOGE("xcomponent null");
+ return;
+ }
+
+ if (nativeXComponentMap_.find(id) == nativeXComponentMap_.end()) {
+ nativeXComponentMap_[id] = nativeXComponent;
+ return;
+ }
+
+ if (nativeXComponentMap_[id] != nativeXComponent) {
+ OH_NativeXComponent *tmp = nativeXComponentMap_[id];
+ delete tmp;
+ tmp = nullptr;
+ nativeXComponentMap_[id] = nativeXComponent;
+ }
+}
+
+SampleXComponent *PluginManager::GetRender(std::string &id)
+{
+ if (pluginRenderMap_.find(id) == pluginRenderMap_.end()) {
+ SampleXComponent *instance = SampleXComponent::GetInstance(id);
+ pluginRenderMap_[id] = instance;
+ return instance;
+ }
+ return pluginRenderMap_[id];
+}
diff --git a/graphic/DisplaySoloist/entry/src/main/cpp/plugin/plugin_manager.h b/graphic/DisplaySoloist/entry/src/main/cpp/plugin/plugin_manager.h
new file mode 100644
index 0000000000000000000000000000000000000000..a590755fba10e296ec10e4825fe08abcab486236
--- /dev/null
+++ b/graphic/DisplaySoloist/entry/src/main/cpp/plugin/plugin_manager.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef PLUGIN_MANAGER_H
+#define PLUGIN_MANAGER_H
+
+#include
+#include
+#include
+#include
+#include
+#include "samples/sample_xcomponent.h"
+
+// [Start display_soloist_create_plugin_manager]
+class PluginManager {
+public:
+ ~PluginManager();
+
+ static PluginManager *GetInstance();
+
+ void SetNativeXComponent(std::string &id, OH_NativeXComponent *nativeXComponent);
+ SampleXComponent *GetRender(std::string &id);
+ void Export(napi_env env, napi_value exports);
+
+private:
+ std::unordered_map nativeXComponentMap_;
+ std::unordered_map pluginRenderMap_;
+};
+// [End display_soloist_create_plugin_manager]
+#endif // PLUGIN_MANAGER_H
diff --git a/graphic/DisplaySoloist/entry/src/main/cpp/samples/sample_xcomponent.cpp b/graphic/DisplaySoloist/entry/src/main/cpp/samples/sample_xcomponent.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e1c3970df38fbeb2f60575368fe35f29e9ee40a2
--- /dev/null
+++ b/graphic/DisplaySoloist/entry/src/main/cpp/samples/sample_xcomponent.cpp
@@ -0,0 +1,472 @@
+/*
+ * Copyright (c) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include
+#include
+#include
+#include
+#include "common/log_common.h"
+#include "sample_xcomponent.h"
+
+static std::unordered_map g_displaySync;
+
+static void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window)
+{
+ SAMPLE_LOGI("OnSurfaceCreatedCB");
+ if ((component == nullptr) || (window == nullptr)) {
+ SAMPLE_LOGE("OnSurfaceCreatedCB: component or window is null");
+ return;
+ }
+ char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
+ uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
+ if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
+ SAMPLE_LOGE("OnSurfaceCreatedCB: Unable to get XComponent id");
+ return;
+ }
+ std::string id(idStr);
+ auto render = SampleXComponent::GetInstance(id);
+ OHNativeWindow *nativeWindow = static_cast(window);
+ render->SetNativeWindow(nativeWindow);
+
+ uint64_t width;
+ uint64_t height;
+ int32_t xSize = OH_NativeXComponent_GetXComponentSize(component, window, &width, &height);
+ if ((xSize == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) && (render != nullptr)) {
+ render->SetHeight(height);
+ render->SetWidth(width);
+ SAMPLE_LOGI("xComponent width = %{public}llu, height = %{public}llu", width, height);
+ }
+}
+
+static void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window)
+{
+ SAMPLE_LOGI("OnSurfaceDestroyedCB");
+ if ((component == nullptr) || (window == nullptr)) {
+ SAMPLE_LOGE("OnSurfaceDestroyedCB: component or window is null");
+ return;
+ }
+ char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
+ uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
+ if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
+ SAMPLE_LOGE("OnSurfaceDestroyedCB: Unable to get XComponent id");
+ return;
+ }
+ std::string id(idStr);
+ SampleXComponent::Release(id);
+}
+
+// [Start display_soloist_frame_rate_setting_and_subscription_function_registration]
+static void TestCallback(long long timestamp, long long targetTimestamp, void *data)
+{
+ SAMPLE_LOGI("test callback timestamp = %{public}llu, ", timestamp);
+ OH_NativeXComponent *component = nullptr;
+ component = static_cast(data);
+ if (component == nullptr) {
+ SAMPLE_LOGE("TestCallback: component is null");
+ return;
+ }
+
+ char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
+ uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
+ if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
+ SAMPLE_LOGE("TestCallback: Unable to get XComponent id");
+ return;
+ }
+
+ std::string id(idStr);
+ auto render = SampleXComponent::GetInstance(id);
+ OHNativeWindow *nativeWindow = render->GetNativeWindow();
+ uint64_t width;
+ uint64_t height;
+
+ int32_t xSize = OH_NativeXComponent_GetXComponentSize(component, nativeWindow, &width, &height);
+ if ((xSize == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) && (render != nullptr)) {
+ render->Prepare();
+ render->Create();
+ if (id == "xcomponentId_30") {
+ int offset = 16;
+ render->ConstructPath(offset, offset, render->defaultOffsetY);
+ }
+ if (id == "xcomponentId_120") {
+ int offset = 4;
+ render->ConstructPath(offset, offset, render->defaultOffsetY);
+ }
+ render->SetPenAndBrush();
+ render->DrawPath();
+ render->DisPlay();
+ render->Destroy();
+ }
+}
+// [End display_soloist_frame_rate_setting_and_subscription_function_registration]
+
+static std::unordered_map g_instance;
+
+void SampleXComponent::SetWidth(uint64_t width) { width_ = width; }
+
+void SampleXComponent::SetHeight(uint64_t height) { height_ = height; }
+
+void SampleXComponent::SetNativeWindow(OHNativeWindow *nativeWindow) { nativeWindow_ = nativeWindow; }
+
+OHNativeWindow *SampleXComponent::GetNativeWindow() { return nativeWindow_; }
+
+void SampleXComponent::Prepare()
+{
+ if (nativeWindow_ == nullptr) {
+ SAMPLE_LOGE("nativeWindow_ is nullptr");
+ return;
+ }
+ int ret = OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow_, &buffer_, &fenceFd_);
+ SAMPLE_LOGI("request buffer ret = %{public}d", ret);
+ bufferHandle_ = OH_NativeWindow_GetBufferHandleFromNative(buffer_);
+ mappedAddr_ = static_cast(
+ mmap(bufferHandle_->virAddr, bufferHandle_->size, PROT_READ | PROT_WRITE, MAP_SHARED, bufferHandle_->fd, 0));
+ if (mappedAddr_ == MAP_FAILED) {
+ SAMPLE_LOGE("mmap failed");
+ }
+}
+
+void SampleXComponent::DisPlay()
+{
+ void *bitmapAddr = OH_Drawing_BitmapGetPixels(cBitmap_);
+ uint32_t *value = static_cast(bitmapAddr);
+
+ uint32_t *pixel = static_cast(mappedAddr_);
+ if (pixel == nullptr) {
+ SAMPLE_LOGE("pixel is null");
+ return;
+ }
+ if (value == nullptr) {
+ SAMPLE_LOGE("value is null");
+ return;
+ }
+ for (uint32_t x = 0; x < width_; x++) {
+ for (uint32_t y = 0; y < height_; y++) {
+ *pixel++ = *value++;
+ }
+ }
+ Region region{nullptr, 0};
+ OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow_, buffer_, fenceFd_, region);
+ int result = munmap(mappedAddr_, bufferHandle_->size);
+ if (result == -1) {
+ SAMPLE_LOGE("munmap failed!");
+ }
+}
+
+void SampleXComponent::Create()
+{
+ uint32_t width = static_cast(bufferHandle_->stride / 4);
+ cBitmap_ = OH_Drawing_BitmapCreate();
+ OH_Drawing_BitmapFormat cFormat{COLOR_FORMAT_RGBA_8888, ALPHA_FORMAT_OPAQUE};
+ OH_Drawing_BitmapBuild(cBitmap_, width, height_, &cFormat);
+
+ cCanvas_ = OH_Drawing_CanvasCreate();
+ OH_Drawing_CanvasBind(cCanvas_, cBitmap_);
+ OH_Drawing_CanvasClear(cCanvas_, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0xFF, 0xFF));
+}
+
+void SampleXComponent::ConstructPath(int x, int y, int offsetY)
+{
+ float offsetOfAy = 100.0;
+ float offsetOfCy = 200.0;
+
+ aY = offsetOfAy + offsetY;
+ cY = offsetOfCy + offsetY;
+
+ if (desc) {
+ float offset = 1.0;
+ aX -= x * offset;
+ bX -= x * offset;
+ } else {
+ float offset = 1.0;
+ aX += x * offset;
+ bX += x * offset;
+ }
+
+ if (bX >= width_) {
+ desc = true;
+ }
+
+ if (aX <= 0) {
+ desc = false;
+ }
+
+ float bY = aY;
+ float cX = bX;
+ float dX = aX;
+ float dY = cY;
+
+ cPath_ = OH_Drawing_PathCreate();
+ OH_Drawing_PathMoveTo(cPath_, aX, aY);
+ OH_Drawing_PathLineTo(cPath_, bX, bY);
+ OH_Drawing_PathLineTo(cPath_, cX, cY);
+ OH_Drawing_PathLineTo(cPath_, dX, dY);
+
+ OH_Drawing_PathClose(cPath_);
+}
+
+void SampleXComponent::SetPenAndBrush()
+{
+ constexpr float penWidth = 10.0f; // pen width 10
+ cPen_ = OH_Drawing_PenCreate();
+ OH_Drawing_PenSetAntiAlias(cPen_, true);
+ OH_Drawing_PenSetColor(cPen_, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0x00, 0x00));
+ OH_Drawing_PenSetWidth(cPen_, penWidth);
+ OH_Drawing_PenSetJoin(cPen_, LINE_ROUND_JOIN);
+ OH_Drawing_CanvasAttachPen(cCanvas_, cPen_);
+
+ cBrush_ = OH_Drawing_BrushCreate();
+ OH_Drawing_BrushSetColor(cBrush_, OH_Drawing_ColorSetArgb(0xFF, 0x00, 0xFF, 0x00));
+
+ OH_Drawing_CanvasAttachBrush(cCanvas_, cBrush_);
+}
+
+void SampleXComponent::DrawPath()
+{
+ OH_Drawing_CanvasDrawPath(cCanvas_, cPath_);
+}
+
+void ExecuteDisplaySoloist(std::string id, DisplaySoloist_ExpectedRateRange range, bool useExclusiveThread,
+ OH_NativeXComponent *nativeXComponent)
+{
+ OH_DisplaySoloist *nativeDisplaySoloist = nullptr;
+ if (g_displaySync.find(id) == g_displaySync.end()) {
+ g_displaySync[id] = OH_DisplaySoloist_Create(useExclusiveThread);
+ }
+ nativeDisplaySoloist = g_displaySync[id];
+ OH_DisplaySoloist_SetExpectedFrameRateRange(nativeDisplaySoloist, &range);
+ OH_DisplaySoloist_Start(nativeDisplaySoloist, TestCallback, nativeXComponent);
+}
+
+// [Start display_soloist_napi_register]
+napi_value SampleXComponent::NapiRegister(napi_env env, napi_callback_info info)
+{
+ SAMPLE_LOGI("NapiRegister");
+ if ((env == nullptr) || (info == nullptr)) {
+ SAMPLE_LOGE("NapiRegister: env or info is null");
+ return nullptr;
+ }
+
+ napi_value thisArg;
+ if (napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr) != napi_ok) {
+ SAMPLE_LOGE("NapiRegister: napi_get_cb_info fail");
+ return nullptr;
+ }
+
+ napi_value exportInstance;
+ if (napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) {
+ SAMPLE_LOGE("NapiRegister: napi_get_named_property fail");
+ return nullptr;
+ }
+
+ OH_NativeXComponent *nativeXComponent = nullptr;
+ if (napi_unwrap(env, exportInstance, reinterpret_cast(&nativeXComponent)) != napi_ok) {
+ SAMPLE_LOGE("NapiRegister: napi_unwrap fail");
+ return nullptr;
+ }
+
+ char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
+ uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
+ if (OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
+ SAMPLE_LOGE("NapiRegister: Unable to get XComponent id");
+ return nullptr;
+ }
+ SAMPLE_LOGI("RegisterID = %{public}s", idStr);
+ std::string id(idStr);
+ SampleXComponent *render = SampleXComponent().GetInstance(id);
+ if (render != nullptr) {
+ DisplaySoloist_ExpectedRateRange range;
+ bool useExclusiveThread = false;
+ if (id == "xcomponentId30") {
+ range = {30, 120, 30};
+ }
+
+ if (id == "xcomponentId120") {
+ range = {30, 120, 120};
+ }
+ ExecuteDisplaySoloist(id, range, useExclusiveThread, nativeXComponent);
+ }
+ return nullptr;
+}
+// [End display_soloist_napi_register]
+
+napi_value SampleXComponent::NapiUnregister(napi_env env, napi_callback_info info)
+{
+ SAMPLE_LOGI("NapiUnregister");
+ if ((env == nullptr) || (info == nullptr)) {
+ SAMPLE_LOGE("NapiUnregister: env or info is null");
+ return nullptr;
+ }
+
+ napi_value thisArg;
+ if (napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr) != napi_ok) {
+ SAMPLE_LOGE("NapiUnregister: napi_get_cb_info fail");
+ return nullptr;
+ }
+
+ napi_value exportInstance;
+ if (napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) {
+ SAMPLE_LOGE("NapiUnregister: napi_get_named_property fail");
+ return nullptr;
+ }
+
+ OH_NativeXComponent *nativeXComponent = nullptr;
+ if (napi_unwrap(env, exportInstance, reinterpret_cast(&nativeXComponent)) != napi_ok) {
+ SAMPLE_LOGE("NapiUnregister: napi_unwrap fail");
+ return nullptr;
+ }
+
+ char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
+ uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
+ if (OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
+ SAMPLE_LOGE("NapiUnregister: Unable to get XComponent id");
+ return nullptr;
+ }
+ SAMPLE_LOGI("ID = %{public}s", idStr);
+ std::string id(idStr);
+ SampleXComponent *render = SampleXComponent().GetInstance(id);
+ if (render != nullptr) {
+ OH_DisplaySoloist_Stop(g_displaySync[id]);
+ SAMPLE_LOGI("NapiUnregister executed");
+ } else {
+ SAMPLE_LOGE("render is nullptr");
+ }
+ return nullptr;
+}
+
+napi_value SampleXComponent::NapiDestroy(napi_env env, napi_callback_info info)
+{
+ SAMPLE_LOGI("NapiUnregister");
+ if ((env == nullptr) || (info == nullptr)) {
+ SAMPLE_LOGE("NapiDestroy: env or info is null");
+ return nullptr;
+ }
+
+ napi_value thisArg;
+ if (napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr) != napi_ok) {
+ SAMPLE_LOGE("NapiDestroy: napi_get_cb_info fail");
+ return nullptr;
+ }
+
+ napi_value exportInstance;
+ if (napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) {
+ SAMPLE_LOGE("NapiDestroy: napi_get_named_property fail");
+ return nullptr;
+ }
+
+ OH_NativeXComponent *nativeXComponent = nullptr;
+ if (napi_unwrap(env, exportInstance, reinterpret_cast(&nativeXComponent)) != napi_ok) {
+ SAMPLE_LOGE("NapiDestroy: napi_unwrap fail");
+ return nullptr;
+ }
+
+ char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
+ uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
+ if (OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
+ SAMPLE_LOGE("NapiDestroy: Unable to get XComponent id");
+ return nullptr;
+ }
+ SAMPLE_LOGI("ID = %{public}s", idStr);
+ std::string id(idStr);
+ SampleXComponent *render = SampleXComponent().GetInstance(id);
+ if (render != nullptr) {
+ OH_DisplaySoloist_Destroy(g_displaySync[id]);
+ g_displaySync.erase(id);
+ SAMPLE_LOGI("NapiUnregister executed");
+ } else {
+ SAMPLE_LOGE("render is nullptr");
+ }
+ return nullptr;
+}
+
+SampleXComponent::~SampleXComponent()
+{
+ OH_Drawing_BrushDestroy(cBrush_);
+ cBrush_ = nullptr;
+ OH_Drawing_PenDestroy(cPen_);
+ cPen_ = nullptr;
+ OH_Drawing_PathDestroy(cPath_);
+ cPath_ = nullptr;
+ OH_Drawing_CanvasDestroy(cCanvas_);
+ cCanvas_ = nullptr;
+ OH_Drawing_BitmapDestroy(cBitmap_);
+ cBitmap_ = nullptr;
+
+ buffer_ = nullptr;
+ bufferHandle_ = nullptr;
+ nativeWindow_ = nullptr;
+ mappedAddr_ = nullptr;
+}
+
+void SampleXComponent::Destroy()
+{
+ OH_Drawing_BrushDestroy(cBrush_);
+ cBrush_ = nullptr;
+ OH_Drawing_PenDestroy(cPen_);
+ cPen_ = nullptr;
+ OH_Drawing_PathDestroy(cPath_);
+ cPath_ = nullptr;
+ OH_Drawing_CanvasDestroy(cCanvas_);
+ cCanvas_ = nullptr;
+ OH_Drawing_BitmapDestroy(cBitmap_);
+ cBitmap_ = nullptr;
+}
+
+void SampleXComponent::Release(std::string &id)
+{
+ SampleXComponent *render = SampleXComponent::GetInstance(id);
+ if (render != nullptr) {
+ delete render;
+ render = nullptr;
+ g_instance.erase(g_instance.find(id));
+ }
+}
+
+void SampleXComponent::Export(napi_env env, napi_value exports)
+{
+ if ((env == nullptr) || (exports == nullptr)) {
+ SAMPLE_LOGE("Export: env or exports is null");
+ return;
+ }
+ napi_property_descriptor desc[] = {
+ {"register", nullptr, SampleXComponent::NapiRegister, nullptr, nullptr, nullptr, napi_default, nullptr},
+ {"unregister", nullptr, SampleXComponent::NapiUnregister, nullptr, nullptr, nullptr, napi_default, nullptr},
+ {"destroy", nullptr, SampleXComponent::NapiDestroy, nullptr, nullptr, nullptr, napi_default, nullptr}};
+
+ if (napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc) != napi_ok) {
+ SAMPLE_LOGE("Export: napi_define_properties failed");
+ }
+}
+
+void SampleXComponent::RegisterCallback(OH_NativeXComponent *nativeXComponent)
+{
+ SAMPLE_LOGI("register callback");
+ renderCallback_.OnSurfaceCreated = OnSurfaceCreatedCB;
+ renderCallback_.OnSurfaceDestroyed = OnSurfaceDestroyedCB;
+ // Callback must be initialized
+ renderCallback_.DispatchTouchEvent = nullptr;
+ renderCallback_.OnSurfaceChanged = nullptr;
+ OH_NativeXComponent_RegisterCallback(nativeXComponent, &renderCallback_);
+}
+
+SampleXComponent *SampleXComponent::GetInstance(std::string &id)
+{
+ if (g_instance.find(id) == g_instance.end()) {
+ SampleXComponent *render = new SampleXComponent(id);
+ g_instance[id] = render;
+ return render;
+ } else {
+ return g_instance[id];
+ }
+}
\ No newline at end of file
diff --git a/graphic/DisplaySoloist/entry/src/main/cpp/samples/sample_xcomponent.h b/graphic/DisplaySoloist/entry/src/main/cpp/samples/sample_xcomponent.h
new file mode 100644
index 0000000000000000000000000000000000000000..926d45738ff1e2a9b077ce6af42fc9bc5b4e866c
--- /dev/null
+++ b/graphic/DisplaySoloist/entry/src/main/cpp/samples/sample_xcomponent.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2024 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef SAMPLE_XCOMPONENT_H
+#define SAMPLE_XCOMPONENT_H
+// [Start display_soloist_import_module]
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include