Skip to content

Commit cbe0e94

Browse files
committed
feat(拼接模式): update
1 parent 873aff7 commit cbe0e94

File tree

7 files changed

+114
-61
lines changed

7 files changed

+114
-61
lines changed

packages/拼接模式/article.md

Lines changed: 102 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -615,7 +615,7 @@ uniform1i
615615
## 概述解决方案
616616

617617
- 将支持各种功能的默认GLSL分解为多个小块
618-
- 用户实现GLSL的JSON配置文件,指定如何组合小块的GLSL,以及指定在渲染时需要发送的顶点数据和Uniform数据的配置数据
618+
- 用户实现GLSL的JSON配置文件,指定如何拼接小块的GLSL,以及指定在渲染时需要发送的顶点数据和Uniform数据的配置数据
619619

620620

621621
## 给出UML?
@@ -631,37 +631,45 @@ Client是用户
631631

632632
我们看下数据和ChunkConverter这两个部分:
633633

634-
GLSL Config是的GLSL的JSON配置文件,它的内容由用户给出,它的格式(也就是类型)由ChunkHandler定义
634+
Target GLSL是支持某些功能的一套GLSL,相当于之前的BasicMaterialShaderGLSL(Add Define)或者PBRMaterialShaderGLSL(Add Define),两者的区别是Target GLSL没有预定义的宏,它只有支持的功能的GLSL,没有分支
635+
一套Target GLSL包括了一个VS GLSL和一个FS GLSL
636+
这里最多可有8套Target GLSL,分别对应基础材质的4种情况和PBR材质的4种情况
637+
638+
639+
Send Config是如何获得和发送顶点数据和Uniform数据的配置数据
640+
具体来说,每个Send Config包括了多个getData函数和多个sendData函数,前者获得对应的顶点数据或者Uniform数据,后者发送它们
641+
因为一个Send Config对应一套Target GLSL,所以最多有8个Send Config
642+
643+
644+
645+
646+
647+
GLSL Config是的GLSL的JSON配置文件,用来指定如何拼接Target GLSL,并包括了Send Config
648+
它的内容由用户给出,它的格式(也就是类型)由ChunkHandler定义
649+
635650

636651
GLSL Chunk是一小块的GLSL,有多个GLSL Chunk,它们由引擎给出
637652
一个GLSL Chunk可以是VS GLSL中一小块GLSL文件(如common_vertex.glsl),也可以是FS GLSL中一小块GLSL文件(common_fragment.glsl)
638653

639654

655+
ChunkConverter负责转换GLSL Chunk
640656
因为GLSL Chunk是自定义文件,有一些自定义的语法,不能直接使用,所以引擎需要调用gulp任务来对其预处理。
641657
在gulp任务中,调用了ChunkConverter来处理所有的GLSL Chunk,并将其合并为一个Merged GLSL Chunk,成为一个Typescript或者Rescript文件
642658
<!-- 这样做的原因是GLSL Chunk是自定义的文件,不能直接被Typescript或者Rescript调用,所以需要将其转换为可被调用文件;另外,需要将其集中在一个文件中,方便管理 -->
643659

644660

645-
Send Config是一个Shader的获得和发送顶点数据和Uniform数据的配置数据
646-
具体来说,每个Send Config包括了多个getData函数和多个sendData函数,前者获得对应的顶点数据或者Uniform数据,后者发送它们
647-
因为这里最多有8个Shader,所以最多有8个Send Config
648-
649661

650-
Target GLSL是支持某些功能的一套GLSL,相当于之前的BasicMaterialShaderGLSL(Add Define)或者PBRMaterialShaderGLSL(Add Define),两者的区别是Target GLSL没有预定义的宏,它只有支持的功能的GLSL,没有分支
651-
一套Target GLSL包括了一个VS GLSL和一个FS GLSL
652-
这里最多可有8套Target GLSL,分别对应基础材质的4种情况和PBR材质的4种情况
653662

663+
我们看下ChunkHandler和引擎这两个部分:
654664

665+
ChunkHandler负责拼接Target GLSL和获得Send Config
655666

656-
我们看下引擎和ChunkHandler这两个部分:
657667

658668
Engine、Render跟之前一样
659669
<!-- Engine是引擎的门户,负责封装API给Client -->
660670
<!-- Engine有一个EngineState,用来保存引擎的所有数据; -->
661671

662672
InitMaterialShader负责初始化所有材质的Shader,它有两个函数:initBasicMaterialShader、initPBRMaterialShader,分别负责初始化所有基础材质的Shader和初始化所有PBR材质的Shader
663-
664-
665673
这两个函数遍历了所有的基础材质或者PBR材质,在每次遍历中的步骤一样,具体步骤如下:
666674
通过调用ChunkHandler的buildGLSL函数,按照GLSL Config的配置数据将Merged GLSL Chunk中对应的GLSL Chunk拼接为一个Target GLSL,然后使用它创建材质使用的shaderIndex和program;
667675
通过调用ChunkHandler的getSendConfig函数,从GLSL Config中获得Send Config
@@ -711,7 +719,7 @@ shader_chunks.json是一个数组,其中的每个元素定义了一套GLSL Chu
711719

712720

713721
这两个文件的关系是“总-分”的关系,具体如下:
714-
因为每种Shader的GLSL由多个GLSL Chunk组合而成,所以shaders.json是“总”,shader_chunks.json是“分”
722+
因为每种Shader的GLSL由多个GLSL Chunk组合拼接而成,所以shaders.json是“总”,shader_chunks.json是“分”
715723

716724

717725
下面我们来看下这两个文件的主要代码:
@@ -821,7 +829,7 @@ shaders字段定义了所有种类的Shader的GLSL配置数据
821829
值得说明的是:
822830
实际上也存在没有材质的Shader,如后处理(如绘制轮廓)的Shader、天空盒的Shader等,这些种类的Shader也定义在shaders字段,只是没有对应材质而已。这种Shader我们会在后面的扩展中讨论
823831

824-
每种Shader的GLSL由多个GLSL Chunk组合而成,它们定义在shader_chunks字段中
832+
每种Shader的GLSL由多个GLSL Chunk组合拼接而成,它们定义在shader_chunks字段中
825833
<!-- groups字段定义了多组GLSL Chunk,每组的value字段包括了多个GLSL Chunk,它们跟shader_chunks.json的name关联 -->
826834
<!-- 此处定义了一个名为render_basic的Shader,它包括的所有的代码块定义在shader_chunks字段中。 -->
827835
在shader_chunks字段中,如果type为static_branch,那么就通过name关联到static_branchs字段;
@@ -990,7 +998,7 @@ export let createState = ([shaders, shaderChunks]): state => {
990998

991999

9921000
引擎定义的GLSL Chunk具体是后缀名为.glsl的文件
993-
我们通过自定义的字符:@top@define@varDeclare@funcDeclare@funcDefine@body以及对应的@end将一个完整的GLSL分割为从上往下的不同区域的的代码片段,这样便于更细粒度的组合
1001+
我们通过自定义的字符:@top@define@varDeclare@funcDeclare@funcDefine@body以及对应的@end将一个完整的GLSL分割为从上往下的不同区域的代码片段,这样便于更细粒度的组合拼接
9941002

9951003
一个GLSL Chunk可以包括多个区域的代码片段
9961004

@@ -1236,7 +1244,7 @@ _initOneMaterialTypeShader函数在遍历所有的基础材质时,首先调用
12361244
<!-- 值得说明的是: -->
12371245
ChunkHandler的buildGLSL函数和getSendConfig函数都接受了引擎实现的函数,它们被用于处理shaders.json和shader_chunks.json中的一些字段,从而实现分支处理或者从中获得Send Config
12381246

1239-
因为这些字段的值是离散的,它们的的范围是引擎定义的,用户只能从范围内选择某个具体的值,所以这些字段的类型是定义在引擎端,类型中明确了有哪些值的范围
1247+
因为这些字段的值是离散的,它们的范围是引擎定义的,用户只能从范围内选择某个具体的值,所以这些字段的类型是定义在引擎端,在类型中明确了有哪些值的范围
12401248
<!-- 具体是定义在引擎的GLSLConfigType.ts中,代码如下: -->
12411249
类型定义的部分代码如下:
12421250
GLSLConfigType
@@ -1402,84 +1410,129 @@ let _sendUniformData = (uniformSendConfig: Array<uniformSendConfig>, state: stat
14021410
## 一句话定义?
14031411

14041412

1405-
TODO continue
1406-
14071413
<!-- 可配置地拼接小块数据 -->
14081414

1409-
分解包括各种分支的大数据为小块单位,按照配置文件来拼接
1415+
分解有各种分支的大数据为多个小块数据,按照配置文件来拼接
14101416

14111417

14121418
## 补充说明
14131419

1414-
把每个分支对应的数据都对应分解为一块数据;
1420+
大数据中的每个分支都可以分解为一块数据,如有下面的一个大数据:
1421+
```ts
1422+
#ifdef INSTANCE
1423+
数据1
1424+
#endif
1425+
1426+
#ifdef NO_INSTANCE
1427+
数据2
1428+
#endif
1429+
```
1430+
它有两个分支,可以将其分解为数据1、数据2这两个小块数据
14151431

1416-
由用户给出配置文件来指定:有哪些分支、要构造哪些Target数据、每个Target数据包括哪些块、每块有哪些配置数据
1432+
1433+
配置文件由用户给出,包括下面的内容:
1434+
有哪些分支、要构造哪些Target数据、每个Target数据包括哪些块、每块有哪些配置数据
14171435

14181436

14191437

14201438

14211439
## 通用UML?
1422-
![image](https://img2023.cnblogs.com/blog/419321/202304/419321-20230403163737312-1241675852.png)
1440+
TODO tu
14231441

14241442

14251443

14261444
## 分析角色?
14271445

14281446
我们来看看模式的相关角色:
14291447

1430-
TODO rename Main to System
1448+
总体来看,分为数据、ChunkConverter、ChunkHandler、系统这四个部分
1449+
1450+
1451+
我们看下数据和ChunkConverter这两个部分:
1452+
1453+
1454+
- Target
1455+
该角色是拼接后的符合某种特定分支条件的数据,如[支持方向光,支持贴图,支持Instance]的GLSL就是一个Target
1456+
1457+
- Runtime Config
1458+
该角色是如何操作运行时数据的配置数据
1459+
具体来说,每个Runtime Config包括了多个getData函数和多个sendData函数,前者获得对应的运行时数据,后者发送它们
1460+
<!-- 因为一个Send Config对应一个Shader,而这里最多有8个Shader,所以最多有8个Send Config -->
1461+
1462+
<!-- ,它在初始化时从Target Config中获得,在运行时被使用 -->
1463+
14311464

14321465

1433-
TODO rename Runtime Data to Runtime Config
14341466

14351467
- Target Config
1436-
该角色是配置数据,用来指定如何拼接数据
1468+
该角色是配置数据,用来指定如何拼接Target,并包括了Runtime Config
1469+
它的内容由用户给出,它的格式(也就是类型)由ChunkHandler定义
1470+
Target Config中某些字段的值是离散的,它们的范围是系统定义的,用户只能从范围内选择某个具体的值
14371471

14381472
- Target Chunk
1439-
该角色是小块的数据,它是通过对原始的大数据抽象分解后得到的,一般来说大数据中的一个分支对应一个Target Chunk数据
1473+
该角色是小块的数据,由系统给出
1474+
<!-- 它是通过对原始的大数据抽象分解后得到的,一般来说大数据中的一个分支对应一个Target Chunk数据 -->
14401475

1441-
- Merged Target Chunk
1442-
该角色是合并了所有的Target Chunk后的数据,它将所有的Target Chunk文件合并为一个Hash Map
14431476

1444-
- Target
1445-
该角色是拼接后的符合某种特定分支条件的数据,如[支持方向光,支持贴图,支持Instance]的GLSL
14461477

1447-
- Runtime Data
1448-
该角色是运行时数据,它在初始化时从Target Config中获得,在运行时被使用
14491478

14501479
- ChunkConverter
1451-
该角色负责在预处理时合并所有的Target Chunk为一个Merged Target Chunk文件
1480+
该角色负责在系统预处理处理Target Chunk,并将其合并为一个Merged Target Chunk
1481+
1482+
1483+
- Merged Target Chunk
1484+
该角色是合并了所有的Target Chunk后的数据,它是一个Typescript或者Rescript文件
1485+
1486+
1487+
1488+
我们看下ChunkHandler和系统这两个部分:
14521489

14531490
- ChunkHandler
1454-
该角色定义了Target Config的格式(也就是类型),并且实现了拼接Target和获得Runtime Data的相关函数
1491+
该角色负责拼接Target和获得Runtime Config
14551492

1456-
- Main
1493+
- System
14571494
该角色为系统的门户,提供API给Client
14581495

14591496
- Init
1460-
该角色实现系统的初始化,调用ChunkHandler->buildTarget来拼接了Target并且直接使用它,调用ChunkHandler->getRuntimeData来获得了Runtime Data
1497+
该角色实现系统的初始化,它包括下面的步骤:
1498+
调用ChunkHandler的buildTarget函数,按照Target Config的配置数据将Merged Target Chunk中对应的Target Chunk拼接为一个Target,然后使用它;
1499+
调用ChunkHandler的getRuntimeConfig函数,从Target Config中获得Runtime Config
14611500

14621501
- OperateWhenRuntime
1463-
该角色进行某个在运行时的操作,使用了Runtime Data
1502+
该角色在运行时进行某个操作(如渲染),使用了Runtime Config
1503+
1504+
1505+
1506+
<!-- ## 与之前构造GLSL案例的UML的区别
1507+
1508+
TODO -->
14641509

14651510

14661511
## 角色之间的关系?
14671512

1468-
- 应该有多个Target Chunk,它们由系统给出
1513+
- 有多个Target Chunk
14691514

1470-
- Target Config的格式由ChunkHandler定义。其中由系统处理的字段的类型由系统再次定义,目的是定义这些字段的所有可能的值
1515+
<!-- - Target Config的格式由ChunkHandler定义。其中由系统处理的字段的类型由系统再次定义,目的是定义这些字段的所有可能的值 -->
14711516

1472-
- Target Config的内容由Client给出
1517+
<!-- - Target Config的内容由Client给出 -->
14731518

14741519
- Target Config通常包含两个配置文件:targets_config、chunks_config
1520+
这两个文件的关系是“总-分”的关系,其中targets_config是“总”,chunks_config是“分”
14751521

1476-
- 应该有多个Target,如[支持方向光,支持贴图,支持Instance]的GLSL和[支持方向光,不支持贴图,支持Instance]的GLSL
1522+
- 有多个Target,如[支持方向光,支持贴图,支持Instance]的GLSL是一个Target,[支持方向光,不支持贴图,支持Instance]的GLSL是另外一个Target
14771523

1524+
- 有多个Runtime Config,一个Runtime Config对应一个Target
14781525

14791526
## 角色的抽象代码?
14801527

1528+
1529+
值得注意的是:
1530+
这里只考虑了一个Target和一个Runtime Config的情况,因此Init中也没有进行遍历
1531+
1532+
14811533
下面我们来看看各个角色的抽象代码:
14821534

1535+
TODO continue
14831536

14841537
- 一个Target Chunk的抽象代码
14851538
```ts
@@ -1659,7 +1712,7 @@ state = operateWhenRuntime(state)
16591712
```ts
16601713
declare function _handleConfigFunc1(state: state, someConfigData): any
16611714
1662-
declare function _addRuntimeDataFunc1(someRuntimeDataFromState, someConfigData): any
1715+
declare function _addRuntimeConfigFunc1(someRuntimeConfigFromState, someConfigData): any
16631716
16641717
export let parseConfig = ChunkHandler.parseConfig
16651718
@@ -1683,21 +1736,21 @@ export let init = (state: state, someConfigData): state => {
16831736
16841737
console.log("使用target...")
16851738
1686-
let runtimeData = ChunkHandler.getRuntimeData(
1687-
[_addRuntimeDataFunc1, ... ],
1739+
let runtimeConfig = ChunkHandler.getRuntimeConfig(
1740+
[_addRuntimeConfigFunc1, ... ],
16881741
16891742
target
16901743
)
16911744
16921745
return {
16931746
...state,
16941747
target: target,
1695-
runtimeData: runtimeData
1748+
runtimeConfig: runtimeConfig
16961749
}
16971750
}
16981751
16991752
export let operateWhenRuntime = (state: state): state => {
1700-
console.log("使用state.runtimeData...")
1753+
console.log("使用state.runtimeConfig...")
17011754
17021755
return state
17031756
}
@@ -1711,9 +1764,9 @@ type target = any
17111764
17121765
export declare function buildTarget(handleConfigFuncs, parsedConfig: config, targetChunk, someConfigData): target
17131766
1714-
type runtimeData = any
1767+
type runtimeConfig = any
17151768
1716-
export declare function getRuntimeData(addRuntimeDataFuncs, target: target): runtimeData
1769+
export declare function getRuntimeConfig(addRuntimeConfigFuncs, target: target): runtimeConfig
17171770
```
17181771

17191772

@@ -1734,7 +1787,7 @@ TODO finish
17341787
拼接后的Target数据没有分支判断,非常精简
17351788

17361789
- 提高性能
1737-
系统能够在初始化时一次性从配置文件中获得Runtime Data,然后在运行时无需进行分支判断而是直接发送Runtime Data,这样就提高了性能
1790+
系统能够在初始化时一次性从配置文件中获得Runtime Config,然后在运行时无需进行分支判断而是直接发送Runtime Config,这样就提高了性能
17381791

17391792

17401793

0 commit comments

Comments
 (0)