Skip to content

反走样 - TAAPost

一种3D渲染 抗锯齿 实现方案。3D渲染栅格化过程将显示对象按二位数组点阵的形式存储起来,得到的原始图像中物体边缘难免会有锯齿样。TAA 采用的方法为按照一定策略轻微的给相机设置一些偏移值,让物体在栅格化时会因不同的相机偏移值得到略微不同的结果。特别是在边缘的地方更为明显。最终输出到屏幕的颜色采用插值历史帧和当前帧的作为结果,且该结果用于下一次的插值。

ts
//初始化引擎
await Engine3D.init();

Engine3D.setting.render.postProcessing.taa.jitterSeedCount = 8;
Engine3D.setting.render.postProcessing.taa.blendFactor = 0.1;
Engine3D.setting.render.postProcessing.taa.sharpFactor = 0.6;
Engine3D.setting.render.postProcessing.taa.sharpPreBlurFactor = 0.5;
Engine3D.setting.render.postProcessing.taa.temporalJitterScale = 0.6;

//创建渲染器
let renderJob = new ForwardRenderJob(this.scene);
renderJob.addPost(new TAAPost());
Engine3D.startRender(renderJob);

Engine3D.setting.render.postProcessing.taa 配置参数。

参数类型描述
jitterSeedCountnumber抖动相机随机种子采用个数,默认8个。(降低个数可以解决一些抖动太明显的问题,但是锯齿会变得更明显)
blendFactornumber合并历史帧与当前帧的系数,参数越小,当前帧占比越小。
sharpFactornumber图像锐化系数[0.1,1.9]:系数越小锐化效果越弱抗锯齿效果好,反之锐化越强抗锯齿效果越弱。
sharpPreBlurFactornumber消图像锐化采样系数缩放系数:锐化时候采样的偏移量缩放。
temporalJitterScalenumber抖动相机随机偏移值的缩放系数[0,1]:系数越小抗锯齿效果变弱,像素抖动也会变弱。


Orillusion powered by WebGPU on Chrome/Edge 113+
Please upgrade to latest Chrome/Edge

<
ts
import {
	Camera3D, defaultTexture, DirectLight, Engine3D,
	ForwardRenderJob, GUIHelp, LitMaterial, HoverCameraController,
	KelvinUtil, MeshRenderer, Object3D, PlaneGeometry, Scene3D, SphereGeometry,
	 CameraUtil, webGPUContext, BoxGeometry, TAAPost
} from '@orillusion/core';

export class Sample_TAA {
	lightObj: Object3D;
	scene: Scene3D;
	constructor() { }

	async run() {
		Engine3D.setting.gi.enable = false;
		Engine3D.setting.shadow.enable = false;
		Engine3D.setting.shadow.debug = true;

		Engine3D.setting.shadow.shadowBound = 100;
		Engine3D.setting.shadow.shadowBias = 0.0002;
		await Engine3D.init({
			renderLoop: () => this.loop(),
		});

		GUIHelp.init();

		this.scene = new Scene3D();
		Camera3D.mainCamera = CameraUtil.createCamera3DObject(this.scene, 'camera');
		Camera3D.mainCamera.perspective(60, webGPUContext.aspect, 1, 5000.0);
		let ctrl = Camera3D.mainCamera.object3D.addComponent(HoverCameraController);
		ctrl.setCamera(0, -15, 20);
		await this.initScene();

		let renderJob = new ForwardRenderJob(this.scene);
		renderJob.addPost(new TAAPost());
		renderJob.debug();
		Engine3D.startRender(renderJob);
	}


	async initScene() {
		{
			this.lightObj = new Object3D();
			this.lightObj.rotationX = 15;
			this.lightObj.rotationY = 110;
			this.lightObj.rotationZ = 0;
			let lc = this.lightObj.addComponent(DirectLight);
			lc.lightColor = KelvinUtil.color_temperature_to_rgb(5355);
			lc.castShadow = true;
			lc.intensity = 10;
			this.scene.addChild(this.lightObj);
		}

		{
			let mat = new LitMaterial();
			mat.baseMap = defaultTexture.grayTexture;
			mat.normalMap = defaultTexture.normalTexture;
			mat.aoMap = defaultTexture.whiteTexture;
			mat.maskMap = defaultTexture.createTexture(32, 32, 255.0, 255.0, 0.0, 1);
			mat.emissiveMap = defaultTexture.blackTexture;
			mat.roughness = 1.0;
			mat.metallic = 0.0;

			let floor = new Object3D();
			let mr = floor.addComponent(MeshRenderer);
			mr.geometry = new PlaneGeometry(2000, 2000);
			mr.material = mat;
			this.scene.addChild(floor);
		}

		this.createPlane(this.scene);

	}

	private createPlane(scene: Scene3D) {
		let mat = new LitMaterial();
		mat.baseMap = defaultTexture.whiteTexture;
		mat.normalMap = defaultTexture.normalTexture;
		mat.aoMap = defaultTexture.whiteTexture;
		mat.maskMap = defaultTexture.createTexture(32, 32, 255.0, 10.0, 0.0, 1);
		mat.emissiveMap = defaultTexture.blackTexture;
		mat.roughness = 0.5;
		mat.roughness_max = 0.1;
		mat.metallic = 0.2;
		{
			let sphereGeometry = new SphereGeometry(1, 50, 50);
			let obj: Object3D = new Object3D();
			let mr = obj.addComponent(MeshRenderer);
			mr.material = mat;
			mr.geometry = sphereGeometry;
			obj.x = 10;
			obj.y = 2;
			scene.addChild(obj);
		}

		const length = 5;
		for (let i = 0; i < length; i++) {
			let cubeGeometry = new BoxGeometry(1, 10, 1);
			for (let j = 0; j < length; j++) {
				let obj: Object3D = new Object3D();
				let mr = obj.addComponent(MeshRenderer);
				mr.material = mat;
				mr.geometry = cubeGeometry;
				obj.localScale = obj.localScale;
				obj.x = (i - 2.5) * 4;
				obj.z = (j - 2.5) * 4;
				obj.y = 5;
				obj.rotationX = (Math.random() - 0.5) * 90;
				obj.rotationY = (Math.random() - 0.5) * 90;
				obj.rotationZ = (Math.random() - 0.5) * 90;
				scene.addChild(obj);
			}
		}
	}

	private loop(): void {
	}
}

new Sample_TAA().run();