1# Creating and Using Material Resources 2<!--Kit: ArkGraphics 3D--> 3<!--Subsystem: Graphics--> 4<!--Owner: @zzhao0--> 5<!--SE: @zdustc--> 6<!--TSE: @zhangyue283--> 7 8Materials are essential resources that define the visual appearance of an object's surface. They determine how an object interacts with light, thereby affecting its final rendering result, such as color, metallic appearance, and roughness. 9 10ArkGraphics 3D uses the Physically Based Rendering (PBR) model. Its material implementation follows the general principles of PBR. You can either use standard materials to quickly achieve realistic effects or customize shader materials to flexibly control the rendering logic. 11 12## Basic Concepts 13 14Shader: a program executed on a GPU to tell the GPU which parallel computing operations can be performed. The default shader provided by the Ark Graphics Platform (AGP) engine implements PBR. You only need to specify parameters to get different PBR effects. 15 16ArkGraphics 3D allows you to create custom shaders. By customizing shaders, you can control the rendering computation process and fully control the rendering workflow. For example, you can control whether an object is affected by a particular light source, customize edge outlining, or create highlight effects for personalized visual presentations. 17 18Shaders are typically used with **MaterialType.SHADER** materials and are an important means of achieving customized rendering. They require a name and sandbox path for creation. Once created, they can be bound to materials to replace the default rendering behavior. 19 20## Material Types 21Material types in ArkGraphics 3D are specified using the enum [MaterialType](../reference/apis-arkgraphics3d/js-apis-inner-scene-resources.md#materialtype). Currently, the following two types are supported: 22 23- **MaterialType.SHADER**: This material type is based on shaders and supports binding custom shaders. You can use custom rendering programs to achieve personalized visual effects. It is suitable for advanced graphics rendering needs. 24 25- **MaterialType.METALLIC_ROUGHNESS**: This is a standard PBR material type based on the metallic-roughness model. It conforms to the glTF material specification and is suitable for quickly building realistic rendering effects. It supports setting common properties such as base color, metallic appearance, roughness, and normal mapping. 26 27Materials are created by calling [SceneResourceFactory.createMaterial()](../reference/apis-arkgraphics3d/js-apis-inner-scene.md#creatematerial), which requires specifying the material name and type. Different material types support different parameter configurations. You can choose as needed to achieve the desired rendering effect. 28 29 30## Material Properties 31Material properties define their visual behavior during rendering, such as color, metallic appearance, roughness, light response, and transparency control. By setting these properties, you can precisely control the appearance of objects in the scene. 32 33In ArkGraphics 3D, material properties are designed to provide both unified basic capabilities and differentiated extensions based on material type, meeting diverse needs from basic scene building to advanced visual customization. 34 35 36### Universal Properties 37All materials have the following basic properties (such as **materialType**, **shadowReceiver**, and **blend**), which can be set through the [Material](../reference/apis-arkgraphics3d/js-apis-inner-scene-resources.md#material) type object to control the type of material and its basic rendering behavior: 38 39- **materialType**: material type, indicating whether it is a standard PBR material or a custom shader material. 40 41 Use case: Choose PBR material for quick use of preset realistic materials. Choose shader material for personalized or special rendering effects. 42 43- **shadowReceiver**: whether the material can receive shadows cast in the scene. **true** if it can receive shadows, false otherwise. The default value is **false**. 44 45 Use case: Enable for objects that need to display shadow effects, such as the ground, walls, and characters. Disable for purely emissive objects or those not participating in shadow calculations to optimize performance. 46 47- **cullMode**: culling mode, which determines whether to cull back-facing geometry. The default value is **BACK**, meaning back-facing surfaces are culled. 48 49 Use case: Enable for ordinary solid models to improve rendering efficiency. Disable for transparent or double-sided materials (such as leaves and fabrics) to display the complete model. 50 51- **blend**: whether to enable the material's transparency mode. **true** means to enable, **false** otherwise. The default value is **false**. 52 53 Use case: Enable for materials that need to display transparency or translucency, such as glass, water surfaces, smoke, and transparent plastics. 54 55- **alphaCutoff**: alpha cutoff value, ranging from [0,1]. The default is **1**. Pixels with an alpha value below this threshold will not be rendered, used to achieve hard transparency clipping. 56 57 Use case: For materials with hard transparency clipping, such as leaves, wire meshes, and fabric edges that have transparent areas without translucent gradients. By setting the threshold, transparent parts can be quickly clipped. 58 59- **renderSort**: rendering sort setting, used to control the rendering order of materials in the rendering queue to ensure correct overlay display of transparent or special effect materials. 60 61 Use case: For scenes with multiple transparent materials, overlay effects, and UI elements, where strict rendering order is required. 62 63### PBR Material Properties 64The metallic-roughness material based on PBR rendering, which conforms to the glTF standard, is implemented by setting [MetallicRoughnessMaterial](../reference/apis-arkgraphics3d/js-apis-inner-scene-resources.md#metallicroughnessmaterial20). Each property is encapsulated using the [MaterialProperty](../reference/apis-arkgraphics3d/js-apis-inner-scene-resources.md#materialproperty20) type, supporting binding textures and setting factor values. Specific properties include: 65 66- **baseColor**: base color and transparency, including texture and corresponding factor, used to define the main color of the material surface. 67 68 Use case: basic color settings for all materials, suitable for any object surface, especially for models that need to display color and transparency. 69 70- **normal**: normal map, used to simulate surface detail bumps and enhance the realism of lighting effects. 71 72 Use case: suitable for models that need to display surface details such as stone textures, skin pores, and wood grain bumps to enhance realism. 73 74- **material**: Metallic, roughness, and reflectivity parameters, describing the optical properties of the material surface. 75 76 Use case: distinguishing between metallic and non-metallic surfaces, controlling the smoothness or roughness of the material, commonly used for metal parts, plastics, rubbers, and various other materials. 77 78- **ambientOcclusion**: ambient occlusion map, enhancing the shadow levels and realism of material details. 79 80 Use case: enhancing the shadow effects of model details, suitable for complex structures or objects with rich details, such as building cracks and mechanical part gaps. 81 82- **emissive**: emissive color and texture, expressing the self-luminous effect of the material. 83 84 Use case: suitable for materials that need to display light sources or self-luminous effects, such as lights, screens, glowing signs, and fluorescent materials. 85 86- **clearCoat**: clear coat strength, simulating materials with a transparent reflective layer, such as car paint. 87 88 Use case: suitable for materials with a glossy coating, such as car bodies and furniture surfaces, to display transparent gloss and reflection. 89 90- **clearCoatRoughness**: roughness of the clear coat, controlling the reflective details of the clear coat. 91 92 Use case: used with **clearCoat** to adjust the smoothness or roughness of the coating surface. 93 94- **clearCoatNormal**: clear coat normal map, enhancing the lighting changes of the clear coat. 95 96 Use case: used when the clear coat has detailed textures to increase the realistic lighting feedback of the coating. 97 98- **sheen**: sheen diffuse layer, used to display the luster of fabrics and textiles. 99 100 Use case: suitable for textiles such as clothing, curtains, and sofas, to display a soft luster and delicate texture. 101 102- **specular**: specular reflection properties, controlling the highlight reflection intensity of non-metallic materials. 103 104 Use case: suitable for non-metallic materials such as glass, water surfaces, and plastics to enhance the specular reflection effect. 105 106 107## How to Develop 108 1. Obtain the resource factory. 109 110 Use a **Scene** object or other interfaces to obtain a **SceneResourceFactory** instance, which is used to create material resources. 111 112 ```ts 113 // Load scene resources, which supports .gltf and .glb formats. The path and file name can be customized based on the specific project resources. 114 let scenePromise: Promise<Scene> = Scene.load($rawfile("gltf/ExampleModel.glb")); 115 scenePromise.then(async (scene: Scene) => { 116 if (!scene.root) { 117 return; 118 } 119 let rf: SceneResourceFactory = scene.getResourceFactory(); 120 // Subsequent operations can be performed based on rf. 121 }); 122 ``` 123 124 2. Create a material and specify the material type. 125 126 Call **createMaterial()** to specify the material type (such as **MaterialType.METALLIC_ROUGHNESS** or **MaterialType.SHADER**), and asynchronously create a material object. 127 128 - You can create a shader material. If you need to customize rendering effects, you can use custom shaders. The sample code is as follows: 129 130 ```ts 131 let shaderMaterialPromise = await rf.createMaterial({ name: "shaderMat" }, MaterialType.SHADER); 132 let shaderMat = shaderMaterialPromise as ShaderMaterial; 133 // Shader binding implementation: 134 let shader = await rf.createShader({ name: "MyShader", uri: $rawfile("shaders/my_shader.shader") }); 135 shaderMat.colorShader = shader; 136 ``` 137 138 - You can also create a PBR material. If you need to quickly build realistic rendering effects, use preset parameters. The sample code is as follows: 139 140 ```ts 141 let pbrMaterialPromise = await rf.createMaterial({ name: "pbrMat" }, MaterialType.METALLIC_ROUGHNESS); 142 let pbrMat = pbrMaterialPromise as MetallicRoughnessMaterial; 143 // Set the base color texture and factor. 144 let baseColorImage = await rf.createImage({ name: "baseColorTex", uri: $rawfile("textures/baseColor.png") }); 145 pbrMat.baseColor.image = baseColorImage; 146 pbrMat.baseColor.factor = { x: 1, y: 1, z: 1, w: 1 }; 147 ``` 148 149 3. Set material properties. 150 151 - Set universal properties. The sample code is as follows: 152 153 ```ts 154 material.shadowReceiver = true; // Enable shadow receiving. 155 material.cullMode = CullMode.BACK; // Enable back-facing culling. 156 material.blend = { enabled: true }; // Enable transparency blending. 157 material.alphaCutoff = 0.5; // Alpha cutoff value. 158 material.renderSort = { renderSortLayer: 32, renderSortLayerOrder: 1 }; // Rendering sort order. 159 ``` 160 161 - When the created material is PBR-based, you can also set PBR material properties. The sample code is as follows: 162 163 The texture maps for different properties generally vary and should be created individually. When several materials use the same texture, you can share a single Image instance to conserve memory. All material property factors use the value range [0, 1]. 164 165 ```ts 166 // Set the base color texture and color factor (supporting the alpha channel). 167 let baseColorImage = await rf.createImage({ name: "baseColorTex", uri: $rawfile("textures/baseColor.png") }); 168 pbrMat.baseColor.image = baseColorImage; 169 pbrMat.baseColor.factor = { x: 1, y: 1, z: 1, w: 1 }; // The components x, y, and z control color, and w controls alpha (0–1). 170 // Set the normal map (controlling surface detail bumps). 171 let normalImage = await rf.createImage({ name: "normalTex", uri: $rawfile("textures/normal.png") }); 172 pbrMat.normal.image = normalImage; 173 pbrMat.normal.factor.x = 0.6; // x component: normal intensity (0–1). 174 // Set roughness, metallic, and reflectivity properties. (A single texture can be shared.) The y, z, and w components are used to control the properties. 175 let metallicRoughnessImage = await rf.createImage({ name: "materialTex", uri: $rawfile("textures/material_texture.png") }); 176 pbrMat.material.image = metallicRoughnessImage; 177 pbrMat.material.factor.y = 1.0; // y component: roughness (0–1). 0 means smooth, and 1 means rough. 178 pbrMat.material.factor.z = 0.5; // z component: metallic (0–1). 0 means non-metallic, and 1 means metallic. 179 pbrMat.material.factor.w = 0.5; // w component: reflectivity (0–1). 180 // Set the ambient occlusion map. The x component is used to control the occlusion strength. 181 let ambientOcclusionImage = await rf.createImage({ name: "ambientOcclusionTex", uri: $rawfile("textures/ambientOcclusion.png") }); 182 pbrMat.ambientOcclusion.image = ambientOcclusionImage; 183 pbrMat.ambientOcclusion.factor.x = 1.0; // Occlusion strength (0–1). 184 // Set the emissive map and color factor (for glow effects). 185 let emissiveImage = await rf.createImage({ name: "emissiveTex", uri: $rawfile("textures/emissive.png") }); 186 pbrMat.emissive.image = emissiveImage; 187 pbrMat.emissive.factor = { x: 1.0, y: 1.0, z: 0.8, w: 1 }; // The components x, y, and z control glow color, and w controls intensity (0–1). 188 // Set the clear coat strength and roughness. 189 pbrMat.clearCoat.factor.x = 1.0; // x component: clear coat strength (0–1). 190 pbrMat.clearCoatRoughness.factor.y = 0.5; // y component: clear coat roughness (0–1). 191 // Set the clear coat normal map. The x, y, and z components control the direction. 192 let clearCoatNormalImage = await rf.createImage({ name: "clearCoatNormalTex", uri: $rawfile("textures/clearCoatNormal.png") }); 193 pbrMat.clearCoatNormal.image = clearCoatNormalImage; 194 pbrMat.clearCoatNormal.factor.x = 1.0; 195 pbrMat.clearCoatNormal.factor.y = 1.0; 196 pbrMat.clearCoatNormal.factor.z = 1.0; 197 // Set more PBR properties as needed, such as sheen and specular. 198 // sheen: controls sheen intensity. 199 // pbrMat.sheen.factor = { x: 1.0, y: 0.5, z: 0.3, w: 1.0 }; // The components x, y, and z control sheen color, and w controls intensity (0–1). 200 201 // specular: controls specularity. 202 // pbrMat.specular.factor = { x: 1.0, y: 1.0, z: 1.0, w: 0.7 }; // The components x, y, and z control specularity color, and w controls intensity (0–1). 203 ``` 204 205 - For Shader materials, bind custom shader resources to implement personalized rendering effects. For details, see [Creating Shader Materials and Setting Properties](#creating-shader-materials-and-setting-properties). 206 207 4. Bind the material to the mesh. 208 209 Assign the created material to the **material** or **subMeshes[i].material** field of a geometry to make it effective. There are two common binding methods: 210 211 - Create a mesh and geometry through the resource factory, and then bind the material. (This method is suitable for creating new geometries.) The sample code is as follows: 212 213 ```ts 214 let mesh = await resourceFactory.createMesh({ name: "mesh" }, geometry); 215 let geometryInstance = await resourceFactory.createGeometry({ name: "geometry" }, mesh); 216 geometryInstance.mesh.subMeshes[0].material = pbrMat; // Bind the material. 217 ``` 218 219 - Directly obtain an existing geometry node via **scene.root.getNodeByPath** and modify the bound material. (This method is suitable for modifying materials after loading a scene.) The sample code is as follows: 220 221 ```ts 222 let pbrNode = scene.root.getNodeByPath("path/to/node"); 223 if (pbrNode) { 224 (pbrNode as Geometry).mesh.subMeshes[0].material = pbrMat; // Bind the material. 225 } 226 ``` 227 228 5. Render the mesh and observe the effect. Execute rendering to visualize the material. 229 230 231## Complete Code 232 233 ### Creating Shader Materials and Setting Properties 234 235 ```ts 236 import { Image, Shader, MaterialType, Material, ShaderMaterial, Animation, Environment, Container, SceneNodeParameters, 237 LightType, Light, Camera, SceneResourceParameters, SceneResourceFactory, Scene, Node, Geometry, 238 CullMode } from '@ohos.graphics.scene'; 239 240 function createAndApplyShaderMaterial(): Promise<void> { 241 // Load scene resources, which supports .gltf and .glb formats. The path and file name can be customized based on the specific project resources. 242 let scenePromise: Promise<Scene> = Scene.load($rawfile("gltf/CubeWithFloor/glTF/AnimatedCube.glb")); 243 return scenePromise.then(async (scene: Scene) => { 244 if (!scene.root) { 245 return; 246 } 247 // Obtain the resource factory. 248 let rf: SceneResourceFactory = scene.getResourceFactory(); 249 // Create a shader material. 250 let materialParams: SceneResourceParameters = { name: "material" }; 251 let material = await rf.createMaterial(materialParams, MaterialType.SHADER); 252 let shaderMat = material as ShaderMaterial; 253 // Load and bind the custom shader. 254 let shader = await rf.createShader({ 255 name: "shaderResource", 256 uri: $rawfile("shaders/custom_shader/custom_material_sample.shader") 257 }); 258 shaderMat.colorShader = shader; 259 // Set universal properties. 260 shaderMat.shadowReceiver = true; 261 shaderMat.cullMode = CullMode.BACK; 262 shaderMat.blend = { enabled: true }; // For example, enable transparency blending. 263 shaderMat.alphaCutoff = 0.5; 264 // Bind the material to an existing mesh node. 265 let shaderNode = scene.root.getNodeByPath("rootNode_/Unnamed Node 1/AnimatedCube"); 266 if (shaderNode) { 267 let geometry = shaderNode as Geometry; 268 geometry.mesh.subMeshes[0].material = shaderMat; 269 } 270 // Render the mesh and observe the effect. 271 }); 272 } 273 ``` 274 275 ### Creating PBR Materials and Setting Properties 276 277Different models may support different PBR properties. Before setting the material, you are advised to adapt it according to the model content. This example uses the CompareClearcoat model to set its supported PBR properties. You can use the corresponding model and set related properties as needed. 278 279 ```ts 280 import { Image, Shader, MaterialType, Material, ShaderMaterial, Animation, Environment, Container, SceneNodeParameters, 281 LightType, Light, Camera, SceneResourceParameters, SceneResourceFactory, Scene, Node, MetallicRoughnessMaterial, 282 Geometry, CullMode } from '@ohos.graphics.scene'; 283 284 function createAndApplyPBRMaterial(): Promise<void> { 285 // Load scene resources, which supports .gltf and .glb formats. The path and file name can be customized based on the specific project resources. 286 // Different models may support different PBR properties. Before setting the material, you are advised to adapt it according to the model content. This example uses the CompareClearcoat model to set its supported PBR properties. 287 let scenePromise: Promise<Scene> = Scene.load($rawfile("CompareClearcoat.glb")); 288 return scenePromise.then(async (scene: Scene) => { 289 if (!scene.root) { 290 return; 291 } 292 // Obtain the resource factory. 293 let rf: SceneResourceFactory = scene.getResourceFactory(); 294 // Create a PBR material. 295 let materialParams: SceneResourceParameters = { name: "MyPBRMaterial" }; 296 let material = await rf.createMaterial(materialParams, MaterialType.METALLIC_ROUGHNESS); 297 let pbrMat = material as MetallicRoughnessMaterial; 298 299 // Share the metallic-roughness texture map, which can be reused by multiple materials to save resources. 300 let metallicImage = await rf.createImage({ 301 name: "materialTex", 302 uri: $rawfile("gltf/DamagedHelmet/glTF/Default_metalRoughness.jpg") 303 }); 304 pbrMat.material.image = metallicImage; 305 // Configure the y, z, and w components to control roughness, metallic appearance, and reflectivity. 306 pbrMat.material.factor = { x: 0, y: 0.8, z: 0.4, w: 0.6 }; 307 // Set the ambient occlusion map. 308 pbrMat.ambientOcclusion.factor.x = 1.0; 309 // Set the clear coat strength and roughness. 310 pbrMat.clearCoat.factor.x = 1.0; 311 pbrMat.clearCoatRoughness.factor.y = 0.5; 312 // Set the sheen gloss properties. 313 pbrMat.sheen.factor = { x: 1.0, y: 0.2, z: 0.2, w: 0.8 }; 314 315 // Set universal properties. 316 pbrMat.shadowReceiver = true; 317 pbrMat.cullMode = CullMode.BACK; 318 pbrMat.blend = { enabled: false }; 319 pbrMat.alphaCutoff = 0.5; 320 // Bind the material to an existing mesh node. 321 let pbrNode = scene.root.getNodeByPath("Unnamed Node 1/GeoSphere002"); 322 if (pbrNode) { 323 let geometry = pbrNode as Geometry; 324 geometry.mesh.subMeshes[0].material = pbrMat; 325 } 326 // Execute rendering to visualize the material. 327 }); 328 } 329 ``` 330