action-engine-js 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/LICENSE +45 -0
  2. package/README.md +348 -0
  3. package/actionengine/3rdparty/goblin/goblin.js +9609 -0
  4. package/actionengine/3rdparty/goblin/goblin.min.js +5 -0
  5. package/actionengine/camera/actioncamera.js +90 -0
  6. package/actionengine/camera/cameracollisionhandler.js +69 -0
  7. package/actionengine/character/actioncharacter.js +360 -0
  8. package/actionengine/character/actioncharacter3D.js +61 -0
  9. package/actionengine/core/app.js +430 -0
  10. package/actionengine/debug/basedebugpanel.js +858 -0
  11. package/actionengine/display/canvasmanager.js +75 -0
  12. package/actionengine/display/gl/programmanager.js +570 -0
  13. package/actionengine/display/gl/shaders/lineshader.js +118 -0
  14. package/actionengine/display/gl/shaders/objectshader.js +1756 -0
  15. package/actionengine/display/gl/shaders/particleshader.js +43 -0
  16. package/actionengine/display/gl/shaders/shadowshader.js +319 -0
  17. package/actionengine/display/gl/shaders/spriteshader.js +100 -0
  18. package/actionengine/display/gl/shaders/watershader.js +67 -0
  19. package/actionengine/display/graphics/actionmodel3D.js +191 -0
  20. package/actionengine/display/graphics/actionsprite3D.js +230 -0
  21. package/actionengine/display/graphics/lighting/actiondirectionalshadowlight.js +864 -0
  22. package/actionengine/display/graphics/lighting/actionlight.js +211 -0
  23. package/actionengine/display/graphics/lighting/actionomnidirectionalshadowlight.js +862 -0
  24. package/actionengine/display/graphics/lighting/lightingconstants.js +263 -0
  25. package/actionengine/display/graphics/lighting/lightmanager.js +789 -0
  26. package/actionengine/display/graphics/renderableobject.js +44 -0
  27. package/actionengine/display/graphics/renderers/actionrenderer2D.js +341 -0
  28. package/actionengine/display/graphics/renderers/actionrenderer3D/actionrenderer3D.js +655 -0
  29. package/actionengine/display/graphics/renderers/actionrenderer3D/canvasmanager3D.js +82 -0
  30. package/actionengine/display/graphics/renderers/actionrenderer3D/debugrenderer3D.js +493 -0
  31. package/actionengine/display/graphics/renderers/actionrenderer3D/objectrenderer3D.js +790 -0
  32. package/actionengine/display/graphics/renderers/actionrenderer3D/spriteRenderer3D.js +266 -0
  33. package/actionengine/display/graphics/renderers/actionrenderer3D/sunrenderer3D.js +140 -0
  34. package/actionengine/display/graphics/renderers/actionrenderer3D/waterrenderer3D.js +173 -0
  35. package/actionengine/display/graphics/renderers/actionrenderer3D/weatherrenderer3D.js +87 -0
  36. package/actionengine/display/graphics/texture/proceduraltexture.js +192 -0
  37. package/actionengine/display/graphics/texture/texturemanager.js +242 -0
  38. package/actionengine/display/graphics/texture/textureregistry.js +177 -0
  39. package/actionengine/input/actionscrollablearea.js +1405 -0
  40. package/actionengine/input/inputhandler.js +1647 -0
  41. package/actionengine/math/geometry/geometrybuilder.js +161 -0
  42. package/actionengine/math/geometry/glbexporter.js +364 -0
  43. package/actionengine/math/geometry/glbloader.js +722 -0
  44. package/actionengine/math/geometry/modelcodegenerator.js +97 -0
  45. package/actionengine/math/geometry/triangle.js +33 -0
  46. package/actionengine/math/geometry/triangleutils.js +34 -0
  47. package/actionengine/math/mathutils.js +25 -0
  48. package/actionengine/math/matrix4.js +785 -0
  49. package/actionengine/math/physics/actionphysics.js +108 -0
  50. package/actionengine/math/physics/actionphysicsobject3D.js +164 -0
  51. package/actionengine/math/physics/actionphysicsworld3D.js +238 -0
  52. package/actionengine/math/physics/actionraycast.js +129 -0
  53. package/actionengine/math/physics/shapes/actionphysicsbox3D.js +158 -0
  54. package/actionengine/math/physics/shapes/actionphysicscapsule3D.js +200 -0
  55. package/actionengine/math/physics/shapes/actionphysicscompoundshape3D.js +147 -0
  56. package/actionengine/math/physics/shapes/actionphysicscone3D.js +126 -0
  57. package/actionengine/math/physics/shapes/actionphysicsconvexshape3D.js +72 -0
  58. package/actionengine/math/physics/shapes/actionphysicscylinder3D.js +117 -0
  59. package/actionengine/math/physics/shapes/actionphysicsmesh3D.js +74 -0
  60. package/actionengine/math/physics/shapes/actionphysicsplane3D.js +100 -0
  61. package/actionengine/math/physics/shapes/actionphysicssphere3D.js +95 -0
  62. package/actionengine/math/quaternion.js +61 -0
  63. package/actionengine/math/vector2.js +277 -0
  64. package/actionengine/math/vector3.js +318 -0
  65. package/actionengine/math/viewfrustum.js +136 -0
  66. package/actionengine/network/ACTIONNETREADME.md +810 -0
  67. package/actionengine/network/client/ActionNetManager.js +802 -0
  68. package/actionengine/network/client/ActionNetManagerGUI.js +1709 -0
  69. package/actionengine/network/client/ActionNetManagerP2P.js +1537 -0
  70. package/actionengine/network/client/SyncSystem.js +422 -0
  71. package/actionengine/network/p2p/ActionNetPeer.js +142 -0
  72. package/actionengine/network/p2p/ActionNetTrackerClient.js +623 -0
  73. package/actionengine/network/p2p/DataConnection.js +282 -0
  74. package/actionengine/network/p2p/README.md +510 -0
  75. package/actionengine/network/p2p/example.html +502 -0
  76. package/actionengine/network/server/ActionNetServer.js +577 -0
  77. package/actionengine/network/server/ActionNetServerSSL.js +579 -0
  78. package/actionengine/network/server/ActionNetServerUtils.js +458 -0
  79. package/actionengine/network/server/SERVERREADME.md +314 -0
  80. package/actionengine/network/server/package-lock.json +35 -0
  81. package/actionengine/network/server/package.json +13 -0
  82. package/actionengine/network/server/start.bat +27 -0
  83. package/actionengine/network/server/start.sh +25 -0
  84. package/actionengine/network/server/startwss.bat +27 -0
  85. package/actionengine/sound/audiomanager.js +1589 -0
  86. package/actionengine/sound/soundfont/ACTIONSOUNDFONT_README.md +205 -0
  87. package/actionengine/sound/soundfont/actionparser.js +718 -0
  88. package/actionengine/sound/soundfont/actionreverb.js +252 -0
  89. package/actionengine/sound/soundfont/actionsoundfont.js +543 -0
  90. package/actionengine/sound/soundfont/sf2playerlicence.txt +29 -0
  91. package/actionengine/sound/soundfont/soundfont.js +2 -0
  92. package/dist/action-engine.min.js +328 -0
  93. package/package.json +35 -0
@@ -0,0 +1,43 @@
1
+ // game/display/gl/shaders/particleshader.js
2
+ class ParticleShader {
3
+ getParticleVertexShader(isWebGL2) {
4
+ return `${isWebGL2 ? "#version 300 es\n" : ""}
5
+ ${isWebGL2 ? "in" : "attribute"} vec3 aPosition;
6
+ ${isWebGL2 ? "in" : "attribute"} float aSize;
7
+ ${isWebGL2 ? "in" : "attribute"} vec4 aColor;
8
+
9
+ uniform mat4 uProjectionMatrix;
10
+ uniform mat4 uViewMatrix;
11
+
12
+ ${isWebGL2 ? "out" : "varying"} vec4 vColor;
13
+
14
+ void main() {
15
+ gl_Position = uProjectionMatrix * uViewMatrix * vec4(aPosition, 1.0);
16
+ gl_PointSize = aSize;
17
+ vColor = aColor;
18
+ }`;
19
+ }
20
+
21
+ getParticleFragmentShader(isWebGL2) {
22
+ return `${isWebGL2 ? "#version 300 es\n" : ""}
23
+ precision mediump float;
24
+ ${isWebGL2 ? "in" : "varying"} vec4 vColor;
25
+ ${isWebGL2 ? "out vec4 fragColor;\n" : ""}
26
+ uniform int uParticleType;
27
+ void main() {
28
+ vec2 coord = gl_PointCoord * 2.0 - 1.0;
29
+ if (uParticleType == 1 || uParticleType == 2) { // Rain types
30
+ coord.y *= 12.0; // Longer streaks
31
+ float r = dot(coord, coord);
32
+ float streak = smoothstep(1.0, 0.0, r);
33
+ float trail = smoothstep(1.0, 0.0, coord.y);
34
+ float droplet = streak * trail;
35
+ ${isWebGL2 ? "fragColor" : "gl_FragColor"} = vec4(0.8, 0.85, 1.0, 1.0); // Blueish tint, more transparent
36
+ } else {
37
+ float r = dot(coord, coord);
38
+ if (r > 1.0) discard;
39
+ ${isWebGL2 ? "fragColor" : "gl_FragColor"} = vColor;
40
+ }
41
+ }`;
42
+ }
43
+ }
@@ -0,0 +1,319 @@
1
+ // actionengine/display/gl/shaders/shadowshader.js
2
+ class ShadowShader {
3
+ /**
4
+ * Dedicated vertex shader for directional shadow mapping
5
+ * This is the clean version that only handles directional shadows
6
+ */
7
+ getDirectionalShadowVertexShader(isWebGL2) {
8
+ return `${isWebGL2 ? "#version 300 es\n" : ""}
9
+ ${isWebGL2 ? "in" : "attribute"} vec3 aPosition;
10
+
11
+ uniform mat4 uLightSpaceMatrix;
12
+ uniform mat4 uModelMatrix;
13
+
14
+ void main() {
15
+ gl_Position = uLightSpaceMatrix * uModelMatrix * vec4(aPosition, 1.0);
16
+ }`;
17
+ }
18
+
19
+ /**
20
+ * Vertex shader for the shadow mapping pass
21
+ * This shader simply transforms vertices to light space
22
+ */
23
+ getShadowVertexShader(isWebGL2) {
24
+ return `${isWebGL2 ? "#version 300 es\n" : ""}
25
+ ${isWebGL2 ? "in" : "attribute"} vec3 aPosition;
26
+
27
+ uniform mat4 uLightSpaceMatrix;
28
+ uniform mat4 uModelMatrix;
29
+ ${isWebGL2 ? "out" : "varying"} vec4 vWorldPos; // For omnidirectional shadows
30
+ uniform vec3 uLightPos; // For omnidirectional shadows
31
+
32
+ void main() {
33
+ vec4 worldPos = uModelMatrix * vec4(aPosition, 1.0);
34
+ vWorldPos = worldPos;
35
+ gl_Position = uLightSpaceMatrix * worldPos;
36
+ }`;
37
+ }
38
+
39
+ /**
40
+ * Get the vertex shader for omnidirectional shadow mapping
41
+ * This variant is optimized for point lights with cubemap shadows
42
+ */
43
+ getOmniShadowVertexShader(isWebGL2) {
44
+ return `${isWebGL2 ? "#version 300 es\n" : ""}
45
+ ${isWebGL2 ? "in" : "attribute"} vec3 aPosition;
46
+
47
+ uniform mat4 uLightSpaceMatrix;
48
+ uniform mat4 uModelMatrix;
49
+ uniform vec3 uLightPos;
50
+
51
+ ${isWebGL2 ? "out" : "varying"} vec3 vFragPos;
52
+
53
+ void main() {
54
+ vec4 worldPos = uModelMatrix * vec4(aPosition, 1.0);
55
+ vFragPos = worldPos.xyz;
56
+ gl_Position = uLightSpaceMatrix * worldPos;
57
+ }`;
58
+ }
59
+
60
+ /**
61
+ * Fragment shader for the shadow mapping pass
62
+ * This shader outputs depth values to the shadow map
63
+ */
64
+ getDirectionalShadowFragmentShader(isWebGL2) {
65
+ if (isWebGL2) {
66
+ return `#version 300 es
67
+ precision mediump float;
68
+
69
+ // Debug uniforms
70
+ uniform bool uDebugShadowMap;
71
+ uniform bool uForceShadowMapTest;
72
+ uniform float uShadowMapSize;
73
+
74
+ out vec4 fragColor;
75
+
76
+ void main() {
77
+ // DIRECTIONAL ONLY: Direct depth from gl_FragCoord.z
78
+ float depth = gl_FragCoord.z;
79
+
80
+ // Apply forcing if in test mode
81
+ if (uForceShadowMapTest) {
82
+ vec2 center = vec2(0.5, 0.5);
83
+ vec2 normalizedCoord = gl_FragCoord.xy / uShadowMapSize;
84
+
85
+ float testSize = 256.0 / uShadowMapSize;
86
+ if (abs(normalizedCoord.x - center.x) < testSize &&
87
+ abs(normalizedCoord.y - center.y) < testSize) {
88
+ depth = 0.5; // Force a mid-range depth value in test area
89
+ }
90
+ }
91
+
92
+ // Pack depth into RGBA (manual encoding for better precision)
93
+ const vec4 bitShift = vec4(1.0, 256.0, 256.0*256.0, 256.0*256.0*256.0);
94
+ const vec4 bitMask = vec4(1.0/256.0, 1.0/256.0, 1.0/256.0, 0.0);
95
+ vec4 encodedDepth = fract(depth * bitShift);
96
+ encodedDepth -= encodedDepth.gbaa * bitMask;
97
+
98
+ fragColor = encodedDepth;
99
+ }`;
100
+ } else {
101
+ // WebGL1 version
102
+ return `precision highp float;
103
+
104
+ // Debug uniforms
105
+ uniform bool uDebugShadowMap;
106
+ uniform bool uForceShadowMapTest;
107
+ uniform float uShadowMapSize;
108
+
109
+ void main() {
110
+ // DIRECTIONAL ONLY: Direct depth from gl_FragCoord.z
111
+ float depth = gl_FragCoord.z;
112
+
113
+ // Create test pattern if enabled
114
+ if (uForceShadowMapTest) {
115
+ vec2 center = vec2(0.5, 0.5);
116
+ vec2 normalizedCoord = gl_FragCoord.xy / uShadowMapSize;
117
+
118
+ float testSize = 256.0 / uShadowMapSize;
119
+ if (abs(normalizedCoord.x - center.x) < testSize &&
120
+ abs(normalizedCoord.y - center.y) < testSize) {
121
+ // For WebGL1, we need to encode depth as RGBA
122
+ gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); // White = 1.0 depth
123
+ return;
124
+ }
125
+ }
126
+
127
+ if (uDebugShadowMap) {
128
+ // For debug visualization
129
+ gl_FragColor = vec4(depth, depth * 0.5, depth * 0.2, 1.0);
130
+
131
+ // Show test area if enabled
132
+ if (uForceShadowMapTest) {
133
+ vec2 center = vec2(0.5, 0.5);
134
+ vec2 normalizedCoord = gl_FragCoord.xy / uShadowMapSize;
135
+
136
+ float testSize = 256.0 / uShadowMapSize;
137
+ if (abs(normalizedCoord.x - center.x) < testSize &&
138
+ abs(normalizedCoord.y - center.y) < testSize) {
139
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // Red for test area
140
+ }
141
+ }
142
+ } else {
143
+ // Pack depth into RGBA (bit-wise encoding) for normal operation
144
+ const vec4 bitShift = vec4(1.0, 256.0, 256.0*256.0, 256.0*256.0*256.0);
145
+ const vec4 bitMask = vec4(1.0/256.0, 1.0/256.0, 1.0/256.0, 0.0);
146
+ vec4 color = fract(depth * bitShift);
147
+ color -= color.gbaa * bitMask;
148
+
149
+ gl_FragColor = color;
150
+ }
151
+ }`;
152
+ }
153
+ }
154
+
155
+ getShadowFragmentShader(isWebGL2) {
156
+ if (isWebGL2) {
157
+ return `#version 300 es
158
+ precision mediump float;
159
+
160
+ // Debug uniforms
161
+ uniform bool uDebugShadowMap;
162
+ uniform bool uForceShadowMapTest;
163
+ uniform float uShadowMapSize; // New uniform for shadow map size
164
+
165
+ // For omnidirectional shadows
166
+ in vec4 vWorldPos;
167
+ uniform vec3 uLightPos;
168
+ uniform float uFarPlane;
169
+
170
+ out vec4 fragColor;
171
+
172
+ void main() {
173
+ // For omnidirectional shadows, compute distance from light to fragment
174
+ vec3 fragToLight = vWorldPos.xyz - uLightPos;
175
+ float lightDistance = length(fragToLight);
176
+
177
+ // Normalize to [0,1] range based on far plane
178
+ float depth = lightDistance / uFarPlane;
179
+
180
+ // Apply forcing if in test mode
181
+ if (uForceShadowMapTest) {
182
+ vec2 center = vec2(0.5, 0.5);
183
+ vec2 normalizedCoord = gl_FragCoord.xy / uShadowMapSize;
184
+
185
+ float testSize = 256.0 / uShadowMapSize;
186
+ if (abs(normalizedCoord.x - center.x) < testSize &&
187
+ abs(normalizedCoord.y - center.y) < testSize) {
188
+ depth = 0.5; // Force a mid-range depth value in test area
189
+ }
190
+ }
191
+
192
+ // Pack depth into RGBA (manual encoding for better precision)
193
+ const vec4 bitShift = vec4(1.0, 256.0, 256.0*256.0, 256.0*256.0*256.0);
194
+ const vec4 bitMask = vec4(1.0/256.0, 1.0/256.0, 1.0/256.0, 0.0);
195
+ vec4 encodedDepth = fract(depth * bitShift);
196
+ encodedDepth -= encodedDepth.gbaa * bitMask;
197
+
198
+ fragColor = encodedDepth;
199
+ }`;
200
+ } else {
201
+ // WebGL1 version
202
+ return `precision highp float;
203
+
204
+ // Debug uniforms
205
+ uniform bool uDebugShadowMap;
206
+ uniform bool uForceShadowMapTest;
207
+ uniform float uShadowMapSize; // New uniform for shadow map size
208
+
209
+ // For omnidirectional shadows
210
+ varying vec4 vWorldPos;
211
+ uniform vec3 uLightPos;
212
+ uniform float uFarPlane;
213
+
214
+ void main() {
215
+ // For omnidirectional shadows, compute distance from light to fragment
216
+ vec3 fragToLight = vWorldPos.xyz - uLightPos;
217
+ float lightDistance = length(fragToLight);
218
+
219
+ // Normalize to [0,1] range based on far plane
220
+ float depth = lightDistance / uFarPlane;
221
+
222
+ // Create test pattern if enabled
223
+ if (uForceShadowMapTest) {
224
+ vec2 center = vec2(0.5, 0.5);
225
+ vec2 normalizedCoord = gl_FragCoord.xy / uShadowMapSize;
226
+
227
+ float testSize = 256.0 / uShadowMapSize;
228
+ if (abs(normalizedCoord.x - center.x) < testSize &&
229
+ abs(normalizedCoord.y - center.y) < testSize) {
230
+ // For WebGL1, we need to encode depth as RGBA
231
+ gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); // White = 1.0 depth
232
+ return;
233
+ }
234
+ }
235
+
236
+ if (uDebugShadowMap) {
237
+ // For debug visualization
238
+ gl_FragColor = vec4(depth, depth * 0.5, depth * 0.2, 1.0);
239
+
240
+ // Show test area if enabled
241
+ if (uForceShadowMapTest) {
242
+ vec2 center = vec2(0.5, 0.5);
243
+ vec2 normalizedCoord = gl_FragCoord.xy / uShadowMapSize;
244
+
245
+ float testSize = 256.0 / uShadowMapSize;
246
+ if (abs(normalizedCoord.x - center.x) < testSize &&
247
+ abs(normalizedCoord.y - center.y) < testSize) {
248
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // Red for test area
249
+ }
250
+ }
251
+ } else {
252
+ // Pack depth into RGBA (bit-wise encoding) for normal operation
253
+ const vec4 bitShift = vec4(1.0, 256.0, 256.0*256.0, 256.0*256.0*256.0);
254
+ const vec4 bitMask = vec4(1.0/256.0, 1.0/256.0, 1.0/256.0, 0.0);
255
+ vec4 color = fract(depth * bitShift);
256
+ color -= color.gbaa * bitMask;
257
+
258
+ gl_FragColor = color;
259
+ }
260
+ }`;
261
+ }
262
+ }
263
+
264
+ /**
265
+ * Fragment shader specifically for omnidirectional shadow mapping
266
+ * Optimized for point lights with cubemap shadows
267
+ */
268
+ getOmniShadowFragmentShader(isWebGL2) {
269
+ if (isWebGL2) {
270
+ return `#version 300 es
271
+ precision mediump float;
272
+
273
+ in vec3 vFragPos;
274
+ uniform vec3 uLightPos;
275
+ uniform float uFarPlane;
276
+
277
+ out vec4 fragColor;
278
+
279
+ void main() {
280
+ // Get distance between fragment and light source
281
+ float lightDistance = length(vFragPos - uLightPos);
282
+
283
+ // Map to [0,1] range by dividing by far plane
284
+ lightDistance = lightDistance / uFarPlane;
285
+
286
+ // Write this as depth value
287
+ const vec4 bitShift = vec4(1.0, 256.0, 256.0*256.0, 256.0*256.0*256.0);
288
+ const vec4 bitMask = vec4(1.0/256.0, 1.0/256.0, 1.0/256.0, 0.0);
289
+ vec4 encodedDepth = fract(lightDistance * bitShift);
290
+ encodedDepth -= encodedDepth.gbaa * bitMask;
291
+
292
+ fragColor = encodedDepth;
293
+ }`;
294
+ } else {
295
+ // WebGL1 version
296
+ return `precision highp float;
297
+
298
+ varying vec3 vFragPos;
299
+ uniform vec3 uLightPos;
300
+ uniform float uFarPlane;
301
+
302
+ void main() {
303
+ // Get distance between fragment and light source
304
+ float lightDistance = length(vFragPos - uLightPos);
305
+
306
+ // Map to [0,1] range by dividing by far plane
307
+ lightDistance = lightDistance / uFarPlane;
308
+
309
+ // Write this as depth value
310
+ const vec4 bitShift = vec4(1.0, 256.0, 256.0*256.0, 256.0*256.0*256.0);
311
+ const vec4 bitMask = vec4(1.0/256.0, 1.0/256.0, 1.0/256.0, 0.0);
312
+ vec4 color = fract(lightDistance * bitShift);
313
+ color -= color.gbaa * bitMask;
314
+
315
+ gl_FragColor = color;
316
+ }`;
317
+ }
318
+ }
319
+ }
@@ -0,0 +1,100 @@
1
+ // actionengine/display/gl/shaders/spriteshader.js
2
+
3
+ class SpriteShader {
4
+ constructor() {
5
+ // No variants needed for sprites - keep it simple
6
+ }
7
+
8
+ /**
9
+ * Get sprite vertex shader
10
+ * @param {boolean} isWebGL2 - Whether WebGL2 is being used
11
+ * @returns {string} - Vertex shader source code
12
+ */
13
+ getVertexShader(isWebGL2) {
14
+ return `${isWebGL2 ? "#version 300 es\n" : ""}
15
+ precision mediump float;
16
+
17
+ ${isWebGL2 ? "in" : "attribute"} vec3 aPosition;
18
+ ${isWebGL2 ? "in" : "attribute"} vec2 aTexCoord;
19
+
20
+ uniform mat4 uProjectionMatrix;
21
+ uniform mat4 uViewMatrix;
22
+ uniform vec3 uSpritePosition; // World position of the sprite
23
+ uniform vec2 uSpriteSize; // Width and height of the sprite
24
+ uniform vec3 uCameraPosition;
25
+ uniform vec3 uCameraRight;
26
+ uniform vec3 uCameraUp;
27
+ uniform bool uIsBillboard; // Whether to use billboard mode
28
+ uniform vec3 uSpriteForward; // Sprite forward direction (for non-billboard)
29
+ uniform vec3 uSpriteUp; // Sprite up direction (for non-billboard)
30
+
31
+ ${isWebGL2 ? "out" : "varying"} vec2 vTexCoord;
32
+
33
+ void main() {
34
+ vec3 worldPos;
35
+
36
+ if (uIsBillboard) {
37
+ // Calculate billboard position in world space
38
+ // aPosition.xy contains the quad vertices (-0.5 to 0.5)
39
+ worldPos = uSpritePosition
40
+ + uCameraRight * aPosition.x * uSpriteSize.x
41
+ + uCameraUp * aPosition.y * uSpriteSize.y;
42
+ } else {
43
+ // Non-billboard mode: Use sprite's own orientation
44
+ // Create a basis using sprite's forward and up vectors
45
+ vec3 forward = normalize(uSpriteForward);
46
+ vec3 up = normalize(uSpriteUp);
47
+
48
+ // Calculate right vector (perpendicular to forward and up)
49
+ vec3 right = normalize(cross(forward, up));
50
+
51
+ // Recalculate up to ensure orthogonality (in case forward/up weren't perfectly perpendicular)
52
+ vec3 correctedUp = normalize(cross(right, forward));
53
+
54
+ // Calculate world position using sprite's local coordinate system
55
+ worldPos = uSpritePosition
56
+ + right * aPosition.x * uSpriteSize.x
57
+ + correctedUp * aPosition.y * uSpriteSize.y;
58
+ }
59
+
60
+ // Transform to screen space
61
+ vec4 viewPos = uViewMatrix * vec4(worldPos, 1.0);
62
+ gl_Position = uProjectionMatrix * viewPos;
63
+
64
+ // Pass through texture coordinates
65
+ vTexCoord = aTexCoord;
66
+ }`;
67
+ }
68
+
69
+ /**
70
+ * Get billboard fragment shader
71
+ * @param {boolean} isWebGL2 - Whether WebGL2 is being used
72
+ * @returns {string} - Fragment shader source code
73
+ */
74
+ getFragmentShader(isWebGL2) {
75
+ return `${isWebGL2 ? "#version 300 es\n" : ""}
76
+ precision mediump float;
77
+
78
+ ${isWebGL2 ? "in" : "varying"} vec2 vTexCoord;
79
+
80
+ uniform sampler2D uTexture;
81
+ uniform vec3 uColor; // Color tint
82
+ uniform float uAlpha; // Alpha value
83
+
84
+ ${isWebGL2 ? "out vec4 fragColor;" : ""}
85
+
86
+ void main() {
87
+ vec4 texColor = texture${isWebGL2 ? "" : "2D"}(uTexture, vTexCoord);
88
+
89
+ // Apply color tint and alpha
90
+ vec4 finalColor = vec4(texColor.rgb * uColor, texColor.a * uAlpha);
91
+
92
+ // Discard transparent pixels
93
+ if (finalColor.a < 0.01) {
94
+ discard;
95
+ }
96
+
97
+ ${isWebGL2 ? "fragColor = finalColor;" : "gl_FragColor = finalColor;"}
98
+ }`;
99
+ }
100
+ }
@@ -0,0 +1,67 @@
1
+ class WaterShader {
2
+ getWaterVertexShader(isWebGL2) {
3
+ return `${isWebGL2 ? "#version 300 es\n" : ""}
4
+ ${isWebGL2 ? "in" : "attribute"} vec3 aPosition;
5
+ ${isWebGL2 ? "in" : "attribute"} vec3 aNormal;
6
+ ${isWebGL2 ? "in" : "attribute"} vec2 aTexCoord;
7
+
8
+ uniform mat4 uProjectionMatrix;
9
+ uniform mat4 uViewMatrix;
10
+ uniform mat4 uModelMatrix;
11
+ uniform float uTime;
12
+
13
+ ${isWebGL2 ? "out" : "varying"} vec3 vPosition;
14
+ ${isWebGL2 ? "out" : "varying"} vec3 vNormal;
15
+ ${isWebGL2 ? "out" : "varying"} vec2 vTexCoord;
16
+
17
+ void main() {
18
+ vec3 pos = aPosition;
19
+
20
+ float wave = sin(pos.x * 2.0 + uTime) * 2.0 +
21
+ sin(pos.z * 1.5 + uTime * 0.8) * 1.8;
22
+ pos.y += wave;
23
+
24
+ vec3 normal = aNormal;
25
+ normal.xz += cos(pos.xz * 2.0 + uTime) * 0.2;
26
+ normal = normalize(normal);
27
+
28
+ vPosition = (uModelMatrix * vec4(pos, 1.0)).xyz;
29
+ vNormal = normal;
30
+ vTexCoord = aTexCoord;
31
+
32
+ gl_Position = uProjectionMatrix * uViewMatrix * vec4(vPosition, 1.0);
33
+ }`;
34
+ }
35
+
36
+ getWaterFragmentShader(isWebGL2) {
37
+ return `${isWebGL2 ? "#version 300 es\n" : ""}
38
+ precision highp float;
39
+
40
+ ${isWebGL2 ? "in" : "varying"} vec3 vPosition;
41
+ ${isWebGL2 ? "in" : "varying"} vec3 vNormal;
42
+ ${isWebGL2 ? "in" : "varying"} vec2 vTexCoord;
43
+
44
+ uniform vec3 uCameraPos;
45
+ uniform vec3 uLightDir;
46
+ uniform float uTime;
47
+
48
+ ${isWebGL2 ? "out vec4 fragColor;\n" : ""}
49
+
50
+ void main() {
51
+ vec3 viewDir = normalize(uCameraPos - vPosition);
52
+
53
+ vec3 waterColor = vec3(0.0, 0.4, 0.6);
54
+
55
+ float fresnel = pow(1.0 - max(dot(viewDir, vNormal), 0.0), 3.0);
56
+
57
+ vec3 reflectDir = reflect(-uLightDir, vNormal);
58
+ float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32.0);
59
+
60
+ vec3 finalColor = waterColor + fresnel * 0.5 + spec;
61
+
62
+ float alpha = mix(0.6, 0.9, fresnel);
63
+
64
+ ${isWebGL2 ? "fragColor" : "gl_FragColor"} = vec4(finalColor, alpha);
65
+ }`;
66
+ }
67
+ }