diff --git a/packages/core/src/Camera.ts b/packages/core/src/Camera.ts
index cb26b35e42..b82ae00e4a 100644
--- a/packages/core/src/Camera.ts
+++ b/packages/core/src/Camera.ts
@@ -436,9 +436,9 @@ export class Camera extends Component {
 
     const transform = this.entity.transform;
     Matrix.multiply(this.projectionMatrix, this.viewMatrix, virtualCamera.viewProjectionMatrix);
-    virtualCamera.forward.copyFrom(transform.worldPosition);
+    virtualCamera.position.copyFrom(transform.worldPosition);
     if (virtualCamera.isOrthographic) {
-      transform.getWorldForward(virtualCamera.forward);
+      virtualCamera.forward.copyFrom(transform.worldForward);
     }
 
     context.camera = this;
diff --git a/packages/core/src/Transform.ts b/packages/core/src/Transform.ts
index 2426853c8d..867f3e8204 100644
--- a/packages/core/src/Transform.ts
+++ b/packages/core/src/Transform.ts
@@ -1,6 +1,6 @@
 import { MathUtil, Matrix, Matrix3x3, Quaternion, Vector3 } from "@oasis-engine/math";
 import { BoolUpdateFlag } from "./BoolUpdateFlag";
-import { assignmentClone, deepClone, ignoreClone } from "./clone/CloneManager";
+import { deepClone, ignoreClone } from "./clone/CloneManager";
 import { Component } from "./Component";
 import { Entity } from "./Entity";
 import { UpdateFlagManager } from "./UpdateFlagManager";
@@ -39,6 +39,13 @@ export class Transform extends Component {
   private _localMatrix: Matrix = new Matrix();
   @deepClone
   private _worldMatrix: Matrix = new Matrix();
+  @ignoreClone
+  private _worldForward: Vector3 = null;
+  @ignoreClone
+  private _worldRight: Vector3 = null;
+  @ignoreClone
+  private _worldUp: Vector3 = null;
+
   @ignoreClone
   private _isParentDirty: boolean = true;
   @ignoreClone
@@ -403,36 +410,33 @@ export class Transform extends Component {
   }
 
   /**
-   * Get the forward direction in world space.
-   * @param forward - Forward vector
-   * @returns Forward vector
+   * The forward direction in world space.
    */
-  getWorldForward(forward: Vector3): Vector3 {
+  get worldForward(): Vector3 {
+    const worldForward = (this._worldForward ||= new Vector3());
     const e = this.worldMatrix.elements;
-    forward.set(-e[8], -e[9], -e[10]);
-    return forward.normalize();
+    worldForward.set(-e[8], -e[9], -e[10]);
+    return worldForward.normalize();
   }
 
   /**
-   * Get the right direction in world space.
-   * @param right - Right vector
-   * @returns Right vector
+   * The right direction in world space.
    */
-  getWorldRight(right: Vector3): Vector3 {
+  get worldRight(): Vector3 {
+    const worldRight = (this._worldRight ||= new Vector3());
     const e = this.worldMatrix.elements;
-    right.set(e[0], e[1], e[2]);
-    return right.normalize();
+    worldRight.set(e[0], e[1], e[2]);
+    return worldRight.normalize();
   }
 
   /**
-   * Get the up direction in world space.
-   * @param up - Up vector
-   * @returns Up vector
+   * The up direction in world space.
    */
-  getWorldUp(up: Vector3): Vector3 {
+  get worldUp(): Vector3 {
+    const worldUp = (this._worldUp ||= new Vector3());
     const e = this.worldMatrix.elements;
-    up.set(e[4], e[5], e[6]);
-    return up.normalize();
+    worldUp.set(e[4], e[5], e[6]);
+    return worldUp.normalize();
   }
 
   /**
diff --git a/packages/core/src/lighting/DirectLight.ts b/packages/core/src/lighting/DirectLight.ts
index 5623f08a2f..4ad99bdb04 100644
--- a/packages/core/src/lighting/DirectLight.ts
+++ b/packages/core/src/lighting/DirectLight.ts
@@ -25,16 +25,13 @@ export class DirectLight extends Light {
     shaderData.setFloatArray(DirectLight._directionProperty, data.direction);
   }
 
-  private _forward: Vector3 = new Vector3();
-
   private _reverseDirection: Vector3 = new Vector3();
 
   /**
    * Get direction.
    */
   get direction(): Vector3 {
-    this.entity.transform.getWorldForward(this._forward);
-    return this._forward;
+    return this.entity.transform.worldForward;
   }
 
   /**
diff --git a/packages/core/src/lighting/SpotLight.ts b/packages/core/src/lighting/SpotLight.ts
index f35c1d6eec..0aee9ea1e8 100644
--- a/packages/core/src/lighting/SpotLight.ts
+++ b/packages/core/src/lighting/SpotLight.ts
@@ -44,7 +44,6 @@ export class SpotLight extends Light {
   /** Angle, in radians, from falloff begins to ends. */
   penumbra: number = Math.PI / 12;
 
-  private _forward: Vector3 = new Vector3();
   private _inverseDirection: Vector3 = new Vector3();
   private _projectMatrix: Matrix = new Matrix();
 
@@ -59,8 +58,7 @@ export class SpotLight extends Light {
    * Get light direction.
    */
   get direction(): Vector3 {
-    this.entity.transform.getWorldForward(this._forward);
-    return this._forward;
+    return this.entity.transform.worldForward;
   }
 
   /**
diff --git a/packages/core/src/shadow/CascadedShadowCasterPass.ts b/packages/core/src/shadow/CascadedShadowCasterPass.ts
index 218e2f8ebb..9a4845b78d 100644
--- a/packages/core/src/shadow/CascadedShadowCasterPass.ts
+++ b/packages/core/src/shadow/CascadedShadowCasterPass.ts
@@ -135,7 +135,8 @@ export class CascadedShadowCasterPass {
       lightSide.set(lightWorldE[0], lightWorldE[1], lightWorldE[2]);
       lightUp.set(lightWorldE[4], lightWorldE[5], lightWorldE[6]);
       lightForward.set(-lightWorldE[8], -lightWorldE[9], -lightWorldE[10]);
-      camera.entity.transform.getWorldForward(CascadedShadowCasterPass._tempVector);
+      const cameraForward = CascadedShadowCasterPass._tempVector;
+      cameraForward.copyFrom(camera.entity.transform.worldForward);
 
       const shadowTileResolution = this._shadowTileResolution;
 
@@ -144,7 +145,7 @@ export class CascadedShadowCasterPass {
           splitDistance[j],
           splitDistance[j + 1],
           camera,
-          CascadedShadowCasterPass._tempVector.normalize(),
+          cameraForward,
           shadowSliceData
         );
         ShadowUtils.getDirectionLightShadowCullPlanes(
@@ -202,7 +203,7 @@ export class CascadedShadowCasterPass {
           const { x, y } = viewports[j];
 
           rhi.setGlobalDepthBias(1.0, 1.0);
-      
+
           rhi.viewport(x, y, shadowTileResolution, shadowTileResolution);
           // for no cascade is for the edge,for cascade is for the beyond maxCascade pixel can use (0,0,0) trick sample the shadowMap
           rhi.scissor(x + 1, y + 1, shadowTileResolution - 2, shadowTileResolution - 2);
diff --git a/tests/src/core/Transform.test.ts b/tests/src/core/Transform.test.ts
new file mode 100644
index 0000000000..60f3c97b0d
--- /dev/null
+++ b/tests/src/core/Transform.test.ts
@@ -0,0 +1,26 @@
+import { MathUtil, Matrix, Ray, Vector2, Vector3, Vector4 } from "@oasis-engine/math";
+import { WebGLEngine } from "@oasis-engine/rhi-webgl";
+import { Camera, Entity } from "@oasis-engine/core";
+import { expect } from "chai";
+
+const canvasDOM = document.createElement("canvas");
+canvasDOM.width = 1024;
+canvasDOM.height = 1024;
+
+describe("Transform test", function () {
+  let entity: Entity;
+  before(() => {
+    const engine = new WebGLEngine(canvasDOM);
+    entity = engine.sceneManager.activeScene.createRootEntity();
+  });
+
+  it("World direction", () => {
+    const transform = entity.transform;
+    transform.position.set(1, -2, 3);
+    transform.rotate(0, 45, 0);
+
+    expect(transform.worldForward).to.deep.equal(new Vector3(-0.7071067811865476, -0, -0.7071067811865476));
+    expect(transform.worldRight).to.deep.equal(new Vector3(0.7071067811865476, 0, -0.7071067811865476));
+    expect(transform.worldUp).to.deep.equal(new Vector3(0, 1, 0));
+  });
+});