Skip to content

Commit

Permalink
fix: support 2 kinds of clip z range #863
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaoiver committed Jun 29, 2023
1 parent a0e71bc commit 26c8a5c
Show file tree
Hide file tree
Showing 12 changed files with 156 additions and 44 deletions.
9 changes: 8 additions & 1 deletion packages/g-lite/src/AbstractRenderer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { CanvasContext } from './dom';
import { GlobalRuntime } from './global-runtime';
import type { RenderingPlugin } from './services';
import type { RendererConfig } from './types';
import { ClipSpaceNearZ, RendererConfig } from './types';

export interface RendererPlugin {
name: string;
Expand Down Expand Up @@ -36,6 +36,12 @@ export abstract class AbstractRendererPlugin<T = any>
}

export interface IRenderer {
/**
* The near/far clip planes correspond to a normalized device coordinate Z range of [0, 1],
* which matches WebGPU/Vulkan/DirectX/Metal's clip volume, while [-1, 1] matches WebGL/OpenGL's clip volume.
*/
clipSpaceNearZ: ClipSpaceNearZ;

getConfig: () => RendererConfig;

/**
Expand All @@ -60,6 +66,7 @@ export interface IRenderer {
}

export class AbstractRenderer implements IRenderer {
clipSpaceNearZ = ClipSpaceNearZ.NEGATIVE_ONE;
private plugins: RendererPlugin[] = [];
private config: RendererConfig;

Expand Down
16 changes: 13 additions & 3 deletions packages/g-lite/src/Canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ import { FrustumCullingStrategy } from './plugins/FrustumCullingStrategy';
import { PrepareRendererPlugin } from './plugins/PrepareRendererPlugin';
import { EventService, RenderReason, RenderingService } from './services';
import type { PointLike } from './shapes';
import type { CanvasConfig, Cursor, InteractivePointerEvent } from './types';
import type {
CanvasConfig,
ClipSpaceNearZ,
Cursor,
InteractivePointerEvent,
} from './types';
import {
caf,
cleanExistedCanvas,
Expand Down Expand Up @@ -227,7 +232,7 @@ export class Canvas extends EventTarget implements ICanvas {
alwaysTriggerPointerEventOnCanvas,
});

this.initDefaultCamera(canvasWidth, canvasHeight);
this.initDefaultCamera(canvasWidth, canvasHeight, renderer.clipSpaceNearZ);

this.initRenderer(renderer, true);
}
Expand All @@ -251,9 +256,14 @@ export class Canvas extends EventTarget implements ICanvas {
};
}

private initDefaultCamera(width: number, height: number) {
private initDefaultCamera(
width: number,
height: number,
clipSpaceNearZ: ClipSpaceNearZ,
) {
// set a default ortho camera
const camera = new runtime.CameraContribution();
camera.clipSpaceNearZ = clipSpaceNearZ;

camera
.setType(CameraType.EXPLORING, CameraTrackingMode.DEFAULT)
Expand Down
10 changes: 8 additions & 2 deletions packages/g-lite/src/camera/Camera.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { vec2 } from 'gl-matrix';
import { mat3, mat4, quat, vec3, vec4 } from 'gl-matrix';
import type { Canvas } from '../Canvas';
import { Frustum } from '../shapes';
import type { TypeEasingFunction } from '../types';
import { ClipSpaceNearZ, TypeEasingFunction } from '../types';
import { ERROR_MSG_METHOD_NOT_IMPLEMENTED } from '../utils/error';
import {
createVec3,
Expand Down Expand Up @@ -36,6 +36,7 @@ const MIN_DISTANCE = 0.0002;

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

eventEmitter = new EventEmitter();

Expand Down Expand Up @@ -490,6 +491,7 @@ export class Camera implements ICamera {
top - height,
near,
this.far,
this.clipSpaceNearZ === ClipSpaceNearZ.ZERO,
);
// flipY since the origin of OpenGL/WebGL is bottom-left compared with top-left in Canvas2D
mat4.scale(
Expand Down Expand Up @@ -542,7 +544,11 @@ export class Camera implements ICamera {
bottom = top - scaleH * this.view.height;
}

mat4.ortho(this.projectionMatrix, left, right, bottom, top, near, far);
if (this.clipSpaceNearZ === ClipSpaceNearZ.NEGATIVE_ONE) {
mat4.ortho(this.projectionMatrix, left, right, bottom, top, near, far);
} else {
mat4.orthoZO(this.projectionMatrix, left, right, bottom, top, near, far);
}

// flipY since the origin of OpenGL/WebGL is bottom-left compared with top-left in Canvas2D
mat4.scale(
Expand Down
5 changes: 5 additions & 0 deletions packages/g-lite/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,11 @@ export type Cursor =
| 'zoom-in'
| 'zoom-out';

export enum ClipSpaceNearZ {
ZERO,
NEGATIVE_ONE,
}

export interface RendererConfig {
/**
* enable dirty check for displayobject
Expand Down
14 changes: 12 additions & 2 deletions packages/g-lite/src/utils/math.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,14 +222,24 @@ export function makePerspective(
bottom: number,
near: number,
far: number,
zero = false,
) {
const x = (2 * near) / (right - left);
const y = (2 * near) / (top - bottom);

const a = (right + left) / (right - left);
const b = (top + bottom) / (top - bottom);
const c = -(far + near) / (far - near);
const d = (-2 * far * near) / (far - near);

let c: number;
let d: number;

if (zero) {
c = -far / (far - near);
d = (-far * near) / (far - near);
} else {
c = -(far + near) / (far - near);
d = (-2 * far * near) / (far - near);
}

out[0] = x;
out[1] = 0;
Expand Down
37 changes: 22 additions & 15 deletions packages/g-plugin-device-renderer/src/RenderGraphPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
SwapChain,
Texture,
TextureDescriptor,
TransparentBlack,
TransparentWhite,
} from './platform';
import {
Expand Down Expand Up @@ -240,20 +241,26 @@ export class RenderGraphPlugin implements RenderingPlugin {
const renderInstManager = this.renderHelper.renderInstManager;
this.builder = this.renderHelper.renderGraph.newGraphBuilder();

// use canvas.background
const backgroundColor = parseColor(
this.context.config.background,
) as CSSRGB;
const clearColor = this.context.config.background
? // use premultipliedAlpha
// @see https://canvatechblog.com/alpha-blending-and-webgl-99feb392779e
colorNewFromRGBA(
(Number(backgroundColor.r) / 255) * Number(backgroundColor.alpha),
(Number(backgroundColor.g) / 255) * Number(backgroundColor.alpha),
(Number(backgroundColor.b) / 255) * Number(backgroundColor.alpha),
Number(backgroundColor.alpha),
)
: TransparentWhite;
let clearColor;
if (this.context.config.background === 'transparent') {
clearColor = TransparentBlack;
} else {
// use canvas.background
const backgroundColor = parseColor(
this.context.config.background,
) as CSSRGB;

clearColor = this.context.config.background
? // use premultipliedAlpha
// @see https://canvatechblog.com/alpha-blending-and-webgl-99feb392779e
colorNewFromRGBA(
(Number(backgroundColor.r) / 255) * Number(backgroundColor.alpha),
(Number(backgroundColor.g) / 255) * Number(backgroundColor.alpha),
(Number(backgroundColor.b) / 255) * Number(backgroundColor.alpha),
Number(backgroundColor.alpha),
)
: TransparentWhite;
}

// retrieve at each frame since canvas may resize
const renderInput = {
Expand Down Expand Up @@ -328,7 +335,7 @@ export class RenderGraphPlugin implements RenderingPlugin {
setAttachmentStateSimple(
{
depthWrite: true,
blendConstant: TransparentWhite,
blendConstant: TransparentBlack,
},
{
rgbBlendMode: BlendMode.Add,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
StencilOp,
TextureDimension,
} from '../interfaces';
import { colorCopy, colorNewCopy, TransparentWhite } from './color';
import { colorCopy, colorNewCopy, TransparentBlack } from './color';
// import { reverseDepthForCompareMode } from './depth';

export function isPowerOfTwo(n: number): boolean {
Expand Down Expand Up @@ -231,7 +231,7 @@ export const defaultMegaState: MegaStateDescriptor = {
},
],

blendConstant: colorNewCopy(TransparentWhite),
blendConstant: colorNewCopy(TransparentBlack),
depthWrite: true,
depthCompare: CompareMode.LessEqual,
// depthCompare: reverseDepthForCompareMode(CompareMode.LessEqual),
Expand Down
2 changes: 1 addition & 1 deletion packages/g-plugin-device-renderer/src/shader/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ layout(set = ${set}, binding = ${binding++}) uniform sampler S_${samplerName};
});

rest = rest.replace(
type === 'frag' ? /^\b(varying|in)\b/gm : /^\b(varying|out)\b/gm,
type === 'frag' ? /^\s*\b\s*(varying|in)\b/gm : /^\s*\b(varying|out)\b/gm,
(substr, tok) => {
return `layout(location = ${location++}) ${tok}`;
},
Expand Down
2 changes: 0 additions & 2 deletions packages/g-plugin-webgpu-device/src/platform/RenderPass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
RenderPass,
RenderPassDescriptor,
RenderPipeline,
TransparentWhite,
} from '@antv/g-plugin-device-renderer';
import {
assert,
Expand Down Expand Up @@ -107,7 +106,6 @@ export class RenderPass_WebGPU implements RenderPass {
dstAttachment.loadOp = 'load';
} else {
dstAttachment.loadOp = 'clear';
console.log(clearColor, TransparentWhite);
dstAttachment.clearValue = clearColor;
}
dstAttachment.storeOp = descriptor.colorStore[i] ? 'store' : 'discard';
Expand Down
4 changes: 3 additions & 1 deletion packages/g-webgpu/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { RendererConfig } from '@antv/g-lite';
import { ClipSpaceNearZ, RendererConfig } from '@antv/g-lite';
import { AbstractRenderer } from '@antv/g-lite';
import * as DeviceRenderer from '@antv/g-plugin-device-renderer';
import * as DomInteraction from '@antv/g-plugin-dom-interaction';
Expand All @@ -15,6 +15,8 @@ interface WebGPURendererConfig extends RendererConfig {
}

export class Renderer extends AbstractRenderer {
clipSpaceNearZ = ClipSpaceNearZ.ZERO;

constructor(config?: Partial<WebGPURendererConfig>) {
super(config);

Expand Down
9 changes: 9 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

88 changes: 73 additions & 15 deletions site/examples/3d/3d-basic/demo/webgpu.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import { Canvas, CanvasEvent, Circle } from '@antv/g';
import {
Canvas,
CanvasEvent,
Circle,
Ellipse,
Rect,
Image,
Line,
Path,
} from '@antv/g';
import { Renderer as WebGPURenderer } from '@antv/g-webgpu';

import Stats from 'stats.js';
Expand All @@ -18,28 +27,77 @@ const canvas = new Canvas({

const circle = new Circle({
style: {
x: 250,
y: 250,
r: 250,
cx: 100,
cy: 100,
r: 50,
fill: 'green',
cursor: 'pointer',
},
});

// const icon = new Image({
// style: {
// x: 200,
// y: 200,
// z: 0,
// width: 200,
// height: 200,
// src: 'https://gw.alipayobjects.com/mdn/rms_6ae20b/afts/img/A*N4ZMS7gHsUIAAAAAAAAAAABkARQnAQ',
// isBillboard: true,
// },
// });
const ellipse = new Ellipse({
style: {
cx: 200,
cy: 100,
rx: 100,
ry: 50,
fill: 'red',
},
});

const rect = new Rect({
style: {
x: 300,
y: 100,
width: 100,
height: 50,
fill: 'blue',
stroke: 'yellow',
lineWidth: 2,
},
});

const line = new Line({
style: {
x1: 100,
y1: 200,
x2: 100,
y2: 400,
stroke: 'red',
lineWidth: 2,
},
});

const path = new Path({
style: {
transform: 'translate(200, 100) scale(10)',
d: 'M2 4C0.8954304997175604 3.9999999991219815 -1.3527075029566811e-16 4.895430499717561 0 6C0 6 0 9.9375 0 12C1.3527075029566811e-16 13.10456950028244 0.8954304997175604 14.00000000087802 2 14C8 14 10.25 14 14 14C15.104569499040734 13.99999999912198 16 13.104569499040734 16 12C16 9 16 7.875 16 6C16 4.895430500959266 15.104569499040734 4.0000000008780185 14 4C13.414 4 13.194249999999998 4 12.828 4C12.297610373455704 3.9998867247945213 11.788985462367364 3.7890987493850155 11.414 3.414C11 3 10.84475 2.8447500000000003 10.586 2.5860000000000003C10.211014537632636 2.210901250614985 9.702389626544296 2.0001132752054787 9.172 2.0000000000000004C8 2.0000000000000004 7.560500000000001 2.0000000000000004 6.828000000000001 2.0000000000000004C6.297610373455706 2.0001132752054787 5.788985462367367 2.210901250614985 5.4140000000000015 2.5860000000000003C5.000000000000002 3 4.844750000000001 3.1552499999999997 4.586000000000001 3.414C4.211014537632636 3.7890987493850155 3.7023896265442966 3.9998867247945213 3.1720000000000015 4C2.5860000000000016 4 2.3662500000000017 4 2.0000000000000018 4C2.000000000000001 4 2.000000000000001 4 2 4M10.5 8.5C10.5 6.575499102701247 8.416666666666666 5.372686041889527 6.75 6.334936490538903C5.976497308103742 6.781518477924107 5.5 7.606836025229591 5.5 8.5C5.5 10.424500897298753 7.583333333333334 11.627313958110474 9.25 10.665063509461097C10.023502691896258 10.218481522075892 10.5 9.39316397477041 10.5 8.5C10.5 8.5 10.5 8.5 10.5 8.5M2.5 6C2.1150998205402494 6.000000000305956 1.874537208444147 5.583333333830511 2.0669872979090567 5.2500000003442C2.1563036954051213 5.095299461648009 2.321367204761929 4.999999999858005 2.5 5C2.8849001794597506 5.000000000305956 3.125462791688336 5.416666667163845 2.933012701693495 5.7500000003442C2.8436963042354777 5.904700538406512 2.6786327946700927 5.999999999858005 2.5 6C2.5 6 2.5 6 2.5 6M11.5 8.5C11.5 11.194301256218253 8.583333333333334 12.878239541354663 6.250000000000001 11.531088913245537C5.167096231345241 10.90587413090625 4.5 9.750429564678573 4.5 8.5C4.5 5.805698743781747 7.416666666666667 4.121760458645338 9.75 5.468911086754464C10.832903768654761 6.094125869093751 11.5 7.249570435321427 11.5 8.5C11.5 8.5 11.5 8.5 11.5 8.5',
lineWidth: 1,
lineJoin: 'round',
stroke: '#54BECC',
cursor: 'pointer',
},
});

const image = new Image({
style: {
x: 200,
y: 200,
z: 0,
width: 200,
height: 200,
src: 'https://gw.alipayobjects.com/mdn/rms_6ae20b/afts/img/A*N4ZMS7gHsUIAAAAAAAAAAABkARQnAQ',
isBillboard: true,
},
});

canvas.addEventListener(CanvasEvent.READY, () => {
canvas.appendChild(circle);
canvas.appendChild(ellipse);
canvas.appendChild(rect);
canvas.appendChild(line);
canvas.appendChild(path);
canvas.appendChild(image);
});

// stats
Expand Down

0 comments on commit 26c8a5c

Please sign in to comment.