Skip to content

Commit

Permalink
fix: make pick async to support impl in WebGPU #1400
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaoiver committed Jun 30, 2023
1 parent 26c8a5c commit d90c2d6
Show file tree
Hide file tree
Showing 9 changed files with 382 additions and 233 deletions.
148 changes: 148 additions & 0 deletions __tests__/unit/camera/camera.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
AdvancedCamera,
CameraProjectionMode,
Canvas,
ClipSpaceNearZ,
} from '../../../packages/g/src';

expect.extend({ toBeDeepCloseTo, toMatchCloseTo });
Expand Down Expand Up @@ -127,6 +128,153 @@ describe('Camera', () => {
expect(camera.getAzimuth()).toBe(0);
});

it('should create an orthoZO camera correctly', () => {
const width = 600;
const height = 500;
const camera = new AdvancedCamera();
camera.clipSpaceNearZ = ClipSpaceNearZ.ZERO;
camera
.setPosition(width / 2, height / 2, 500)
.setFocalPoint(width / 2, height / 2, 0)
.setOrthographic(
width / -2,
width / 2,
height / -2,
height / 2,
0.1,
1000,
);

expect(camera.getProjectionMode()).toBe(CameraProjectionMode.ORTHOGRAPHIC);
expect(camera.getZoom()).toBe(1);
expect(camera.getFar()).toBe(1000);
expect(camera.getNear()).toBe(0.1);
expect(camera.getPosition()).toStrictEqual(vec3.fromValues(300, 250, 500));
expect(camera.getFocalPoint()).toStrictEqual(vec3.fromValues(300, 250, 0));
expect(camera.getDistance()).toBe(500);

expect(camera.getViewTransform()).toStrictEqual(
mat4.fromValues(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -300, -250, -500, 1),
);
expect(camera.getWorldTransform()).toStrictEqual(
mat4.fromValues(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 300, 250, 500, 1),
);

expect(camera.getPerspective()).toBeDeepCloseTo(
mat4.fromValues(
0.0033333334140479565,
0,
0,
0,
-0,
0.004000000189989805,
-0,
-0,
0,
0,
-0.0020002000965178013,
0,
-0,
0,
-0.00010001000191550702,
1,
),
);
});

it('should create an perspective camera correctly', () => {
const width = 600;
const height = 500;
const camera = new AdvancedCamera();
camera
.setPosition(width / 2, height / 2, 500)
.setFocalPoint(width / 2, height / 2, 0)
.setPerspective(0.1, 1000, 45, width / height);

expect(camera.getProjectionMode()).toBe(CameraProjectionMode.PERSPECTIVE);
expect(camera.getZoom()).toBe(1);
expect(camera.getFar()).toBe(1000);
expect(camera.getNear()).toBe(0.1);
expect(camera.getPosition()).toStrictEqual(vec3.fromValues(300, 250, 500));
expect(camera.getFocalPoint()).toStrictEqual(vec3.fromValues(300, 250, 0));
expect(camera.getDistance()).toBe(500);

expect(camera.getViewTransform()).toStrictEqual(
mat4.fromValues(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -300, -250, -500, 1),
);
expect(camera.getWorldTransform()).toStrictEqual(
mat4.fromValues(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 300, 250, 500, 1),
);

expect(camera.getPerspective()).toBeDeepCloseTo(
mat4.fromValues(
2.0118446350097656,
0,
0,
0,
-0,
-2.4142136573791504,
-0,
-0,
0,
0,
-1.0002000331878662,
-1,
-0,
0,
-0.20002000033855438,
0,
),
);
});

it('should create an perspectiveZO camera correctly', () => {
const width = 600;
const height = 500;
const camera = new AdvancedCamera();
camera.clipSpaceNearZ = ClipSpaceNearZ.ZERO;
camera
.setPosition(width / 2, height / 2, 500)
.setFocalPoint(width / 2, height / 2, 0)
.setPerspective(0.1, 1000, 45, width / height);

expect(camera.getProjectionMode()).toBe(CameraProjectionMode.PERSPECTIVE);
expect(camera.getZoom()).toBe(1);
expect(camera.getFar()).toBe(1000);
expect(camera.getNear()).toBe(0.1);
expect(camera.getPosition()).toStrictEqual(vec3.fromValues(300, 250, 500));
expect(camera.getFocalPoint()).toStrictEqual(vec3.fromValues(300, 250, 0));
expect(camera.getDistance()).toBe(500);

expect(camera.getViewTransform()).toStrictEqual(
mat4.fromValues(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -300, -250, -500, 1),
);
expect(camera.getWorldTransform()).toStrictEqual(
mat4.fromValues(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 300, 250, 500, 1),
);

expect(camera.getPerspective()).toBeDeepCloseTo(
mat4.fromValues(
2.0118446350097656,
0,
0,
0,
-0,
-2.4142136573791504,
-0,
-0,
0,
0,
-1.0002000331878662,
-1,
-0,
0,
-0.10001000016927719,
0,
),
);
});

it('should setDistance correctly.', () => {
const width = 600;
const height = 500;
Expand Down
22 changes: 12 additions & 10 deletions packages/g-lite/src/camera/Camera.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,49 +36,51 @@ const MIN_DISTANCE = 0.0002;

export class Camera implements ICamera {
canvas: Canvas;
clipSpaceNearZ: ClipSpaceNearZ;

/**
* Clip space near Z, default to range `[-1, 1]`
*/
clipSpaceNearZ = ClipSpaceNearZ.NEGATIVE_ONE;

eventEmitter = new EventEmitter();

/**
* 相机矩阵
* Matrix of camera
*/
protected matrix = mat4.create();

/**
* u
* u axis +X is right
* @see http://learnwebgl.brown37.net/07_cameras/camera_introduction.html#a-camera-definition
*/
protected right = vec3.fromValues(1, 0, 0);

/**
* v +Y is down
* v axis +Y is up
*/
protected up = vec3.fromValues(0, 1, 0);

/**
* n +Z is inside
* n axis +Z is inside
*/
protected forward = vec3.fromValues(0, 0, 1);

/**
* 相机位置
* Position of camera.
*/
protected position = vec3.fromValues(0, 0, 1);

/**
* 视点位置
* Position of focal point.
*/
protected focalPoint = vec3.fromValues(0, 0, 0);

/**
* 视点到相机位置的向量
* focalPoint - position
* vector from focalPoint to position
*/
protected distanceVector = vec3.fromValues(0, 0, -1);

/**
* 相机位置到视点距离
* length(focalPoint - position)
*/
protected distance = 1;
Expand Down
19 changes: 11 additions & 8 deletions packages/g-lite/src/plugins/EventPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,17 @@ export class EventPlugin implements RenderingPlugin {

const canvas = this.context.renderingContext.root.ownerDocument.defaultView;

this.context.eventService.setPickHandler((position: EventPosition) => {
const { picked } = this.context.renderingService.hooks.pickSync.call({
position,
picked: [],
topmost: true, // we only concern the topmost element
});
return picked[0] || null;
});
this.context.eventService.setPickHandler(
async (position: EventPosition) => {
const { picked } =
await this.context.renderingService.hooks.pick.promise({
position,
picked: [],
topmost: true, // we only concern the topmost element
});
return picked[0] || null;
},
);

renderingService.hooks.pointerWheel.tap(
EventPlugin.tag,
Expand Down
Loading

0 comments on commit d90c2d6

Please sign in to comment.