7
7
*/
8
8
9
9
import * as C from './constants' ;
10
+ import { Vector } from '../math/p5.Vector' ;
10
11
11
12
function environment ( p5 , fn ) {
12
13
const standardCursors = [ C . ARROW , C . CROSS , C . HAND , C . MOVE , C . TEXT , C . WAIT ] ;
@@ -1261,10 +1262,154 @@ function environment(p5, fn){
1261
1262
}
1262
1263
return v ;
1263
1264
} ;
1265
+
1266
+ /**
1267
+ * Converts 3D world coordinates to 2D screen coordinates.
1268
+ *
1269
+ * This function takes a 3D vector and converts its coordinates
1270
+ * from the world space to screen space. This can be useful for placing
1271
+ * 2D elements in a 3D scene or for determining the screen position
1272
+ * of 3D objects.
1273
+ *
1274
+ * @method worldToScreen
1275
+ * @param {p5.Vector } worldPosition The 3D coordinates in the world space.
1276
+ * @return {p5.Vector } A vector containing the 2D screen coordinates.
1277
+ * @example
1278
+ * <div>
1279
+ * <code>
1280
+ *
1281
+ * function setup() {
1282
+ * createCanvas(150, 150);
1283
+ * let vertices = [
1284
+ * createVector(-20, -20),
1285
+ * createVector(20, -20),
1286
+ * createVector(20, 20),
1287
+ * createVector(-20, 20)
1288
+ * ];
1289
+ *
1290
+ * push();
1291
+ * translate(75, 55);
1292
+ * rotate(PI / 4);
1293
+ *
1294
+ * // Convert world coordinates to screen coordinates
1295
+ * let screenPos = vertices.map(v => worldToScreen(v));
1296
+ * pop();
1297
+ *
1298
+ * background(200);
1299
+ *
1300
+ * stroke(0);
1301
+ * fill(100, 150, 255, 100);
1302
+ * beginShape();
1303
+ * screenPos.forEach(pos => vertex(pos.x, pos.y));
1304
+ * endShape(CLOSE);
1305
+ *
1306
+ * screenPos.forEach((pos, i) => {
1307
+ * fill(0);
1308
+ * textSize(10);
1309
+ * if (i === 0) {
1310
+ * text(i + 1, pos.x + 3, pos.y - 7);
1311
+ * } else if (i === 1) {
1312
+ * text(i + 1, pos.x + 7, pos.y + 2);
1313
+ * } else if (i === 2) {
1314
+ * text(i + 1, pos.x - 2, pos.y + 12);
1315
+ * } else if (i === 3) {
1316
+ * text(i + 1, pos.x - 12, pos.y - 2);
1317
+ * }
1318
+ * });
1319
+ *
1320
+ * fill(0);
1321
+ * noStroke();
1322
+ * textSize(10);
1323
+ * let legendY = height - 35;
1324
+ * screenPos.forEach((pos, i) => {
1325
+ * text(`Vertex ${i + 1}: (${pos.x.toFixed(1)}, ${pos.y.toFixed(1)})`, 5, legendY + i * 10);
1326
+ * });
1327
+ *
1328
+ * describe('A rotating square is transformed and drawn using screen coordinates.');
1329
+ *
1330
+ * }
1331
+ * </code>
1332
+ * </div>
1333
+ *
1334
+ * @example
1335
+ * <div>
1336
+ * <code>
1337
+ * let vertices;
1338
+ *
1339
+ * function setup() {
1340
+ * createCanvas(100, 100, WEBGL);
1341
+ * vertices = [
1342
+ * createVector(-25, -25, -25),
1343
+ * createVector(25, -25, -25),
1344
+ * createVector(25, 25, -25),
1345
+ * createVector(-25, 25, -25),
1346
+ * createVector(-25, -25, 25),
1347
+ * createVector(25, -25, 25),
1348
+ * createVector(25, 25, 25),
1349
+ * createVector(-25, 25, 25)
1350
+ * ];
1351
+ *
1352
+ * describe('A rotating cube with points mapped to 2D screen space and displayed as ellipses.');
1353
+ *
1354
+ * }
1355
+ *
1356
+ * function draw() {
1357
+ * background(200);
1358
+ *
1359
+ * // Animate rotation
1360
+ * let rotationX = millis() / 1000;
1361
+ * let rotationY = millis() / 1200;
1362
+ *
1363
+ * push();
1364
+ *
1365
+ * rotateX(rotationX);
1366
+ * rotateY(rotationY);
1367
+ *
1368
+ * // Convert world coordinates to screen coordinates
1369
+ * let screenPos = vertices.map(v => worldToScreen(v));
1370
+ *
1371
+ * pop();
1372
+ *
1373
+ * screenPos.forEach((pos, i) => {
1374
+ *
1375
+ * let screenX = pos.x - width / 2;
1376
+ * let screenY = pos.y - height / 2;
1377
+ * fill(0);
1378
+ * noStroke();
1379
+ * ellipse(screenX, screenY, 3, 3);
1380
+ * });
1381
+ * }
1382
+ * </code>
1383
+ * </div>
1384
+ *
1385
+ */
1386
+ fn . worldToScreen = function ( worldPosition ) {
1387
+ const renderer = this . _renderer ;
1388
+ if ( renderer . drawingContext instanceof CanvasRenderingContext2D ) {
1389
+ // Handle 2D context
1390
+ const transformMatrix = new DOMMatrix ( )
1391
+ . scale ( 1 / renderer . _pInst . pixelDensity ( ) )
1392
+ . multiply ( renderer . drawingContext . getTransform ( ) ) ;
1393
+ const screenCoordinates = transformMatrix . transformPoint (
1394
+ new DOMPoint ( worldPosition . x , worldPosition . y )
1395
+ ) ;
1396
+ return new p5 . Vector ( screenCoordinates . x , screenCoordinates . y ) ;
1397
+ } else {
1398
+ // Handle WebGL context (3D)
1399
+ const modelViewMatrix = renderer . calculateCombinedMatrix ( ) ;
1400
+ const cameraCoordinates = modelViewMatrix . multiplyPoint ( worldPosition ) ;
1401
+ const normalizedDeviceCoordinates =
1402
+ renderer . states . uPMatrix . multiplyAndNormalizePoint ( cameraCoordinates ) ;
1403
+ const screenX = ( 0.5 + 0.5 * normalizedDeviceCoordinates . x ) * this . width ;
1404
+ const screenY = ( 0.5 - 0.5 * normalizedDeviceCoordinates . y ) * this . height ;
1405
+ const screenZ = 0.5 + 0.5 * normalizedDeviceCoordinates . z ;
1406
+ return new Vector ( screenX , screenY , screenZ ) ;
1407
+ }
1408
+ } ;
1264
1409
}
1265
1410
1266
1411
export default environment ;
1267
1412
1268
1413
if ( typeof p5 !== 'undefined' ) {
1269
1414
environment ( p5 , p5 . prototype ) ;
1270
- }
1415
+ }
0 commit comments