1 | import { toRad, m4_identity, ViewService, RenderManager, PM_Camera, PM_Visible } from "@croquet/worldcore-kernel";
|
2 |
|
3 | import { MainDisplay, Scene, Camera, Lights, GeometryBuffer, Framebuffer, SharedStencilFramebuffer, GetGLVersion, SetGLCamera, SetGLPipeline, StartStencilCapture, EndStencil, StartStencilApply } from "./Render";
|
4 | import { BasicShader, DecalShader, TranslucentShader, InstancedShader, GeometryShader, InstancedGeometryShader, TranslucentGeometryShader, PassthruShader, BlendShader, AOShader, InstancedDecalShader } from "./Shaders";
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 | export const PM_WebGLVisible = superclass => class extends PM_Visible(superclass) {
|
20 |
|
21 | constructor(...args) {
|
22 | super(...args);
|
23 | this.listen("viewGlobalChanged", this.refreshDrawTransform);
|
24 | }
|
25 |
|
26 | destroy() {
|
27 | super.destroy();
|
28 | if (this.draw) this.service('WebGLRenderManager').scene.removeDrawCall(this.draw);
|
29 | }
|
30 |
|
31 | refreshDrawTransform() {
|
32 | if (this.draw) this.draw.transform.set(this.global);
|
33 | }
|
34 |
|
35 | setDrawCall(draw) {
|
36 | if (this.draw === draw) return;
|
37 | const scene = this.service('WebGLRenderManager').scene;
|
38 | if (this.draw) scene.removeDrawCall(this.draw);
|
39 | this.draw = draw;
|
40 | if (this.draw) {
|
41 | this.draw.transform.set(this.global || m4_identity());
|
42 | scene.addDrawCall(this.draw);
|
43 | }
|
44 |
|
45 | }
|
46 |
|
47 | };
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 | export const PM_WebGLInstancedVisible = superclass => class extends superclass {
|
58 |
|
59 | constructor(...args) {
|
60 | super(...args);
|
61 | this.listen("viewGlobalChanged", this.refreshDrawTransform);
|
62 | }
|
63 |
|
64 | destroy() {
|
65 | super.destroy();
|
66 | if (this.draw) this.draw.instances.delete(this.actor.id);
|
67 | }
|
68 |
|
69 | refreshDrawTransform() {
|
70 | if (this.draw) this.draw.instances.set(this.actor.id, this.global);
|
71 | }
|
72 |
|
73 | setDrawCall(draw) {
|
74 | const scene = this.service('WebGLRenderManager').scene;
|
75 |
|
76 | this.draw = draw;
|
77 | if (this.draw) {
|
78 | this.draw.instances.set(this.actor.id, this.global);
|
79 | scene.addDrawCall(this.draw);
|
80 | }
|
81 | }
|
82 |
|
83 | }
|
84 |
|
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 |
|
91 | export const PM_WebGLCamera = superclass => class extends PM_Camera(superclass) {
|
92 |
|
93 | constructor(...args) {
|
94 | super(...args);
|
95 | const render = this.service("WebGLRenderManager");
|
96 | if (this.isMyPlayerPawn && render) {
|
97 | render.camera.setLocation(this.lookGlobal);
|
98 | render.camera.setProjection(toRad(60), 1.0, 10000.0);
|
99 | }
|
100 | this.listen("lookGlobalChanged", this.refreshCameraTransform);
|
101 | }
|
102 |
|
103 | refreshCameraTransform() {
|
104 | const render = this.service("WebGLRenderManager");
|
105 | if (!this.isMyPlayerPawn || !render) return;
|
106 | render.camera.setLocation(this.lookGlobal);
|
107 | }
|
108 |
|
109 | };
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 |
|
117 | export class WebGLRenderManager extends RenderManager {
|
118 | constructor(options, name) {
|
119 | super(options, name || "WebGLRenderManager");
|
120 | SetGLPipeline(this);
|
121 | this.display = new MainDisplay();
|
122 | this.buildBuffers();
|
123 | this.buildShaders();
|
124 | this.setScene(new Scene());
|
125 | this.setCamera(new Camera());
|
126 | this.setLights(new Lights());
|
127 | this.setBackground([0,0,0,1]);
|
128 | }
|
129 |
|
130 | destroy() {
|
131 | this.display.destroy();
|
132 | if (this.geometryBuffer) this.geometryBuffer.destroy();
|
133 | if (this.aoBuffer) this.aoBuffer.destroy();
|
134 | if (this.composeBuffer) this.composeBuffer.destroy();
|
135 | }
|
136 |
|
137 | buildBuffers() {
|
138 | if (GetGLVersion() === 0) return;
|
139 | this.geometryBuffer = new GeometryBuffer({autoResize: 1});
|
140 | this.aoBuffer = new Framebuffer({autoResize: 0.5});
|
141 | this.composeBuffer = new SharedStencilFramebuffer(this.geometryBuffer);
|
142 | this.composeBuffer.setBackground([1,1,1,1]);
|
143 | }
|
144 |
|
145 | buildShaders() {
|
146 | if (GetGLVersion() === 0) {
|
147 | this.basicShader = new BasicShader();
|
148 | this.decalShader = new DecalShader();
|
149 | this.translucentShader = new TranslucentShader();
|
150 | } else {
|
151 | this.instancedShader = new InstancedShader();
|
152 | this.decalShader = new DecalShader();
|
153 | this.instancedDecalShader = new InstancedDecalShader();
|
154 | this.translucentShader = new TranslucentShader();
|
155 |
|
156 | this.geometryShader = new GeometryShader();
|
157 | this.instancedGeometryShader = new InstancedGeometryShader();
|
158 | this.translucentGeometryShader = new TranslucentGeometryShader();
|
159 | this.passthruShader = new PassthruShader();
|
160 | this.blendShader = new BlendShader();
|
161 | this.aoShader = new AOShader();
|
162 | }
|
163 | }
|
164 |
|
165 | setLights(lights) {
|
166 | this.lights = lights;
|
167 | }
|
168 |
|
169 | setCamera(camera) {
|
170 | SetGLCamera(camera);
|
171 | this.camera = camera;
|
172 | if (GetGLVersion() === 0) {
|
173 | this.display.setCamera(camera);
|
174 | } else {
|
175 | this.geometryBuffer.setCamera(camera);
|
176 | }
|
177 | }
|
178 |
|
179 |
|
180 | updateFOV() {
|
181 | if (this.aoShader) this.aoShader.setFOV(this.camera.fov);
|
182 | }
|
183 |
|
184 | setBackground(background) {
|
185 | this.background = background;
|
186 | this.display.setBackground(background);
|
187 | if (GetGLVersion() > 0) this.geometryBuffer.setBackground(background);
|
188 | }
|
189 |
|
190 | setScene(scene) {
|
191 | this.scene = scene;
|
192 | }
|
193 |
|
194 | update() {
|
195 | this.draw();
|
196 | }
|
197 |
|
198 | draw() {
|
199 | if (!this.scene) return;
|
200 | if (GetGLVersion() === 0) {
|
201 | this.drawForward();
|
202 | } else {
|
203 | this.drawDeferred();
|
204 | }
|
205 | }
|
206 |
|
207 | drawDeferred() {
|
208 |
|
209 |
|
210 |
|
211 | this.geometryBuffer.start();
|
212 |
|
213 | StartStencilCapture();
|
214 |
|
215 | this.geometryShader.apply();
|
216 | this.lights.apply();
|
217 | this.camera.apply();
|
218 | this.scene.drawPass('opaque');
|
219 |
|
220 | this.instancedGeometryShader.apply();
|
221 | this.lights.apply();
|
222 | this.camera.apply();
|
223 | this.scene.drawPass('instanced');
|
224 |
|
225 | EndStencil();
|
226 |
|
227 | this.translucentGeometryShader.apply();
|
228 | this.camera.apply();
|
229 | this.scene.drawPass('translucent');
|
230 |
|
231 |
|
232 |
|
233 | this.aoBuffer.start();
|
234 | this.aoShader.apply();
|
235 | this.geometryBuffer.normal.apply(0);
|
236 | this.geometryBuffer.position.apply(1);
|
237 | this.aoBuffer.draw();
|
238 |
|
239 | StartStencilApply();
|
240 |
|
241 | this.composeBuffer.start();
|
242 | this.passthruShader.apply();
|
243 | this.aoBuffer.texture.apply(0);
|
244 | this.composeBuffer.draw();
|
245 |
|
246 | EndStencil();
|
247 |
|
248 | this.display.start();
|
249 | this.blendShader.apply();
|
250 | this.geometryBuffer.diffuse.apply(0);
|
251 | this.composeBuffer.texture.apply(1);
|
252 | this.display.draw();
|
253 | }
|
254 |
|
255 | drawForward() {
|
256 | this.display.start();
|
257 |
|
258 | this.decalShader.apply();
|
259 | this.lights.apply();
|
260 | this.camera.apply();
|
261 | this.scene.drawPass('opaque');
|
262 |
|
263 | this.lights.apply();
|
264 | this.camera.apply();
|
265 | this.scene.drawPass('instanced');
|
266 |
|
267 | this.translucentShader.apply();
|
268 | this.camera.apply();
|
269 | this.scene.drawPass('translucent');
|
270 | }
|
271 | }
|