Creating and Using Image Resources
Image is essentially a two-dimensional buffer for storing information required for 3D rendering calculation, such as basic colors and normals.
ArkGraphics 3D provides the capability of creating image resources in PNG, JPG, and KTX formats and customizing image resources.
How to Develop
-
Import the required modules.
Import the core types provided by ArkGraphics 3D in the page script to create objects like scenes, cameras, materials, and images.
import { Camera, Environment, Geometry, Image, Material, MaterialType, Scene, SceneResourceFactory, SceneResourceParameters, Shader, ShaderMaterial, EnvironmentBackgroundType } from '@kit.ArkGraphics3D'; -
Load the scene and configure rendering parameters.
Call Scene.load() to load model files in .glb or .gltf format, and obtain a scene object upon completion. Then, construct a SceneOptions object to specify the scene and rendering mode for rendering the scene content via Component3D.
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(); // ... }) .catch((error: string) => { console.error('init error: ' + error + '.'); }); } -
Initialize the camera.
Create a camera object, and set its enabled state and viewing position for subsequent model display.
this.cam = await this.rf.createCamera({ 'name': 'Camera1' }); this.cam.enabled = true; this.cam.position.z = 5; -
Obtain the geometry node.
Call Scene.getNodeByPath() to obtain the geometry node of the target model, and record its original material. This enables rollback or recovery in case the material is later modified.
this.geom = this.scene.getNodeByPath('rootNode_/Unnamed Node 1/AnimatedCube') as Geometry; // record original material this.originalMat = this.geom.mesh.subMeshes[0].material; -
Create an image resource and bind it to the material.
Call SceneResourceFactory.createImage() to create an image resource, and call createMaterial() to create a shader material. Bind the image resource to the shader input property BASE_COLOR_Image to apply the texture to the model surface.
function createImagePromise(): Promise<Image> { 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') }; let image: Promise<Image> = sceneFactory.createImage(sceneImageParameter); image.then((imageEntity: Image) => { resolve(imageEntity); }).catch((err: string) => { console.error('Image load failed: ' + err + '.'); reject(err); }); } else { reject('Scene is not loaded yet.'); } }); } -
Apply the image material to the model node.
In the button click callback, call createShader() to create a shader, bind the shader to the material object, call createImagePromise() to obtain the image resource, and apply the image resource to the model geometry to replace the texture.
Button('Replace with a Image material') // ... .onClick(async (): Promise<void> => { console.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; })
Samples
The following sample is provided to help you better understand how to efficiently use 3D resources: