1/* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import scene3d from '@ohos.graphics.scene' 17import animator, { AnimatorResult } from '@ohos.animator'; 18import router from '@ohos.router'; 19import Logger from '../util/Logger'; 20 21@Entry 22@Component 23struct sceneShader { 24 scene: scene3d.Scene | null = null; 25 @State sceneOpt: SceneOptions | null = null; 26 rf: scene3d.SceneResourceFactory | null = null; 27 cam: scene3d.Camera | null = null; 28 shader: scene3d.Shader | null = null; 29 material: scene3d.ShaderMaterial | null = null; 30 geom: scene3d.Geometry | null = null; 31 image: scene3d.Image | null = null; 32 materialOrg: scene3d.Material | null = null; 33 backAnimator: AnimatorResult | undefined = undefined; 34 step: number = 0; 35 @State hierarchy: string = ''; 36 @State meshInfo: string = ''; 37 38 traversal(node: scene3d.Node | null): void { 39 if (!node) { 40 return; 41 } 42 this.hierarchy += node.path + '/' + node.name + '\n'; 43 let container: scene3d.Container<scene3d.Node> = node.children; 44 let count: number = container.count(); 45 this.hierarchy += ' '; 46 for (let i = 0; i < count; i++) { 47 this.traversal(container.get(i)); 48 } 49 } 50 51 onPageShow(): void { 52 this.init(); 53 } 54 55 PrintAabb(aabb: scene3d.Aabb, append: string): string { 56 let info: string = '' 57 info += append + " max aabb [ " + aabb.aabbMax.x + " "+ aabb.aabbMax.y + " "+ aabb.aabbMax.z + " ]"; 58 info += "\n" + append + " min aabb [ " + aabb.aabbMin.x + " "+ aabb.aabbMin.y + " "+ aabb.aabbMin.z + " ]"; 59 return info; 60 } 61 62 onPageHide(): void { 63 if (this.scene) { 64 this.scene.destroy(); 65 } 66 67 this.cam = null; 68 this.scene = null; 69 } 70 71 init(): void { 72 this.backAnimator = animator.create({ 73 duration: 2000, // duration 74 easing: "ease", 75 delay: 0, 76 fill: "none", 77 direction: "normal", 78 iterations: -1, // endless loop 79 begin: 100, // begin 80 end: 200 // end 81 }) 82 this.backAnimator.onframe = value => { 83 this.step++; 84 if (this.material && this.material.colorShader) { 85 // just give a random effect 86 (this.material.colorShader.inputs["vec_1"] as scene3d.Vec4) = { x: Math.abs(Math.sin(this.step) + 0.5), 87 y: Math.abs(Math.sin(this.step * 0.86) + 0.5), 88 z: Math.abs(Math.sin(this.step * 0.91) + 0.5), w: 1.0 }; 89 (this.material.colorShader.inputs["time"] as number) = this.step; 90 } 91 } 92 if (this.scene === null) { 93 scene3d.Scene.load($rawfile("gltf/Cube/glTF/Cube.glb")) 94 .then(async (result: scene3d.Scene) => { 95 this.scene = result; 96 this.sceneOpt = { scene: this.scene, modelType: ModelType.SURFACE } as SceneOptions; 97 this.rf = this.scene.getResourceFactory(); 98 this.cam = await this.rf.createCamera({ "name": "Camera1" }); 99 this.cam.enabled = true; 100 this.cam.position.z = 5; // put camera to 5 at z 101 102 this.image = await this.rf.createImage({ name: "envImg3", uri: $rawfile("gltf/DamagedHelmet/glTF/Default_AO.jpg") }); 103 this.traversal(this.scene?.root); 104 if (!this.geom) { 105 this.geom = this.scene.getNodeByPath("rootNode_/Unnamed Node 1/Cube") as scene3d.Geometry; 106 this.meshInfo += this.PrintAabb(this.geom.mesh.aabb, 'Mesh '); 107 let i = 0; 108 for (let M of this.geom.mesh.subMeshes) { 109 this.meshInfo += '\n'; 110 this.meshInfo += this.PrintAabb(this.geom.mesh.aabb, 'Submesh[' + i + "]"); 111 i++; 112 } 113 114 } 115 this.materialOrg = this.geom.mesh.subMeshes[0].material; 116 117 }) 118 .catch((reason: string) => { 119 Logger.error("init error", reason); 120 }); 121 } 122 } 123 124 build() { 125 Row() { 126 Column() { 127 Column() { 128 if (this.sceneOpt) { 129 Component3D(this.sceneOpt) 130 .renderWidth('60%') 131 .renderHeight('60%').onAppear(()=>{ 132 this.backAnimator?.play() 133 }) 134 } 135 else { 136 Text("loading 1..."); 137 } 138 } 139 .height('30%') 140 141 Button('create shader and change material').onClick(async () => { 142 if (!this.scene || !this.rf) { 143 return; 144 } 145 if (!this.material) { 146 this.material = await this.rf.createMaterial({ name: "CustomMaterial" }, scene3d.MaterialType.SHADER); 147 } 148 if (!this.shader) { 149 this.shader = await this.rf.createShader({ name: "CustomShader", uri: $rawfile("shaders/custom_shader/custom_material_sample.shader") }); 150 } 151 152 if (this.material) { 153 this.material.colorShader = this.shader; 154 } 155 156 if (!this.geom) { 157 this.geom = this.scene.getNodeByPath("rootNode_/Unnamed Node 1/Cube") as scene3d.Geometry; 158 } 159 160 this.geom.mesh.materialOverride = undefined; 161 this.geom.mesh.subMeshes[0].material = this.material; 162 163 if (this.material && this.material.colorShader && this.image) { 164 (this.material.colorShader.inputs["BASE_COLOR_Image"] as scene3d.Image) = this.image; 165 } 166 }).id('create_shader_change_material'); 167 168 Button('recovery original material').onClick(async () => { 169 if (this.geom) { 170 this.geom.mesh.materialOverride = undefined; 171 this.geom.mesh.subMeshes[0].material = this.materialOrg as scene3d.ShaderMaterial; 172 } 173 }).id('recovery_original') 174 175 Button('material override').onClick(async () => { 176 if (this.geom) { 177 this.geom.mesh.subMeshes[0].material = this.materialOrg as scene3d.ShaderMaterial; 178 } 179 if (this.geom && this.material) { 180 this.geom.mesh.materialOverride = this.material as scene3d.ShaderMaterial; 181 } 182 }).id('material_override') 183 184 Text(this.meshInfo); 185 Text(this.hierarchy); 186 Button('back').onClick(() => { 187 this.backAnimator?.cancel(); 188 router.back() 189 }).id('back_shader') 190 } 191 .width('100%') 192 } 193 .height('100%') 194 } 195} 196