|
| 1 | +# [引入故事,提出问题] |
| 2 | + |
| 3 | +## 需求 |
| 4 | + |
| 5 | +甲想要实现3D引擎中的渲染,需要同时支持PC端、移动端 |
| 6 | + |
| 7 | +两个运行环境的差异如下所示: |
| 8 | + |
| 9 | +- PC端支持WebGL2,移动端只支持WebGL1 |
| 10 | +- PC端可以使用延迟渲染的算法来渲染,移动端因为不支持multi render targets,所以只能使用前向渲染的算法来渲染 |
| 11 | + |
| 12 | + |
| 13 | +## 实现思路 |
| 14 | + |
| 15 | +甲实现了一个Render模块,该模块实现了初始化WebGL、渲染、Tonemap后处理的逻辑 |
| 16 | + |
| 17 | +为了处理运行环境的差异,他的思路如下; |
| 18 | + |
| 19 | +- 在“初始化WebGL”中判断运行环境,如果是PC端就获得WebGL2的上下文,如果是移动端就获得WebGL1的上下文 |
| 20 | +- 在“渲染”中判断运行环境,如果是PC端就使用延迟渲染算法,如果是移动端就使用前向渲染算法 |
| 21 | +- 在“Tonemap”中判断运行环境,如果是PC端就使用WebGL2的上下文,如果是移动端就使用WebGL1的上下文 |
| 22 | + |
| 23 | + |
| 24 | + |
| 25 | +## 给出UML |
| 26 | + |
| 27 | +TODO tu |
| 28 | + |
| 29 | +Render实现了渲染 |
| 30 | + |
| 31 | + |
| 32 | +## 给出代码 |
| 33 | + |
| 34 | +Client |
| 35 | +```ts |
| 36 | +//假canvas |
| 37 | +let canvas = { |
| 38 | + getContext: (_) => 1 as any |
| 39 | +} |
| 40 | + |
| 41 | +//指定运行环境 |
| 42 | +globalThis.isPC = true |
| 43 | + |
| 44 | + |
| 45 | +let renderState = createState() |
| 46 | + |
| 47 | +renderState = render(renderState, canvas) |
| 48 | +``` |
| 49 | + |
| 50 | +我们首先创建了引擎的RenderState,保存渲染的所有数据; |
| 51 | +最后进行渲染 |
| 52 | + |
| 53 | +我们看下Renderd相关代码: |
| 54 | +RenderStateType |
| 55 | +```ts |
| 56 | +export type state = { |
| 57 | + gl: WebGLRenderingContext | WebGL2RenderingContext | null |
| 58 | +} |
| 59 | +``` |
| 60 | +Render |
| 61 | +```ts |
| 62 | +let _isPC = () => { |
| 63 | + console.log(globalThis.isPC ? "is PC" : "is mobile") |
| 64 | + |
| 65 | + return globalThis.isPC |
| 66 | +} |
| 67 | + |
| 68 | +let _initWebGL = (state, canvas) => { |
| 69 | + let gl = null |
| 70 | + |
| 71 | + if (_isPC()) { |
| 72 | + gl = canvas.getContext("webgl2") |
| 73 | + } |
| 74 | + else { |
| 75 | + gl = canvas.getContext("webgl1") |
| 76 | + } |
| 77 | + |
| 78 | + return { |
| 79 | + ...state, |
| 80 | + gl: gl |
| 81 | + } |
| 82 | +} |
| 83 | + |
| 84 | +let _render = (state) => { |
| 85 | + if (_isPC()) { |
| 86 | + let gl = getExnFromStrictNull(state.gl) as WebGL2RenderingContext |
| 87 | + |
| 88 | + console.log("延迟渲染") |
| 89 | + } |
| 90 | + else { |
| 91 | + let gl = getExnFromStrictNull(state.gl) as WebGLRenderingContext |
| 92 | + |
| 93 | + console.log("前向渲染") |
| 94 | + } |
| 95 | + |
| 96 | + return state |
| 97 | +} |
| 98 | + |
| 99 | +let _tonemap = (state) => { |
| 100 | + let gl = null |
| 101 | + |
| 102 | + if (_isPC()) { |
| 103 | + gl = getExnFromStrictNull(state.gl) as WebGL2RenderingContext |
| 104 | + } |
| 105 | + else { |
| 106 | + gl = getExnFromStrictNull(state.gl) as WebGLRenderingContext |
| 107 | + } |
| 108 | + |
| 109 | + console.log("tonemap") |
| 110 | + |
| 111 | + return state |
| 112 | +} |
| 113 | + |
| 114 | +export let createState = (): state => { |
| 115 | + return { |
| 116 | + gl: null |
| 117 | + } |
| 118 | +} |
| 119 | + |
| 120 | +export let render = (state: state, canvas) => { |
| 121 | + state = _initWebGL(state, canvas) |
| 122 | + state = _render(state) |
| 123 | + state = _tonemap(state) |
| 124 | + |
| 125 | + return state |
| 126 | +} |
| 127 | +``` |
| 128 | + |
| 129 | +在渲染的时候判断了运行环境,执行对应的逻辑 |
| 130 | + |
| 131 | + |
| 132 | +下面,我们运行代码,运行结果如下: |
| 133 | +```text |
| 134 | +is PC |
| 135 | +初始化WebGL2 |
| 136 | +延迟渲染 |
| 137 | +tonemap for WebGL2 |
| 138 | +``` |
| 139 | + |
| 140 | +因为这里指定环境为PC端,所以执行的是PC端的渲染逻辑 |
| 141 | + |
| 142 | + |
| 143 | + |
| 144 | + |
| 145 | +## 提出问题 |
| 146 | + |
| 147 | +为了加快开发进度,甲找到了开发者乙一起开发,其中甲负责PC端的渲染实现,乙负责移动端的渲染实现 |
| 148 | + |
| 149 | +- 由于两个运行环境的逻辑混杂在一起,导致两个开发者开发时互相影响,容易出现代码冲突,最终导致开发进度逐渐变慢 |
| 150 | + |
| 151 | + |
| 152 | + |
| 153 | +# [给出可能的改进方案,分析存在的问题]? |
| 154 | + |
| 155 | + |
| 156 | +## 概述解决方案? |
| 157 | + |
| 158 | +TODO continue |
| 159 | + |
| 160 | +## 给出UML? |
| 161 | +## 结合UML图,描述如何具体地解决问题? |
| 162 | +## 给出代码? |
| 163 | + |
| 164 | + |
| 165 | +<!-- ## 请分析存在的问题? |
| 166 | +## 提出改进方向? --> |
| 167 | +## 提出问题 |
| 168 | + |
| 169 | + |
| 170 | +# [给出使用模式的改进方案] |
| 171 | + |
| 172 | +## 概述解决方案 |
| 173 | +## 给出UML? |
| 174 | +## 结合UML图,描述如何具体地解决问题? |
| 175 | +## 给出代码? |
| 176 | + |
| 177 | + |
| 178 | + |
| 179 | +<!-- # 设计意图 |
| 180 | +
|
| 181 | +阐明模式的设计目标 --> |
| 182 | + |
| 183 | +# 定义 |
| 184 | + |
| 185 | +## 一句话定义? |
| 186 | +<!-- ## 概述抽象的解决方案 --> |
| 187 | +## 补充说明 |
| 188 | +## 通用UML? |
| 189 | +## 分析角色? |
| 190 | +## 角色之间的关系? |
| 191 | +## 角色的抽象代码? |
| 192 | +## 遵循的设计原则在UML中的体现? |
| 193 | + |
| 194 | + |
| 195 | + |
| 196 | + |
| 197 | +# 应用 |
| 198 | + |
| 199 | +## 优点 |
| 200 | + |
| 201 | +## 缺点 |
| 202 | + |
| 203 | +## 使用场景 |
| 204 | + |
| 205 | +### 场景描述 |
| 206 | + |
| 207 | +<!-- ### 解决方案 --> |
| 208 | + |
| 209 | +### 具体案例 |
| 210 | + |
| 211 | +<!-- ## 实现该场景需要修改模式的哪些角色? --> |
| 212 | +<!-- ## 使用模式有什么好处? --> |
| 213 | + |
| 214 | +## 注意事项 |
| 215 | + |
| 216 | + |
| 217 | +# 扩展 |
| 218 | + |
| 219 | + |
| 220 | +# 结合其它模式 |
| 221 | + |
| 222 | +## 结合哪些模式? |
| 223 | +## 使用场景是什么? |
| 224 | +## UML如何变化? |
| 225 | +## 代码如何变化? |
| 226 | + |
| 227 | + |
| 228 | + |
| 229 | + |
| 230 | +# 最佳实践 |
| 231 | + |
| 232 | +<!-- ## 结合具体项目实践经验,如何应用模式来改进项目? --> |
| 233 | +## 哪些场景不需要使用模式? |
| 234 | +<!-- ## 哪些场景需要使用模式? --> |
| 235 | +## 给出具体的实践案例? |
| 236 | + |
| 237 | + |
| 238 | + |
| 239 | +# 更多资料推荐 |
0 commit comments