Three使用WebGPU的关键TSL

Three.js 使用 WebGPU 的关键 TSL

TSL: three.js shader language

介绍 three.js 材质转为webgpu的关键流程, 从而引出 TSL.

1、关键类关系

在这里插入图片描述

WebGPURenderer
    |-- library: StandardNodeLibrary
    |-- _nodes: Nodes
    |-- _objects: RenderObjects
    |-- createRenderObject()


StandardNodeLibrary extends NodeLibrary
    |-- materialNodes: Map
    |-- fromMaterial()

Nodes
  |-- backend: WebGPUBackend
  |-- needsRefresh()
  |-- getForRender()

RenderObjects

RenderObject
   |-- _nodes: Nodes
   |-- _monitor: NodeMaterialObserver
   |-- _nodeBuilderState: NodeBuilderState
   |-- getNodeBuilderState()
   |-- getMonitor()

WebGPUBackend

WGSLNodeBuilder
  |-- object: Mesh
  |-- stack: StackNode // 被代理
  |-- renderer: WebGPURenderer
  |-- cache: NodeCatche
  |-- build()


NodeFrame

NodeBuilderState
  |-- binding: BindGroup[]
  |-- updateNodes: NodeAttribute []
  |-- nodeAttributes: UniformNode []

NodeMaterialObserver
  |-- monitor: NodeMaterialObserver


NodeMaterial
  |-- build()
  |-- setup()


MeshBasicNodeMaterial extends NodeMaterial
2、执行流程
2.1 注册材质解析类

在创建 WebGPURenderer 时,会创建 StandardNodeLibrary。

StandardNodeLibrary.addMaterial( MeshBasicNodeMaterial, 'MeshBasicMaterial' );
2.2 创建 WGSLNodeBuilder

这个 WGSLNodeBuilder 是和 Mesh 一一对应。

WebGPURenderer.render()._renderObjectDirect()
  // step1: 创建 RenderObject
  const renderObject: RenderObject = this._objects.get();

  // step2: 创建 WGSLNodeBuilder
  this._nodes.needsRefresh( renderObject );

详细调用过程:

Nodes.needsRefresh() {
  const monitor = renderObject.getMonitor();
}

RenderObject.getMonitor() {
  return this._monitor = this.getNodeBuilderState().monitor;
}

RenderObject.getNodeBuilderState() {
  return this._nodeBuilderState = this._nodes.getForRender();
}

Nodes.getForRender() {
  const nodeBuilder: WGSLNodeBuilder = this.backend.createNodeBuilder();

  nodeBuilder.build();
}
2.3 开始构建
// 书接上文, 创建后开始构建
nodeBuilder.build() {
  // 根据材质类型,获取对应的 NodeMaterial
  let nodeMaterial = renderer.library.fromMaterial( material );

	if ( nodeMaterial === null ) {
    console.error( `NodeMaterial: Material "${ material.type }" is not compatible.` );
    nodeMaterial = new NodeMaterial();
  }
  nodeMaterial.build( this );
}

这里以MeshBasicMaterial为例, 那么nodeMaterial就是 MeshBasicNodeMaterial

NodeMaterial.build() {
  this.setup( this.nodeBuilder );
}

NodeMaterial.setup() {
  const vertexNode = this.setupVertex()
}

NodeMaterial.setupVertex() {
  return modelViewProjection;
}

// modelViewProjection 被引入:
import { modelViewProjection } from '../../nodes/accessors/ModelViewProjectionNode.js';

至此, 就拉开了 TSL 的序幕。

附录、测试例子
<html lang="en">

	<body>

		<div id="container"></div>
		<script type="importmap">
			{
				"imports": {
					"three": "../build/three.webgpu.js",
					"three/webgpu": "../build/three.webgpu.js",
					"three/tsl": "../build/three.tsl.js",
					"three/addons/": "./jsm/"
				}
			}
		</script>

		<script type="module">

			import * as THREE from 'three';

			import Stats from 'three/addons/libs/stats.module.js';

			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
			import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

			let container, stats;
			let camera, scene, renderer;
			let controls, water, sun, mesh;

			init();

			function init() {

				container = document.getElementById('container');

				//

				renderer = new THREE.WebGPURenderer();
				renderer.setPixelRatio(window.devicePixelRatio);
				renderer.setSize(window.innerWidth, window.innerHeight);
				renderer.setAnimationLoop(animate);
				renderer.toneMapping = THREE.ACESFilmicToneMapping;
				renderer.toneMappingExposure = 0.5;
				container.appendChild(renderer.domElement);
				window.renderer = renderer;
				//

				scene = new THREE.Scene();

				camera = new THREE.PerspectiveCamera(55, window.innerWidth / window.innerHeight, 1, 20000);
				camera.position.set(30, 30, 100);

				const waterGeometry = new THREE.PlaneGeometry( 100, 100 );
				mesh = new THREE.Mesh(waterGeometry, new THREE.MeshBasicMaterial({
					color: 0x00ff00
				}));
				scene.add(mesh)
			}

			function onWindowResize() {

				camera.aspect = window.innerWidth / window.innerHeight;
				camera.updateProjectionMatrix();

				renderer.setSize(window.innerWidth, window.innerHeight);

			}

			function animate() {
				render();
			}

			function render() {

				const time = performance.now() * 0.001;

				renderer.render(scene, camera);

			}

		</script>
	</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值