HarmonyOS鸿蒙Next中如何获取node节点的世界坐标
HarmonyOS鸿蒙Next中如何获取node节点的世界坐标 这是官方智能大师给的
import { Scene, Node, Mat4, Vec3 } from '@kit.ArkGraphics3D';
// 假设已加载场景并获取到 scene 对象
let scene: Promise<Scene> = Scene.load($rawfile("模型文件.glb"));
scene.then((result: Scene) => { if (result && result.root) {
// 通过路径查找节点,例如 "scene/box"
let targetNode: Node | null = result.root.getNodeByPath("scene/box");
if (targetNode) {
// 获取节点的世界变换矩阵
let worldMat: Mat4 = targetNode.worldTransform;
// 从矩阵中提取位置(矩阵的第四列,索引为12、13、14的元素)
let worldPosition: Vec3 = new Vec3(worldMat, worldMat, worldMat);
console.info(`World position of node: x=${worldPosition.x}, y=${worldPosition.y}, z=${worldPosition.z}`); } } });
可是property ‘worldTransform’ does not exist on type ‘Node’. <ArkTSCheck>?
更多关于HarmonyOS鸿蒙Next中如何获取node节点的世界坐标的实战教程也可以访问 https://www.itying.com/category-93-b0.html
尊敬的开发者,您好,node节点位置坐标也可以代表世界坐标节点坐标,详细参考:node
Node
3D场景由树状层次结构的节点组成,其中每个节点都实现了Node接口。继承自SceneResource。
属性
系统能力: SystemCapability.ArkUi.Graphics3D
| 名称 | 类型 | 只读 | 可选 | 说明 |
|---|---|---|---|---|
| position | Position3 | 否 | 否 | 节点位置,单位为世界坐标系下的场景单位(比如cm、m、km等)。 |
| rotation | Quaternion | 否 | 否 | 节点旋转角度。 |
| scale | Scale3 | 否 | 否 | 节点缩放。 |
| visible | boolean | 否 | 否 | 节点是否可见。true表示该节点可见,false表示不可见。 |
| nodeType | NodeType | 是 | 否 | 节点类型。 |
| layerMask | LayerMask | 是 | 否 | 节点的图层掩码。 |
| path | string | 是 | 否 | 节点路径。 |
| parent | Node | null | 是 | 否 |
| children | Container<Node> | 是 | 否 | 节点的子节点,不存在则为空值。为只读属性,表示不能替换整个children容器,但可以通过容器方法操作子节点(如append()、insertAfter()、remove()或clear())。如果append或insertAfter的节点已存在于容器中,容器会先移除该节点再插入,因此数量不会增加,看似“无效”;添加新节点才会真正增加子节点数量。 |
示例代码如下:
import {
Image,
Shader,
MaterialType,
Material,
ShaderMaterial,
Animation,
Environment,
Container,
SceneNodeParameters,
LightType,
Light,
Camera,
SceneResourceParameters,
SceneResourceFactory,
Scene,
Node,
Vec3
} from '@kit.ArkGraphics3D';
import { LengthMetrics } from '@kit.ArkUI';
@Entry
@Component
struct Index {
scene: Scene | null = null;
@State sceneOpt: SceneOptions | null = null;
cam: Camera | null = null;
@State x: number = 0
@State y: number = 0
@State z: number = 0
aboutToAppear(): void {
this.Init();
}
Init(): void {
if (this.scene == null) {
// 加载模型,将gltf文件放置到相关路径,加载时以实际路径为准
Scene.load($rawfile("box.glb"))
.then(async (result: Scene) => {
this.scene = result;
let rf: SceneResourceFactory = this.scene.getResourceFactory();
// 创建相机
this.cam = await rf.createCamera({ "name": "Camera" });
// 设置合适的相机参数
this.cam.enabled = true;
this.sceneOpt = { scene: this.scene, modelType: ModelType.SURFACE } as SceneOptions;
if (result && result.root) {
let targetNode = result.root.getNodeByPath(`Scene/Cube`)
if (targetNode) {
console.info(`节点的世界坐标为: x=${targetNode.position.x}, y=${targetNode.position.y}, z=${targetNode.position.z}`);
let worldPos: Vec3 = targetNode.position;
// 2. 向上追溯父节点,累加其坐标得到绝对世界坐标
let parent = targetNode.parent;
while (parent && parent !== result.root) {
worldPos.x += parent.position.x;
worldPos.y += parent.position.y;
worldPos.z += parent.position.z;
parent = parent.parent;
}
console.info(`节点的世界坐标为: x=${worldPos.x}, y=${worldPos.y}, z=${worldPos.z}`);
}
}
})
.catch((reason: string) => {
console.log(reason);
});
}
}
build() {
Flex({ direction: FlexDirection.Column }) {
if (this.sceneOpt) {
// 通过Component3D呈现3D场景
Component3D(this.sceneOpt)
.flexGrow(1).flexBasis(1).flexShrink(1)
Flex({ space: { main: LengthMetrics.vp(5), cross: LengthMetrics.vp(5) } }) {
Column() {
Row() {
Text(`x:${this.x.toFixed(1)}`)
Slider({
value: this.x,
min: -50,
max: 50,
step: 0.1,
style: SliderStyle.OutSet
}).onChange((value: number) => {
if (this.cam) {
this.x = this.cam.position.x = value
}
}).showSteps(true)
}
Row() {
Text(`y:${this.y.toFixed(1)}`)
Slider({
value: this.y,
min: -50,
max: 50,
step: 0.1,
style: SliderStyle.OutSet
}).onChange((value: number) => {
if (this.cam) {
this.y = this.cam.position.y = value
}
}).showSteps(true)
}
Row() {
Text(`z:${this.z.toFixed(1)}`)
Slider({
value: this.z,
min: -50,
max: 50,
step: 0.1,
style: SliderStyle.OutSet
}).onChange((value: number) => {
if (this.cam) {
this.z = this.cam.position.z = value
}
}).showSteps(true)
}
}
}
} else {
Text("loading ...")
}
}.width('100%').height('100%')
}
}
更多关于HarmonyOS鸿蒙Next中如何获取node节点的世界坐标的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
这个报错是正常的:当前 ArkGraphics3D 的 Node 接口没有 worldTransform 属性,智能生成的这段代码不能直接用。官方 SceneNode 文档里 Node 暴露的是 position、rotation、scale、path、parent、children 等属性;getNodeByPath() 返回的是 Node | null,所以获取“世界坐标”要沿 parent 链把本地坐标逐级变换到根节点坐标系。
可以先封装一个工具方法,节点自身原点的世界坐标用 getWorldPosition(targetNode):
import { Node, Vec3, Quaternion } from '@kit.ArkGraphics3D';
function add(a: Vec3, b: Vec3): Vec3 {
return { x: a.x + b.x, y: a.y + b.y, z: a.z + b.z };
}
function rotate(v: Vec3, q: Quaternion): Vec3 {
const ix = q.w * v.x + q.y * v.z - q.z * v.y;
const iy = q.w * v.y + q.z * v.x - q.x * v.z;
const iz = q.w * v.z + q.x * v.y - q.y * v.x;
const iw = -q.x * v.x - q.y * v.y - q.z * v.z;
return {
x: ix * q.w + iw * -q.x + iy * -q.z - iz * -q.y,
y: iy * q.w + iw * -q.y + iz * -q.x - ix * -q.z,
z: iz * q.w + iw * -q.z + ix * -q.y - iy * -q.x
};
}
function applyParent(p: Vec3, parent: Node): Vec3 {
const s = parent.scale;
const scaled: Vec3 = { x: p.x * s.x, y: p.y * s.y, z: p.z * s.z };
return add(rotate(scaled, parent.rotation), parent.position);
}
function getWorldPosition(node: Node): Vec3 {
let p: Vec3 = { ...node.position };
let cur: Node | null = node.parent;
while (cur) {
p = applyParent(p, cur);
cur = cur.parent;
}
return p;
}
如果模型层级没有父节点旋转/缩放,简化版就是沿 parent 累加 position;如果要算某个顶点或包围盒中心的世界坐标,则先把该点按节点自身的 scale/rotation/position 转到父坐标系,再继续向上套父节点变换。
来源: SceneNode API: https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-inner-scene-nodes SceneType API: https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-inner-scene-types#position3
在HarmonyOS Next中,获取Node节点的世界坐标可通过组件提供的getGlobalOffset()方法实现。调用this.getGlobalOffset()返回一个Offset对象,包含相对于屏幕左上角的x和y值。若需实时获取,建议在onPageShow或布局完成后的回调中调用,确保坐标已更新。
在HarmonyOS Next的ArkGraphics3D中,Node 类并没有直接暴露 worldTransform 属性,需要通过 getWorldTransform 方法获取世界变换矩阵。提取坐标时,应使用矩阵元素的正确索引。修正后的代码如下:
import { Scene, Node, Mat4, Vec3 } from '@kit.ArkGraphics3D';
let scene: Promise<Scene> = Scene.load($rawfile("模型文件.glb"));
scene.then((result: Scene) => {
if (result && result.root) {
let targetNode: Node | null = result.root.getNodeByPath("scene/box");
if (targetNode) {
// 通过方法获取世界变换矩阵
let worldMat: Mat4 = targetNode.getWorldTransform();
// 从矩阵提取平移分量(第12、13、14个元素,索引从0开始)
let worldPosition: Vec3 = new Vec3(
worldMat.get(12),
worldMat.get(13),
worldMat.get(14)
);
console.info(`World position: x=${worldPosition.x}, y=${worldPosition.y}, z=${worldPosition.z}`);
}
}
});
getWorldTransform() 返回 Mat4 对象,其 get(index) 方法按列主序访问元素,索引12-14对应世界坐标的xyz平移量。,

