• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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