p5 2.0.0 → 2.0.2

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 (267) hide show
  1. package/{src → dist}/accessibility/color_namer.js +48 -3
  2. package/{src → dist}/accessibility/describe.js +12 -2
  3. package/{src → dist}/accessibility/gridOutput.js +2 -2
  4. package/dist/accessibility/index.js +60 -0
  5. package/{src → dist}/accessibility/outputs.js +23 -2
  6. package/{src → dist}/accessibility/textOutput.js +2 -2
  7. package/dist/app.js +120 -0
  8. package/{src → dist}/color/color_conversion.js +48 -10
  9. package/{src → dist}/color/color_spaces/hsb.js +3 -1
  10. package/dist/color/creating_reading.js +3 -0
  11. package/dist/color/index.js +13 -0
  12. package/dist/color/p5.Color.culori.js +1 -0
  13. package/dist/color/p5.Color.js +3 -0
  14. package/{src → dist}/color/setting.js +9 -6
  15. package/{src/core/constants.js → dist/constants-tYr0tCl8.js} +284 -132
  16. package/{src → dist}/core/States.js +3 -1
  17. package/dist/core/constants.js +1 -0
  18. package/{src → dist}/core/environment.js +12 -10
  19. package/{src → dist}/core/friendly_errors/browser_errors.js +1 -1
  20. package/{src → dist}/core/friendly_errors/fes_core.js +14 -44
  21. package/{src → dist}/core/friendly_errors/file_errors.js +6 -3
  22. package/dist/core/friendly_errors/index.js +23 -0
  23. package/dist/core/friendly_errors/param_validator.js +5421 -0
  24. package/{src → dist}/core/friendly_errors/sketch_reader.js +50 -4
  25. package/{src → dist}/core/friendly_errors/sketch_verifier.js +6 -6
  26. package/{src → dist}/core/friendly_errors/stacktrace.js +3 -5
  27. package/{src → dist}/core/friendly_errors/validate_params.js +50 -41
  28. package/{src → dist}/core/helpers.js +9 -6
  29. package/dist/core/init.js +105 -0
  30. package/dist/core/internationalization.js +302 -0
  31. package/dist/core/legacy.js +73 -0
  32. package/dist/core/main.js +44 -0
  33. package/dist/core/noop.js +3 -0
  34. package/dist/core/p5.Graphics.js +40 -0
  35. package/dist/core/p5.Renderer.js +11 -0
  36. package/dist/core/p5.Renderer2D.js +44 -0
  37. package/dist/core/reference.js +1 -0
  38. package/dist/core/rendering.js +40 -0
  39. package/{src → dist}/core/structure.js +3 -3
  40. package/{src → dist}/core/transform.js +2 -2
  41. package/{src/color/creating_reading.js → dist/creating_reading-Cr8L2Jnm.js} +841 -13
  42. package/{src → dist}/data/index.js +3 -1
  43. package/{src → dist}/data/local_storage.js +2 -8
  44. package/{src → dist}/dom/dom.js +19 -13
  45. package/dist/dom/index.js +18 -0
  46. package/{src → dist}/dom/p5.Element.js +14 -12
  47. package/{src → dist}/dom/p5.File.js +4 -4
  48. package/{src → dist}/dom/p5.MediaElement.js +10 -4
  49. package/{src → dist}/events/acceleration.js +26 -26
  50. package/{src → dist}/events/index.js +3 -1
  51. package/{src → dist}/events/keyboard.js +14 -12
  52. package/{src → dist}/events/pointer.js +16 -17
  53. package/dist/image/const.js +9 -0
  54. package/{src → dist}/image/filterRenderer2D.js +57 -37
  55. package/{src → dist}/image/filters.js +1 -3
  56. package/dist/image/image.js +40 -0
  57. package/dist/image/index.js +51 -0
  58. package/dist/image/loading_displaying.js +40 -0
  59. package/dist/image/p5.Image.js +11 -0
  60. package/{src → dist}/image/pixels.js +5 -3
  61. package/{src → dist}/io/csv.js +72 -70
  62. package/dist/io/files.js +40 -0
  63. package/dist/io/index.js +51 -0
  64. package/{src → dist}/io/p5.Table.js +6 -6
  65. package/{src → dist}/io/p5.TableRow.js +5 -6
  66. package/{src → dist}/io/p5.XML.js +2 -5
  67. package/{src → dist}/io/utilities.js +1 -1
  68. package/{src/core/p5.Renderer2D.js → dist/main-CAxvgiOV.js} +738 -57
  69. package/{src → dist}/math/Matrices/Matrix.js +10 -8
  70. package/{src → dist}/math/Matrices/MatrixInterface.js +5 -3
  71. package/{src → dist}/math/Matrices/MatrixNumjs.js +12 -26
  72. package/{src → dist}/math/calculation.js +2 -2
  73. package/{src → dist}/math/index.js +6 -3
  74. package/{src → dist}/math/math.js +3 -3
  75. package/{src → dist}/math/noise.js +2 -2
  76. package/{src → dist}/math/p5.Matrix.js +7 -4
  77. package/{src → dist}/math/p5.Vector.js +6 -6
  78. package/{src → dist}/math/random.js +2 -2
  79. package/{src → dist}/math/trigonometry.js +16 -15
  80. package/{src/image/p5.Image.js → dist/p5.Renderer-Swjl9HQO.js} +393 -22
  81. package/dist/rendering-B5TRR7aY.js +24960 -0
  82. package/{src → dist}/shape/2d_primitives.js +18 -17
  83. package/{src → dist}/shape/attributes.js +18 -17
  84. package/{src → dist}/shape/curves.js +2 -2
  85. package/{src → dist}/shape/custom_shapes.js +44 -64
  86. package/{src → dist}/shape/index.js +10 -2
  87. package/{src → dist}/shape/vertex.js +2 -3
  88. package/dist/type/index.js +25 -0
  89. package/{src → dist}/type/lib/Typr.js +76 -94
  90. package/{src → dist}/type/p5.Font.js +37 -63
  91. package/{src → dist}/type/textCore.js +35 -58
  92. package/{src → dist}/type/unicodeRanges.js +3 -1
  93. package/{src → dist}/utilities/conversion.js +2 -2
  94. package/{src → dist}/utilities/index.js +3 -1
  95. package/{src → dist}/utilities/time_date.js +6 -7
  96. package/{src → dist}/utilities/utility_functions.js +2 -2
  97. package/dist/webgl/3d_primitives.js +40 -0
  98. package/{src → dist}/webgl/GeometryBufferCache.js +3 -1
  99. package/{src → dist}/webgl/GeometryBuilder.js +12 -8
  100. package/{src → dist}/webgl/ShaderGenerator.js +79 -82
  101. package/{src → dist}/webgl/ShapeBuilder.js +26 -23
  102. package/dist/webgl/index.js +76 -0
  103. package/{src → dist}/webgl/interaction.js +7 -6
  104. package/dist/webgl/light.js +40 -0
  105. package/{src → dist}/webgl/loading.js +45 -12
  106. package/dist/webgl/material.js +40 -0
  107. package/dist/webgl/p5.Camera.js +40 -0
  108. package/{src → dist}/webgl/p5.DataArray.js +3 -5
  109. package/dist/webgl/p5.Framebuffer.js +40 -0
  110. package/{src → dist}/webgl/p5.Geometry.js +12 -15
  111. package/{src → dist}/webgl/p5.Quat.js +5 -4
  112. package/{src → dist}/webgl/p5.RenderBuffer.js +2 -3
  113. package/dist/webgl/p5.RendererGL.js +40 -0
  114. package/dist/webgl/p5.Shader.js +40 -0
  115. package/dist/webgl/p5.Texture.js +40 -0
  116. package/{src → dist}/webgl/text.js +78 -38
  117. package/lib/p5.esm.js +296 -194
  118. package/lib/p5.js +296 -194
  119. package/lib/p5.min.js +1 -1
  120. package/package.json +17 -17
  121. package/translations/dev.js +6 -6
  122. package/translations/index.js +1 -1
  123. package/types/accessibility/color_namer.d.ts +8 -0
  124. package/types/accessibility/describe.d.ts +184 -0
  125. package/types/accessibility/gridOutput.d.ts +8 -0
  126. package/types/accessibility/outputs.d.ts +235 -0
  127. package/types/accessibility/textOutput.d.ts +8 -0
  128. package/types/color/color_conversion.d.ts +47 -0
  129. package/types/color/creating_reading.d.ts +1348 -0
  130. package/types/color/p5.Color.d.ts +1070 -0
  131. package/types/color/setting.d.ts +2085 -0
  132. package/types/core/constants.d.ts +341 -0
  133. package/types/core/environment.d.ts +668 -0
  134. package/types/core/friendly_errors/fes_core.d.ts +8 -0
  135. package/types/core/friendly_errors/file_errors.d.ts +8 -0
  136. package/types/core/friendly_errors/param_validator.d.ts +30 -0
  137. package/types/core/friendly_errors/sketch_reader.d.ts +8 -0
  138. package/types/core/friendly_errors/stacktrace.d.ts +11 -0
  139. package/types/core/friendly_errors/validate_params.d.ts +8 -0
  140. package/types/core/helpers.d.ts +8 -0
  141. package/types/core/legacy.d.ts +8 -0
  142. package/types/core/main.d.ts +5996 -0
  143. package/types/core/p5.Graphics.d.ts +484 -0
  144. package/types/core/p5.Renderer.d.ts +14 -0
  145. package/types/core/reference.d.ts +8 -0
  146. package/types/core/rendering.d.ts +481 -0
  147. package/types/core/structure.d.ts +492 -0
  148. package/types/core/transform.d.ts +1638 -0
  149. package/types/data/local_storage.d.ts +323 -0
  150. package/types/dom/dom.d.ts +1295 -0
  151. package/types/dom/p5.Element.d.ts +2011 -0
  152. package/types/dom/p5.File.d.ts +13 -0
  153. package/types/dom/p5.MediaElement.d.ts +1249 -0
  154. package/types/events/acceleration.d.ts +193 -0
  155. package/types/events/keyboard.d.ts +499 -0
  156. package/types/events/pointer.d.ts +782 -0
  157. package/types/global.d.ts +5542 -0
  158. package/types/image/filterRenderer2D.d.ts +54 -0
  159. package/types/image/image.d.ts +326 -0
  160. package/types/image/loading_displaying.d.ts +580 -0
  161. package/types/image/p5.Image.d.ts +5882 -0
  162. package/types/image/pixels.d.ts +832 -0
  163. package/types/io/files.d.ts +1447 -0
  164. package/types/io/p5.Table.d.ts +1247 -0
  165. package/types/io/p5.TableRow.d.ts +343 -0
  166. package/types/io/p5.XML.d.ts +1188 -0
  167. package/types/math/Matrices/Matrix.d.ts +1029 -0
  168. package/types/math/Matrices/MatrixNumjs.d.ts +8 -0
  169. package/types/math/calculation.d.ts +923 -0
  170. package/types/math/math.d.ts +90 -0
  171. package/types/math/noise.d.ts +311 -0
  172. package/types/math/p5.Matrix.d.ts +8 -0
  173. package/types/math/p5.Vector.d.ts +3416 -0
  174. package/types/math/random.d.ts +267 -0
  175. package/types/math/trigonometry.d.ts +663 -0
  176. package/types/p5.d.ts +6663 -0
  177. package/types/shape/2d_primitives.d.ts +1033 -0
  178. package/types/shape/attributes.d.ts +466 -0
  179. package/types/shape/curves.d.ts +740 -0
  180. package/types/shape/custom_shapes.d.ts +888 -0
  181. package/types/shape/vertex.d.ts +1141 -0
  182. package/types/type/p5.Font.d.ts +575 -0
  183. package/types/type/textCore.d.ts +1198 -0
  184. package/types/utilities/conversion.d.ts +894 -0
  185. package/types/utilities/time_date.d.ts +295 -0
  186. package/types/utilities/utility_functions.d.ts +587 -0
  187. package/types/webgl/3d_primitives.d.ts +1432 -0
  188. package/types/webgl/ShaderGenerator.d.ts +8 -0
  189. package/types/webgl/interaction.d.ts +371 -0
  190. package/types/webgl/light.d.ts +1184 -0
  191. package/types/webgl/loading.d.ts +481 -0
  192. package/types/webgl/material.d.ts +2656 -0
  193. package/types/webgl/p5.Camera.d.ts +3023 -0
  194. package/types/webgl/p5.DataArray.d.ts +61 -0
  195. package/types/webgl/p5.Framebuffer.d.ts +760 -0
  196. package/types/webgl/p5.Geometry.d.ts +1191 -0
  197. package/types/webgl/p5.Quat.d.ts +45 -0
  198. package/types/webgl/p5.RendererGL.d.ts +234 -0
  199. package/types/webgl/p5.Shader.d.ts +660 -0
  200. package/types/webgl/p5.Texture.d.ts +61 -0
  201. package/types/webgl/text.d.ts +74 -0
  202. package/src/README.md +0 -27
  203. package/src/accessibility/index.js +0 -13
  204. package/src/app.js +0 -61
  205. package/src/color/index.js +0 -9
  206. package/src/color/p5.Color.culori.js +0 -66
  207. package/src/color/p5.Color.js +0 -851
  208. package/src/core/README.md +0 -91
  209. package/src/core/friendly_errors/index.js +0 -13
  210. package/src/core/friendly_errors/param_validator.js +0 -561
  211. package/src/core/init.js +0 -58
  212. package/src/core/internationalization.js +0 -195
  213. package/src/core/legacy.js +0 -29
  214. package/src/core/main.js +0 -689
  215. package/src/core/noop.js +0 -1
  216. package/src/core/p5.Graphics.js +0 -696
  217. package/src/core/p5.Renderer.js +0 -408
  218. package/src/core/reference.js +0 -2060
  219. package/src/core/rendering.js +0 -697
  220. package/src/dom/index.js +0 -11
  221. package/src/image/const.js +0 -6
  222. package/src/image/image.js +0 -731
  223. package/src/image/index.js +0 -15
  224. package/src/image/loading_displaying.js +0 -1431
  225. package/src/io/files.js +0 -2210
  226. package/src/io/index.js +0 -11
  227. package/src/math/README.md +0 -40
  228. package/src/type/index.js +0 -9
  229. package/src/webgl/3d_primitives.js +0 -2741
  230. package/src/webgl/index.js +0 -37
  231. package/src/webgl/light.js +0 -1851
  232. package/src/webgl/material.js +0 -3854
  233. package/src/webgl/p5.Camera.js +0 -4010
  234. package/src/webgl/p5.Framebuffer.js +0 -1865
  235. package/src/webgl/p5.RendererGL.js +0 -2867
  236. package/src/webgl/p5.Shader.js +0 -1505
  237. package/src/webgl/p5.Texture.js +0 -541
  238. package/src/webgl/shaders/basic.frag +0 -6
  239. package/src/webgl/shaders/filters/base.frag +0 -22
  240. package/src/webgl/shaders/filters/base.vert +0 -19
  241. package/src/webgl/shaders/filters/blur.frag +0 -60
  242. package/src/webgl/shaders/filters/default.vert +0 -18
  243. package/src/webgl/shaders/filters/dilate.frag +0 -39
  244. package/src/webgl/shaders/filters/erode.frag +0 -39
  245. package/src/webgl/shaders/filters/gray.frag +0 -16
  246. package/src/webgl/shaders/filters/invert.frag +0 -15
  247. package/src/webgl/shaders/filters/opaque.frag +0 -12
  248. package/src/webgl/shaders/filters/posterize.frag +0 -29
  249. package/src/webgl/shaders/filters/threshold.frag +0 -23
  250. package/src/webgl/shaders/font.frag +0 -216
  251. package/src/webgl/shaders/font.vert +0 -44
  252. package/src/webgl/shaders/imageLight.vert +0 -33
  253. package/src/webgl/shaders/imageLightDiffused.frag +0 -82
  254. package/src/webgl/shaders/imageLightSpecular.frag +0 -134
  255. package/src/webgl/shaders/light.vert +0 -37
  256. package/src/webgl/shaders/light_texture.frag +0 -26
  257. package/src/webgl/shaders/lighting.glsl +0 -227
  258. package/src/webgl/shaders/line.frag +0 -74
  259. package/src/webgl/shaders/line.vert +0 -294
  260. package/src/webgl/shaders/normal.frag +0 -6
  261. package/src/webgl/shaders/normal.vert +0 -72
  262. package/src/webgl/shaders/phong.frag +0 -84
  263. package/src/webgl/shaders/phong.vert +0 -87
  264. package/src/webgl/shaders/point.frag +0 -29
  265. package/src/webgl/shaders/point.vert +0 -19
  266. package/src/webgl/shaders/sphereMapping.frag +0 -26
  267. package/src/webgl/shaders/webgl2Compatibility.glsl +0 -34
@@ -1,4010 +0,0 @@
1
- /**
2
- * @module 3D
3
- * @submodule Camera
4
- * @requires core
5
- */
6
-
7
- import { Matrix } from '../math/p5.Matrix';
8
- import { Vector } from '../math/p5.Vector';
9
- import { Quat } from './p5.Quat';
10
- import { RendererGL } from './p5.RendererGL';
11
-
12
- class Camera {
13
- constructor(renderer) {
14
- this._renderer = renderer;
15
-
16
- this.cameraType = 'default';
17
- this.useLinePerspective = true;
18
- this.cameraMatrix = new Matrix(4);
19
- this.projMatrix = new Matrix(4);
20
- this.yScale = 1;
21
- }
22
- /**
23
- * The camera’s x-coordinate.
24
- *
25
- * By default, the camera’s x-coordinate is set to 0 in "world" space.
26
- *
27
- * @property {Number} eyeX
28
- * @readonly
29
- *
30
- * @example
31
- * <div>
32
- * <code>
33
- * let cam;
34
- * let font;
35
- *
36
- * async function setup() {
37
- * // Load a font and create a p5.Font object.
38
- * font = await loadFont('assets/inconsolata.otf');
39
- * createCanvas(100, 100, WEBGL);
40
- *
41
- * // Create a p5.Camera object.
42
- * cam = createCamera();
43
- *
44
- * // Set the camera
45
- * setCamera(cam);
46
- *
47
- * // Place the camera at the top-center.
48
- * cam.setPosition(0, -400, 800);
49
- *
50
- * // Point the camera at the origin.
51
- * cam.lookAt(0, 0, 0);
52
- *
53
- * describe(
54
- * 'A white cube on a gray background. The text "eyeX: 0" is written in black beneath it.'
55
- * );
56
- * }
57
- *
58
- * function draw() {
59
- * background(200);
60
- *
61
- * // Style the box.
62
- * fill(255);
63
- *
64
- * // Draw the box.
65
- * box();
66
- *
67
- * // Style the text.
68
- * textAlign(CENTER);
69
- * textSize(16);
70
- * textFont(font);
71
- * fill(0);
72
- *
73
- * // Display the value of eyeX, rounded to the nearest integer.
74
- * text(`eyeX: ${round(cam.eyeX)}`, 0, 55);
75
- * }
76
- * </code>
77
- * </div>
78
- *
79
- * <div>
80
- * <code>
81
- * let cam;
82
- * let font;
83
- *
84
- * async function setup() {
85
- * // Load a font and create a p5.Font object.
86
- * font = await loadFont('assets/inconsolata.otf');
87
- * createCanvas(100, 100, WEBGL);
88
- *
89
- * // Create a p5.Camera object.
90
- * cam = createCamera();
91
- *
92
- * // Set the camera
93
- * setCamera(cam);
94
- *
95
- * // Place the camera at the top-center.
96
- * cam.setPosition(0, -400, 800);
97
- *
98
- * // Point the camera at the origin.
99
- * cam.lookAt(0, 0, 0);
100
- *
101
- * describe(
102
- * 'A white cube on a gray background. The cube appears to move left and right as the camera moves. The text "eyeX: X" is written in black beneath the cube. X oscillates between -25 and 25.'
103
- * );
104
- * }
105
- *
106
- * function draw() {
107
- * background(200);
108
- *
109
- * // Style the box.
110
- * fill(255);
111
- *
112
- * // Draw the box.
113
- * box();
114
- *
115
- * // Style the text.
116
- * textAlign(CENTER);
117
- * textSize(16);
118
- * textFont(font);
119
- * fill(0);
120
- *
121
- * // Calculate the new x-coordinate.
122
- * let x = 25 * sin(frameCount * 0.01);
123
- *
124
- * // Set the camera's position.
125
- * cam.setPosition(x, -400, 800);
126
- *
127
- * // Display the value of eyeX, rounded to the nearest integer.
128
- * text(`eyeX: ${round(cam.eyeX)}`, 0, 55);
129
- * }
130
- * </code>
131
- * </div>
132
- */
133
-
134
- /**
135
- * The camera’s y-coordinate.
136
- *
137
- * By default, the camera’s y-coordinate is set to 0 in "world" space.
138
- *
139
- * @property {Number} eyeY
140
- * @readonly
141
- *
142
- * @example
143
- * <div>
144
- * <code>
145
- * let cam;
146
- * let font;
147
- *
148
- * async function setup() {
149
- * // Load a font and create a p5.Font object.
150
- * font = await loadFont('assets/inconsolata.otf');
151
- * createCanvas(100, 100, WEBGL);
152
- *
153
- * // Create a p5.Camera object.
154
- * cam = createCamera();
155
- *
156
- * // Place the camera at the top-center.
157
- * cam.setPosition(0, -400, 800);
158
- *
159
- * // Point the camera at the origin.
160
- * cam.lookAt(0, 0, 0);
161
- *
162
- * // Set the camera.
163
- * setCamera(cam);
164
- *
165
- * describe(
166
- * 'A white cube on a gray background. The text "eyeY: -400" is written in black beneath it.'
167
- * );
168
- * }
169
- *
170
- * function draw() {
171
- * background(200);
172
- *
173
- * // Style the box.
174
- * fill(255);
175
- *
176
- * // Draw the box.
177
- * box();
178
- *
179
- * // Style the text.
180
- * textAlign(CENTER);
181
- * textSize(16);
182
- * textFont(font);
183
- * fill(0);
184
- *
185
- * // Display the value of eyeY, rounded to the nearest integer.
186
- * text(`eyeY: ${round(cam.eyeY)}`, 0, 55);
187
- * }
188
- * </code>
189
- * </div>
190
- *
191
- * <div>
192
- * <code>
193
- * let cam;
194
- * let font;
195
- *
196
- * async function setup() {
197
- * // Load a font and create a p5.Font object.
198
- * font = await loadFont('assets/inconsolata.otf');
199
- * createCanvas(100, 100, WEBGL);
200
- *
201
- * // Create a p5.Camera object.
202
- * cam = createCamera();
203
- *
204
- * // Set the camera
205
- * setCamera(cam);
206
- *
207
- * // Place the camera at the top-center.
208
- * cam.setPosition(0, -400, 800);
209
- *
210
- * // Point the camera at the origin.
211
- * cam.lookAt(0, 0, 0);
212
- *
213
- * describe(
214
- * 'A white cube on a gray background. The cube appears to move up and down as the camera moves. The text "eyeY: Y" is written in black beneath the cube. Y oscillates between -374 and -425.'
215
- * );
216
- * }
217
- *
218
- * function draw() {
219
- * background(200);
220
- *
221
- * // Style the box.
222
- * fill(255);
223
- *
224
- * // Draw the box.
225
- * box();
226
- *
227
- * // Style the text.
228
- * textAlign(CENTER);
229
- * textSize(16);
230
- * textFont(font);
231
- * fill(0);
232
- *
233
- * // Calculate the new y-coordinate.
234
- * let y = 25 * sin(frameCount * 0.01) - 400;
235
- *
236
- * // Set the camera's position.
237
- * cam.setPosition(0, y, 800);
238
- *
239
- * // Display the value of eyeY, rounded to the nearest integer.
240
- * text(`eyeY: ${round(cam.eyeY)}`, 0, 55);
241
- * }
242
- * </code>
243
- * </div>
244
- */
245
-
246
- /**
247
- * The camera’s z-coordinate.
248
- *
249
- * By default, the camera’s z-coordinate is set to 800 in "world" space.
250
- *
251
- * @property {Number} eyeZ
252
- * @readonly
253
- *
254
- * @example
255
- * <div>
256
- * <code>
257
- * let cam;
258
- * let font;
259
- *
260
- * async function setup() {
261
- * // Load a font and create a p5.Font object.
262
- * font = await loadFont('assets/inconsolata.otf');
263
- * createCanvas(100, 100, WEBGL);
264
- *
265
- * // Create a p5.Camera object.
266
- * cam = createCamera();
267
- *
268
- * // Set the camera
269
- * setCamera(cam);
270
- *
271
- * // Place the camera at the top-center.
272
- * cam.setPosition(0, -400, 800);
273
- *
274
- * // Point the camera at the origin.
275
- * cam.lookAt(0, 0, 0);
276
- *
277
- * describe(
278
- * 'A white cube on a gray background. The text "eyeZ: 800" is written in black beneath it.'
279
- * );
280
- * }
281
- *
282
- * function draw() {
283
- * background(200);
284
- *
285
- * // Style the box.
286
- * fill(255);
287
- *
288
- * // Draw the box.
289
- * box();
290
- *
291
- * // Style the text.
292
- * textAlign(CENTER);
293
- * textSize(16);
294
- * textFont(font);
295
- * fill(0);
296
- *
297
- * // Display the value of eyeZ, rounded to the nearest integer.
298
- * text(`eyeZ: ${round(cam.eyeZ)}`, 0, 55);
299
- * }
300
- * </code>
301
- * </div>
302
- *
303
- * <div>
304
- * <code>
305
- * let cam;
306
- * let font;
307
- *
308
- * async function setup() {
309
- * // Load a font and create a p5.Font object.
310
- * font = await loadFont('assets/inconsolata.otf');
311
- * createCanvas(100, 100, WEBGL);
312
- *
313
- * // Create a p5.Camera object.
314
- * cam = createCamera();
315
- *
316
- * // Set the camera
317
- * setCamera(cam);
318
- *
319
- * // Place the camera at the top-center.
320
- * cam.setPosition(0, -400, 800);
321
- *
322
- * // Point the camera at the origin.
323
- * cam.lookAt(0, 0, 0);
324
- *
325
- * describe(
326
- * 'A white cube on a gray background. The cube appears to move forward and back as the camera moves. The text "eyeZ: Z" is written in black beneath the cube. Z oscillates between 700 and 900.'
327
- * );
328
- * }
329
- *
330
- * function draw() {
331
- * background(200);
332
- *
333
- * // Style the box.
334
- * fill(255);
335
- *
336
- * // Draw the box.
337
- * box();
338
- *
339
- * // Style the text.
340
- * textAlign(CENTER);
341
- * textSize(16);
342
- * textFont(font);
343
- * fill(0);
344
- *
345
- * // Calculate the new z-coordinate.
346
- * let z = 100 * sin(frameCount * 0.01) + 800;
347
- *
348
- * // Set the camera's position.
349
- * cam.setPosition(0, -400, z);
350
- *
351
- * // Display the value of eyeZ, rounded to the nearest integer.
352
- * text(`eyeZ: ${round(cam.eyeZ)}`, 0, 55);
353
- * }
354
- * </code>
355
- * </div>
356
- */
357
-
358
- /**
359
- * The x-coordinate of the place where the camera looks.
360
- *
361
- * By default, the camera looks at the origin `(0, 0, 0)` in "world" space, so
362
- * `myCamera.centerX` is 0.
363
- *
364
- * @property {Number} centerX
365
- * @readonly
366
- *
367
- * @example
368
- * <div>
369
- * <code>
370
- * let cam;
371
- * let font;
372
- *
373
- * async function setup() {
374
- * // Load a font and create a p5.Font object.
375
- * font = await loadFont('assets/inconsolata.otf');
376
- * createCanvas(100, 100, WEBGL);
377
- *
378
- * // Create a p5.Camera object.
379
- * cam = createCamera();
380
- *
381
- * // Set the camera
382
- * setCamera(cam);
383
- *
384
- * // Place the camera at the top-center.
385
- * cam.setPosition(0, -400, 800);
386
- *
387
- * // Point the camera at (10, 20, -30).
388
- * cam.lookAt(10, 20, -30);
389
- *
390
- * describe(
391
- * 'A white cube on a gray background. The text "centerX: 10" is written in black beneath it.'
392
- * );
393
- * }
394
- *
395
- * function draw() {
396
- * background(200);
397
- *
398
- * // Style the box.
399
- * fill(255);
400
- *
401
- * // Draw the box.
402
- * box();
403
- *
404
- * // Style the text.
405
- * textAlign(CENTER);
406
- * textSize(16);
407
- * textFont(font);
408
- * fill(0);
409
- *
410
- * // Display the value of centerX, rounded to the nearest integer.
411
- * text(`centerX: ${round(cam.centerX)}`, 0, 55);
412
- * }
413
- * </code>
414
- * </div>
415
- *
416
- * <div>
417
- * <code>
418
- * let cam;
419
- * let font;
420
- *
421
- * async function setup() {
422
- * // Load a font and create a p5.Font object.
423
- * font = await loadFont('assets/inconsolata.otf');
424
- * createCanvas(100, 100, WEBGL);
425
- *
426
- * // Create a p5.Camera object.
427
- * cam = createCamera();
428
- *
429
- * // Set the camera
430
- * setCamera(cam);
431
- *
432
- * // Place the camera at the top-right.
433
- * cam.setPosition(100, -400, 800);
434
- *
435
- * // Point the camera at (10, 20, -30).
436
- * cam.lookAt(10, 20, -30);
437
- *
438
- * describe(
439
- * 'A white cube on a gray background. The cube appears to move left and right as the camera shifts its focus. The text "centerX: X" is written in black beneath the cube. X oscillates between -15 and 35.'
440
- * );
441
- * }
442
- *
443
- * function draw() {
444
- * background(200);
445
- *
446
- * // Style the box.
447
- * fill(255);
448
- *
449
- * // Draw the box.
450
- * box();
451
- *
452
- * // Style the text.
453
- * textAlign(CENTER);
454
- * textSize(16);
455
- * textFont(font);
456
- * fill(0);
457
- *
458
- * // Calculate the new x-coordinate.
459
- * let x = 25 * sin(frameCount * 0.01) + 10;
460
- *
461
- * // Point the camera.
462
- * cam.lookAt(x, 20, -30);
463
- *
464
- * // Display the value of centerX, rounded to the nearest integer.
465
- * text(`centerX: ${round(cam.centerX)}`, 0, 55);
466
- * }
467
- * </code>
468
- * </div>
469
- */
470
-
471
- /**
472
- * The y-coordinate of the place where the camera looks.
473
- *
474
- * By default, the camera looks at the origin `(0, 0, 0)` in "world" space, so
475
- * `myCamera.centerY` is 0.
476
- *
477
- * @property {Number} centerY
478
- * @readonly
479
- *
480
- * @example
481
- * <div>
482
- * <code>
483
- * let cam;
484
- * let font;
485
- *
486
- * async function setup() {
487
- * // Load a font and create a p5.Font object.
488
- * font = await loadFont('assets/inconsolata.otf');
489
- * createCanvas(100, 100, WEBGL);
490
- *
491
- * // Create a p5.Camera object.
492
- * cam = createCamera();
493
- *
494
- * // Set the camera
495
- * setCamera(cam);
496
- *
497
- * // Place the camera at the top-center.
498
- * cam.setPosition(0, -400, 800);
499
- *
500
- * // Point the camera at (10, 20, -30).
501
- * cam.lookAt(10, 20, -30);
502
- *
503
- * describe(
504
- * 'A white cube on a gray background. The text "centerY: 20" is written in black beneath it.'
505
- * );
506
- * }
507
- *
508
- * function draw() {
509
- * background(200);
510
- *
511
- * // Style the box.
512
- * fill(255);
513
- *
514
- * // Draw the box.
515
- * box();
516
- *
517
- * // Style the text.
518
- * textAlign(CENTER);
519
- * textSize(16);
520
- * textFont(font);
521
- * fill(0);
522
- *
523
- * // Display the value of centerY, rounded to the nearest integer.
524
- * text(`centerY: ${round(cam.centerY)}`, 0, 55);
525
- * }
526
- * </code>
527
- * </div>
528
- *
529
- * <div>
530
- * <code>
531
- * let cam;
532
- * let font;
533
- *
534
- * async function setup() {
535
- * // Load a font and create a p5.Font object.
536
- * font = await loadFont('assets/inconsolata.otf');
537
- * createCanvas(100, 100, WEBGL);
538
- *
539
- * // Create a p5.Camera object.
540
- * cam = createCamera();
541
- *
542
- * // Set the camera
543
- * setCamera(cam);
544
- *
545
- * // Place the camera at the top-right.
546
- * cam.setPosition(100, -400, 800);
547
- *
548
- * // Point the camera at (10, 20, -30).
549
- * cam.lookAt(10, 20, -30);
550
- *
551
- * describe(
552
- * 'A white cube on a gray background. The cube appears to move up and down as the camera shifts its focus. The text "centerY: Y" is written in black beneath the cube. Y oscillates between -5 and 45.'
553
- * );
554
- * }
555
- *
556
- * function draw() {
557
- * background(200);
558
- *
559
- * // Style the box.
560
- * fill(255);
561
- *
562
- * // Draw the box.
563
- * box();
564
- *
565
- * // Style the text.
566
- * textAlign(CENTER);
567
- * textSize(16);
568
- * textFont(font);
569
- * fill(0);
570
- *
571
- * // Calculate the new y-coordinate.
572
- * let y = 25 * sin(frameCount * 0.01) + 20;
573
- *
574
- * // Point the camera.
575
- * cam.lookAt(10, y, -30);
576
- *
577
- * // Display the value of centerY, rounded to the nearest integer.
578
- * text(`centerY: ${round(cam.centerY)}`, 0, 55);
579
- * }
580
- * </code>
581
- * </div>
582
- */
583
-
584
- /**
585
- * The y-coordinate of the place where the camera looks.
586
- *
587
- * By default, the camera looks at the origin `(0, 0, 0)` in "world" space, so
588
- * `myCamera.centerZ` is 0.
589
- *
590
- * @property {Number} centerZ
591
- * @readonly
592
- *
593
- * @example
594
- * <div>
595
- * <code>
596
- * let cam;
597
- * let font;
598
- *
599
- * async function setup() {
600
- * // Load a font and create a p5.Font object.
601
- * font = await loadFont('assets/inconsolata.otf');
602
- * createCanvas(100, 100, WEBGL);
603
- *
604
- * // Create a p5.Camera object.
605
- * cam = createCamera();
606
- *
607
- * // Set the camera
608
- * setCamera(cam);
609
- *
610
- * // Place the camera at the top-center.
611
- * cam.setPosition(0, -400, 800);
612
- *
613
- * // Point the camera at (10, 20, -30).
614
- * cam.lookAt(10, 20, -30);
615
- *
616
- * describe(
617
- * 'A white cube on a gray background. The text "centerZ: -30" is written in black beneath it.'
618
- * );
619
- * }
620
- *
621
- * function draw() {
622
- * background(200);
623
- *
624
- * // Style the box.
625
- * fill(255);
626
- *
627
- * // Draw the box.
628
- * box();
629
- *
630
- * // Style the text.
631
- * textAlign(CENTER);
632
- * textSize(16);
633
- * textFont(font);
634
- * fill(0);
635
- *
636
- * // Display the value of centerZ, rounded to the nearest integer.
637
- * text(`centerZ: ${round(cam.centerZ)}`, 0, 55);
638
- * }
639
- * </code>
640
- * </div>
641
- *
642
- * <div>
643
- * <code>
644
- * let cam;
645
- * let font;
646
- *
647
- * async function setup() {
648
- * // Load a font and create a p5.Font object.
649
- * font = await loadFont('assets/inconsolata.otf');
650
- * createCanvas(100, 100, WEBGL);
651
- *
652
- * // Create a p5.Camera object.
653
- * cam = createCamera();
654
- *
655
- * // Set the camera
656
- * setCamera(cam);
657
- *
658
- * // Place the camera at the top-right.
659
- * cam.setPosition(100, -400, 800);
660
- *
661
- * // Point the camera at (10, 20, -30).
662
- * cam.lookAt(10, 20, -30);
663
- *
664
- * describe(
665
- * 'A white cube on a gray background. The cube appears to move forward and back as the camera shifts its focus. The text "centerZ: Z" is written in black beneath the cube. Z oscillates between -55 and -25.'
666
- * );
667
- * }
668
- *
669
- * function draw() {
670
- * background(200);
671
- *
672
- * // Style the box.
673
- * fill(255);
674
- *
675
- * // Draw the box.
676
- * box();
677
- *
678
- * // Style the text.
679
- * textAlign(CENTER);
680
- * textSize(16);
681
- * textFont(font);
682
- * fill(0);
683
- *
684
- * // Calculate the new z-coordinate.
685
- * let z = 25 * sin(frameCount * 0.01) - 30;
686
- *
687
- * // Point the camera.
688
- * cam.lookAt(10, 20, z);
689
- *
690
- * // Display the value of centerZ, rounded to the nearest integer.
691
- * text(`centerZ: ${round(cam.centerZ)}`, 0, 55);
692
- * }
693
- * </code>
694
- * </div>
695
- */
696
-
697
- /**
698
- * The x-component of the camera's "up" vector.
699
- *
700
- * The camera's "up" vector orients its y-axis. By default, the "up" vector is
701
- * `(0, 1, 0)`, so its x-component is 0 in "local" space.
702
- *
703
- * @property {Number} upX
704
- * @readonly
705
- *
706
- * @example
707
- * <div>
708
- * <code>
709
- * let cam;
710
- * let font;
711
- *
712
- * async function setup() {
713
- * // Load a font and create a p5.Font object.
714
- * font = await loadFont('assets/inconsolata.otf');
715
- * createCanvas(100, 100, WEBGL);
716
- *
717
- * // Create a p5.Camera object.
718
- * cam = createCamera();
719
- *
720
- * // Set the camera
721
- * setCamera(cam);
722
- *
723
- * // Place the camera at the top-right: (100, -400, 800)
724
- * // Point it at the origin: (0, 0, 0)
725
- * // Set its "up" vector: (0, 1, 0).
726
- * cam.camera(100, -400, 800, 0, 0, 0, 0, 1, 0);
727
- *
728
- * describe(
729
- * 'A white cube on a gray background. The text "upX: 0" is written in black beneath it.'
730
- * );
731
- * }
732
- *
733
- * function draw() {
734
- * background(200);
735
- *
736
- * // Style the box.
737
- * fill(255);
738
- *
739
- * // Draw the box.
740
- * box();
741
- *
742
- * // Style the text.
743
- * textAlign(CENTER);
744
- * textSize(16);
745
- * textFont(font);
746
- * fill(0);
747
- *
748
- * // Display the value of upX, rounded to the nearest tenth.
749
- * text(`upX: ${round(cam.upX, 1)}`, 0, 55);
750
- * }
751
- * </code>
752
- * </div>
753
- *
754
- * <div>
755
- * <code>
756
- * let cam;
757
- * let font;
758
- *
759
- * async function setup() {
760
- * // Load a font and create a p5.Font object.
761
- * font = await loadFont('assets/inconsolata.otf');
762
- * createCanvas(100, 100, WEBGL);
763
- *
764
- * // Create a p5.Camera object.
765
- * cam = createCamera();
766
- *
767
- * // Set the camera
768
- * setCamera(cam);
769
- *
770
- * // Place the camera at the top-right: (100, -400, 800)
771
- * // Point it at the origin: (0, 0, 0)
772
- * // Set its "up" vector: (0, 1, 0).
773
- * cam.camera(100, -400, 800, 0, 0, 0, 0, 1, 0);
774
- *
775
- * describe(
776
- * 'A white cube on a gray background. The cube appears to rock back and forth. The text "upX: X" is written in black beneath it. X oscillates between -1 and 1.'
777
- * );
778
- * }
779
- *
780
- * function draw() {
781
- * background(200);
782
- *
783
- * // Style the box.
784
- * fill(255);
785
- *
786
- * // Draw the box.
787
- * box();
788
- *
789
- * // Style the text.
790
- * textAlign(CENTER);
791
- * textSize(16);
792
- * textFont(font);
793
- * fill(0);
794
- *
795
- * // Calculate the x-component.
796
- * let x = sin(frameCount * 0.01);
797
- *
798
- * // Update the camera's "up" vector.
799
- * cam.camera(100, -400, 800, 0, 0, 0, x, 1, 0);
800
- *
801
- * // Display the value of upX, rounded to the nearest tenth.
802
- * text(`upX: ${round(cam.upX, 1)}`, 0, 55);
803
- * }
804
- * </code>
805
- * </div>
806
- */
807
-
808
- /**
809
- * The y-component of the camera's "up" vector.
810
- *
811
- * The camera's "up" vector orients its y-axis. By default, the "up" vector is
812
- * `(0, 1, 0)`, so its y-component is 1 in "local" space.
813
- *
814
- * @property {Number} upY
815
- * @readonly
816
- *
817
- * @example
818
- * <div>
819
- * <code>
820
- * let cam;
821
- * let font;
822
- *
823
- * async function setup() {
824
- * // Load a font and create a p5.Font object.
825
- * font = await loadFont('assets/inconsolata.otf');
826
- * createCanvas(100, 100, WEBGL);
827
- *
828
- * // Create a p5.Camera object.
829
- * cam = createCamera();
830
- *
831
- * // Set the camera
832
- * setCamera(cam);
833
- *
834
- * // Place the camera at the top-right: (100, -400, 800)
835
- * // Point it at the origin: (0, 0, 0)
836
- * // Set its "up" vector: (0, 1, 0).
837
- * cam.camera(100, -400, 800, 0, 0, 0, 0, 1, 0);
838
- *
839
- * describe(
840
- * 'A white cube on a gray background. The text "upY: 1" is written in black beneath it.'
841
- * );
842
- * }
843
- *
844
- * function draw() {
845
- * background(200);
846
- *
847
- * // Style the box.
848
- * fill(255);
849
- *
850
- * // Draw the box.
851
- * box();
852
- *
853
- * // Style the text.
854
- * textAlign(CENTER);
855
- * textSize(16);
856
- * textFont(font);
857
- * fill(0);
858
- *
859
- * // Display the value of upY, rounded to the nearest tenth.
860
- * text(`upY: ${round(cam.upY, 1)}`, 0, 55);
861
- * }
862
- * </code>
863
- * </div>
864
- *
865
- * <div>
866
- * <code>
867
- * let cam;
868
- * let font;
869
- *
870
- * async function setup() {
871
- * // Load a font and create a p5.Font object.
872
- * font = await loadFont('assets/inconsolata.otf');
873
- * createCanvas(100, 100, WEBGL);
874
- *
875
- * // Create a p5.Camera object.
876
- * cam = createCamera();
877
- *
878
- * // Set the camera
879
- * setCamera(cam);
880
- *
881
- * // Place the camera at the top-right: (100, -400, 800)
882
- * // Point it at the origin: (0, 0, 0)
883
- * // Set its "up" vector: (0, 1, 0).
884
- * cam.camera(100, -400, 800, 0, 0, 0, 0, 1, 0);
885
- *
886
- * describe(
887
- * 'A white cube on a gray background. The cube flips upside-down periodically. The text "upY: Y" is written in black beneath it. Y oscillates between -1 and 1.'
888
- * );
889
- * }
890
- *
891
- * function draw() {
892
- * background(200);
893
- *
894
- * // Style the box.
895
- * fill(255);
896
- *
897
- * // Draw the box.
898
- * box();
899
- *
900
- * // Style the text.
901
- * textAlign(CENTER);
902
- * textSize(16);
903
- * textFont(font);
904
- * fill(0);
905
- *
906
- * // Calculate the y-component.
907
- * let y = sin(frameCount * 0.01);
908
- *
909
- * // Update the camera's "up" vector.
910
- * cam.camera(100, -400, 800, 0, 0, 0, 0, y, 0);
911
- *
912
- * // Display the value of upY, rounded to the nearest tenth.
913
- * text(`upY: ${round(cam.upY, 1)}`, 0, 55);
914
- * }
915
- * </code>
916
- * </div>
917
- */
918
-
919
- /**
920
- * The z-component of the camera's "up" vector.
921
- *
922
- * The camera's "up" vector orients its y-axis. By default, the "up" vector is
923
- * `(0, 1, 0)`, so its z-component is 0 in "local" space.
924
- *
925
- * @property {Number} upZ
926
- * @readonly
927
- *
928
- * @example
929
- * <div>
930
- * <code>
931
- * let cam;
932
- * let font;
933
- *
934
- * async function setup() {
935
- * // Load a font and create a p5.Font object.
936
- * font = await loadFont('assets/inconsolata.otf');
937
- * createCanvas(100, 100, WEBGL);
938
- *
939
- * // Create a p5.Camera object.
940
- * cam = createCamera();
941
- *
942
- * // Set the camera
943
- * setCamera(cam);
944
- *
945
- * // Place the camera at the top-right: (100, -400, 800)
946
- * // Point it at the origin: (0, 0, 0)
947
- * // Set its "up" vector: (0, 1, 0).
948
- * cam.camera(100, -400, 800, 0, 0, 0, 0, 1, 0);
949
- *
950
- * describe(
951
- * 'A white cube on a gray background. The text "upZ: 0" is written in black beneath it.'
952
- * );
953
- * }
954
- *
955
- * function draw() {
956
- * background(200);
957
- *
958
- * // Style the box.
959
- * fill(255);
960
- *
961
- * // Draw the box.
962
- * box();
963
- *
964
- * // Style the text.
965
- * textAlign(CENTER);
966
- * textSize(16);
967
- * textFont(font);
968
- * fill(0);
969
- *
970
- * // Display the value of upZ, rounded to the nearest tenth.
971
- * text(`upZ: ${round(cam.upZ, 1)}`, 0, 55);
972
- * }
973
- * </code>
974
- * </div>
975
- *
976
- * <div>
977
- * <code>
978
- * let cam;
979
- * let font;
980
- *
981
- * async function setup() {
982
- * // Load a font and create a p5.Font object.
983
- * font = await loadFont('assets/inconsolata.otf');
984
- * createCanvas(100, 100, WEBGL);
985
- *
986
- * // Create a p5.Camera object.
987
- * cam = createCamera();
988
- *
989
- * // Set the camera
990
- * setCamera(cam);
991
- *
992
- * // Place the camera at the top-right: (100, -400, 800)
993
- * // Point it at the origin: (0, 0, 0)
994
- * // Set its "up" vector: (0, 1, 0).
995
- * cam.camera(100, -400, 800, 0, 0, 0, 0, 1, 0);
996
- *
997
- * describe(
998
- * 'A white cube on a gray background. The cube appears to rock back and forth. The text "upZ: Z" is written in black beneath it. Z oscillates between -1 and 1.'
999
- * );
1000
- * }
1001
- *
1002
- * function draw() {
1003
- * background(200);
1004
- *
1005
- * // Style the box.
1006
- * fill(255);
1007
- *
1008
- * // Draw the box.
1009
- * box();
1010
- *
1011
- * // Style the text.
1012
- * textAlign(CENTER);
1013
- * textSize(16);
1014
- * textFont(font);
1015
- * fill(0);
1016
- *
1017
- * // Calculate the z-component.
1018
- * let z = sin(frameCount * 0.01);
1019
- *
1020
- * // Update the camera's "up" vector.
1021
- * cam.camera(100, -400, 800, 0, 0, 0, 0, 1, z);
1022
- *
1023
- * // Display the value of upZ, rounded to the nearest tenth.
1024
- * text(`upZ: ${round(cam.upZ, 1)}`, 0, 55);
1025
- * }
1026
- * </code>
1027
- * </div>
1028
- */
1029
-
1030
- ////////////////////////////////////////////////////////////////////////////////
1031
- // Camera Projection Methods
1032
- ////////////////////////////////////////////////////////////////////////////////
1033
-
1034
- /**
1035
- * Sets a perspective projection for the camera.
1036
- *
1037
- * In a perspective projection, shapes that are further from the camera appear
1038
- * smaller than shapes that are near the camera. This technique, called
1039
- * foreshortening, creates realistic 3D scenes. It’s applied by default in new
1040
- * `p5.Camera` objects.
1041
- *
1042
- * `myCamera.perspective()` changes the camera’s perspective by changing its
1043
- * viewing frustum. The frustum is the volume of space that’s visible to the
1044
- * camera. The frustum’s shape is a pyramid with its top cut off. The camera
1045
- * is placed where the top of the pyramid should be and points towards the
1046
- * base of the pyramid. It views everything within the frustum.
1047
- *
1048
- * The first parameter, `fovy`, is the camera’s vertical field of view. It’s
1049
- * an angle that describes how tall or narrow a view the camera has. For
1050
- * example, calling `myCamera.perspective(0.5)` sets the camera’s vertical
1051
- * field of view to 0.5 radians. By default, `fovy` is calculated based on the
1052
- * sketch’s height and the camera’s default z-coordinate, which is 800. The
1053
- * formula for the default `fovy` is `2 * atan(height / 2 / 800)`.
1054
- *
1055
- * The second parameter, `aspect`, is the camera’s aspect ratio. It’s a number
1056
- * that describes the ratio of the top plane’s width to its height. For
1057
- * example, calling `myCamera.perspective(0.5, 1.5)` sets the camera’s field
1058
- * of view to 0.5 radians and aspect ratio to 1.5, which would make shapes
1059
- * appear thinner on a square canvas. By default, `aspect` is set to
1060
- * `width / height`.
1061
- *
1062
- * The third parameter, `near`, is the distance from the camera to the near
1063
- * plane. For example, calling `myCamera.perspective(0.5, 1.5, 100)` sets the
1064
- * camera’s field of view to 0.5 radians, its aspect ratio to 1.5, and places
1065
- * the near plane 100 pixels from the camera. Any shapes drawn less than 100
1066
- * pixels from the camera won’t be visible. By default, `near` is set to
1067
- * `0.1 * 800`, which is 1/10th the default distance between the camera and
1068
- * the origin.
1069
- *
1070
- * The fourth parameter, `far`, is the distance from the camera to the far
1071
- * plane. For example, calling `myCamera.perspective(0.5, 1.5, 100, 10000)`
1072
- * sets the camera’s field of view to 0.5 radians, its aspect ratio to 1.5,
1073
- * places the near plane 100 pixels from the camera, and places the far plane
1074
- * 10,000 pixels from the camera. Any shapes drawn more than 10,000 pixels
1075
- * from the camera won’t be visible. By default, `far` is set to `10 * 800`,
1076
- * which is 10 times the default distance between the camera and the origin.
1077
- *
1078
- * @for p5.Camera
1079
- * @param {Number} [fovy] camera frustum vertical field of view. Defaults to
1080
- * `2 * atan(height / 2 / 800)`.
1081
- * @param {Number} [aspect] camera frustum aspect ratio. Defaults to
1082
- * `width / height`.
1083
- * @param {Number} [near] distance from the camera to the near clipping plane.
1084
- * Defaults to `0.1 * 800`.
1085
- * @param {Number} [far] distance from the camera to the far clipping plane.
1086
- * Defaults to `10 * 800`.
1087
- *
1088
- * @example
1089
- * <div>
1090
- * <code>
1091
- * // Double-click to toggle between cameras.
1092
- *
1093
- * let cam1;
1094
- * let cam2;
1095
- * let isDefaultCamera = true;
1096
- *
1097
- * function setup() {
1098
- * createCanvas(100, 100, WEBGL);
1099
- *
1100
- * // Create the first camera.
1101
- * // Keep its default settings.
1102
- * cam1 = createCamera();
1103
- *
1104
- * // Create the second camera.
1105
- * cam2 = createCamera();
1106
- *
1107
- * // Place it at the top-right.
1108
- * cam2.camera(400, -400, 800);
1109
- *
1110
- * // Set its fovy to 0.2.
1111
- * // Set its aspect to 1.5.
1112
- * // Set its near to 600.
1113
- * // Set its far to 1200.
1114
- * cam2.perspective(0.2, 1.5, 600, 1200);
1115
- *
1116
- * // Set the current camera to cam1.
1117
- * setCamera(cam1);
1118
- *
1119
- * describe('A white cube on a gray background. The camera toggles between a frontal view and a skewed aerial view when the user double-clicks.');
1120
- * }
1121
- *
1122
- * function draw() {
1123
- * background(200);
1124
- *
1125
- * // Draw the box.
1126
- * box();
1127
- * }
1128
- *
1129
- * // Toggle the current camera when the user double-clicks.
1130
- * function doubleClicked() {
1131
- * if (isDefaultCamera === true) {
1132
- * setCamera(cam2);
1133
- * isDefaultCamera = false;
1134
- * } else {
1135
- * setCamera(cam1);
1136
- * isDefaultCamera = true;
1137
- * }
1138
- * }
1139
- * </code>
1140
- * </div>
1141
- *
1142
- * <div>
1143
- * <code>
1144
- * // Double-click to toggle between cameras.
1145
- *
1146
- * let cam1;
1147
- * let cam2;
1148
- * let isDefaultCamera = true;
1149
- *
1150
- * function setup() {
1151
- * createCanvas(100, 100, WEBGL);
1152
- *
1153
- * // Create the first camera.
1154
- * // Keep its default settings.
1155
- * cam1 = createCamera();
1156
- *
1157
- * // Create the second camera.
1158
- * cam2 = createCamera();
1159
- *
1160
- * // Place it at the top-right.
1161
- * cam2.camera(400, -400, 800);
1162
- *
1163
- * // Set its fovy to 0.2.
1164
- * // Set its aspect to 1.5.
1165
- * // Set its near to 600.
1166
- * // Set its far to 1200.
1167
- * cam2.perspective(0.2, 1.5, 600, 1200);
1168
- *
1169
- * // Set the current camera to cam1.
1170
- * setCamera(cam1);
1171
- *
1172
- * describe('A white cube moves left and right on a gray background. The camera toggles between a frontal and a skewed aerial view when the user double-clicks.');
1173
- * }
1174
- *
1175
- * function draw() {
1176
- * background(200);
1177
- *
1178
- * // Translate the origin left and right.
1179
- * let x = 100 * sin(frameCount * 0.01);
1180
- * translate(x, 0, 0);
1181
- *
1182
- * // Draw the box.
1183
- * box();
1184
- * }
1185
- *
1186
- * // Toggle the current camera when the user double-clicks.
1187
- * function doubleClicked() {
1188
- * if (isDefaultCamera === true) {
1189
- * setCamera(cam2);
1190
- * isDefaultCamera = false;
1191
- * } else {
1192
- * setCamera(cam1);
1193
- * isDefaultCamera = true;
1194
- * }
1195
- * }
1196
- * </code>
1197
- * </div>
1198
- */
1199
- perspective(fovy, aspect, near, far) {
1200
- this.cameraType = arguments.length > 0 ? 'custom' : 'default';
1201
- if (typeof fovy === 'undefined') {
1202
- fovy = this.defaultCameraFOV;
1203
- // this avoids issue where setting angleMode(DEGREES) before calling
1204
- // perspective leads to a smaller than expected FOV (because
1205
- // _computeCameraDefaultSettings computes in radians)
1206
- this.cameraFOV = fovy;
1207
- } else {
1208
- this.cameraFOV = this._renderer._pInst._toRadians(fovy);
1209
- }
1210
- if (typeof aspect === 'undefined') {
1211
- aspect = this.defaultAspectRatio;
1212
- }
1213
- if (typeof near === 'undefined') {
1214
- near = this.defaultCameraNear;
1215
- }
1216
- if (typeof far === 'undefined') {
1217
- far = this.defaultCameraFar;
1218
- }
1219
-
1220
- if (near <= 0.0001) {
1221
- near = 0.01;
1222
- console.log(
1223
- 'Avoid perspective near plane values close to or below 0. ' +
1224
- 'Setting value to 0.01.'
1225
- );
1226
- }
1227
-
1228
- if (far < near) {
1229
- console.log(
1230
- 'Perspective far plane value is less than near plane value. ' +
1231
- 'Nothing will be shown.'
1232
- );
1233
- }
1234
-
1235
- this.aspectRatio = aspect;
1236
- this.cameraNear = near;
1237
- this.cameraFar = far;
1238
-
1239
- this.projMatrix = new Matrix(4);
1240
-
1241
- const f = 1.0 / Math.tan(this.cameraFOV / 2);
1242
- const nf = 1.0 / (this.cameraNear - this.cameraFar);
1243
-
1244
- /* eslint-disable indent */
1245
- this.projMatrix.set(f / aspect, 0, 0, 0,
1246
- 0, -f * this.yScale, 0, 0,
1247
- 0, 0, (far + near) * nf, -1,
1248
- 0, 0, (2 * far * near) * nf, 0);
1249
- /* eslint-enable indent */
1250
-
1251
- if (this._isActive()) {
1252
- this._renderer.states.setValue('uPMatrix', this._renderer.states.uPMatrix.clone());
1253
- this._renderer.states.uPMatrix.set(this.projMatrix);
1254
- }
1255
- }
1256
-
1257
- /**
1258
- * Sets an orthographic projection for the camera.
1259
- *
1260
- * In an orthographic projection, shapes with the same size always appear the
1261
- * same size, regardless of whether they are near or far from the camera.
1262
- *
1263
- * `myCamera.ortho()` changes the camera’s perspective by changing its viewing
1264
- * frustum from a truncated pyramid to a rectangular prism. The frustum is the
1265
- * volume of space that’s visible to the camera. The camera is placed in front
1266
- * of the frustum and views everything within the frustum. `myCamera.ortho()`
1267
- * has six optional parameters to define the viewing frustum.
1268
- *
1269
- * The first four parameters, `left`, `right`, `bottom`, and `top`, set the
1270
- * coordinates of the frustum’s sides, bottom, and top. For example, calling
1271
- * `myCamera.ortho(-100, 100, 200, -200)` creates a frustum that’s 200 pixels
1272
- * wide and 400 pixels tall. By default, these dimensions are set based on
1273
- * the sketch’s width and height, as in
1274
- * `myCamera.ortho(-width / 2, width / 2, -height / 2, height / 2)`.
1275
- *
1276
- * The last two parameters, `near` and `far`, set the distance of the
1277
- * frustum’s near and far plane from the camera. For example, calling
1278
- * `myCamera.ortho(-100, 100, 200, -200, 50, 1000)` creates a frustum that’s
1279
- * 200 pixels wide, 400 pixels tall, starts 50 pixels from the camera, and
1280
- * ends 1,000 pixels from the camera. By default, `near` and `far` are set to
1281
- * 0 and `max(width, height) + 800`, respectively.
1282
- *
1283
- * @for p5.Camera
1284
- * @param {Number} [left] x-coordinate of the frustum’s left plane. Defaults to `-width / 2`.
1285
- * @param {Number} [right] x-coordinate of the frustum’s right plane. Defaults to `width / 2`.
1286
- * @param {Number} [bottom] y-coordinate of the frustum’s bottom plane. Defaults to `height / 2`.
1287
- * @param {Number} [top] y-coordinate of the frustum’s top plane. Defaults to `-height / 2`.
1288
- * @param {Number} [near] z-coordinate of the frustum’s near plane. Defaults to 0.
1289
- * @param {Number} [far] z-coordinate of the frustum’s far plane. Defaults to `max(width, height) + 800`.
1290
- *
1291
- * @example
1292
- * <div>
1293
- * <code>
1294
- * // Double-click to toggle between cameras.
1295
- *
1296
- * let cam1;
1297
- * let cam2;
1298
- * let isDefaultCamera = true;
1299
- *
1300
- * function setup() {
1301
- * createCanvas(100, 100, WEBGL);
1302
- *
1303
- * // Create the first camera.
1304
- * // Keep its default settings.
1305
- * cam1 = createCamera();
1306
- *
1307
- * // Create the second camera.
1308
- * cam2 = createCamera();
1309
- *
1310
- * // Apply an orthographic projection.
1311
- * cam2.ortho();
1312
- *
1313
- * // Set the current camera to cam1.
1314
- * setCamera(cam1);
1315
- *
1316
- * describe('A row of white cubes against a gray background. The camera toggles between a perspective and an orthographic projection when the user double-clicks.');
1317
- * }
1318
- *
1319
- * function draw() {
1320
- * background(200);
1321
- *
1322
- * // Translate the origin toward the camera.
1323
- * translate(-10, 10, 500);
1324
- *
1325
- * // Rotate the coordinate system.
1326
- * rotateY(-0.1);
1327
- * rotateX(-0.1);
1328
- *
1329
- * // Draw the row of boxes.
1330
- * for (let i = 0; i < 6; i += 1) {
1331
- * translate(0, 0, -40);
1332
- * box(10);
1333
- * }
1334
- * }
1335
- *
1336
- * // Toggle the current camera when the user double-clicks.
1337
- * function doubleClicked() {
1338
- * if (isDefaultCamera === true) {
1339
- * setCamera(cam2);
1340
- * isDefaultCamera = false;
1341
- * } else {
1342
- * setCamera(cam1);
1343
- * isDefaultCamera = true;
1344
- * }
1345
- * }
1346
- * </code>
1347
- * </div>
1348
- *
1349
- * <div>
1350
- * <code>
1351
- * // Double-click to toggle between cameras.
1352
- *
1353
- * let cam1;
1354
- * let cam2;
1355
- * let isDefaultCamera = true;
1356
- *
1357
- * function setup() {
1358
- * createCanvas(100, 100, WEBGL);
1359
- *
1360
- * // Create the first camera.
1361
- * // Keep its default settings.
1362
- * cam1 = createCamera();
1363
- *
1364
- * // Create the second camera.
1365
- * cam2 = createCamera();
1366
- *
1367
- * // Apply an orthographic projection.
1368
- * cam2.ortho();
1369
- *
1370
- * // Set the current camera to cam1.
1371
- * setCamera(cam1);
1372
- *
1373
- * describe('A row of white cubes slither like a snake against a gray background. The camera toggles between a perspective and an orthographic projection when the user double-clicks.');
1374
- * }
1375
- *
1376
- * function draw() {
1377
- * background(200);
1378
- *
1379
- * // Translate the origin toward the camera.
1380
- * translate(-10, 10, 500);
1381
- *
1382
- * // Rotate the coordinate system.
1383
- * rotateY(-0.1);
1384
- * rotateX(-0.1);
1385
- *
1386
- * // Draw the row of boxes.
1387
- * for (let i = 0; i < 6; i += 1) {
1388
- * push();
1389
- * // Calculate the box's coordinates.
1390
- * let x = 10 * sin(frameCount * 0.02 + i * 0.6);
1391
- * let z = -40 * i;
1392
- * // Translate the origin.
1393
- * translate(x, 0, z);
1394
- * // Draw the box.
1395
- * box(10);
1396
- * pop();
1397
- * }
1398
- * }
1399
- *
1400
- * // Toggle the current camera when the user double-clicks.
1401
- * function doubleClicked() {
1402
- * if (isDefaultCamera === true) {
1403
- * setCamera(cam2);
1404
- * isDefaultCamera = false;
1405
- * } else {
1406
- * setCamera(cam1);
1407
- * isDefaultCamera = true;
1408
- * }
1409
- * }
1410
- * </code>
1411
- * </div>
1412
- */
1413
- ortho(left, right, bottom, top, near, far) {
1414
- const source = this.fbo || this._renderer;
1415
- if (left === undefined) left = -source.width / 2;
1416
- if (right === undefined) right = +source.width / 2;
1417
- if (bottom === undefined) bottom = -source.height / 2;
1418
- if (top === undefined) top = +source.height / 2;
1419
- if (near === undefined) near = 0;
1420
- if (far === undefined) far = Math.max(source.width, source.height) + 800;
1421
- this.cameraNear = near;
1422
- this.cameraFar = far;
1423
- const w = right - left;
1424
- const h = top - bottom;
1425
- const d = far - near;
1426
- const x = +2.0 / w;
1427
- const y = +2.0 / h * this.yScale;
1428
- const z = -2.0 / d;
1429
- const tx = -(right + left) / w;
1430
- const ty = -(top + bottom) / h;
1431
- const tz = -(far + near) / d;
1432
- this.projMatrix = new Matrix(4);
1433
- /* eslint-disable indent */
1434
- this.projMatrix.set(x, 0, 0, 0,
1435
- 0, -y, 0, 0,
1436
- 0, 0, z, 0,
1437
- tx, ty, tz, 1);
1438
- /* eslint-enable indent */
1439
- if (this._isActive()) {
1440
- this._renderer.states.setValue('uPMatrix', this._renderer.states.uPMatrix.clone());
1441
- this._renderer.states.uPMatrix.set(this.projMatrix);
1442
- }
1443
- this.cameraType = 'custom';
1444
- }
1445
- /**
1446
- * Sets the camera's frustum.
1447
- *
1448
- * In a frustum projection, shapes that are further from the camera appear
1449
- * smaller than shapes that are near the camera. This technique, called
1450
- * foreshortening, creates realistic 3D scenes.
1451
- *
1452
- * `myCamera.frustum()` changes the camera’s perspective by changing its
1453
- * viewing frustum. The frustum is the volume of space that’s visible to the
1454
- * camera. The frustum’s shape is a pyramid with its top cut off. The camera
1455
- * is placed where the top of the pyramid should be and points towards the
1456
- * base of the pyramid. It views everything within the frustum.
1457
- *
1458
- * The first four parameters, `left`, `right`, `bottom`, and `top`, set the
1459
- * coordinates of the frustum’s sides, bottom, and top. For example, calling
1460
- * `myCamera.frustum(-100, 100, 200, -200)` creates a frustum that’s 200
1461
- * pixels wide and 400 pixels tall. By default, these coordinates are set
1462
- * based on the sketch’s width and height, as in
1463
- * `myCamera.frustum(-width / 20, width / 20, height / 20, -height / 20)`.
1464
- *
1465
- * The last two parameters, `near` and `far`, set the distance of the
1466
- * frustum’s near and far plane from the camera. For example, calling
1467
- * `myCamera.frustum(-100, 100, 200, -200, 50, 1000)` creates a frustum that’s
1468
- * 200 pixels wide, 400 pixels tall, starts 50 pixels from the camera, and ends
1469
- * 1,000 pixels from the camera. By default, near is set to `0.1 * 800`, which
1470
- * is 1/10th the default distance between the camera and the origin. `far` is
1471
- * set to `10 * 800`, which is 10 times the default distance between the
1472
- * camera and the origin.
1473
- *
1474
- * @for p5.Camera
1475
- * @param {Number} [left] x-coordinate of the frustum’s left plane. Defaults to `-width / 20`.
1476
- * @param {Number} [right] x-coordinate of the frustum’s right plane. Defaults to `width / 20`.
1477
- * @param {Number} [bottom] y-coordinate of the frustum’s bottom plane. Defaults to `height / 20`.
1478
- * @param {Number} [top] y-coordinate of the frustum’s top plane. Defaults to `-height / 20`.
1479
- * @param {Number} [near] z-coordinate of the frustum’s near plane. Defaults to `0.1 * 800`.
1480
- * @param {Number} [far] z-coordinate of the frustum’s far plane. Defaults to `10 * 800`.
1481
- *
1482
- * @example
1483
- * <div>
1484
- * <code>
1485
- * // Double-click to toggle between cameras.
1486
- *
1487
- * let cam1;
1488
- * let cam2;
1489
- * let isDefaultCamera = true;
1490
- *
1491
- * function setup() {
1492
- * createCanvas(100, 100, WEBGL);
1493
- *
1494
- * // Create the first camera.
1495
- * // Keep its default settings.
1496
- * cam1 = createCamera();
1497
- *
1498
- * // Create the second camera.
1499
- * cam2 = createCamera();
1500
- *
1501
- * // Adjust the frustum.
1502
- * // Center it.
1503
- * // Set its width and height to 20 pixels.
1504
- * // Place its near plane 300 pixels from the camera.
1505
- * // Place its far plane 350 pixels from the camera.
1506
- * cam2.frustum(-10, 10, -10, 10, 300, 350);
1507
- *
1508
- * // Set the current camera to cam1.
1509
- * setCamera(cam1);
1510
- *
1511
- * describe(
1512
- * 'A row of white cubes against a gray background. The camera zooms in on one cube when the user double-clicks.'
1513
- * );
1514
- * }
1515
- *
1516
- * function draw() {
1517
- * background(200);
1518
- *
1519
- * // Translate the origin toward the camera.
1520
- * translate(-10, 10, 600);
1521
- *
1522
- * // Rotate the coordinate system.
1523
- * rotateY(-0.1);
1524
- * rotateX(-0.1);
1525
- *
1526
- * // Draw the row of boxes.
1527
- * for (let i = 0; i < 6; i += 1) {
1528
- * translate(0, 0, -40);
1529
- * box(10);
1530
- * }
1531
- * }
1532
- *
1533
- * // Toggle the current camera when the user double-clicks.
1534
- * function doubleClicked() {
1535
- * if (isDefaultCamera === true) {
1536
- * setCamera(cam2);
1537
- * isDefaultCamera = false;
1538
- * } else {
1539
- * setCamera(cam1);
1540
- * isDefaultCamera = true;
1541
- * }
1542
- * }
1543
- * </code>
1544
- * </div>
1545
- */
1546
- frustum(left, right, bottom, top, near, far) {
1547
- if (left === undefined) left = -this._renderer.width * 0.05;
1548
- if (right === undefined) right = +this._renderer.width * 0.05;
1549
- if (bottom === undefined) bottom = +this._renderer.height * 0.05;
1550
- if (top === undefined) top = -this._renderer.height * 0.05;
1551
- if (near === undefined) near = this.defaultCameraNear;
1552
- if (far === undefined) far = this.defaultCameraFar;
1553
-
1554
- this.cameraNear = near;
1555
- this.cameraFar = far;
1556
-
1557
- const w = right - left;
1558
- const h = top - bottom;
1559
- const d = far - near;
1560
-
1561
- const x = +(2.0 * near) / w;
1562
- const y = +(2.0 * near) / h * this.yScale;
1563
- const z = -(2.0 * far * near) / d;
1564
-
1565
- const tx = (right + left) / w;
1566
- const ty = (top + bottom) / h;
1567
- const tz = -(far + near) / d;
1568
-
1569
- this.projMatrix = new Matrix(4);
1570
-
1571
- /* eslint-disable indent */
1572
- this.projMatrix.set(x, 0, 0, 0,
1573
- 0, -y, 0, 0,
1574
- tx, ty, tz, -1,
1575
- 0, 0, z, 0);
1576
- /* eslint-enable indent */
1577
-
1578
- if (this._isActive()) {
1579
- this._renderer.states.setValue('uPMatrix', this._renderer.states.uPMatrix.clone());
1580
- this._renderer.states.uPMatrix.set(this.projMatrix);
1581
- }
1582
-
1583
- this.cameraType = 'custom';
1584
- }
1585
-
1586
- ////////////////////////////////////////////////////////////////////////////////
1587
- // Camera Orientation Methods
1588
- ////////////////////////////////////////////////////////////////////////////////
1589
-
1590
- /**
1591
- * Rotate camera view about arbitrary axis defined by x,y,z
1592
- * based on http://learnwebgl.brown37.net/07_cameras/camera_rotating_motion.html
1593
- * @private
1594
- */
1595
- _rotateView(a, x, y, z) {
1596
- let centerX = this.centerX;
1597
- let centerY = this.centerY;
1598
- let centerZ = this.centerZ;
1599
-
1600
- // move center by eye position such that rotation happens around eye position
1601
- centerX -= this.eyeX;
1602
- centerY -= this.eyeY;
1603
- centerZ -= this.eyeZ;
1604
-
1605
- const rotation = new Matrix(4); // TODO Maybe pass p5
1606
- rotation.rotate4x4(this._renderer._pInst._toRadians(a), x, y, z);
1607
-
1608
- /* eslint-disable max-len */
1609
- const rotatedCenter = [
1610
- centerX * rotation.mat4[0] + centerY * rotation.mat4[4] + centerZ * rotation.mat4[8],
1611
- centerX * rotation.mat4[1] + centerY * rotation.mat4[5] + centerZ * rotation.mat4[9],
1612
- centerX * rotation.mat4[2] + centerY * rotation.mat4[6] + centerZ * rotation.mat4[10]
1613
- ];
1614
- /* eslint-enable max-len */
1615
-
1616
- // add eye position back into center
1617
- rotatedCenter[0] += this.eyeX;
1618
- rotatedCenter[1] += this.eyeY;
1619
- rotatedCenter[2] += this.eyeZ;
1620
-
1621
- this.camera(
1622
- this.eyeX,
1623
- this.eyeY,
1624
- this.eyeZ,
1625
- rotatedCenter[0],
1626
- rotatedCenter[1],
1627
- rotatedCenter[2],
1628
- this.upX,
1629
- this.upY,
1630
- this.upZ
1631
- );
1632
- }
1633
-
1634
- /**
1635
- * Rotates the camera in a clockwise/counter-clockwise direction.
1636
- *
1637
- * Rolling rotates the camera without changing its orientation. The rotation
1638
- * happens in the camera’s "local" space.
1639
- *
1640
- * The parameter, `angle`, is the angle the camera should rotate. Passing a
1641
- * positive angle, as in `myCamera.roll(0.001)`, rotates the camera in counter-clockwise direction.
1642
- * Passing a negative angle, as in `myCamera.roll(-0.001)`, rotates the
1643
- * camera in clockwise direction.
1644
- *
1645
- * Note: Angles are interpreted based on the current
1646
- * <a href="#/p5/angleMode">angleMode()</a>.
1647
- *
1648
- * @method roll
1649
- * @param {Number} angle amount to rotate camera in current
1650
- * <a href="#/p5/angleMode">angleMode</a> units.
1651
- * @example
1652
- * <div>
1653
- * <code>
1654
- * let cam;
1655
- * let delta = 0.01;
1656
- *
1657
- * function setup() {
1658
- * createCanvas(100, 100, WEBGL);
1659
- * normalMaterial();
1660
- * // Create a p5.Camera object.
1661
- * cam = createCamera();
1662
- *
1663
- * // Set the camera
1664
- * setCamera(cam);
1665
- * }
1666
- *
1667
- * function draw() {
1668
- * background(200);
1669
- *
1670
- * // Roll camera according to angle 'delta'
1671
- * cam.roll(delta);
1672
- *
1673
- * translate(0, 0, 0);
1674
- * box(20);
1675
- * translate(0, 25, 0);
1676
- * box(20);
1677
- * translate(0, 26, 0);
1678
- * box(20);
1679
- * translate(0, 27, 0);
1680
- * box(20);
1681
- * translate(0, 28, 0);
1682
- * box(20);
1683
- * translate(0,29, 0);
1684
- * box(20);
1685
- * translate(0, 30, 0);
1686
- * box(20);
1687
- * }
1688
- * </code>
1689
- * </div>
1690
- *
1691
- * @alt
1692
- * camera view rotates in counter clockwise direction with vertically stacked boxes in front of it.
1693
- */
1694
- roll(amount) {
1695
- const local = this._getLocalAxes();
1696
- const axisQuaternion = Quat.fromAxisAngle(
1697
- this._renderer._pInst._toRadians(amount),
1698
- local.z[0], local.z[1], local.z[2]);
1699
- // const upQuat = new p5.Quat(0, this.upX, this.upY, this.upZ);
1700
- const newUpVector = axisQuaternion.rotateVector(
1701
- new Vector(this.upX, this.upY, this.upZ));
1702
- this.camera(
1703
- this.eyeX,
1704
- this.eyeY,
1705
- this.eyeZ,
1706
- this.centerX,
1707
- this.centerY,
1708
- this.centerZ,
1709
- newUpVector.x,
1710
- newUpVector.y,
1711
- newUpVector.z
1712
- );
1713
- }
1714
-
1715
- /**
1716
- * Rotates the camera left and right.
1717
- *
1718
- * Panning rotates the camera without changing its position. The rotation
1719
- * happens in the camera’s "local" space.
1720
- *
1721
- * The parameter, `angle`, is the angle the camera should rotate. Passing a
1722
- * positive angle, as in `myCamera.pan(0.001)`, rotates the camera to the
1723
- * right. Passing a negative angle, as in `myCamera.pan(-0.001)`, rotates the
1724
- * camera to the left.
1725
- *
1726
- * Note: Angles are interpreted based on the current
1727
- * <a href="#/p5/angleMode">angleMode()</a>.
1728
- *
1729
- * @param {Number} angle amount to rotate in the current
1730
- * <a href="#/p5/angleMode">angleMode()</a>.
1731
- *
1732
- * @example
1733
- * <div>
1734
- * <code>
1735
- * let cam;
1736
- * let delta = 0.001;
1737
- *
1738
- * function setup() {
1739
- * createCanvas(100, 100, WEBGL);
1740
- *
1741
- * // Create a p5.Camera object.
1742
- * cam = createCamera();
1743
- *
1744
- * // Set the camera
1745
- * setCamera(cam);
1746
- *
1747
- * // Place the camera at the top-center.
1748
- * cam.setPosition(0, -400, 800);
1749
- *
1750
- * // Point the camera at the origin.
1751
- * cam.lookAt(0, 0, 0);
1752
- *
1753
- * describe(
1754
- * 'A white cube on a gray background. The cube goes in and out of view as the camera pans left and right.'
1755
- * );
1756
- * }
1757
- *
1758
- * function draw() {
1759
- * background(200);
1760
- *
1761
- * // Pan with the camera.
1762
- * cam.pan(delta);
1763
- *
1764
- * // Switch directions every 120 frames.
1765
- * if (frameCount % 120 === 0) {
1766
- * delta *= -1;
1767
- * }
1768
- *
1769
- * // Draw the box.
1770
- * box();
1771
- * }
1772
- * </code>
1773
- * </div>
1774
- */
1775
- pan(amount) {
1776
- const local = this._getLocalAxes();
1777
- this._rotateView(amount, local.y[0], local.y[1], local.y[2]);
1778
- }
1779
-
1780
- /**
1781
- * Rotates the camera up and down.
1782
- *
1783
- * Tilting rotates the camera without changing its position. The rotation
1784
- * happens in the camera’s "local" space.
1785
- *
1786
- * The parameter, `angle`, is the angle the camera should rotate. Passing a
1787
- * positive angle, as in `myCamera.tilt(0.001)`, rotates the camera down.
1788
- * Passing a negative angle, as in `myCamera.tilt(-0.001)`, rotates the camera
1789
- * up.
1790
- *
1791
- * Note: Angles are interpreted based on the current
1792
- * <a href="#/p5/angleMode">angleMode()</a>.
1793
- *
1794
- * @param {Number} angle amount to rotate in the current
1795
- * <a href="#/p5/angleMode">angleMode()</a>.
1796
- *
1797
- * @example
1798
- * <div>
1799
- * <code>
1800
- * let cam;
1801
- * let delta = 0.001;
1802
- *
1803
- * function setup() {
1804
- * createCanvas(100, 100, WEBGL);
1805
- *
1806
- * // Create a p5.Camera object.
1807
- * cam = createCamera();
1808
- *
1809
- * // Set the camera
1810
- * setCamera(cam);
1811
- *
1812
- * // Place the camera at the top-center.
1813
- * cam.setPosition(0, -400, 800);
1814
- *
1815
- * // Point the camera at the origin.
1816
- * cam.lookAt(0, 0, 0);
1817
- *
1818
- * describe(
1819
- * 'A white cube on a gray background. The cube goes in and out of view as the camera tilts up and down.'
1820
- * );
1821
- * }
1822
- *
1823
- * function draw() {
1824
- * background(200);
1825
- *
1826
- * // Pan with the camera.
1827
- * cam.tilt(delta);
1828
- *
1829
- * // Switch directions every 120 frames.
1830
- * if (frameCount % 120 === 0) {
1831
- * delta *= -1;
1832
- * }
1833
- *
1834
- * // Draw the box.
1835
- * box();
1836
- * }
1837
- * </code>
1838
- * </div>
1839
- */
1840
- tilt(amount) {
1841
- const local = this._getLocalAxes();
1842
- this._rotateView(amount, local.x[0], local.x[1], local.x[2]);
1843
- }
1844
-
1845
- /**
1846
- * Points the camera at a location.
1847
- *
1848
- * `myCamera.lookAt()` changes the camera’s orientation without changing its
1849
- * position.
1850
- *
1851
- * The parameters, `x`, `y`, and `z`, are the coordinates in "world" space
1852
- * where the camera should point. For example, calling
1853
- * `myCamera.lookAt(10, 20, 30)` points the camera at the coordinates
1854
- * `(10, 20, 30)`.
1855
- *
1856
- * @for p5.Camera
1857
- * @param {Number} x x-coordinate of the position where the camera should look in "world" space.
1858
- * @param {Number} y y-coordinate of the position where the camera should look in "world" space.
1859
- * @param {Number} z z-coordinate of the position where the camera should look in "world" space.
1860
- *
1861
- * @example
1862
- * <div>
1863
- * <code>
1864
- * // Double-click to look at a different cube.
1865
- *
1866
- * let cam;
1867
- * let isLookingLeft = true;
1868
- *
1869
- * function setup() {
1870
- * createCanvas(100, 100, WEBGL);
1871
- *
1872
- * // Create a p5.Camera object.
1873
- * cam = createCamera();
1874
- *
1875
- * // Set the camera
1876
- * setCamera(cam);
1877
- *
1878
- * // Place the camera at the top-center.
1879
- * cam.setPosition(0, -400, 800);
1880
- *
1881
- * // Point the camera at the origin.
1882
- * cam.lookAt(-30, 0, 0);
1883
- *
1884
- * describe(
1885
- * 'A red cube and a blue cube on a gray background. The camera switches focus between the cubes when the user double-clicks.'
1886
- * );
1887
- * }
1888
- *
1889
- * function draw() {
1890
- * background(200);
1891
- *
1892
- * // Draw the box on the left.
1893
- * push();
1894
- * // Translate the origin to the left.
1895
- * translate(-30, 0, 0);
1896
- * // Style the box.
1897
- * fill(255, 0, 0);
1898
- * // Draw the box.
1899
- * box(20);
1900
- * pop();
1901
- *
1902
- * // Draw the box on the right.
1903
- * push();
1904
- * // Translate the origin to the right.
1905
- * translate(30, 0, 0);
1906
- * // Style the box.
1907
- * fill(0, 0, 255);
1908
- * // Draw the box.
1909
- * box(20);
1910
- * pop();
1911
- * }
1912
- *
1913
- * // Change the camera's focus when the user double-clicks.
1914
- * function doubleClicked() {
1915
- * if (isLookingLeft === true) {
1916
- * cam.lookAt(30, 0, 0);
1917
- * isLookingLeft = false;
1918
- * } else {
1919
- * cam.lookAt(-30, 0, 0);
1920
- * isLookingLeft = true;
1921
- * }
1922
- * }
1923
- * </code>
1924
- * </div>
1925
- */
1926
- lookAt(x, y, z) {
1927
- this.camera(
1928
- this.eyeX,
1929
- this.eyeY,
1930
- this.eyeZ,
1931
- x,
1932
- y,
1933
- z,
1934
- this.upX,
1935
- this.upY,
1936
- this.upZ
1937
- );
1938
- }
1939
-
1940
- ////////////////////////////////////////////////////////////////////////////////
1941
- // Camera Position Methods
1942
- ////////////////////////////////////////////////////////////////////////////////
1943
-
1944
- /**
1945
- * Sets the position and orientation of the camera.
1946
- *
1947
- * `myCamera.camera()` allows objects to be viewed from different angles. It
1948
- * has nine parameters that are all optional.
1949
- *
1950
- * The first three parameters, `x`, `y`, and `z`, are the coordinates of the
1951
- * camera’s position in "world" space. For example, calling
1952
- * `myCamera.camera(0, 0, 0)` places the camera at the origin `(0, 0, 0)`. By
1953
- * default, the camera is placed at `(0, 0, 800)`.
1954
- *
1955
- * The next three parameters, `centerX`, `centerY`, and `centerZ` are the
1956
- * coordinates of the point where the camera faces in "world" space. For
1957
- * example, calling `myCamera.camera(0, 0, 0, 10, 20, 30)` places the camera
1958
- * at the origin `(0, 0, 0)` and points it at `(10, 20, 30)`. By default, the
1959
- * camera points at the origin `(0, 0, 0)`.
1960
- *
1961
- * The last three parameters, `upX`, `upY`, and `upZ` are the components of
1962
- * the "up" vector in "local" space. The "up" vector orients the camera’s
1963
- * y-axis. For example, calling
1964
- * `myCamera.camera(0, 0, 0, 10, 20, 30, 0, -1, 0)` places the camera at the
1965
- * origin `(0, 0, 0)`, points it at `(10, 20, 30)`, and sets the "up" vector
1966
- * to `(0, -1, 0)` which is like holding it upside-down. By default, the "up"
1967
- * vector is `(0, 1, 0)`.
1968
- *
1969
- * @for p5.Camera
1970
- * @param {Number} [x] x-coordinate of the camera. Defaults to 0.
1971
- * @param {Number} [y] y-coordinate of the camera. Defaults to 0.
1972
- * @param {Number} [z] z-coordinate of the camera. Defaults to 800.
1973
- * @param {Number} [centerX] x-coordinate of the point the camera faces. Defaults to 0.
1974
- * @param {Number} [centerY] y-coordinate of the point the camera faces. Defaults to 0.
1975
- * @param {Number} [centerZ] z-coordinate of the point the camera faces. Defaults to 0.
1976
- * @param {Number} [upX] x-component of the camera’s "up" vector. Defaults to 0.
1977
- * @param {Number} [upY] x-component of the camera’s "up" vector. Defaults to 1.
1978
- * @param {Number} [upZ] z-component of the camera’s "up" vector. Defaults to 0.
1979
- *
1980
- * @example
1981
- * <div>
1982
- * <code>
1983
- * // Double-click to toggle between cameras.
1984
- *
1985
- * let cam1;
1986
- * let cam2;
1987
- * let isDefaultCamera = true;
1988
- *
1989
- * function setup() {
1990
- * createCanvas(100, 100, WEBGL);
1991
- *
1992
- * // Create the first camera.
1993
- * // Keep its default settings.
1994
- * cam1 = createCamera();
1995
- *
1996
- * // Create the second camera.
1997
- * cam2 = createCamera();
1998
- *
1999
- * // Place it at the top-right: (1200, -600, 100)
2000
- * // Point it at the row of boxes: (-10, -10, 400)
2001
- * // Set its "up" vector to the default: (0, 1, 0)
2002
- * cam2.camera(1200, -600, 100, -10, -10, 400, 0, 1, 0);
2003
- *
2004
- * // Set the current camera to cam1.
2005
- * setCamera(cam1);
2006
- *
2007
- * describe(
2008
- * 'A row of white cubes against a gray background. The camera toggles between a frontal and an aerial view when the user double-clicks.'
2009
- * );
2010
- * }
2011
- *
2012
- * function draw() {
2013
- * background(200);
2014
- *
2015
- * // Translate the origin toward the camera.
2016
- * translate(-10, 10, 500);
2017
- *
2018
- * // Rotate the coordinate system.
2019
- * rotateY(-0.1);
2020
- * rotateX(-0.1);
2021
- *
2022
- * // Draw the row of boxes.
2023
- * for (let i = 0; i < 6; i += 1) {
2024
- * translate(0, 0, -30);
2025
- * box(10);
2026
- * }
2027
- * }
2028
- *
2029
- * // Toggle the current camera when the user double-clicks.
2030
- * function doubleClicked() {
2031
- * if (isDefaultCamera === true) {
2032
- * setCamera(cam2);
2033
- * isDefaultCamera = false;
2034
- * } else {
2035
- * setCamera(cam1);
2036
- * isDefaultCamera = true;
2037
- * }
2038
- * }
2039
- * </code>
2040
- * </div>
2041
- *
2042
- * <div>
2043
- * <code>
2044
- * // Double-click to toggle between cameras.
2045
- *
2046
- * let cam1;
2047
- * let cam2;
2048
- * let isDefaultCamera = true;
2049
- *
2050
- * function setup() {
2051
- * createCanvas(100, 100, WEBGL);
2052
- *
2053
- * // Create the first camera.
2054
- * // Keep its default settings.
2055
- * cam1 = createCamera();
2056
- *
2057
- * // Create the second camera.
2058
- * cam2 = createCamera();
2059
- *
2060
- * // Place it at the right: (1200, 0, 100)
2061
- * // Point it at the row of boxes: (-10, -10, 400)
2062
- * // Set its "up" vector to the default: (0, 1, 0)
2063
- * cam2.camera(1200, 0, 100, -10, -10, 400, 0, 1, 0);
2064
- *
2065
- * // Set the current camera to cam1.
2066
- * setCamera(cam1);
2067
- *
2068
- * describe(
2069
- * 'A row of white cubes against a gray background. The camera toggles between a static frontal view and an orbiting view when the user double-clicks.'
2070
- * );
2071
- * }
2072
- *
2073
- * function draw() {
2074
- * background(200);
2075
- *
2076
- * // Update cam2's position.
2077
- * let x = 1200 * cos(frameCount * 0.01);
2078
- * let y = -600 * sin(frameCount * 0.01);
2079
- * cam2.camera(x, y, 100, -10, -10, 400, 0, 1, 0);
2080
- *
2081
- * // Translate the origin toward the camera.
2082
- * translate(-10, 10, 500);
2083
- *
2084
- * // Rotate the coordinate system.
2085
- * rotateY(-0.1);
2086
- * rotateX(-0.1);
2087
- *
2088
- * // Draw the row of boxes.
2089
- * for (let i = 0; i < 6; i += 1) {
2090
- * translate(0, 0, -30);
2091
- * box(10);
2092
- * }
2093
- * }
2094
- *
2095
- * // Toggle the current camera when the user double-clicks.
2096
- * function doubleClicked() {
2097
- * if (isDefaultCamera === true) {
2098
- * setCamera(cam2);
2099
- * isDefaultCamera = false;
2100
- * } else {
2101
- * setCamera(cam1);
2102
- * isDefaultCamera = true;
2103
- * }
2104
- * }
2105
- * </code>
2106
- * </div>
2107
- */
2108
- camera(
2109
- eyeX,
2110
- eyeY,
2111
- eyeZ,
2112
- centerX,
2113
- centerY,
2114
- centerZ,
2115
- upX,
2116
- upY,
2117
- upZ
2118
- ) {
2119
- if (typeof eyeX === 'undefined') {
2120
- eyeX = this.defaultEyeX;
2121
- eyeY = this.defaultEyeY;
2122
- eyeZ = this.defaultEyeZ;
2123
- centerX = eyeX;
2124
- centerY = eyeY;
2125
- centerZ = 0;
2126
- upX = 0;
2127
- upY = 1;
2128
- upZ = 0;
2129
- }
2130
-
2131
- this.eyeX = eyeX;
2132
- this.eyeY = eyeY;
2133
- this.eyeZ = eyeZ;
2134
-
2135
- if (typeof centerX !== 'undefined') {
2136
- this.centerX = centerX;
2137
- this.centerY = centerY;
2138
- this.centerZ = centerZ;
2139
- }
2140
-
2141
- if (typeof upX !== 'undefined') {
2142
- this.upX = upX;
2143
- this.upY = upY;
2144
- this.upZ = upZ;
2145
- }
2146
-
2147
- const local = this._getLocalAxes();
2148
-
2149
- // the camera affects the model view matrix, insofar as it
2150
- // inverse translates the world to the eye position of the camera
2151
- // and rotates it.
2152
- /* eslint-disable indent */
2153
- this.cameraMatrix.set(local.x[0], local.y[0], local.z[0], 0,
2154
- local.x[1], local.y[1], local.z[1], 0,
2155
- local.x[2], local.y[2], local.z[2], 0,
2156
- 0, 0, 0, 1);
2157
- /* eslint-enable indent */
2158
-
2159
- const tx = -eyeX;
2160
- const ty = -eyeY;
2161
- const tz = -eyeZ;
2162
-
2163
- this.cameraMatrix.translate([tx, ty, tz]);
2164
-
2165
- if (this._isActive()) {
2166
- this._renderer.states.setValue('uViewMatrix', this._renderer.states.uViewMatrix.clone());
2167
- this._renderer.states.uViewMatrix.set(this.cameraMatrix);
2168
- }
2169
- return this;
2170
- }
2171
-
2172
- /**
2173
- * Moves the camera along its "local" axes without changing its orientation.
2174
- *
2175
- * The parameters, `x`, `y`, and `z`, are the distances the camera should
2176
- * move. For example, calling `myCamera.move(10, 20, 30)` moves the camera 10
2177
- * pixels to the right, 20 pixels down, and 30 pixels backward in its "local"
2178
- * space.
2179
- *
2180
- * @param {Number} x distance to move along the camera’s "local" x-axis.
2181
- * @param {Number} y distance to move along the camera’s "local" y-axis.
2182
- * @param {Number} z distance to move along the camera’s "local" z-axis.
2183
- * @example
2184
- * <div>
2185
- * <code>
2186
- * // Click the canvas to begin detecting key presses.
2187
- *
2188
- * let cam;
2189
- *
2190
- * function setup() {
2191
- * createCanvas(100, 100, WEBGL);
2192
- *
2193
- * // Create the first camera.
2194
- * // Keep its default settings.
2195
- * cam = createCamera();
2196
- *
2197
- * // Place the camera at the top-right.
2198
- * cam.setPosition(400, -400, 800);
2199
- *
2200
- * // Point it at the origin.
2201
- * cam.lookAt(0, 0, 0);
2202
- *
2203
- * // Set the camera.
2204
- * setCamera(cam);
2205
- *
2206
- * describe(
2207
- * 'A white cube drawn against a gray background. The cube appears to move when the user presses certain keys.'
2208
- * );
2209
- * }
2210
- *
2211
- * function draw() {
2212
- * background(200);
2213
- *
2214
- * // Move the camera along its "local" axes
2215
- * // when the user presses certain keys.
2216
- *
2217
- * // Move horizontally.
2218
- * if (keyIsDown(LEFT_ARROW)) {
2219
- * cam.move(-1, 0, 0);
2220
- * }
2221
- * if (keyIsDown(RIGHT_ARROW)) {
2222
- * cam.move(1, 0, 0);
2223
- * }
2224
- *
2225
- * // Move vertically.
2226
- * if (keyIsDown(UP_ARROW)) {
2227
- * cam.move(0, -1, 0);
2228
- * }
2229
- * if (keyIsDown(DOWN_ARROW)) {
2230
- * cam.move(0, 1, 0);
2231
- * }
2232
- *
2233
- * // Move in/out of the screen.
2234
- * if (keyIsDown('i')) {
2235
- * cam.move(0, 0, -1);
2236
- * }
2237
- * if (keyIsDown('o')) {
2238
- * cam.move(0, 0, 1);
2239
- * }
2240
- *
2241
- * // Draw the box.
2242
- * box();
2243
- * }
2244
- * </code>
2245
- * </div>
2246
- */
2247
- move(x, y, z) {
2248
- const local = this._getLocalAxes();
2249
-
2250
- // scale local axes by movement amounts
2251
- // based on http://learnwebgl.brown37.net/07_cameras/camera_linear_motion.html
2252
- const dx = [local.x[0] * x, local.x[1] * x, local.x[2] * x];
2253
- const dy = [local.y[0] * y, local.y[1] * y, local.y[2] * y];
2254
- const dz = [local.z[0] * z, local.z[1] * z, local.z[2] * z];
2255
-
2256
- this.camera(
2257
- this.eyeX + dx[0] + dy[0] + dz[0],
2258
- this.eyeY + dx[1] + dy[1] + dz[1],
2259
- this.eyeZ + dx[2] + dy[2] + dz[2],
2260
- this.centerX + dx[0] + dy[0] + dz[0],
2261
- this.centerY + dx[1] + dy[1] + dz[1],
2262
- this.centerZ + dx[2] + dy[2] + dz[2],
2263
- this.upX,
2264
- this.upY,
2265
- this.upZ
2266
- );
2267
- }
2268
-
2269
- /**
2270
- * Sets the camera’s position in "world" space without changing its
2271
- * orientation.
2272
- *
2273
- * The parameters, `x`, `y`, and `z`, are the coordinates where the camera
2274
- * should be placed. For example, calling `myCamera.setPosition(10, 20, 30)`
2275
- * places the camera at coordinates `(10, 20, 30)` in "world" space.
2276
- *
2277
- * @param {Number} x x-coordinate in "world" space.
2278
- * @param {Number} y y-coordinate in "world" space.
2279
- * @param {Number} z z-coordinate in "world" space.
2280
- *
2281
- * @example
2282
- * <div>
2283
- * <code>
2284
- * // Double-click to toggle between cameras.
2285
- *
2286
- * let cam1;
2287
- * let cam2;
2288
- * let isDefaultCamera = true;
2289
- *
2290
- * function setup() {
2291
- * createCanvas(100, 100, WEBGL);
2292
- *
2293
- * // Create the first camera.
2294
- * // Keep its default settings.
2295
- * cam1 = createCamera();
2296
- *
2297
- * // Create the second camera.
2298
- * cam2 = createCamera();
2299
- *
2300
- * // Place it closer to the origin.
2301
- * cam2.setPosition(0, 0, 600);
2302
- *
2303
- * // Set the current camera to cam1.
2304
- * setCamera(cam1);
2305
- *
2306
- * describe(
2307
- * 'A row of white cubes against a gray background. The camera toggles the amount of zoom when the user double-clicks.'
2308
- * );
2309
- * }
2310
- *
2311
- * function draw() {
2312
- * background(200);
2313
- *
2314
- * // Translate the origin toward the camera.
2315
- * translate(-10, 10, 500);
2316
- *
2317
- * // Rotate the coordinate system.
2318
- * rotateY(-0.1);
2319
- * rotateX(-0.1);
2320
- *
2321
- * // Draw the row of boxes.
2322
- * for (let i = 0; i < 6; i += 1) {
2323
- * translate(0, 0, -30);
2324
- * box(10);
2325
- * }
2326
- * }
2327
- *
2328
- * // Toggle the current camera when the user double-clicks.
2329
- * function doubleClicked() {
2330
- * if (isDefaultCamera === true) {
2331
- * setCamera(cam2);
2332
- * isDefaultCamera = false;
2333
- * } else {
2334
- * setCamera(cam1);
2335
- * isDefaultCamera = true;
2336
- * }
2337
- * }
2338
- * </code>
2339
- * </div>
2340
- *
2341
- * <div>
2342
- * <code>
2343
- * // Double-click to toggle between cameras.
2344
- *
2345
- * let cam1;
2346
- * let cam2;
2347
- * let isDefaultCamera = true;
2348
- *
2349
- * function setup() {
2350
- * createCanvas(100, 100, WEBGL);
2351
- *
2352
- * // Create the first camera.
2353
- * // Keep its default settings.
2354
- * cam1 = createCamera();
2355
- *
2356
- * // Create the second camera.
2357
- * cam2 = createCamera();
2358
- *
2359
- * // Place it closer to the origin.
2360
- * cam2.setPosition(0, 0, 600);
2361
- *
2362
- * // Set the current camera to cam1.
2363
- * setCamera(cam1);
2364
- *
2365
- * describe(
2366
- * 'A row of white cubes against a gray background. The camera toggles between a static view and a view that zooms in and out when the user double-clicks.'
2367
- * );
2368
- * }
2369
- *
2370
- * function draw() {
2371
- * background(200);
2372
- *
2373
- * // Update cam2's z-coordinate.
2374
- * let z = 100 * sin(frameCount * 0.01) + 700;
2375
- * cam2.setPosition(0, 0, z);
2376
- *
2377
- * // Translate the origin toward the camera.
2378
- * translate(-10, 10, 500);
2379
- *
2380
- * // Rotate the coordinate system.
2381
- * rotateY(-0.1);
2382
- * rotateX(-0.1);
2383
- *
2384
- * // Draw the row of boxes.
2385
- * for (let i = 0; i < 6; i += 1) {
2386
- * translate(0, 0, -30);
2387
- * box(10);
2388
- * }
2389
- * }
2390
- *
2391
- * // Toggle the current camera when the user double-clicks.
2392
- * function doubleClicked() {
2393
- * if (isDefaultCamera === true) {
2394
- * setCamera(cam2);
2395
- * isDefaultCamera = false;
2396
- * } else {
2397
- * setCamera(cam1);
2398
- * isDefaultCamera = true;
2399
- * }
2400
- * }
2401
- * </code>
2402
- * </div>
2403
- */
2404
- setPosition(x, y, z) {
2405
- const diffX = x - this.eyeX;
2406
- const diffY = y - this.eyeY;
2407
- const diffZ = z - this.eyeZ;
2408
-
2409
- this.camera(
2410
- x,
2411
- y,
2412
- z,
2413
- this.centerX + diffX,
2414
- this.centerY + diffY,
2415
- this.centerZ + diffZ,
2416
- this.upX,
2417
- this.upY,
2418
- this.upZ
2419
- );
2420
- }
2421
-
2422
- /**
2423
- * Sets the camera’s position, orientation, and projection by copying another
2424
- * camera.
2425
- *
2426
- * The parameter, `cam`, is the `p5.Camera` object to copy. For example, calling
2427
- * `cam2.set(cam1)` will set `cam2` using `cam1`’s configuration.
2428
- *
2429
- * @param {p5.Camera} cam camera to copy.
2430
- *
2431
- * @example
2432
- * <div>
2433
- * <code>
2434
- * // Double-click to "reset" the camera zoom.
2435
- *
2436
- * let cam1;
2437
- * let cam2;
2438
- *
2439
- * function setup() {
2440
- * createCanvas(100, 100, WEBGL);
2441
- *
2442
- * // Create the first camera.
2443
- * cam1 = createCamera();
2444
- *
2445
- * // Place the camera at the top-right.
2446
- * cam1.setPosition(400, -400, 800);
2447
- *
2448
- * // Point it at the origin.
2449
- * cam1.lookAt(0, 0, 0);
2450
- *
2451
- * // Create the second camera.
2452
- * cam2 = createCamera();
2453
- *
2454
- * // Copy cam1's configuration.
2455
- * cam2.set(cam1);
2456
- *
2457
- * // Set the camera.
2458
- * setCamera(cam2);
2459
- *
2460
- * describe(
2461
- * 'A white cube drawn against a gray background. The camera slowly moves forward. The camera resets when the user double-clicks.'
2462
- * );
2463
- * }
2464
- *
2465
- * function draw() {
2466
- * background(200);
2467
- *
2468
- * // Update cam2's position.
2469
- * cam2.move(0, 0, -1);
2470
- *
2471
- * // Draw the box.
2472
- * box();
2473
- * }
2474
- *
2475
- * // "Reset" the camera when the user double-clicks.
2476
- * function doubleClicked() {
2477
- * cam2.set(cam1);
2478
- * }
2479
- */
2480
- set(cam) {
2481
- const keyNamesOfThePropToCopy = [
2482
- 'eyeX', 'eyeY', 'eyeZ',
2483
- 'centerX', 'centerY', 'centerZ',
2484
- 'upX', 'upY', 'upZ',
2485
- 'cameraFOV', 'aspectRatio', 'cameraNear', 'cameraFar', 'cameraType',
2486
- 'yScale', 'useLinePerspective'
2487
- ];
2488
- for (const keyName of keyNamesOfThePropToCopy) {
2489
- this[keyName] = cam[keyName];
2490
- }
2491
-
2492
- this.cameraMatrix = cam.cameraMatrix.copy();
2493
- this.projMatrix = cam.projMatrix.copy();
2494
-
2495
- if (this._isActive()) {
2496
- this._renderer.states.setValue('uModelMatrix', this._renderer.states.uModelMatrix.clone());
2497
- this._renderer.states.setValue('uViewMatrix', this._renderer.states.uViewMatrix.clone());
2498
- this._renderer.states.setValue('uPMatrix', this._renderer.states.uPMatrix.clone());
2499
- this._renderer.states.uModelMatrix.reset();
2500
- this._renderer.states.uViewMatrix.set(this.cameraMatrix);
2501
- this._renderer.states.uPMatrix.set(this.projMatrix);
2502
- }
2503
- }
2504
- /**
2505
- * Sets the camera’s position and orientation to values that are in-between
2506
- * those of two other cameras.
2507
- *
2508
- * `myCamera.slerp()` uses spherical linear interpolation to calculate a
2509
- * position and orientation that’s in-between two other cameras. Doing so is
2510
- * helpful for transitioning smoothly between two perspectives.
2511
- *
2512
- * The first two parameters, `cam0` and `cam1`, are the `p5.Camera` objects
2513
- * that should be used to set the current camera.
2514
- *
2515
- * The third parameter, `amt`, is the amount to interpolate between `cam0` and
2516
- * `cam1`. 0.0 keeps the camera’s position and orientation equal to `cam0`’s,
2517
- * 0.5 sets them halfway between `cam0`’s and `cam1`’s , and 1.0 sets the
2518
- * position and orientation equal to `cam1`’s.
2519
- *
2520
- * For example, calling `myCamera.slerp(cam0, cam1, 0.1)` sets cam’s position
2521
- * and orientation very close to `cam0`’s. Calling
2522
- * `myCamera.slerp(cam0, cam1, 0.9)` sets cam’s position and orientation very
2523
- * close to `cam1`’s.
2524
- *
2525
- * Note: All of the cameras must use the same projection.
2526
- *
2527
- * @param {p5.Camera} cam0 first camera.
2528
- * @param {p5.Camera} cam1 second camera.
2529
- * @param {Number} amt amount of interpolation between 0.0 (`cam0`) and 1.0 (`cam1`).
2530
- *
2531
- * @example
2532
- * <div>
2533
- * <code>
2534
- * let cam;
2535
- * let cam0;
2536
- * let cam1;
2537
- *
2538
- * function setup() {
2539
- * createCanvas(100, 100, WEBGL);
2540
- *
2541
- * // Create the main camera.
2542
- * // Keep its default settings.
2543
- * cam = createCamera();
2544
- *
2545
- * // Create the first camera.
2546
- * // Keep its default settings.
2547
- * cam0 = createCamera();
2548
- *
2549
- * // Create the second camera.
2550
- * cam1 = createCamera();
2551
- *
2552
- * // Place it at the top-right.
2553
- * cam1.setPosition(400, -400, 800);
2554
- *
2555
- * // Point it at the origin.
2556
- * cam1.lookAt(0, 0, 0);
2557
- *
2558
- * // Set the current camera to cam.
2559
- * setCamera(cam);
2560
- *
2561
- * describe('A white cube drawn against a gray background. The camera slowly oscillates between a frontal view and an aerial view.');
2562
- * }
2563
- *
2564
- * function draw() {
2565
- * background(200);
2566
- *
2567
- * // Calculate the amount to interpolate between cam0 and cam1.
2568
- * let amt = 0.5 * sin(frameCount * 0.01) + 0.5;
2569
- *
2570
- * // Update the main camera's position and orientation.
2571
- * cam.slerp(cam0, cam1, amt);
2572
- *
2573
- * box();
2574
- * }
2575
- * </code>
2576
- * </div>
2577
- */
2578
- slerp(cam0, cam1, amt) {
2579
- // If t is 0 or 1, do not interpolate and set the argument camera.
2580
- if (amt === 0) {
2581
- this.set(cam0);
2582
- return;
2583
- } else if (amt === 1) {
2584
- this.set(cam1);
2585
- return;
2586
- }
2587
-
2588
- // For this cameras is ortho, assume that cam0 and cam1 are also ortho
2589
- // and interpolate the elements of the projection matrix.
2590
- // Use logarithmic interpolation for interpolation.
2591
- if (this.projMatrix.mat4[15] !== 0) {
2592
- this.projMatrix.setElement(
2593
- 0,
2594
- cam0.projMatrix.mat4[0] *
2595
- Math.pow(cam1.projMatrix.mat4[0] / cam0.projMatrix.mat4[0], amt)
2596
- );
2597
- this.projMatrix.setElement(
2598
- 5,
2599
- cam0.projMatrix.mat4[5] *
2600
- Math.pow(cam1.projMatrix.mat4[5] / cam0.projMatrix.mat4[5], amt)
2601
- );
2602
- // If the camera is active, make uPMatrix reflect changes in projMatrix.
2603
- if (this._isActive()) {
2604
- this._renderer.states.setValue('uPMatrix', this._renderer.states.uPMatrix.clone());
2605
- this._renderer.states.uPMatrix.mat4 = this.projMatrix.mat4.slice();
2606
- }
2607
- }
2608
-
2609
- // prepare eye vector and center vector of argument cameras.
2610
- const eye0 = new Vector(cam0.eyeX, cam0.eyeY, cam0.eyeZ);
2611
- const eye1 = new Vector(cam1.eyeX, cam1.eyeY, cam1.eyeZ);
2612
- const center0 = new Vector(cam0.centerX, cam0.centerY, cam0.centerZ);
2613
- const center1 = new Vector(cam1.centerX, cam1.centerY, cam1.centerZ);
2614
-
2615
- // Calculate the distance between eye and center for each camera.
2616
- // Logarithmically interpolate these with amt.
2617
- const dist0 = Vector.dist(eye0, center0);
2618
- const dist1 = Vector.dist(eye1, center1);
2619
- const lerpedDist = dist0 * Math.pow(dist1 / dist0, amt);
2620
-
2621
- // Next, calculate the ratio to interpolate the eye and center by a constant
2622
- // ratio for each camera. This ratio is the same for both. Also, with this ratio
2623
- // of points, the distance is the minimum distance of the two points of
2624
- // the same ratio.
2625
- // With this method, if the viewpoint is fixed, linear interpolation is performed
2626
- // at the viewpoint, and if the center is fixed, linear interpolation is performed
2627
- // at the center, resulting in reasonable interpolation. If both move, the point
2628
- // halfway between them is taken.
2629
- const eyeDiff = Vector.sub(eye0, eye1);
2630
- const diffDiff = eye0.copy().sub(eye1).sub(center0).add(center1);
2631
- // Suppose there are two line segments. Consider the distance between the points
2632
- // above them as if they were taken in the same ratio. This calculation figures out
2633
- // a ratio that minimizes this.
2634
- // Each line segment is, a line segment connecting the viewpoint and the center
2635
- // for each camera.
2636
- const divider = diffDiff.magSq();
2637
- let ratio = 1; // default.
2638
- if (divider > 0.000001) {
2639
- ratio = Vector.dot(eyeDiff, diffDiff) / divider;
2640
- ratio = Math.max(0, Math.min(ratio, 1));
2641
- }
2642
-
2643
- // Take the appropriate proportions and work out the points
2644
- // that are between the new viewpoint and the new center position.
2645
- const lerpedMedium = Vector.lerp(
2646
- Vector.lerp(eye0, center0, ratio),
2647
- Vector.lerp(eye1, center1, ratio),
2648
- amt
2649
- );
2650
-
2651
- // Prepare each of rotation matrix from their camera matrix
2652
- const rotMat0 = cam0.cameraMatrix.createSubMatrix3x3();
2653
- const rotMat1 = cam1.cameraMatrix.createSubMatrix3x3();
2654
-
2655
- // get front and up vector from local-coordinate-system.
2656
- const front0 = rotMat0.row(2);
2657
- const front1 = rotMat1.row(2);
2658
- const up0 = rotMat0.row(1);
2659
- const up1 = rotMat1.row(1);
2660
-
2661
- // prepare new vectors.
2662
- const newFront = new Vector();
2663
- const newUp = new Vector();
2664
- const newEye = new Vector();
2665
- const newCenter = new Vector();
2666
-
2667
- // Create the inverse matrix of mat0 by transposing mat0,
2668
- // and multiply it to mat1 from the right.
2669
- // This matrix represents the difference between the two.
2670
- // 'deltaRot' means 'difference of rotation matrices'.
2671
- const deltaRot = rotMat1.mult(rotMat0.copy().transpose()); // mat1 is 3x3
2672
-
2673
- // Calculate the trace and from it the cos value of the angle.
2674
- // An orthogonal matrix is just an orthonormal basis. If this is not the identity
2675
- // matrix, it is a centered orthonormal basis plus some angle of rotation about
2676
- // some axis. That's the angle. Letting this be theta, trace becomes 1+2cos(theta).
2677
- // reference: https://en.wikipedia.org/wiki/Rotation_matrix#Determining_the_angle
2678
- const diag = deltaRot.diagonal();
2679
- let cosTheta = 0.5 * (diag[0] + diag[1] + diag[2] - 1);
2680
-
2681
- // If the angle is close to 0, the two matrices are very close,
2682
- // so in that case we execute linearly interpolate.
2683
- if (1 - cosTheta < 0.0000001) {
2684
- // Obtain the front vector and up vector by linear interpolation
2685
- // and normalize them.
2686
- // calculate newEye, newCenter with newFront vector.
2687
- newFront.set(Vector.lerp(front0, front1, amt)).normalize();
2688
-
2689
- newEye.set(newFront).mult(ratio * lerpedDist).add(lerpedMedium);
2690
- newCenter.set(newFront).mult((ratio - 1) * lerpedDist).add(lerpedMedium);
2691
-
2692
- newUp.set(Vector.lerp(up0, up1, amt)).normalize();
2693
-
2694
- // set the camera
2695
- this.camera(
2696
- newEye.x, newEye.y, newEye.z,
2697
- newCenter.x, newCenter.y, newCenter.z,
2698
- newUp.x, newUp.y, newUp.z
2699
- );
2700
- return;
2701
- }
2702
-
2703
- // Calculates the axis vector and the angle of the difference orthogonal matrix.
2704
- // The axis vector is what I explained earlier in the comments.
2705
- // similar calculation is here:
2706
- // https://github.com/mrdoob/three.js/blob/883249620049d1632e8791732808fefd1a98c871/src/math/Quaternion.js#L294
2707
- let a, b, c, sinTheta;
2708
- let invOneMinusCosTheta = 1 / (1 - cosTheta);
2709
- const maxDiag = Math.max(diag[0], diag[1], diag[2]);
2710
- const offDiagSum13 = deltaRot.mat3[1] + deltaRot.mat3[3];
2711
- const offDiagSum26 = deltaRot.mat3[2] + deltaRot.mat3[6];
2712
- const offDiagSum57 = deltaRot.mat3[5] + deltaRot.mat3[7];
2713
-
2714
- if (maxDiag === diag[0]) {
2715
- a = Math.sqrt((diag[0] - cosTheta) * invOneMinusCosTheta); // not zero.
2716
- invOneMinusCosTheta /= a;
2717
- b = 0.5 * offDiagSum13 * invOneMinusCosTheta;
2718
- c = 0.5 * offDiagSum26 * invOneMinusCosTheta;
2719
- sinTheta = 0.5 * (deltaRot.mat3[7] - deltaRot.mat3[5]) / a;
2720
-
2721
- } else if (maxDiag === diag[1]) {
2722
- b = Math.sqrt((diag[1] - cosTheta) * invOneMinusCosTheta); // not zero.
2723
- invOneMinusCosTheta /= b;
2724
- c = 0.5 * offDiagSum57 * invOneMinusCosTheta;
2725
- a = 0.5 * offDiagSum13 * invOneMinusCosTheta;
2726
- sinTheta = 0.5 * (deltaRot.mat3[2] - deltaRot.mat3[6]) / b;
2727
-
2728
- } else {
2729
- c = Math.sqrt((diag[2] - cosTheta) * invOneMinusCosTheta); // not zero.
2730
- invOneMinusCosTheta /= c;
2731
- a = 0.5 * offDiagSum26 * invOneMinusCosTheta;
2732
- b = 0.5 * offDiagSum57 * invOneMinusCosTheta;
2733
- sinTheta = 0.5 * (deltaRot.mat3[3] - deltaRot.mat3[1]) / c;
2734
- }
2735
-
2736
- // Constructs a new matrix after interpolating the angles.
2737
- // Multiplying mat0 by the first matrix yields mat1, but by creating a state
2738
- // in the middle of that matrix, you can obtain a matrix that is
2739
- // an intermediate state between mat0 and mat1.
2740
- const angle = amt * Math.atan2(sinTheta, cosTheta);
2741
- const cosAngle = Math.cos(angle);
2742
- const sinAngle = Math.sin(angle);
2743
- const oneMinusCosAngle = 1 - cosAngle;
2744
- const ab = a * b;
2745
- const bc = b * c;
2746
- const ca = c * a;
2747
- // 3x3
2748
- const lerpedRotMat = new Matrix( [
2749
- cosAngle + oneMinusCosAngle * a * a,
2750
- oneMinusCosAngle * ab + sinAngle * c,
2751
- oneMinusCosAngle * ca - sinAngle * b,
2752
- oneMinusCosAngle * ab - sinAngle * c,
2753
- cosAngle + oneMinusCosAngle * b * b,
2754
- oneMinusCosAngle * bc + sinAngle * a,
2755
- oneMinusCosAngle * ca + sinAngle * b,
2756
- oneMinusCosAngle * bc - sinAngle * a,
2757
- cosAngle + oneMinusCosAngle * c * c
2758
- ]);
2759
-
2760
- // Multiply this to mat0 from left to get the interpolated front vector.
2761
- // calculate newEye, newCenter with newFront vector.
2762
- lerpedRotMat.multiplyVec(front0, newFront); // this is vec3
2763
-
2764
- newEye.set(newFront).mult(ratio * lerpedDist).add(lerpedMedium);
2765
- newCenter.set(newFront).mult((ratio - 1) * lerpedDist).add(lerpedMedium);
2766
-
2767
- lerpedRotMat.multiplyVec(up0, newUp); // this is vec3
2768
-
2769
- // We also get the up vector in the same way and set the camera.
2770
- // The eye position and center position are calculated based on the front vector.
2771
- this.camera(
2772
- newEye.x, newEye.y, newEye.z,
2773
- newCenter.x, newCenter.y, newCenter.z,
2774
- newUp.x, newUp.y, newUp.z
2775
- );
2776
- }
2777
-
2778
- ////////////////////////////////////////////////////////////////////////////////
2779
- // Camera Helper Methods
2780
- ////////////////////////////////////////////////////////////////////////////////
2781
-
2782
- // @TODO: combine this function with _setDefaultCamera to compute these values
2783
- // as-needed
2784
- _computeCameraDefaultSettings() {
2785
- this.defaultAspectRatio = this._renderer.width / this._renderer.height;
2786
- this.defaultEyeX = 0;
2787
- this.defaultEyeY = 0;
2788
- this.defaultEyeZ = 800;
2789
- this.defaultCameraFOV =
2790
- 2 * Math.atan(this._renderer.height / 2 / this.defaultEyeZ);
2791
- this.defaultCenterX = 0;
2792
- this.defaultCenterY = 0;
2793
- this.defaultCenterZ = 0;
2794
- this.defaultCameraNear = this.defaultEyeZ * 0.1;
2795
- this.defaultCameraFar = this.defaultEyeZ * 10;
2796
- }
2797
-
2798
- //detect if user didn't set the camera
2799
- //then call this function below
2800
- _setDefaultCamera() {
2801
- this.cameraFOV = this.defaultCameraFOV;
2802
- this.aspectRatio = this.defaultAspectRatio;
2803
- this.eyeX = this.defaultEyeX;
2804
- this.eyeY = this.defaultEyeY;
2805
- this.eyeZ = this.defaultEyeZ;
2806
- this.centerX = this.defaultCenterX;
2807
- this.centerY = this.defaultCenterY;
2808
- this.centerZ = this.defaultCenterZ;
2809
- this.upX = 0;
2810
- this.upY = 1;
2811
- this.upZ = 0;
2812
- this.cameraNear = this.defaultCameraNear;
2813
- this.cameraFar = this.defaultCameraFar;
2814
-
2815
- this.perspective();
2816
- this.camera();
2817
-
2818
- this.cameraType = 'default';
2819
- }
2820
-
2821
- _resize() {
2822
- // If we're using the default camera, update the aspect ratio
2823
- if (this.cameraType === 'default') {
2824
- this._computeCameraDefaultSettings();
2825
- this.cameraFOV = this.defaultCameraFOV;
2826
- this.aspectRatio = this.defaultAspectRatio;
2827
- this.perspective();
2828
- }
2829
- }
2830
-
2831
- /**
2832
- * Returns a copy of a camera.
2833
- * @private
2834
- */
2835
- copy() {
2836
- const _cam = new Camera(this._renderer);
2837
- _cam.cameraFOV = this.cameraFOV;
2838
- _cam.aspectRatio = this.aspectRatio;
2839
- _cam.eyeX = this.eyeX;
2840
- _cam.eyeY = this.eyeY;
2841
- _cam.eyeZ = this.eyeZ;
2842
- _cam.centerX = this.centerX;
2843
- _cam.centerY = this.centerY;
2844
- _cam.centerZ = this.centerZ;
2845
- _cam.upX = this.upX;
2846
- _cam.upY = this.upY;
2847
- _cam.upZ = this.upZ;
2848
- _cam.cameraNear = this.cameraNear;
2849
- _cam.cameraFar = this.cameraFar;
2850
-
2851
- _cam.cameraType = this.cameraType;
2852
- _cam.useLinePerspective = this.useLinePerspective;
2853
-
2854
- _cam.cameraMatrix = this.cameraMatrix.copy();
2855
- _cam.projMatrix = this.projMatrix.copy();
2856
- _cam.yScale = this.yScale;
2857
-
2858
- return _cam;
2859
- }
2860
-
2861
- clone() {
2862
- return this.copy();
2863
- }
2864
-
2865
- /**
2866
- * Returns a camera's local axes: left-right, up-down, and forward-backward,
2867
- * as defined by vectors in world-space.
2868
- * @private
2869
- */
2870
- _getLocalAxes() {
2871
- // calculate camera local Z vector
2872
- let z0 = this.eyeX - this.centerX;
2873
- let z1 = this.eyeY - this.centerY;
2874
- let z2 = this.eyeZ - this.centerZ;
2875
-
2876
- // normalize camera local Z vector
2877
- const eyeDist = Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
2878
- if (eyeDist !== 0) {
2879
- z0 /= eyeDist;
2880
- z1 /= eyeDist;
2881
- z2 /= eyeDist;
2882
- }
2883
-
2884
- // calculate camera Y vector
2885
- let y0 = this.upX;
2886
- let y1 = this.upY;
2887
- let y2 = this.upZ;
2888
-
2889
- // compute camera local X vector as up vector (local Y) cross local Z
2890
- let x0 = y1 * z2 - y2 * z1;
2891
- let x1 = -y0 * z2 + y2 * z0;
2892
- let x2 = y0 * z1 - y1 * z0;
2893
-
2894
- // recompute y = z cross x
2895
- y0 = z1 * x2 - z2 * x1;
2896
- y1 = -z0 * x2 + z2 * x0;
2897
- y2 = z0 * x1 - z1 * x0;
2898
-
2899
- // cross product gives area of parallelogram, which is < 1.0 for
2900
- // non-perpendicular unit-length vectors; so normalize x, y here:
2901
- const xmag = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
2902
- if (xmag !== 0) {
2903
- x0 /= xmag;
2904
- x1 /= xmag;
2905
- x2 /= xmag;
2906
- }
2907
-
2908
- const ymag = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
2909
- if (ymag !== 0) {
2910
- y0 /= ymag;
2911
- y1 /= ymag;
2912
- y2 /= ymag;
2913
- }
2914
-
2915
- return {
2916
- x: [x0, x1, x2],
2917
- y: [y0, y1, y2],
2918
- z: [z0, z1, z2]
2919
- };
2920
- }
2921
-
2922
- /**
2923
- * Orbits the camera about center point. For use with orbitControl().
2924
- * @private
2925
- * @param {Number} dTheta change in spherical coordinate theta
2926
- * @param {Number} dPhi change in spherical coordinate phi
2927
- * @param {Number} dRadius change in radius
2928
- */
2929
- _orbit(dTheta, dPhi, dRadius) {
2930
- // Calculate the vector and its magnitude from the center to the viewpoint
2931
- const diffX = this.eyeX - this.centerX;
2932
- const diffY = this.eyeY - this.centerY;
2933
- const diffZ = this.eyeZ - this.centerZ;
2934
- let camRadius = Math.hypot(diffX, diffY, diffZ);
2935
- // front vector. unit vector from center to eye.
2936
- const front = new Vector(diffX, diffY, diffZ).normalize();
2937
- // up vector. normalized camera's up vector.
2938
- const up = new Vector(this.upX, this.upY, this.upZ).normalize(); // y-axis
2939
- // side vector. Right when viewed from the front
2940
- const side = Vector.cross(up, front).normalize(); // x-axis
2941
- // vertical vector. normalized vector of projection of front vector.
2942
- const vertical = Vector.cross(side, up); // z-axis
2943
-
2944
- // update camRadius
2945
- camRadius *= Math.pow(10, dRadius);
2946
- // prevent zooming through the center:
2947
- if (camRadius < this.cameraNear) {
2948
- camRadius = this.cameraNear;
2949
- }
2950
- if (camRadius > this.cameraFar) {
2951
- camRadius = this.cameraFar;
2952
- }
2953
-
2954
- // calculate updated camera angle
2955
- // Find the angle between the "up" and the "front", add dPhi to that.
2956
- // angleBetween() may return negative value. Since this specification is subject to change
2957
- // due to version updates, it cannot be adopted, so here we calculate using a method
2958
- // that directly obtains the absolute value.
2959
- const camPhi =
2960
- Math.acos(Math.max(-1, Math.min(1, Vector.dot(front, up)))) + dPhi;
2961
- // Rotate by dTheta in the shortest direction from "vertical" to "side"
2962
- const camTheta = dTheta;
2963
-
2964
- // Invert camera's upX, upY, upZ if dPhi is below 0 or above PI
2965
- if (camPhi <= 0 || camPhi >= Math.PI) {
2966
- this.upX *= -1;
2967
- this.upY *= -1;
2968
- this.upZ *= -1;
2969
- }
2970
-
2971
- // update eye vector by calculate new front vector
2972
- up.mult(Math.cos(camPhi));
2973
- vertical.mult(Math.cos(camTheta) * Math.sin(camPhi));
2974
- side.mult(Math.sin(camTheta) * Math.sin(camPhi));
2975
-
2976
- front.set(up).add(vertical).add(side);
2977
-
2978
- this.eyeX = camRadius * front.x + this.centerX;
2979
- this.eyeY = camRadius * front.y + this.centerY;
2980
- this.eyeZ = camRadius * front.z + this.centerZ;
2981
-
2982
- // update camera
2983
- this.camera(
2984
- this.eyeX, this.eyeY, this.eyeZ,
2985
- this.centerX, this.centerY, this.centerZ,
2986
- this.upX, this.upY, this.upZ
2987
- );
2988
- }
2989
-
2990
- /**
2991
- * Orbits the camera about center point. For use with orbitControl().
2992
- * Unlike _orbit(), the direction of rotation always matches the direction of pointer movement.
2993
- * @private
2994
- * @param {Number} dx the x component of the rotation vector.
2995
- * @param {Number} dy the y component of the rotation vector.
2996
- * @param {Number} dRadius change in radius
2997
- */
2998
- _orbitFree(dx, dy, dRadius) {
2999
- // Calculate the vector and its magnitude from the center to the viewpoint
3000
- const diffX = this.eyeX - this.centerX;
3001
- const diffY = this.eyeY - this.centerY;
3002
- const diffZ = this.eyeZ - this.centerZ;
3003
- let camRadius = Math.hypot(diffX, diffY, diffZ);
3004
- // front vector. unit vector from center to eye.
3005
- const front = new Vector(diffX, diffY, diffZ).normalize();
3006
- // up vector. camera's up vector.
3007
- const up = new Vector(this.upX, this.upY, this.upZ);
3008
- // side vector. Right when viewed from the front. (like x-axis)
3009
- const side = Vector.cross(up, front).normalize();
3010
- // down vector. Bottom when viewed from the front. (like y-axis)
3011
- const down = Vector.cross(front, side);
3012
-
3013
- // side vector and down vector are no longer used as-is.
3014
- // Create a vector representing the direction of rotation
3015
- // in the form cos(direction)*side + sin(direction)*down.
3016
- // Make the current side vector into this.
3017
- const directionAngle = Math.atan2(dy, dx);
3018
- down.mult(Math.sin(directionAngle));
3019
- side.mult(Math.cos(directionAngle)).add(down);
3020
- // The amount of rotation is the size of the vector (dx, dy).
3021
- const rotAngle = Math.sqrt(dx * dx + dy * dy);
3022
- // The vector that is orthogonal to both the front vector and
3023
- // the rotation direction vector is the rotation axis vector.
3024
- const axis = Vector.cross(front, side);
3025
-
3026
- // update camRadius
3027
- camRadius *= Math.pow(10, dRadius);
3028
- // prevent zooming through the center:
3029
- if (camRadius < this.cameraNear) {
3030
- camRadius = this.cameraNear;
3031
- }
3032
- if (camRadius > this.cameraFar) {
3033
- camRadius = this.cameraFar;
3034
- }
3035
-
3036
- // If the axis vector is likened to the z-axis, the front vector is
3037
- // the x-axis and the side vector is the y-axis. Rotate the up and front
3038
- // vectors respectively by thinking of them as rotations around the z-axis.
3039
-
3040
- // Calculate the components by taking the dot product and
3041
- // calculate a rotation based on that.
3042
- const c = Math.cos(rotAngle);
3043
- const s = Math.sin(rotAngle);
3044
- const dotFront = up.dot(front);
3045
- const dotSide = up.dot(side);
3046
- const ux = dotFront * c + dotSide * s;
3047
- const uy = -dotFront * s + dotSide * c;
3048
- const uz = up.dot(axis);
3049
- up.x = ux * front.x + uy * side.x + uz * axis.x;
3050
- up.y = ux * front.y + uy * side.y + uz * axis.y;
3051
- up.z = ux * front.z + uy * side.z + uz * axis.z;
3052
- // We won't be using the side vector and the front vector anymore,
3053
- // so let's make the front vector into the vector from the center to the new eye.
3054
- side.mult(-s);
3055
- front.mult(c).add(side).mult(camRadius);
3056
-
3057
- // it's complete. let's update camera.
3058
- this.camera(
3059
- front.x + this.centerX,
3060
- front.y + this.centerY,
3061
- front.z + this.centerZ,
3062
- this.centerX, this.centerY, this.centerZ,
3063
- up.x, up.y, up.z
3064
- );
3065
- }
3066
-
3067
- /**
3068
- * Returns true if camera is currently attached to renderer.
3069
- * @private
3070
- */
3071
- _isActive() {
3072
- return this === this._renderer.states.curCamera;
3073
- }
3074
- };
3075
-
3076
- function camera(p5, fn){
3077
- ////////////////////////////////////////////////////////////////////////////////
3078
- // p5.Prototype Methods
3079
- ////////////////////////////////////////////////////////////////////////////////
3080
-
3081
- /**
3082
- * Sets the position and orientation of the current camera in a 3D sketch.
3083
- *
3084
- * `camera()` allows objects to be viewed from different angles. It has nine
3085
- * parameters that are all optional.
3086
- *
3087
- * The first three parameters, `x`, `y`, and `z`, are the coordinates of the
3088
- * camera’s position. For example, calling `camera(0, 0, 0)` places the camera
3089
- * at the origin `(0, 0, 0)`. By default, the camera is placed at
3090
- * `(0, 0, 800)`.
3091
- *
3092
- * The next three parameters, `centerX`, `centerY`, and `centerZ` are the
3093
- * coordinates of the point where the camera faces. For example, calling
3094
- * `camera(0, 0, 0, 10, 20, 30)` places the camera at the origin `(0, 0, 0)`
3095
- * and points it at `(10, 20, 30)`. By default, the camera points at the
3096
- * origin `(0, 0, 0)`.
3097
- *
3098
- * The last three parameters, `upX`, `upY`, and `upZ` are the components of
3099
- * the "up" vector. The "up" vector orients the camera’s y-axis. For example,
3100
- * calling `camera(0, 0, 0, 10, 20, 30, 0, -1, 0)` places the camera at the
3101
- * origin `(0, 0, 0)`, points it at `(10, 20, 30)`, and sets the "up" vector
3102
- * to `(0, -1, 0)` which is like holding it upside-down. By default, the "up"
3103
- * vector is `(0, 1, 0)`.
3104
- *
3105
- * Note: `camera()` can only be used in WebGL mode.
3106
- *
3107
- * @method camera
3108
- * @for p5
3109
- * @param {Number} [x] x-coordinate of the camera. Defaults to 0.
3110
- * @param {Number} [y] y-coordinate of the camera. Defaults to 0.
3111
- * @param {Number} [z] z-coordinate of the camera. Defaults to 800.
3112
- * @param {Number} [centerX] x-coordinate of the point the camera faces. Defaults to 0.
3113
- * @param {Number} [centerY] y-coordinate of the point the camera faces. Defaults to 0.
3114
- * @param {Number} [centerZ] z-coordinate of the point the camera faces. Defaults to 0.
3115
- * @param {Number} [upX] x-component of the camera’s "up" vector. Defaults to 0.
3116
- * @param {Number} [upY] y-component of the camera’s "up" vector. Defaults to 1.
3117
- * @param {Number} [upZ] z-component of the camera’s "up" vector. Defaults to 0.
3118
- * @chainable
3119
- *
3120
- * @example
3121
- * <div>
3122
- * <code>
3123
- * function setup() {
3124
- * createCanvas(100, 100, WEBGL);
3125
- *
3126
- * describe('A white cube on a gray background.');
3127
- * }
3128
- *
3129
- * function draw() {
3130
- * background(200);
3131
- *
3132
- * // Move the camera to the top-right.
3133
- * camera(200, -400, 800);
3134
- *
3135
- * // Draw the box.
3136
- * box();
3137
- * }
3138
- * </code>
3139
- * </div>
3140
- *
3141
- * <div>
3142
- * <code>
3143
- * function setup() {
3144
- * createCanvas(100, 100, WEBGL);
3145
- *
3146
- * describe('A white cube apperas to sway left and right on a gray background.');
3147
- * }
3148
- *
3149
- * function draw() {
3150
- * background(200);
3151
- *
3152
- * // Calculate the camera's x-coordinate.
3153
- * let x = 400 * cos(frameCount * 0.01);
3154
- *
3155
- * // Orbit the camera around the box.
3156
- * camera(x, -400, 800);
3157
- *
3158
- * // Draw the box.
3159
- * box();
3160
- * }
3161
- * </code>
3162
- * </div>
3163
- *
3164
- * <div>
3165
- * <code>
3166
- * // Adjust the range sliders to change the camera's position.
3167
- *
3168
- * let xSlider;
3169
- * let ySlider;
3170
- * let zSlider;
3171
- *
3172
- * function setup() {
3173
- * createCanvas(100, 100, WEBGL);
3174
- *
3175
- * // Create slider objects to set the camera's coordinates.
3176
- * xSlider = createSlider(-400, 400, 400);
3177
- * xSlider.position(0, 100);
3178
- * xSlider.size(100);
3179
- * ySlider = createSlider(-400, 400, -200);
3180
- * ySlider.position(0, 120);
3181
- * ySlider.size(100);
3182
- * zSlider = createSlider(0, 1600, 800);
3183
- * zSlider.position(0, 140);
3184
- * zSlider.size(100);
3185
- *
3186
- * describe(
3187
- * 'A white cube drawn against a gray background. Three range sliders appear beneath the image. The camera position changes when the user moves the sliders.'
3188
- * );
3189
- * }
3190
- *
3191
- * function draw() {
3192
- * background(200);
3193
- *
3194
- * // Get the camera's coordinates from the sliders.
3195
- * let x = xSlider.value();
3196
- * let y = ySlider.value();
3197
- * let z = zSlider.value();
3198
- *
3199
- * // Move the camera.
3200
- * camera(x, y, z);
3201
- *
3202
- * // Draw the box.
3203
- * box();
3204
- * }
3205
- * </code>
3206
- * </div>
3207
- */
3208
- fn.camera = function (...args) {
3209
- this._assert3d('camera');
3210
- // p5._validateParameters('camera', args);
3211
- this._renderer.camera(...args);
3212
- return this;
3213
- };
3214
-
3215
- /**
3216
- * Sets a perspective projection for the current camera in a 3D sketch.
3217
- *
3218
- * In a perspective projection, shapes that are further from the camera appear
3219
- * smaller than shapes that are near the camera. This technique, called
3220
- * foreshortening, creates realistic 3D scenes. It’s applied by default in
3221
- * WebGL mode.
3222
- *
3223
- * `perspective()` changes the camera’s perspective by changing its viewing
3224
- * frustum. The frustum is the volume of space that’s visible to the camera.
3225
- * Its shape is a pyramid with its top cut off. The camera is placed where
3226
- * the top of the pyramid should be and views everything between the frustum’s
3227
- * top (near) plane and its bottom (far) plane.
3228
- *
3229
- * The first parameter, `fovy`, is the camera’s vertical field of view. It’s
3230
- * an angle that describes how tall or narrow a view the camera has. For
3231
- * example, calling `perspective(0.5)` sets the camera’s vertical field of
3232
- * view to 0.5 radians. By default, `fovy` is calculated based on the sketch’s
3233
- * height and the camera’s default z-coordinate, which is 800. The formula for
3234
- * the default `fovy` is `2 * atan(height / 2 / 800)`.
3235
- *
3236
- * The second parameter, `aspect`, is the camera’s aspect ratio. It’s a number
3237
- * that describes the ratio of the top plane’s width to its height. For
3238
- * example, calling `perspective(0.5, 1.5)` sets the camera’s field of view to
3239
- * 0.5 radians and aspect ratio to 1.5, which would make shapes appear thinner
3240
- * on a square canvas. By default, aspect is set to `width / height`.
3241
- *
3242
- * The third parameter, `near`, is the distance from the camera to the near
3243
- * plane. For example, calling `perspective(0.5, 1.5, 100)` sets the camera’s
3244
- * field of view to 0.5 radians, its aspect ratio to 1.5, and places the near
3245
- * plane 100 pixels from the camera. Any shapes drawn less than 100 pixels
3246
- * from the camera won’t be visible. By default, near is set to `0.1 * 800`,
3247
- * which is 1/10th the default distance between the camera and the origin.
3248
- *
3249
- * The fourth parameter, `far`, is the distance from the camera to the far
3250
- * plane. For example, calling `perspective(0.5, 1.5, 100, 10000)` sets the
3251
- * camera’s field of view to 0.5 radians, its aspect ratio to 1.5, places the
3252
- * near plane 100 pixels from the camera, and places the far plane 10,000
3253
- * pixels from the camera. Any shapes drawn more than 10,000 pixels from the
3254
- * camera won’t be visible. By default, far is set to `10 * 800`, which is 10
3255
- * times the default distance between the camera and the origin.
3256
- *
3257
- * Note: `perspective()` can only be used in WebGL mode.
3258
- *
3259
- * @method perspective
3260
- * @for p5
3261
- * @param {Number} [fovy] camera frustum vertical field of view. Defaults to
3262
- * `2 * atan(height / 2 / 800)`.
3263
- * @param {Number} [aspect] camera frustum aspect ratio. Defaults to
3264
- * `width / height`.
3265
- * @param {Number} [near] distance from the camera to the near clipping plane.
3266
- * Defaults to `0.1 * 800`.
3267
- * @param {Number} [far] distance from the camera to the far clipping plane.
3268
- * Defaults to `10 * 800`.
3269
- * @chainable
3270
- *
3271
- * @example
3272
- * <div>
3273
- * <code>
3274
- * // Double-click to squeeze the box.
3275
- *
3276
- * let isSqueezed = false;
3277
- *
3278
- * function setup() {
3279
- * createCanvas(100, 100, WEBGL);
3280
- *
3281
- * describe('A white rectangular prism on a gray background. The box appears to become thinner when the user double-clicks.');
3282
- * }
3283
- *
3284
- * function draw() {
3285
- * background(200);
3286
- *
3287
- * // Place the camera at the top-right.
3288
- * camera(400, -400, 800);
3289
- *
3290
- * if (isSqueezed === true) {
3291
- * // Set fovy to 0.2.
3292
- * // Set aspect to 1.5.
3293
- * perspective(0.2, 1.5);
3294
- * }
3295
- *
3296
- * // Draw the box.
3297
- * box();
3298
- * }
3299
- *
3300
- * // Change the camera's perspective when the user double-clicks.
3301
- * function doubleClicked() {
3302
- * isSqueezed = true;
3303
- * }
3304
- * </code>
3305
- * </div>
3306
- *
3307
- * <div>
3308
- * <code>
3309
- * function setup() {
3310
- * createCanvas(100, 100, WEBGL);
3311
- *
3312
- * describe('A white rectangular prism on a gray background. The prism moves away from the camera until it disappears.');
3313
- * }
3314
- *
3315
- * function draw() {
3316
- * background(200);
3317
- *
3318
- * // Place the camera at the top-right.
3319
- * camera(400, -400, 800);
3320
- *
3321
- * // Set fovy to 0.2.
3322
- * // Set aspect to 1.5.
3323
- * // Set near to 600.
3324
- * // Set far to 1200.
3325
- * perspective(0.2, 1.5, 600, 1200);
3326
- *
3327
- * // Move the origin away from the camera.
3328
- * let x = -frameCount;
3329
- * let y = frameCount;
3330
- * let z = -2 * frameCount;
3331
- * translate(x, y, z);
3332
- *
3333
- * // Draw the box.
3334
- * box();
3335
- * }
3336
- * </code>
3337
- * </div>
3338
- */
3339
- fn.perspective = function (...args) {
3340
- this._assert3d('perspective');
3341
- // p5._validateParameters('perspective', args);
3342
- this._renderer.perspective(...args);
3343
- return this;
3344
- };
3345
-
3346
-
3347
- /**
3348
- * Enables or disables perspective for lines in 3D sketches.
3349
- *
3350
- * In WebGL mode, lines can be drawn with a thinner stroke when they’re
3351
- * further from the camera. Doing so gives them a more realistic appearance.
3352
- *
3353
- * By default, lines are drawn differently based on the type of perspective
3354
- * being used:
3355
- * - `perspective()` and `frustum()` simulate a realistic perspective. In
3356
- * these modes, stroke weight is affected by the line’s distance from the
3357
- * camera. Doing so results in a more natural appearance. `perspective()` is
3358
- * the default mode for 3D sketches.
3359
- * - `ortho()` doesn’t simulate a realistic perspective. In this mode, stroke
3360
- * weights are consistent regardless of the line’s distance from the camera.
3361
- * Doing so results in a more predictable and consistent appearance.
3362
- *
3363
- * `linePerspective()` can override the default line drawing mode.
3364
- *
3365
- * The parameter, `enable`, is optional. It’s a `Boolean` value that sets the
3366
- * way lines are drawn. If `true` is passed, as in `linePerspective(true)`,
3367
- * then lines will appear thinner when they are further from the camera. If
3368
- * `false` is passed, as in `linePerspective(false)`, then lines will have
3369
- * consistent stroke weights regardless of their distance from the camera. By
3370
- * default, `linePerspective()` is enabled.
3371
- *
3372
- * Calling `linePerspective()` without passing an argument returns `true` if
3373
- * it's enabled and `false` if not.
3374
- *
3375
- * Note: `linePerspective()` can only be used in WebGL mode.
3376
- *
3377
- * @method linePerspective
3378
- * @for p5
3379
- * @param {Boolean} enable whether to enable line perspective.
3380
- *
3381
- * @example
3382
- * <div>
3383
- * <code>
3384
- * // Double-click the canvas to toggle the line perspective.
3385
- *
3386
- * function setup() {
3387
- * createCanvas(100, 100, WEBGL);
3388
- *
3389
- * describe(
3390
- * 'A white cube with black edges on a gray background. Its edges toggle between thick and thin when the user double-clicks.'
3391
- * );
3392
- * }
3393
- *
3394
- * function draw() {
3395
- * background(200);
3396
- *
3397
- * // Translate the origin toward the camera.
3398
- * translate(-10, 10, 600);
3399
- *
3400
- * // Rotate the coordinate system.
3401
- * rotateY(-0.1);
3402
- * rotateX(-0.1);
3403
- *
3404
- * // Draw the row of boxes.
3405
- * for (let i = 0; i < 6; i += 1) {
3406
- * translate(0, 0, -40);
3407
- * box(10);
3408
- * }
3409
- * }
3410
- *
3411
- * // Toggle the line perspective when the user double-clicks.
3412
- * function doubleClicked() {
3413
- * let isEnabled = linePerspective();
3414
- * linePerspective(!isEnabled);
3415
- * }
3416
- * </code>
3417
- * </div>
3418
- *
3419
- * <div>
3420
- * <code>
3421
- * // Double-click the canvas to toggle the line perspective.
3422
- *
3423
- * function setup() {
3424
- * createCanvas(100, 100, WEBGL);
3425
- *
3426
- * describe(
3427
- * 'A row of cubes with black edges on a gray background. Their edges toggle between thick and thin when the user double-clicks.'
3428
- * );
3429
- * }
3430
- *
3431
- * function draw() {
3432
- * background(200);
3433
- *
3434
- * // Use an orthographic projection.
3435
- * ortho();
3436
- *
3437
- * // Translate the origin toward the camera.
3438
- * translate(-10, 10, 600);
3439
- *
3440
- * // Rotate the coordinate system.
3441
- * rotateY(-0.1);
3442
- * rotateX(-0.1);
3443
- *
3444
- * // Draw the row of boxes.
3445
- * for (let i = 0; i < 6; i += 1) {
3446
- * translate(0, 0, -40);
3447
- * box(10);
3448
- * }
3449
- * }
3450
- *
3451
- * // Toggle the line perspective when the user double-clicks.
3452
- * function doubleClicked() {
3453
- * let isEnabled = linePerspective();
3454
- * linePerspective(!isEnabled);
3455
- * }
3456
- * </code>
3457
- * </div>
3458
- */
3459
- /**
3460
- * @method linePerspective
3461
- * @return {boolean} whether line perspective is enabled.
3462
- */
3463
- fn.linePerspective = function (enable) {
3464
- // p5._validateParameters('linePerspective', arguments);
3465
- if (!(this._renderer instanceof RendererGL)) {
3466
- throw new Error('linePerspective() must be called in WebGL mode.');
3467
- }
3468
- return this._renderer.linePerspective(enable);
3469
- };
3470
-
3471
-
3472
- /**
3473
- * Sets an orthographic projection for the current camera in a 3D sketch.
3474
- *
3475
- * In an orthographic projection, shapes with the same size always appear the
3476
- * same size, regardless of whether they are near or far from the camera.
3477
- *
3478
- * `ortho()` changes the camera’s perspective by changing its viewing frustum
3479
- * from a truncated pyramid to a rectangular prism. The camera is placed in
3480
- * front of the frustum and views everything between the frustum’s near plane
3481
- * and its far plane. `ortho()` has six optional parameters to define the
3482
- * frustum.
3483
- *
3484
- * The first four parameters, `left`, `right`, `bottom`, and `top`, set the
3485
- * coordinates of the frustum’s sides, bottom, and top. For example, calling
3486
- * `ortho(-100, 100, 200, -200)` creates a frustum that’s 200 pixels wide and
3487
- * 400 pixels tall. By default, these coordinates are set based on the
3488
- * sketch’s width and height, as in
3489
- * `ortho(-width / 2, width / 2, -height / 2, height / 2)`.
3490
- *
3491
- * The last two parameters, `near` and `far`, set the distance of the
3492
- * frustum’s near and far plane from the camera. For example, calling
3493
- * `ortho(-100, 100, 200, 200, 50, 1000)` creates a frustum that’s 200 pixels
3494
- * wide, 400 pixels tall, starts 50 pixels from the camera, and ends 1,000
3495
- * pixels from the camera. By default, `near` and `far` are set to 0 and
3496
- * `max(width, height) + 800`, respectively.
3497
- *
3498
- * Note: `ortho()` can only be used in WebGL mode.
3499
- *
3500
- * @method ortho
3501
- * @for p5
3502
- * @param {Number} [left] x-coordinate of the frustum’s left plane. Defaults to `-width / 2`.
3503
- * @param {Number} [right] x-coordinate of the frustum’s right plane. Defaults to `width / 2`.
3504
- * @param {Number} [bottom] y-coordinate of the frustum’s bottom plane. Defaults to `height / 2`.
3505
- * @param {Number} [top] y-coordinate of the frustum’s top plane. Defaults to `-height / 2`.
3506
- * @param {Number} [near] z-coordinate of the frustum’s near plane. Defaults to 0.
3507
- * @param {Number} [far] z-coordinate of the frustum’s far plane. Defaults to `max(width, height) + 800`.
3508
- * @chainable
3509
- *
3510
- * @example
3511
- * <div>
3512
- * <code>
3513
- * function setup() {
3514
- * createCanvas(100, 100, WEBGL);
3515
- *
3516
- * describe('A row of tiny, white cubes on a gray background. All the cubes appear the same size.');
3517
- * }
3518
- *
3519
- * function draw() {
3520
- * background(200);
3521
- *
3522
- * // Apply an orthographic projection.
3523
- * ortho();
3524
- *
3525
- * // Translate the origin toward the camera.
3526
- * translate(-10, 10, 600);
3527
- *
3528
- * // Rotate the coordinate system.
3529
- * rotateY(-0.1);
3530
- * rotateX(-0.1);
3531
- *
3532
- * // Draw the row of boxes.
3533
- * for (let i = 0; i < 6; i += 1) {
3534
- * translate(0, 0, -40);
3535
- * box(10);
3536
- * }
3537
- * }
3538
- * </code>
3539
- * </div>
3540
- *
3541
- * <div>
3542
- * <code>
3543
- * function setup() {
3544
- * createCanvas(100, 100, WEBGL);
3545
- *
3546
- * describe('A white cube on a gray background.');
3547
- * }
3548
- *
3549
- * function draw() {
3550
- * background(200);
3551
- *
3552
- * // Apply an orthographic projection.
3553
- * // Center the frustum.
3554
- * // Set its width and height to 20.
3555
- * // Place its near plane 300 pixels from the camera.
3556
- * // Place its far plane 350 pixels from the camera.
3557
- * ortho(-10, 10, -10, 10, 300, 350);
3558
- *
3559
- * // Translate the origin toward the camera.
3560
- * translate(-10, 10, 600);
3561
- *
3562
- * // Rotate the coordinate system.
3563
- * rotateY(-0.1);
3564
- * rotateX(-0.1);
3565
- *
3566
- * // Draw the row of boxes.
3567
- * for (let i = 0; i < 6; i += 1) {
3568
- * translate(0, 0, -40);
3569
- * box(10);
3570
- * }
3571
- * }
3572
- * </code>
3573
- * </div>
3574
- */
3575
- fn.ortho = function (...args) {
3576
- this._assert3d('ortho');
3577
- // p5._validateParameters('ortho', args);
3578
- this._renderer.ortho(...args);
3579
- return this;
3580
- };
3581
-
3582
- /**
3583
- * Sets the frustum of the current camera in a 3D sketch.
3584
- *
3585
- * In a frustum projection, shapes that are further from the camera appear
3586
- * smaller than shapes that are near the camera. This technique, called
3587
- * foreshortening, creates realistic 3D scenes.
3588
- *
3589
- * `frustum()` changes the default camera’s perspective by changing its
3590
- * viewing frustum. The frustum is the volume of space that’s visible to the
3591
- * camera. The frustum’s shape is a pyramid with its top cut off. The camera
3592
- * is placed where the top of the pyramid should be and points towards the
3593
- * base of the pyramid. It views everything within the frustum.
3594
- *
3595
- * The first four parameters, `left`, `right`, `bottom`, and `top`, set the
3596
- * coordinates of the frustum’s sides, bottom, and top. For example, calling
3597
- * `frustum(-100, 100, 200, -200)` creates a frustum that’s 200 pixels wide
3598
- * and 400 pixels tall. By default, these coordinates are set based on the
3599
- * sketch’s width and height, as in
3600
- * `ortho(-width / 20, width / 20, height / 20, -height / 20)`.
3601
- *
3602
- * The last two parameters, `near` and `far`, set the distance of the
3603
- * frustum’s near and far plane from the camera. For example, calling
3604
- * `ortho(-100, 100, 200, -200, 50, 1000)` creates a frustum that’s 200 pixels
3605
- * wide, 400 pixels tall, starts 50 pixels from the camera, and ends 1,000
3606
- * pixels from the camera. By default, near is set to `0.1 * 800`, which is
3607
- * 1/10th the default distance between the camera and the origin. `far` is set
3608
- * to `10 * 800`, which is 10 times the default distance between the camera
3609
- * and the origin.
3610
- *
3611
- * Note: `frustum()` can only be used in WebGL mode.
3612
- *
3613
- * @method frustum
3614
- * @for p5
3615
- * @param {Number} [left] x-coordinate of the frustum’s left plane. Defaults to `-width / 20`.
3616
- * @param {Number} [right] x-coordinate of the frustum’s right plane. Defaults to `width / 20`.
3617
- * @param {Number} [bottom] y-coordinate of the frustum’s bottom plane. Defaults to `height / 20`.
3618
- * @param {Number} [top] y-coordinate of the frustum’s top plane. Defaults to `-height / 20`.
3619
- * @param {Number} [near] z-coordinate of the frustum’s near plane. Defaults to `0.1 * 800`.
3620
- * @param {Number} [far] z-coordinate of the frustum’s far plane. Defaults to `10 * 800`.
3621
- * @chainable
3622
- *
3623
- * @example
3624
- * <div>
3625
- * <code>
3626
- * function setup() {
3627
- * createCanvas(100, 100, WEBGL);
3628
- *
3629
- * describe('A row of white cubes on a gray background.');
3630
- * }
3631
- *
3632
- * function draw() {
3633
- * background(200);
3634
- *
3635
- * // Apply the default frustum projection.
3636
- * frustum();
3637
- *
3638
- * // Translate the origin toward the camera.
3639
- * translate(-10, 10, 600);
3640
- *
3641
- * // Rotate the coordinate system.
3642
- * rotateY(-0.1);
3643
- * rotateX(-0.1);
3644
- *
3645
- * // Draw the row of boxes.
3646
- * for (let i = 0; i < 6; i += 1) {
3647
- * translate(0, 0, -40);
3648
- * box(10);
3649
- * }
3650
- * }
3651
- * </code>
3652
- * </div>
3653
- *
3654
- * <div>
3655
- * <code>
3656
- * function setup() {
3657
- * createCanvas(100, 100, WEBGL);
3658
- * describe('A white cube on a gray background.');
3659
- * }
3660
- *
3661
- * function draw() {
3662
- * background(200);
3663
- *
3664
- * // Adjust the frustum.
3665
- * // Center it.
3666
- * // Set its width and height to 20 pixels.
3667
- * // Place its near plane 300 pixels from the camera.
3668
- * // Place its far plane 350 pixels from the camera.
3669
- * frustum(-10, 10, -10, 10, 300, 350);
3670
- *
3671
- * // Translate the origin toward the camera.
3672
- * translate(-10, 10, 600);
3673
- *
3674
- * // Rotate the coordinate system.
3675
- * rotateY(-0.1);
3676
- * rotateX(-0.1);
3677
- *
3678
- * // Draw the row of boxes.
3679
- * for (let i = 0; i < 6; i += 1) {
3680
- * translate(0, 0, -40);
3681
- * box(10);
3682
- * }
3683
- * }
3684
- * </code>
3685
- * </div>
3686
- */
3687
- fn.frustum = function (...args) {
3688
- this._assert3d('frustum');
3689
- // p5._validateParameters('frustum', args);
3690
- this._renderer.frustum(...args);
3691
- return this;
3692
- };
3693
-
3694
- /**
3695
- * Creates a new <a href="#/p5.Camera">p5.Camera</a> object and sets it
3696
- * as the current (active) camera.
3697
- *
3698
- * The new camera is initialized with a default position `(0, 0, 800)` and a
3699
- * default perspective projection. Its properties can be controlled with
3700
- * <a href="#/p5.Camera">p5.Camera</a> methods such as
3701
- * `myCamera.lookAt(0, 0, 0)`.
3702
- *
3703
- * Note: Every 3D sketch starts with a default camera initialized.
3704
- * This camera can be controlled with the functions
3705
- * <a href="#/p5/camera">camera()</a>,
3706
- * <a href="#/p5/perspective">perspective()</a>,
3707
- * <a href="#/p5/ortho">ortho()</a>, and
3708
- * <a href="#/p5/frustum">frustum()</a> if it's the only camera in the scene.
3709
- *
3710
- * Note: `createCamera()` can only be used in WebGL mode.
3711
- *
3712
- * @method createCamera
3713
- * @return {p5.Camera} the new camera.
3714
- * @for p5
3715
- *
3716
- * @example
3717
- * <div>
3718
- * <code>
3719
- * // Double-click to toggle between cameras.
3720
- *
3721
- * let cam1;
3722
- * let cam2;
3723
- * let usingCam1 = true;
3724
- *
3725
- * function setup() {
3726
- * createCanvas(100, 100, WEBGL);
3727
- *
3728
- * // Create the first camera.
3729
- * // Keep its default settings.
3730
- * cam1 = createCamera();
3731
- *
3732
- * // Create the second camera.
3733
- * // Place it at the top-left.
3734
- * // Point it at the origin.
3735
- * cam2 = createCamera();
3736
- * cam2.setPosition(400, -400, 800);
3737
- * cam2.lookAt(0, 0, 0);
3738
- *
3739
- * // Set the current camera to cam1.
3740
- * setCamera(cam1);
3741
- *
3742
- * describe('A white cube on a gray background. The camera toggles between frontal and aerial views when the user double-clicks.');
3743
- * }
3744
- *
3745
- * function draw() {
3746
- * background(200);
3747
- *
3748
- * // Draw the box.
3749
- * box();
3750
- * }
3751
- *
3752
- * // Toggle the current camera when the user double-clicks.
3753
- * function doubleClicked() {
3754
- * if (usingCam1 === true) {
3755
- * setCamera(cam2);
3756
- * usingCam1 = false;
3757
- * } else {
3758
- * setCamera(cam1);
3759
- * usingCam1 = true;
3760
- * }
3761
- * }
3762
- * </code>
3763
- * </div>
3764
- */
3765
- fn.createCamera = function () {
3766
- this._assert3d('createCamera');
3767
-
3768
- return this._renderer.createCamera();
3769
- };
3770
-
3771
- /**
3772
- * Sets the current (active) camera of a 3D sketch.
3773
- *
3774
- * `setCamera()` allows for switching between multiple cameras created with
3775
- * <a href="#/p5/createCamera">createCamera()</a>.
3776
- *
3777
- * Note: `setCamera()` can only be used in WebGL mode.
3778
- *
3779
- * @method setCamera
3780
- * @param {p5.Camera} cam camera that should be made active.
3781
- * @for p5
3782
- *
3783
- * @example
3784
- * <div>
3785
- * <code>
3786
- * // Double-click to toggle between cameras.
3787
- *
3788
- * let cam1;
3789
- * let cam2;
3790
- * let usingCam1 = true;
3791
- *
3792
- * function setup() {
3793
- * createCanvas(100, 100, WEBGL);
3794
- *
3795
- * // Create the first camera.
3796
- * // Keep its default settings.
3797
- * cam1 = createCamera();
3798
- *
3799
- * // Create the second camera.
3800
- * // Place it at the top-left.
3801
- * // Point it at the origin.
3802
- * cam2 = createCamera();
3803
- * cam2.setPosition(400, -400, 800);
3804
- * cam2.lookAt(0, 0, 0);
3805
- *
3806
- * // Set the current camera to cam1.
3807
- * setCamera(cam1);
3808
- *
3809
- * describe('A white cube on a gray background. The camera toggles between frontal and aerial views when the user double-clicks.');
3810
- * }
3811
- *
3812
- * function draw() {
3813
- * background(200);
3814
- *
3815
- * // Draw the box.
3816
- * box();
3817
- * }
3818
- *
3819
- * // Toggle the current camera when the user double-clicks.
3820
- * function doubleClicked() {
3821
- * if (usingCam1 === true) {
3822
- * setCamera(cam2);
3823
- * usingCam1 = false;
3824
- * } else {
3825
- * setCamera(cam1);
3826
- * usingCam1 = true;
3827
- * }
3828
- * }
3829
- * </code>
3830
- * </div>
3831
- */
3832
- fn.setCamera = function (cam) {
3833
- this._renderer.setCamera(cam);
3834
- };
3835
-
3836
- /**
3837
- * A class to describe a camera for viewing a 3D sketch.
3838
- *
3839
- * Each `p5.Camera` object represents a camera that views a section of 3D
3840
- * space. It stores information about the camera’s position, orientation, and
3841
- * projection.
3842
- *
3843
- * In WebGL mode, the default camera is a `p5.Camera` object that can be
3844
- * controlled with the <a href="#/p5/camera">camera()</a>,
3845
- * <a href="#/p5/perspective">perspective()</a>,
3846
- * <a href="#/p5/ortho">ortho()</a>, and
3847
- * <a href="#/p5/frustum">frustum()</a> functions. Additional cameras can be
3848
- * created with <a href="#/p5/createCamera">createCamera()</a> and activated
3849
- * with <a href="#/p5/setCamera">setCamera()</a>.
3850
- *
3851
- * Note: `p5.Camera`’s methods operate in two coordinate systems:
3852
- * - The “world” coordinate system describes positions in terms of their
3853
- * relationship to the origin along the x-, y-, and z-axes. For example,
3854
- * calling `myCamera.setPosition()` places the camera in 3D space using
3855
- * "world" coordinates.
3856
- * - The "local" coordinate system describes positions from the camera's point
3857
- * of view: left-right, up-down, and forward-backward. For example, calling
3858
- * `myCamera.move()` moves the camera along its own axes.
3859
- *
3860
- * @class p5.Camera
3861
- * @constructor
3862
- * @param {rendererGL} rendererGL instance of WebGL renderer
3863
- *
3864
- * @example
3865
- * <div>
3866
- * <code>
3867
- * let cam;
3868
- * let delta = 0.001;
3869
- *
3870
- * function setup() {
3871
- * createCanvas(100, 100, WEBGL);
3872
- *
3873
- * // Create a p5.Camera object.
3874
- * cam = createCamera();
3875
- *
3876
- * // Set the camera
3877
- * setCamera(cam);
3878
- *
3879
- * // Place the camera at the top-center.
3880
- * cam.setPosition(0, -400, 800);
3881
- *
3882
- * // Point the camera at the origin.
3883
- * cam.lookAt(0, 0, 0);
3884
- *
3885
- * describe(
3886
- * 'A white cube on a gray background. The cube goes in and out of view as the camera pans left and right.'
3887
- * );
3888
- * }
3889
- *
3890
- * function draw() {
3891
- * background(200);
3892
- *
3893
- * // Turn the camera left and right, called "panning".
3894
- * cam.pan(delta);
3895
- *
3896
- * // Switch directions every 120 frames.
3897
- * if (frameCount % 120 === 0) {
3898
- * delta *= -1;
3899
- * }
3900
- *
3901
- * // Draw the box.
3902
- * box();
3903
- * }
3904
- * </code>
3905
- * </div>
3906
- *
3907
- * <div>
3908
- * <code>
3909
- * // Double-click to toggle between cameras.
3910
- *
3911
- * let cam1;
3912
- * let cam2;
3913
- * let isDefaultCamera = true;
3914
- *
3915
- * function setup() {
3916
- * createCanvas(100, 100, WEBGL);
3917
- *
3918
- * // Create the first camera.
3919
- * // Keep its default settings.
3920
- * cam1 = createCamera();
3921
- *
3922
- * // Create the second camera.
3923
- * // Place it at the top-left.
3924
- * // Point it at the origin.
3925
- * cam2 = createCamera();
3926
- * cam2.setPosition(400, -400, 800);
3927
- * cam2.lookAt(0, 0, 0);
3928
- *
3929
- * // Set the current camera to cam1.
3930
- * setCamera(cam1);
3931
- *
3932
- * describe(
3933
- * 'A white cube on a gray background. The camera toggles between frontal and aerial views when the user double-clicks.'
3934
- * );
3935
- * }
3936
- *
3937
- * function draw() {
3938
- * background(200);
3939
- *
3940
- * // Draw the box.
3941
- * box();
3942
- * }
3943
- *
3944
- * // Toggle the current camera when the user double-clicks.
3945
- * function doubleClicked() {
3946
- * if (isDefaultCamera === true) {
3947
- * setCamera(cam2);
3948
- * isDefaultCamera = false;
3949
- * } else {
3950
- * setCamera(cam1);
3951
- * isDefaultCamera = true;
3952
- * }
3953
- * }
3954
- * </code>
3955
- * </div>
3956
- */
3957
- p5.Camera = Camera;
3958
-
3959
- RendererGL.prototype.camera = function(...args) {
3960
- this.states.curCamera.camera(...args);
3961
- }
3962
-
3963
- RendererGL.prototype.perspective = function(...args) {
3964
- this.states.curCamera.perspective(...args);
3965
- }
3966
-
3967
- RendererGL.prototype.linePerspective = function(enable) {
3968
- if (enable !== undefined) {
3969
- // Set the line perspective if enable is provided
3970
- this.states.curCamera.useLinePerspective = enable;
3971
- } else {
3972
- // If no argument is provided, return the current value
3973
- return this.states.curCamera.useLinePerspective;
3974
- }
3975
- }
3976
-
3977
- RendererGL.prototype.ortho = function(...args) {
3978
- this.states.curCamera.ortho(...args);
3979
- }
3980
-
3981
- RendererGL.prototype.frustum = function(...args) {
3982
- this.states.curCamera.frustum(...args);
3983
- }
3984
-
3985
- RendererGL.prototype.createCamera = function() {
3986
- // compute default camera settings, then set a default camera
3987
- const _cam = new Camera(this);
3988
- _cam._computeCameraDefaultSettings();
3989
- _cam._setDefaultCamera();
3990
-
3991
- return _cam;
3992
- }
3993
-
3994
- RendererGL.prototype.setCamera = function(cam) {
3995
- this.states.setValue('curCamera', cam);
3996
-
3997
- // set the projection matrix (which is not normally updated each frame)
3998
- this.states.setValue('uPMatrix', this.states.uPMatrix.clone());
3999
- this.states.uPMatrix.set(cam.projMatrix);
4000
- this.states.setValue('uViewMatrix', this.states.uViewMatrix.clone());
4001
- this.states.uViewMatrix.set(cam.cameraMatrix);
4002
- }
4003
- }
4004
-
4005
- export default camera;
4006
- export { Camera };
4007
-
4008
- if(typeof p5 !== 'undefined'){
4009
- camera(p5, p5.prototype);
4010
- }