Game
- Create class "player"
This commit is contained in:
176
site/real_game/node_modules/three/src/extras/DataUtils.js
generated
vendored
Normal file
176
site/real_game/node_modules/three/src/extras/DataUtils.js
generated
vendored
Normal file
@ -0,0 +1,176 @@
|
||||
import { clamp } from '../math/MathUtils.js';
|
||||
|
||||
// Fast Half Float Conversions, http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf
|
||||
|
||||
const _tables = /*@__PURE__*/ _generateTables();
|
||||
|
||||
function _generateTables() {
|
||||
|
||||
// float32 to float16 helpers
|
||||
|
||||
const buffer = new ArrayBuffer( 4 );
|
||||
const floatView = new Float32Array( buffer );
|
||||
const uint32View = new Uint32Array( buffer );
|
||||
|
||||
const baseTable = new Uint32Array( 512 );
|
||||
const shiftTable = new Uint32Array( 512 );
|
||||
|
||||
for ( let i = 0; i < 256; ++ i ) {
|
||||
|
||||
const e = i - 127;
|
||||
|
||||
// very small number (0, -0)
|
||||
|
||||
if ( e < - 27 ) {
|
||||
|
||||
baseTable[ i ] = 0x0000;
|
||||
baseTable[ i | 0x100 ] = 0x8000;
|
||||
shiftTable[ i ] = 24;
|
||||
shiftTable[ i | 0x100 ] = 24;
|
||||
|
||||
// small number (denorm)
|
||||
|
||||
} else if ( e < - 14 ) {
|
||||
|
||||
baseTable[ i ] = 0x0400 >> ( - e - 14 );
|
||||
baseTable[ i | 0x100 ] = ( 0x0400 >> ( - e - 14 ) ) | 0x8000;
|
||||
shiftTable[ i ] = - e - 1;
|
||||
shiftTable[ i | 0x100 ] = - e - 1;
|
||||
|
||||
// normal number
|
||||
|
||||
} else if ( e <= 15 ) {
|
||||
|
||||
baseTable[ i ] = ( e + 15 ) << 10;
|
||||
baseTable[ i | 0x100 ] = ( ( e + 15 ) << 10 ) | 0x8000;
|
||||
shiftTable[ i ] = 13;
|
||||
shiftTable[ i | 0x100 ] = 13;
|
||||
|
||||
// large number (Infinity, -Infinity)
|
||||
|
||||
} else if ( e < 128 ) {
|
||||
|
||||
baseTable[ i ] = 0x7c00;
|
||||
baseTable[ i | 0x100 ] = 0xfc00;
|
||||
shiftTable[ i ] = 24;
|
||||
shiftTable[ i | 0x100 ] = 24;
|
||||
|
||||
// stay (NaN, Infinity, -Infinity)
|
||||
|
||||
} else {
|
||||
|
||||
baseTable[ i ] = 0x7c00;
|
||||
baseTable[ i | 0x100 ] = 0xfc00;
|
||||
shiftTable[ i ] = 13;
|
||||
shiftTable[ i | 0x100 ] = 13;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// float16 to float32 helpers
|
||||
|
||||
const mantissaTable = new Uint32Array( 2048 );
|
||||
const exponentTable = new Uint32Array( 64 );
|
||||
const offsetTable = new Uint32Array( 64 );
|
||||
|
||||
for ( let i = 1; i < 1024; ++ i ) {
|
||||
|
||||
let m = i << 13; // zero pad mantissa bits
|
||||
let e = 0; // zero exponent
|
||||
|
||||
// normalized
|
||||
while ( ( m & 0x00800000 ) === 0 ) {
|
||||
|
||||
m <<= 1;
|
||||
e -= 0x00800000; // decrement exponent
|
||||
|
||||
}
|
||||
|
||||
m &= ~ 0x00800000; // clear leading 1 bit
|
||||
e += 0x38800000; // adjust bias
|
||||
|
||||
mantissaTable[ i ] = m | e;
|
||||
|
||||
}
|
||||
|
||||
for ( let i = 1024; i < 2048; ++ i ) {
|
||||
|
||||
mantissaTable[ i ] = 0x38000000 + ( ( i - 1024 ) << 13 );
|
||||
|
||||
}
|
||||
|
||||
for ( let i = 1; i < 31; ++ i ) {
|
||||
|
||||
exponentTable[ i ] = i << 23;
|
||||
|
||||
}
|
||||
|
||||
exponentTable[ 31 ] = 0x47800000;
|
||||
exponentTable[ 32 ] = 0x80000000;
|
||||
|
||||
for ( let i = 33; i < 63; ++ i ) {
|
||||
|
||||
exponentTable[ i ] = 0x80000000 + ( ( i - 32 ) << 23 );
|
||||
|
||||
}
|
||||
|
||||
exponentTable[ 63 ] = 0xc7800000;
|
||||
|
||||
for ( let i = 1; i < 64; ++ i ) {
|
||||
|
||||
if ( i !== 32 ) {
|
||||
|
||||
offsetTable[ i ] = 1024;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
floatView: floatView,
|
||||
uint32View: uint32View,
|
||||
baseTable: baseTable,
|
||||
shiftTable: shiftTable,
|
||||
mantissaTable: mantissaTable,
|
||||
exponentTable: exponentTable,
|
||||
offsetTable: offsetTable
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// float32 to float16
|
||||
|
||||
function toHalfFloat( val ) {
|
||||
|
||||
if ( Math.abs( val ) > 65504 ) console.warn( 'THREE.DataUtils.toHalfFloat(): Value out of range.' );
|
||||
|
||||
val = clamp( val, - 65504, 65504 );
|
||||
|
||||
_tables.floatView[ 0 ] = val;
|
||||
const f = _tables.uint32View[ 0 ];
|
||||
const e = ( f >> 23 ) & 0x1ff;
|
||||
return _tables.baseTable[ e ] + ( ( f & 0x007fffff ) >> _tables.shiftTable[ e ] );
|
||||
|
||||
}
|
||||
|
||||
// float16 to float32
|
||||
|
||||
function fromHalfFloat( val ) {
|
||||
|
||||
const m = val >> 10;
|
||||
_tables.uint32View[ 0 ] = _tables.mantissaTable[ _tables.offsetTable[ m ] + ( val & 0x3ff ) ] + _tables.exponentTable[ m ];
|
||||
return _tables.floatView[ 0 ];
|
||||
|
||||
}
|
||||
|
||||
const DataUtils = {
|
||||
toHalfFloat: toHalfFloat,
|
||||
fromHalfFloat: fromHalfFloat,
|
||||
};
|
||||
|
||||
export {
|
||||
toHalfFloat,
|
||||
fromHalfFloat,
|
||||
DataUtils
|
||||
};
|
789
site/real_game/node_modules/three/src/extras/Earcut.js
generated
vendored
Normal file
789
site/real_game/node_modules/three/src/extras/Earcut.js
generated
vendored
Normal file
@ -0,0 +1,789 @@
|
||||
/**
|
||||
* Port from https://github.com/mapbox/earcut (v2.2.4)
|
||||
*/
|
||||
|
||||
const Earcut = {
|
||||
|
||||
triangulate: function ( data, holeIndices, dim = 2 ) {
|
||||
|
||||
const hasHoles = holeIndices && holeIndices.length;
|
||||
const outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length;
|
||||
let outerNode = linkedList( data, 0, outerLen, dim, true );
|
||||
const triangles = [];
|
||||
|
||||
if ( ! outerNode || outerNode.next === outerNode.prev ) return triangles;
|
||||
|
||||
let minX, minY, maxX, maxY, x, y, invSize;
|
||||
|
||||
if ( hasHoles ) outerNode = eliminateHoles( data, holeIndices, outerNode, dim );
|
||||
|
||||
// if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
|
||||
if ( data.length > 80 * dim ) {
|
||||
|
||||
minX = maxX = data[ 0 ];
|
||||
minY = maxY = data[ 1 ];
|
||||
|
||||
for ( let i = dim; i < outerLen; i += dim ) {
|
||||
|
||||
x = data[ i ];
|
||||
y = data[ i + 1 ];
|
||||
if ( x < minX ) minX = x;
|
||||
if ( y < minY ) minY = y;
|
||||
if ( x > maxX ) maxX = x;
|
||||
if ( y > maxY ) maxY = y;
|
||||
|
||||
}
|
||||
|
||||
// minX, minY and invSize are later used to transform coords into integers for z-order calculation
|
||||
invSize = Math.max( maxX - minX, maxY - minY );
|
||||
invSize = invSize !== 0 ? 32767 / invSize : 0;
|
||||
|
||||
}
|
||||
|
||||
earcutLinked( outerNode, triangles, dim, minX, minY, invSize, 0 );
|
||||
|
||||
return triangles;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// create a circular doubly linked list from polygon points in the specified winding order
|
||||
function linkedList( data, start, end, dim, clockwise ) {
|
||||
|
||||
let i, last;
|
||||
|
||||
if ( clockwise === ( signedArea( data, start, end, dim ) > 0 ) ) {
|
||||
|
||||
for ( i = start; i < end; i += dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last );
|
||||
|
||||
} else {
|
||||
|
||||
for ( i = end - dim; i >= start; i -= dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last );
|
||||
|
||||
}
|
||||
|
||||
if ( last && equals( last, last.next ) ) {
|
||||
|
||||
removeNode( last );
|
||||
last = last.next;
|
||||
|
||||
}
|
||||
|
||||
return last;
|
||||
|
||||
}
|
||||
|
||||
// eliminate colinear or duplicate points
|
||||
function filterPoints( start, end ) {
|
||||
|
||||
if ( ! start ) return start;
|
||||
if ( ! end ) end = start;
|
||||
|
||||
let p = start,
|
||||
again;
|
||||
do {
|
||||
|
||||
again = false;
|
||||
|
||||
if ( ! p.steiner && ( equals( p, p.next ) || area( p.prev, p, p.next ) === 0 ) ) {
|
||||
|
||||
removeNode( p );
|
||||
p = end = p.prev;
|
||||
if ( p === p.next ) break;
|
||||
again = true;
|
||||
|
||||
} else {
|
||||
|
||||
p = p.next;
|
||||
|
||||
}
|
||||
|
||||
} while ( again || p !== end );
|
||||
|
||||
return end;
|
||||
|
||||
}
|
||||
|
||||
// main ear slicing loop which triangulates a polygon (given as a linked list)
|
||||
function earcutLinked( ear, triangles, dim, minX, minY, invSize, pass ) {
|
||||
|
||||
if ( ! ear ) return;
|
||||
|
||||
// interlink polygon nodes in z-order
|
||||
if ( ! pass && invSize ) indexCurve( ear, minX, minY, invSize );
|
||||
|
||||
let stop = ear,
|
||||
prev, next;
|
||||
|
||||
// iterate through ears, slicing them one by one
|
||||
while ( ear.prev !== ear.next ) {
|
||||
|
||||
prev = ear.prev;
|
||||
next = ear.next;
|
||||
|
||||
if ( invSize ? isEarHashed( ear, minX, minY, invSize ) : isEar( ear ) ) {
|
||||
|
||||
// cut off the triangle
|
||||
triangles.push( prev.i / dim | 0 );
|
||||
triangles.push( ear.i / dim | 0 );
|
||||
triangles.push( next.i / dim | 0 );
|
||||
|
||||
removeNode( ear );
|
||||
|
||||
// skipping the next vertex leads to less sliver triangles
|
||||
ear = next.next;
|
||||
stop = next.next;
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
ear = next;
|
||||
|
||||
// if we looped through the whole remaining polygon and can't find any more ears
|
||||
if ( ear === stop ) {
|
||||
|
||||
// try filtering points and slicing again
|
||||
if ( ! pass ) {
|
||||
|
||||
earcutLinked( filterPoints( ear ), triangles, dim, minX, minY, invSize, 1 );
|
||||
|
||||
// if this didn't work, try curing all small self-intersections locally
|
||||
|
||||
} else if ( pass === 1 ) {
|
||||
|
||||
ear = cureLocalIntersections( filterPoints( ear ), triangles, dim );
|
||||
earcutLinked( ear, triangles, dim, minX, minY, invSize, 2 );
|
||||
|
||||
// as a last resort, try splitting the remaining polygon into two
|
||||
|
||||
} else if ( pass === 2 ) {
|
||||
|
||||
splitEarcut( ear, triangles, dim, minX, minY, invSize );
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// check whether a polygon node forms a valid ear with adjacent nodes
|
||||
function isEar( ear ) {
|
||||
|
||||
const a = ear.prev,
|
||||
b = ear,
|
||||
c = ear.next;
|
||||
|
||||
if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear
|
||||
|
||||
// now make sure we don't have other points inside the potential ear
|
||||
const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;
|
||||
|
||||
// triangle bbox; min & max are calculated like this for speed
|
||||
const x0 = ax < bx ? ( ax < cx ? ax : cx ) : ( bx < cx ? bx : cx ),
|
||||
y0 = ay < by ? ( ay < cy ? ay : cy ) : ( by < cy ? by : cy ),
|
||||
x1 = ax > bx ? ( ax > cx ? ax : cx ) : ( bx > cx ? bx : cx ),
|
||||
y1 = ay > by ? ( ay > cy ? ay : cy ) : ( by > cy ? by : cy );
|
||||
|
||||
let p = c.next;
|
||||
while ( p !== a ) {
|
||||
|
||||
if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 &&
|
||||
pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) &&
|
||||
area( p.prev, p, p.next ) >= 0 ) return false;
|
||||
p = p.next;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
function isEarHashed( ear, minX, minY, invSize ) {
|
||||
|
||||
const a = ear.prev,
|
||||
b = ear,
|
||||
c = ear.next;
|
||||
|
||||
if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear
|
||||
|
||||
const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;
|
||||
|
||||
// triangle bbox; min & max are calculated like this for speed
|
||||
const x0 = ax < bx ? ( ax < cx ? ax : cx ) : ( bx < cx ? bx : cx ),
|
||||
y0 = ay < by ? ( ay < cy ? ay : cy ) : ( by < cy ? by : cy ),
|
||||
x1 = ax > bx ? ( ax > cx ? ax : cx ) : ( bx > cx ? bx : cx ),
|
||||
y1 = ay > by ? ( ay > cy ? ay : cy ) : ( by > cy ? by : cy );
|
||||
|
||||
// z-order range for the current triangle bbox;
|
||||
const minZ = zOrder( x0, y0, minX, minY, invSize ),
|
||||
maxZ = zOrder( x1, y1, minX, minY, invSize );
|
||||
|
||||
let p = ear.prevZ,
|
||||
n = ear.nextZ;
|
||||
|
||||
// look for points inside the triangle in both directions
|
||||
while ( p && p.z >= minZ && n && n.z <= maxZ ) {
|
||||
|
||||
if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&
|
||||
pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && area( p.prev, p, p.next ) >= 0 ) return false;
|
||||
p = p.prevZ;
|
||||
|
||||
if ( n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&
|
||||
pointInTriangle( ax, ay, bx, by, cx, cy, n.x, n.y ) && area( n.prev, n, n.next ) >= 0 ) return false;
|
||||
n = n.nextZ;
|
||||
|
||||
}
|
||||
|
||||
// look for remaining points in decreasing z-order
|
||||
while ( p && p.z >= minZ ) {
|
||||
|
||||
if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&
|
||||
pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && area( p.prev, p, p.next ) >= 0 ) return false;
|
||||
p = p.prevZ;
|
||||
|
||||
}
|
||||
|
||||
// look for remaining points in increasing z-order
|
||||
while ( n && n.z <= maxZ ) {
|
||||
|
||||
if ( n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&
|
||||
pointInTriangle( ax, ay, bx, by, cx, cy, n.x, n.y ) && area( n.prev, n, n.next ) >= 0 ) return false;
|
||||
n = n.nextZ;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// go through all polygon nodes and cure small local self-intersections
|
||||
function cureLocalIntersections( start, triangles, dim ) {
|
||||
|
||||
let p = start;
|
||||
do {
|
||||
|
||||
const a = p.prev,
|
||||
b = p.next.next;
|
||||
|
||||
if ( ! equals( a, b ) && intersects( a, p, p.next, b ) && locallyInside( a, b ) && locallyInside( b, a ) ) {
|
||||
|
||||
triangles.push( a.i / dim | 0 );
|
||||
triangles.push( p.i / dim | 0 );
|
||||
triangles.push( b.i / dim | 0 );
|
||||
|
||||
// remove two nodes involved
|
||||
removeNode( p );
|
||||
removeNode( p.next );
|
||||
|
||||
p = start = b;
|
||||
|
||||
}
|
||||
|
||||
p = p.next;
|
||||
|
||||
} while ( p !== start );
|
||||
|
||||
return filterPoints( p );
|
||||
|
||||
}
|
||||
|
||||
// try splitting polygon into two and triangulate them independently
|
||||
function splitEarcut( start, triangles, dim, minX, minY, invSize ) {
|
||||
|
||||
// look for a valid diagonal that divides the polygon into two
|
||||
let a = start;
|
||||
do {
|
||||
|
||||
let b = a.next.next;
|
||||
while ( b !== a.prev ) {
|
||||
|
||||
if ( a.i !== b.i && isValidDiagonal( a, b ) ) {
|
||||
|
||||
// split the polygon in two by the diagonal
|
||||
let c = splitPolygon( a, b );
|
||||
|
||||
// filter colinear points around the cuts
|
||||
a = filterPoints( a, a.next );
|
||||
c = filterPoints( c, c.next );
|
||||
|
||||
// run earcut on each half
|
||||
earcutLinked( a, triangles, dim, minX, minY, invSize, 0 );
|
||||
earcutLinked( c, triangles, dim, minX, minY, invSize, 0 );
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
b = b.next;
|
||||
|
||||
}
|
||||
|
||||
a = a.next;
|
||||
|
||||
} while ( a !== start );
|
||||
|
||||
}
|
||||
|
||||
// link every hole into the outer loop, producing a single-ring polygon without holes
|
||||
function eliminateHoles( data, holeIndices, outerNode, dim ) {
|
||||
|
||||
const queue = [];
|
||||
let i, len, start, end, list;
|
||||
|
||||
for ( i = 0, len = holeIndices.length; i < len; i ++ ) {
|
||||
|
||||
start = holeIndices[ i ] * dim;
|
||||
end = i < len - 1 ? holeIndices[ i + 1 ] * dim : data.length;
|
||||
list = linkedList( data, start, end, dim, false );
|
||||
if ( list === list.next ) list.steiner = true;
|
||||
queue.push( getLeftmost( list ) );
|
||||
|
||||
}
|
||||
|
||||
queue.sort( compareX );
|
||||
|
||||
// process holes from left to right
|
||||
for ( i = 0; i < queue.length; i ++ ) {
|
||||
|
||||
outerNode = eliminateHole( queue[ i ], outerNode );
|
||||
|
||||
}
|
||||
|
||||
return outerNode;
|
||||
|
||||
}
|
||||
|
||||
function compareX( a, b ) {
|
||||
|
||||
return a.x - b.x;
|
||||
|
||||
}
|
||||
|
||||
// find a bridge between vertices that connects hole with an outer ring and link it
|
||||
function eliminateHole( hole, outerNode ) {
|
||||
|
||||
const bridge = findHoleBridge( hole, outerNode );
|
||||
if ( ! bridge ) {
|
||||
|
||||
return outerNode;
|
||||
|
||||
}
|
||||
|
||||
const bridgeReverse = splitPolygon( bridge, hole );
|
||||
|
||||
// filter collinear points around the cuts
|
||||
filterPoints( bridgeReverse, bridgeReverse.next );
|
||||
return filterPoints( bridge, bridge.next );
|
||||
|
||||
}
|
||||
|
||||
// David Eberly's algorithm for finding a bridge between hole and outer polygon
|
||||
function findHoleBridge( hole, outerNode ) {
|
||||
|
||||
let p = outerNode,
|
||||
qx = - Infinity,
|
||||
m;
|
||||
|
||||
const hx = hole.x, hy = hole.y;
|
||||
|
||||
// find a segment intersected by a ray from the hole's leftmost point to the left;
|
||||
// segment's endpoint with lesser x will be potential connection point
|
||||
do {
|
||||
|
||||
if ( hy <= p.y && hy >= p.next.y && p.next.y !== p.y ) {
|
||||
|
||||
const x = p.x + ( hy - p.y ) * ( p.next.x - p.x ) / ( p.next.y - p.y );
|
||||
if ( x <= hx && x > qx ) {
|
||||
|
||||
qx = x;
|
||||
m = p.x < p.next.x ? p : p.next;
|
||||
if ( x === hx ) return m; // hole touches outer segment; pick leftmost endpoint
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
p = p.next;
|
||||
|
||||
} while ( p !== outerNode );
|
||||
|
||||
if ( ! m ) return null;
|
||||
|
||||
// look for points inside the triangle of hole point, segment intersection and endpoint;
|
||||
// if there are no points found, we have a valid connection;
|
||||
// otherwise choose the point of the minimum angle with the ray as connection point
|
||||
|
||||
const stop = m,
|
||||
mx = m.x,
|
||||
my = m.y;
|
||||
let tanMin = Infinity, tan;
|
||||
|
||||
p = m;
|
||||
|
||||
do {
|
||||
|
||||
if ( hx >= p.x && p.x >= mx && hx !== p.x &&
|
||||
pointInTriangle( hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y ) ) {
|
||||
|
||||
tan = Math.abs( hy - p.y ) / ( hx - p.x ); // tangential
|
||||
|
||||
if ( locallyInside( p, hole ) && ( tan < tanMin || ( tan === tanMin && ( p.x > m.x || ( p.x === m.x && sectorContainsSector( m, p ) ) ) ) ) ) {
|
||||
|
||||
m = p;
|
||||
tanMin = tan;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
p = p.next;
|
||||
|
||||
} while ( p !== stop );
|
||||
|
||||
return m;
|
||||
|
||||
}
|
||||
|
||||
// whether sector in vertex m contains sector in vertex p in the same coordinates
|
||||
function sectorContainsSector( m, p ) {
|
||||
|
||||
return area( m.prev, m, p.prev ) < 0 && area( p.next, m, m.next ) < 0;
|
||||
|
||||
}
|
||||
|
||||
// interlink polygon nodes in z-order
|
||||
function indexCurve( start, minX, minY, invSize ) {
|
||||
|
||||
let p = start;
|
||||
do {
|
||||
|
||||
if ( p.z === 0 ) p.z = zOrder( p.x, p.y, minX, minY, invSize );
|
||||
p.prevZ = p.prev;
|
||||
p.nextZ = p.next;
|
||||
p = p.next;
|
||||
|
||||
} while ( p !== start );
|
||||
|
||||
p.prevZ.nextZ = null;
|
||||
p.prevZ = null;
|
||||
|
||||
sortLinked( p );
|
||||
|
||||
}
|
||||
|
||||
// Simon Tatham's linked list merge sort algorithm
|
||||
// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
|
||||
function sortLinked( list ) {
|
||||
|
||||
let i, p, q, e, tail, numMerges, pSize, qSize,
|
||||
inSize = 1;
|
||||
|
||||
do {
|
||||
|
||||
p = list;
|
||||
list = null;
|
||||
tail = null;
|
||||
numMerges = 0;
|
||||
|
||||
while ( p ) {
|
||||
|
||||
numMerges ++;
|
||||
q = p;
|
||||
pSize = 0;
|
||||
for ( i = 0; i < inSize; i ++ ) {
|
||||
|
||||
pSize ++;
|
||||
q = q.nextZ;
|
||||
if ( ! q ) break;
|
||||
|
||||
}
|
||||
|
||||
qSize = inSize;
|
||||
|
||||
while ( pSize > 0 || ( qSize > 0 && q ) ) {
|
||||
|
||||
if ( pSize !== 0 && ( qSize === 0 || ! q || p.z <= q.z ) ) {
|
||||
|
||||
e = p;
|
||||
p = p.nextZ;
|
||||
pSize --;
|
||||
|
||||
} else {
|
||||
|
||||
e = q;
|
||||
q = q.nextZ;
|
||||
qSize --;
|
||||
|
||||
}
|
||||
|
||||
if ( tail ) tail.nextZ = e;
|
||||
else list = e;
|
||||
|
||||
e.prevZ = tail;
|
||||
tail = e;
|
||||
|
||||
}
|
||||
|
||||
p = q;
|
||||
|
||||
}
|
||||
|
||||
tail.nextZ = null;
|
||||
inSize *= 2;
|
||||
|
||||
} while ( numMerges > 1 );
|
||||
|
||||
return list;
|
||||
|
||||
}
|
||||
|
||||
// z-order of a point given coords and inverse of the longer side of data bbox
|
||||
function zOrder( x, y, minX, minY, invSize ) {
|
||||
|
||||
// coords are transformed into non-negative 15-bit integer range
|
||||
x = ( x - minX ) * invSize | 0;
|
||||
y = ( y - minY ) * invSize | 0;
|
||||
|
||||
x = ( x | ( x << 8 ) ) & 0x00FF00FF;
|
||||
x = ( x | ( x << 4 ) ) & 0x0F0F0F0F;
|
||||
x = ( x | ( x << 2 ) ) & 0x33333333;
|
||||
x = ( x | ( x << 1 ) ) & 0x55555555;
|
||||
|
||||
y = ( y | ( y << 8 ) ) & 0x00FF00FF;
|
||||
y = ( y | ( y << 4 ) ) & 0x0F0F0F0F;
|
||||
y = ( y | ( y << 2 ) ) & 0x33333333;
|
||||
y = ( y | ( y << 1 ) ) & 0x55555555;
|
||||
|
||||
return x | ( y << 1 );
|
||||
|
||||
}
|
||||
|
||||
// find the leftmost node of a polygon ring
|
||||
function getLeftmost( start ) {
|
||||
|
||||
let p = start,
|
||||
leftmost = start;
|
||||
do {
|
||||
|
||||
if ( p.x < leftmost.x || ( p.x === leftmost.x && p.y < leftmost.y ) ) leftmost = p;
|
||||
p = p.next;
|
||||
|
||||
} while ( p !== start );
|
||||
|
||||
return leftmost;
|
||||
|
||||
}
|
||||
|
||||
// check if a point lies within a convex triangle
|
||||
function pointInTriangle( ax, ay, bx, by, cx, cy, px, py ) {
|
||||
|
||||
return ( cx - px ) * ( ay - py ) >= ( ax - px ) * ( cy - py ) &&
|
||||
( ax - px ) * ( by - py ) >= ( bx - px ) * ( ay - py ) &&
|
||||
( bx - px ) * ( cy - py ) >= ( cx - px ) * ( by - py );
|
||||
|
||||
}
|
||||
|
||||
// check if a diagonal between two polygon nodes is valid (lies in polygon interior)
|
||||
function isValidDiagonal( a, b ) {
|
||||
|
||||
return a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) && // dones't intersect other edges
|
||||
( locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b ) && // locally visible
|
||||
( area( a.prev, a, b.prev ) || area( a, b.prev, b ) ) || // does not create opposite-facing sectors
|
||||
equals( a, b ) && area( a.prev, a, a.next ) > 0 && area( b.prev, b, b.next ) > 0 ); // special zero-length case
|
||||
|
||||
}
|
||||
|
||||
// signed area of a triangle
|
||||
function area( p, q, r ) {
|
||||
|
||||
return ( q.y - p.y ) * ( r.x - q.x ) - ( q.x - p.x ) * ( r.y - q.y );
|
||||
|
||||
}
|
||||
|
||||
// check if two points are equal
|
||||
function equals( p1, p2 ) {
|
||||
|
||||
return p1.x === p2.x && p1.y === p2.y;
|
||||
|
||||
}
|
||||
|
||||
// check if two segments intersect
|
||||
function intersects( p1, q1, p2, q2 ) {
|
||||
|
||||
const o1 = sign( area( p1, q1, p2 ) );
|
||||
const o2 = sign( area( p1, q1, q2 ) );
|
||||
const o3 = sign( area( p2, q2, p1 ) );
|
||||
const o4 = sign( area( p2, q2, q1 ) );
|
||||
|
||||
if ( o1 !== o2 && o3 !== o4 ) return true; // general case
|
||||
|
||||
if ( o1 === 0 && onSegment( p1, p2, q1 ) ) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1
|
||||
if ( o2 === 0 && onSegment( p1, q2, q1 ) ) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1
|
||||
if ( o3 === 0 && onSegment( p2, p1, q2 ) ) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2
|
||||
if ( o4 === 0 && onSegment( p2, q1, q2 ) ) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// for collinear points p, q, r, check if point q lies on segment pr
|
||||
function onSegment( p, q, r ) {
|
||||
|
||||
return q.x <= Math.max( p.x, r.x ) && q.x >= Math.min( p.x, r.x ) && q.y <= Math.max( p.y, r.y ) && q.y >= Math.min( p.y, r.y );
|
||||
|
||||
}
|
||||
|
||||
function sign( num ) {
|
||||
|
||||
return num > 0 ? 1 : num < 0 ? - 1 : 0;
|
||||
|
||||
}
|
||||
|
||||
// check if a polygon diagonal intersects any polygon segments
|
||||
function intersectsPolygon( a, b ) {
|
||||
|
||||
let p = a;
|
||||
do {
|
||||
|
||||
if ( p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&
|
||||
intersects( p, p.next, a, b ) ) return true;
|
||||
p = p.next;
|
||||
|
||||
} while ( p !== a );
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// check if a polygon diagonal is locally inside the polygon
|
||||
function locallyInside( a, b ) {
|
||||
|
||||
return area( a.prev, a, a.next ) < 0 ?
|
||||
area( a, b, a.next ) >= 0 && area( a, a.prev, b ) >= 0 :
|
||||
area( a, b, a.prev ) < 0 || area( a, a.next, b ) < 0;
|
||||
|
||||
}
|
||||
|
||||
// check if the middle point of a polygon diagonal is inside the polygon
|
||||
function middleInside( a, b ) {
|
||||
|
||||
let p = a,
|
||||
inside = false;
|
||||
const px = ( a.x + b.x ) / 2,
|
||||
py = ( a.y + b.y ) / 2;
|
||||
do {
|
||||
|
||||
if ( ( ( p.y > py ) !== ( p.next.y > py ) ) && p.next.y !== p.y &&
|
||||
( px < ( p.next.x - p.x ) * ( py - p.y ) / ( p.next.y - p.y ) + p.x ) )
|
||||
inside = ! inside;
|
||||
p = p.next;
|
||||
|
||||
} while ( p !== a );
|
||||
|
||||
return inside;
|
||||
|
||||
}
|
||||
|
||||
// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
|
||||
// if one belongs to the outer ring and another to a hole, it merges it into a single ring
|
||||
function splitPolygon( a, b ) {
|
||||
|
||||
const a2 = new Node( a.i, a.x, a.y ),
|
||||
b2 = new Node( b.i, b.x, b.y ),
|
||||
an = a.next,
|
||||
bp = b.prev;
|
||||
|
||||
a.next = b;
|
||||
b.prev = a;
|
||||
|
||||
a2.next = an;
|
||||
an.prev = a2;
|
||||
|
||||
b2.next = a2;
|
||||
a2.prev = b2;
|
||||
|
||||
bp.next = b2;
|
||||
b2.prev = bp;
|
||||
|
||||
return b2;
|
||||
|
||||
}
|
||||
|
||||
// create a node and optionally link it with previous one (in a circular doubly linked list)
|
||||
function insertNode( i, x, y, last ) {
|
||||
|
||||
const p = new Node( i, x, y );
|
||||
|
||||
if ( ! last ) {
|
||||
|
||||
p.prev = p;
|
||||
p.next = p;
|
||||
|
||||
} else {
|
||||
|
||||
p.next = last.next;
|
||||
p.prev = last;
|
||||
last.next.prev = p;
|
||||
last.next = p;
|
||||
|
||||
}
|
||||
|
||||
return p;
|
||||
|
||||
}
|
||||
|
||||
function removeNode( p ) {
|
||||
|
||||
p.next.prev = p.prev;
|
||||
p.prev.next = p.next;
|
||||
|
||||
if ( p.prevZ ) p.prevZ.nextZ = p.nextZ;
|
||||
if ( p.nextZ ) p.nextZ.prevZ = p.prevZ;
|
||||
|
||||
}
|
||||
|
||||
function Node( i, x, y ) {
|
||||
|
||||
// vertex index in coordinates array
|
||||
this.i = i;
|
||||
|
||||
// vertex coordinates
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
// previous and next vertex nodes in a polygon ring
|
||||
this.prev = null;
|
||||
this.next = null;
|
||||
|
||||
// z-order curve value
|
||||
this.z = 0;
|
||||
|
||||
// previous and next nodes in z-order
|
||||
this.prevZ = null;
|
||||
this.nextZ = null;
|
||||
|
||||
// indicates whether this is a steiner point
|
||||
this.steiner = false;
|
||||
|
||||
}
|
||||
|
||||
function signedArea( data, start, end, dim ) {
|
||||
|
||||
let sum = 0;
|
||||
for ( let i = start, j = end - dim; i < end; i += dim ) {
|
||||
|
||||
sum += ( data[ j ] - data[ i ] ) * ( data[ i + 1 ] + data[ j + 1 ] );
|
||||
j = i;
|
||||
|
||||
}
|
||||
|
||||
return sum;
|
||||
|
||||
}
|
||||
|
||||
export { Earcut };
|
129
site/real_game/node_modules/three/src/extras/ImageUtils.js
generated
vendored
Normal file
129
site/real_game/node_modules/three/src/extras/ImageUtils.js
generated
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
import { createElementNS } from '../utils.js';
|
||||
import { SRGBToLinear } from '../math/ColorManagement.js';
|
||||
|
||||
let _canvas;
|
||||
|
||||
class ImageUtils {
|
||||
|
||||
static getDataURL( image ) {
|
||||
|
||||
if ( /^data:/i.test( image.src ) ) {
|
||||
|
||||
return image.src;
|
||||
|
||||
}
|
||||
|
||||
if ( typeof HTMLCanvasElement === 'undefined' ) {
|
||||
|
||||
return image.src;
|
||||
|
||||
}
|
||||
|
||||
let canvas;
|
||||
|
||||
if ( image instanceof HTMLCanvasElement ) {
|
||||
|
||||
canvas = image;
|
||||
|
||||
} else {
|
||||
|
||||
if ( _canvas === undefined ) _canvas = createElementNS( 'canvas' );
|
||||
|
||||
_canvas.width = image.width;
|
||||
_canvas.height = image.height;
|
||||
|
||||
const context = _canvas.getContext( '2d' );
|
||||
|
||||
if ( image instanceof ImageData ) {
|
||||
|
||||
context.putImageData( image, 0, 0 );
|
||||
|
||||
} else {
|
||||
|
||||
context.drawImage( image, 0, 0, image.width, image.height );
|
||||
|
||||
}
|
||||
|
||||
canvas = _canvas;
|
||||
|
||||
}
|
||||
|
||||
if ( canvas.width > 2048 || canvas.height > 2048 ) {
|
||||
|
||||
console.warn( 'THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons', image );
|
||||
|
||||
return canvas.toDataURL( 'image/jpeg', 0.6 );
|
||||
|
||||
} else {
|
||||
|
||||
return canvas.toDataURL( 'image/png' );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static sRGBToLinear( image ) {
|
||||
|
||||
if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
|
||||
( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||
|
||||
( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {
|
||||
|
||||
const canvas = createElementNS( 'canvas' );
|
||||
|
||||
canvas.width = image.width;
|
||||
canvas.height = image.height;
|
||||
|
||||
const context = canvas.getContext( '2d' );
|
||||
context.drawImage( image, 0, 0, image.width, image.height );
|
||||
|
||||
const imageData = context.getImageData( 0, 0, image.width, image.height );
|
||||
const data = imageData.data;
|
||||
|
||||
for ( let i = 0; i < data.length; i ++ ) {
|
||||
|
||||
data[ i ] = SRGBToLinear( data[ i ] / 255 ) * 255;
|
||||
|
||||
}
|
||||
|
||||
context.putImageData( imageData, 0, 0 );
|
||||
|
||||
return canvas;
|
||||
|
||||
} else if ( image.data ) {
|
||||
|
||||
const data = image.data.slice( 0 );
|
||||
|
||||
for ( let i = 0; i < data.length; i ++ ) {
|
||||
|
||||
if ( data instanceof Uint8Array || data instanceof Uint8ClampedArray ) {
|
||||
|
||||
data[ i ] = Math.floor( SRGBToLinear( data[ i ] / 255 ) * 255 );
|
||||
|
||||
} else {
|
||||
|
||||
// assuming float
|
||||
|
||||
data[ i ] = SRGBToLinear( data[ i ] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
data: data,
|
||||
width: image.width,
|
||||
height: image.height
|
||||
};
|
||||
|
||||
} else {
|
||||
|
||||
console.warn( 'THREE.ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied.' );
|
||||
return image;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { ImageUtils };
|
918
site/real_game/node_modules/three/src/extras/PMREMGenerator.js
generated
vendored
Normal file
918
site/real_game/node_modules/three/src/extras/PMREMGenerator.js
generated
vendored
Normal file
@ -0,0 +1,918 @@
|
||||
import {
|
||||
CubeReflectionMapping,
|
||||
CubeRefractionMapping,
|
||||
CubeUVReflectionMapping,
|
||||
LinearFilter,
|
||||
NoToneMapping,
|
||||
NoBlending,
|
||||
RGBAFormat,
|
||||
HalfFloatType,
|
||||
BackSide,
|
||||
LinearSRGBColorSpace
|
||||
} from '../constants.js';
|
||||
|
||||
import { BufferAttribute } from '../core/BufferAttribute.js';
|
||||
import { BufferGeometry } from '../core/BufferGeometry.js';
|
||||
import { Mesh } from '../objects/Mesh.js';
|
||||
import { OrthographicCamera } from '../cameras/OrthographicCamera.js';
|
||||
import { PerspectiveCamera } from '../cameras/PerspectiveCamera.js';
|
||||
import { ShaderMaterial } from '../materials/ShaderMaterial.js';
|
||||
import { Vector3 } from '../math/Vector3.js';
|
||||
import { Color } from '../math/Color.js';
|
||||
import { WebGLRenderTarget } from '../renderers/WebGLRenderTarget.js';
|
||||
import { MeshBasicMaterial } from '../materials/MeshBasicMaterial.js';
|
||||
import { BoxGeometry } from '../geometries/BoxGeometry.js';
|
||||
|
||||
const LOD_MIN = 4;
|
||||
|
||||
// The standard deviations (radians) associated with the extra mips. These are
|
||||
// chosen to approximate a Trowbridge-Reitz distribution function times the
|
||||
// geometric shadowing function. These sigma values squared must match the
|
||||
// variance #defines in cube_uv_reflection_fragment.glsl.js.
|
||||
const EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ];
|
||||
|
||||
// The maximum length of the blur for loop. Smaller sigmas will use fewer
|
||||
// samples and exit early, but not recompile the shader.
|
||||
const MAX_SAMPLES = 20;
|
||||
|
||||
const _flatCamera = /*@__PURE__*/ new OrthographicCamera();
|
||||
const _clearColor = /*@__PURE__*/ new Color();
|
||||
let _oldTarget = null;
|
||||
let _oldActiveCubeFace = 0;
|
||||
let _oldActiveMipmapLevel = 0;
|
||||
let _oldXrEnabled = false;
|
||||
|
||||
// Golden Ratio
|
||||
const PHI = ( 1 + Math.sqrt( 5 ) ) / 2;
|
||||
const INV_PHI = 1 / PHI;
|
||||
|
||||
// Vertices of a dodecahedron (except the opposites, which represent the
|
||||
// same axis), used as axis directions evenly spread on a sphere.
|
||||
const _axisDirections = [
|
||||
/*@__PURE__*/ new Vector3( - PHI, INV_PHI, 0 ),
|
||||
/*@__PURE__*/ new Vector3( PHI, INV_PHI, 0 ),
|
||||
/*@__PURE__*/ new Vector3( - INV_PHI, 0, PHI ),
|
||||
/*@__PURE__*/ new Vector3( INV_PHI, 0, PHI ),
|
||||
/*@__PURE__*/ new Vector3( 0, PHI, - INV_PHI ),
|
||||
/*@__PURE__*/ new Vector3( 0, PHI, INV_PHI ),
|
||||
/*@__PURE__*/ new Vector3( - 1, 1, - 1 ),
|
||||
/*@__PURE__*/ new Vector3( 1, 1, - 1 ),
|
||||
/*@__PURE__*/ new Vector3( - 1, 1, 1 ),
|
||||
/*@__PURE__*/ new Vector3( 1, 1, 1 ) ];
|
||||
|
||||
/**
|
||||
* This class generates a Prefiltered, Mipmapped Radiance Environment Map
|
||||
* (PMREM) from a cubeMap environment texture. This allows different levels of
|
||||
* blur to be quickly accessed based on material roughness. It is packed into a
|
||||
* special CubeUV format that allows us to perform custom interpolation so that
|
||||
* we can support nonlinear formats such as RGBE. Unlike a traditional mipmap
|
||||
* chain, it only goes down to the LOD_MIN level (above), and then creates extra
|
||||
* even more filtered 'mips' at the same LOD_MIN resolution, associated with
|
||||
* higher roughness levels. In this way we maintain resolution to smoothly
|
||||
* interpolate diffuse lighting while limiting sampling computation.
|
||||
*
|
||||
* Paper: Fast, Accurate Image-Based Lighting
|
||||
* https://drive.google.com/file/d/15y8r_UpKlU9SvV4ILb0C3qCPecS8pvLz/view
|
||||
*/
|
||||
|
||||
class PMREMGenerator {
|
||||
|
||||
constructor( renderer ) {
|
||||
|
||||
this._renderer = renderer;
|
||||
this._pingPongRenderTarget = null;
|
||||
|
||||
this._lodMax = 0;
|
||||
this._cubeSize = 0;
|
||||
this._lodPlanes = [];
|
||||
this._sizeLods = [];
|
||||
this._sigmas = [];
|
||||
|
||||
this._blurMaterial = null;
|
||||
this._cubemapMaterial = null;
|
||||
this._equirectMaterial = null;
|
||||
|
||||
this._compileMaterial( this._blurMaterial );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a PMREM from a supplied Scene, which can be faster than using an
|
||||
* image if networking bandwidth is low. Optional sigma specifies a blur radius
|
||||
* in radians to be applied to the scene before PMREM generation. Optional near
|
||||
* and far planes ensure the scene is rendered in its entirety (the cubeCamera
|
||||
* is placed at the origin).
|
||||
*/
|
||||
fromScene( scene, sigma = 0, near = 0.1, far = 100 ) {
|
||||
|
||||
_oldTarget = this._renderer.getRenderTarget();
|
||||
_oldActiveCubeFace = this._renderer.getActiveCubeFace();
|
||||
_oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel();
|
||||
_oldXrEnabled = this._renderer.xr.enabled;
|
||||
|
||||
this._renderer.xr.enabled = false;
|
||||
|
||||
this._setSize( 256 );
|
||||
|
||||
const cubeUVRenderTarget = this._allocateTargets();
|
||||
cubeUVRenderTarget.depthBuffer = true;
|
||||
|
||||
this._sceneToCubeUV( scene, near, far, cubeUVRenderTarget );
|
||||
|
||||
if ( sigma > 0 ) {
|
||||
|
||||
this._blur( cubeUVRenderTarget, 0, 0, sigma );
|
||||
|
||||
}
|
||||
|
||||
this._applyPMREM( cubeUVRenderTarget );
|
||||
this._cleanup( cubeUVRenderTarget );
|
||||
|
||||
return cubeUVRenderTarget;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a PMREM from an equirectangular texture, which can be either LDR
|
||||
* or HDR. The ideal input image size is 1k (1024 x 512),
|
||||
* as this matches best with the 256 x 256 cubemap output.
|
||||
* The smallest supported equirectangular image size is 64 x 32.
|
||||
*/
|
||||
fromEquirectangular( equirectangular, renderTarget = null ) {
|
||||
|
||||
return this._fromTexture( equirectangular, renderTarget );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a PMREM from an cubemap texture, which can be either LDR
|
||||
* or HDR. The ideal input cube size is 256 x 256,
|
||||
* as this matches best with the 256 x 256 cubemap output.
|
||||
* The smallest supported cube size is 16 x 16.
|
||||
*/
|
||||
fromCubemap( cubemap, renderTarget = null ) {
|
||||
|
||||
return this._fromTexture( cubemap, renderTarget );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during
|
||||
* your texture's network fetch for increased concurrency.
|
||||
*/
|
||||
compileCubemapShader() {
|
||||
|
||||
if ( this._cubemapMaterial === null ) {
|
||||
|
||||
this._cubemapMaterial = _getCubemapMaterial();
|
||||
this._compileMaterial( this._cubemapMaterial );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during
|
||||
* your texture's network fetch for increased concurrency.
|
||||
*/
|
||||
compileEquirectangularShader() {
|
||||
|
||||
if ( this._equirectMaterial === null ) {
|
||||
|
||||
this._equirectMaterial = _getEquirectMaterial();
|
||||
this._compileMaterial( this._equirectMaterial );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class,
|
||||
* so you should not need more than one PMREMGenerator object. If you do, calling dispose() on
|
||||
* one of them will cause any others to also become unusable.
|
||||
*/
|
||||
dispose() {
|
||||
|
||||
this._dispose();
|
||||
|
||||
if ( this._cubemapMaterial !== null ) this._cubemapMaterial.dispose();
|
||||
if ( this._equirectMaterial !== null ) this._equirectMaterial.dispose();
|
||||
|
||||
}
|
||||
|
||||
// private interface
|
||||
|
||||
_setSize( cubeSize ) {
|
||||
|
||||
this._lodMax = Math.floor( Math.log2( cubeSize ) );
|
||||
this._cubeSize = Math.pow( 2, this._lodMax );
|
||||
|
||||
}
|
||||
|
||||
_dispose() {
|
||||
|
||||
if ( this._blurMaterial !== null ) this._blurMaterial.dispose();
|
||||
|
||||
if ( this._pingPongRenderTarget !== null ) this._pingPongRenderTarget.dispose();
|
||||
|
||||
for ( let i = 0; i < this._lodPlanes.length; i ++ ) {
|
||||
|
||||
this._lodPlanes[ i ].dispose();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_cleanup( outputTarget ) {
|
||||
|
||||
this._renderer.setRenderTarget( _oldTarget, _oldActiveCubeFace, _oldActiveMipmapLevel );
|
||||
this._renderer.xr.enabled = _oldXrEnabled;
|
||||
|
||||
outputTarget.scissorTest = false;
|
||||
_setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height );
|
||||
|
||||
}
|
||||
|
||||
_fromTexture( texture, renderTarget ) {
|
||||
|
||||
if ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ) {
|
||||
|
||||
this._setSize( texture.image.length === 0 ? 16 : ( texture.image[ 0 ].width || texture.image[ 0 ].image.width ) );
|
||||
|
||||
} else { // Equirectangular
|
||||
|
||||
this._setSize( texture.image.width / 4 );
|
||||
|
||||
}
|
||||
|
||||
_oldTarget = this._renderer.getRenderTarget();
|
||||
_oldActiveCubeFace = this._renderer.getActiveCubeFace();
|
||||
_oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel();
|
||||
_oldXrEnabled = this._renderer.xr.enabled;
|
||||
|
||||
this._renderer.xr.enabled = false;
|
||||
|
||||
const cubeUVRenderTarget = renderTarget || this._allocateTargets();
|
||||
this._textureToCubeUV( texture, cubeUVRenderTarget );
|
||||
this._applyPMREM( cubeUVRenderTarget );
|
||||
this._cleanup( cubeUVRenderTarget );
|
||||
|
||||
return cubeUVRenderTarget;
|
||||
|
||||
}
|
||||
|
||||
_allocateTargets() {
|
||||
|
||||
const width = 3 * Math.max( this._cubeSize, 16 * 7 );
|
||||
const height = 4 * this._cubeSize;
|
||||
|
||||
const params = {
|
||||
magFilter: LinearFilter,
|
||||
minFilter: LinearFilter,
|
||||
generateMipmaps: false,
|
||||
type: HalfFloatType,
|
||||
format: RGBAFormat,
|
||||
colorSpace: LinearSRGBColorSpace,
|
||||
depthBuffer: false
|
||||
};
|
||||
|
||||
const cubeUVRenderTarget = _createRenderTarget( width, height, params );
|
||||
|
||||
if ( this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width || this._pingPongRenderTarget.height !== height ) {
|
||||
|
||||
if ( this._pingPongRenderTarget !== null ) {
|
||||
|
||||
this._dispose();
|
||||
|
||||
}
|
||||
|
||||
this._pingPongRenderTarget = _createRenderTarget( width, height, params );
|
||||
|
||||
const { _lodMax } = this;
|
||||
( { sizeLods: this._sizeLods, lodPlanes: this._lodPlanes, sigmas: this._sigmas } = _createPlanes( _lodMax ) );
|
||||
|
||||
this._blurMaterial = _getBlurShader( _lodMax, width, height );
|
||||
|
||||
}
|
||||
|
||||
return cubeUVRenderTarget;
|
||||
|
||||
}
|
||||
|
||||
_compileMaterial( material ) {
|
||||
|
||||
const tmpMesh = new Mesh( this._lodPlanes[ 0 ], material );
|
||||
this._renderer.compile( tmpMesh, _flatCamera );
|
||||
|
||||
}
|
||||
|
||||
_sceneToCubeUV( scene, near, far, cubeUVRenderTarget ) {
|
||||
|
||||
const fov = 90;
|
||||
const aspect = 1;
|
||||
const cubeCamera = new PerspectiveCamera( fov, aspect, near, far );
|
||||
const upSign = [ 1, - 1, 1, 1, 1, 1 ];
|
||||
const forwardSign = [ 1, 1, 1, - 1, - 1, - 1 ];
|
||||
const renderer = this._renderer;
|
||||
|
||||
const originalAutoClear = renderer.autoClear;
|
||||
const toneMapping = renderer.toneMapping;
|
||||
renderer.getClearColor( _clearColor );
|
||||
|
||||
renderer.toneMapping = NoToneMapping;
|
||||
renderer.autoClear = false;
|
||||
|
||||
const backgroundMaterial = new MeshBasicMaterial( {
|
||||
name: 'PMREM.Background',
|
||||
side: BackSide,
|
||||
depthWrite: false,
|
||||
depthTest: false,
|
||||
} );
|
||||
|
||||
const backgroundBox = new Mesh( new BoxGeometry(), backgroundMaterial );
|
||||
|
||||
let useSolidColor = false;
|
||||
const background = scene.background;
|
||||
|
||||
if ( background ) {
|
||||
|
||||
if ( background.isColor ) {
|
||||
|
||||
backgroundMaterial.color.copy( background );
|
||||
scene.background = null;
|
||||
useSolidColor = true;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
backgroundMaterial.color.copy( _clearColor );
|
||||
useSolidColor = true;
|
||||
|
||||
}
|
||||
|
||||
for ( let i = 0; i < 6; i ++ ) {
|
||||
|
||||
const col = i % 3;
|
||||
|
||||
if ( col === 0 ) {
|
||||
|
||||
cubeCamera.up.set( 0, upSign[ i ], 0 );
|
||||
cubeCamera.lookAt( forwardSign[ i ], 0, 0 );
|
||||
|
||||
} else if ( col === 1 ) {
|
||||
|
||||
cubeCamera.up.set( 0, 0, upSign[ i ] );
|
||||
cubeCamera.lookAt( 0, forwardSign[ i ], 0 );
|
||||
|
||||
} else {
|
||||
|
||||
cubeCamera.up.set( 0, upSign[ i ], 0 );
|
||||
cubeCamera.lookAt( 0, 0, forwardSign[ i ] );
|
||||
|
||||
}
|
||||
|
||||
const size = this._cubeSize;
|
||||
|
||||
_setViewport( cubeUVRenderTarget, col * size, i > 2 ? size : 0, size, size );
|
||||
|
||||
renderer.setRenderTarget( cubeUVRenderTarget );
|
||||
|
||||
if ( useSolidColor ) {
|
||||
|
||||
renderer.render( backgroundBox, cubeCamera );
|
||||
|
||||
}
|
||||
|
||||
renderer.render( scene, cubeCamera );
|
||||
|
||||
}
|
||||
|
||||
backgroundBox.geometry.dispose();
|
||||
backgroundBox.material.dispose();
|
||||
|
||||
renderer.toneMapping = toneMapping;
|
||||
renderer.autoClear = originalAutoClear;
|
||||
scene.background = background;
|
||||
|
||||
}
|
||||
|
||||
_textureToCubeUV( texture, cubeUVRenderTarget ) {
|
||||
|
||||
const renderer = this._renderer;
|
||||
|
||||
const isCubeTexture = ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping );
|
||||
|
||||
if ( isCubeTexture ) {
|
||||
|
||||
if ( this._cubemapMaterial === null ) {
|
||||
|
||||
this._cubemapMaterial = _getCubemapMaterial();
|
||||
|
||||
}
|
||||
|
||||
this._cubemapMaterial.uniforms.flipEnvMap.value = ( texture.isRenderTargetTexture === false ) ? - 1 : 1;
|
||||
|
||||
} else {
|
||||
|
||||
if ( this._equirectMaterial === null ) {
|
||||
|
||||
this._equirectMaterial = _getEquirectMaterial();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const material = isCubeTexture ? this._cubemapMaterial : this._equirectMaterial;
|
||||
const mesh = new Mesh( this._lodPlanes[ 0 ], material );
|
||||
|
||||
const uniforms = material.uniforms;
|
||||
|
||||
uniforms[ 'envMap' ].value = texture;
|
||||
|
||||
const size = this._cubeSize;
|
||||
|
||||
_setViewport( cubeUVRenderTarget, 0, 0, 3 * size, 2 * size );
|
||||
|
||||
renderer.setRenderTarget( cubeUVRenderTarget );
|
||||
renderer.render( mesh, _flatCamera );
|
||||
|
||||
}
|
||||
|
||||
_applyPMREM( cubeUVRenderTarget ) {
|
||||
|
||||
const renderer = this._renderer;
|
||||
const autoClear = renderer.autoClear;
|
||||
renderer.autoClear = false;
|
||||
const n = this._lodPlanes.length;
|
||||
|
||||
for ( let i = 1; i < n; i ++ ) {
|
||||
|
||||
const sigma = Math.sqrt( this._sigmas[ i ] * this._sigmas[ i ] - this._sigmas[ i - 1 ] * this._sigmas[ i - 1 ] );
|
||||
|
||||
const poleAxis = _axisDirections[ ( n - i - 1 ) % _axisDirections.length ];
|
||||
|
||||
this._blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis );
|
||||
|
||||
}
|
||||
|
||||
renderer.autoClear = autoClear;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a two-pass Gaussian blur for a cubemap. Normally this is done
|
||||
* vertically and horizontally, but this breaks down on a cube. Here we apply
|
||||
* the blur latitudinally (around the poles), and then longitudinally (towards
|
||||
* the poles) to approximate the orthogonally-separable blur. It is least
|
||||
* accurate at the poles, but still does a decent job.
|
||||
*/
|
||||
_blur( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) {
|
||||
|
||||
const pingPongRenderTarget = this._pingPongRenderTarget;
|
||||
|
||||
this._halfBlur(
|
||||
cubeUVRenderTarget,
|
||||
pingPongRenderTarget,
|
||||
lodIn,
|
||||
lodOut,
|
||||
sigma,
|
||||
'latitudinal',
|
||||
poleAxis );
|
||||
|
||||
this._halfBlur(
|
||||
pingPongRenderTarget,
|
||||
cubeUVRenderTarget,
|
||||
lodOut,
|
||||
lodOut,
|
||||
sigma,
|
||||
'longitudinal',
|
||||
poleAxis );
|
||||
|
||||
}
|
||||
|
||||
_halfBlur( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) {
|
||||
|
||||
const renderer = this._renderer;
|
||||
const blurMaterial = this._blurMaterial;
|
||||
|
||||
if ( direction !== 'latitudinal' && direction !== 'longitudinal' ) {
|
||||
|
||||
console.error(
|
||||
'blur direction must be either latitudinal or longitudinal!' );
|
||||
|
||||
}
|
||||
|
||||
// Number of standard deviations at which to cut off the discrete approximation.
|
||||
const STANDARD_DEVIATIONS = 3;
|
||||
|
||||
const blurMesh = new Mesh( this._lodPlanes[ lodOut ], blurMaterial );
|
||||
const blurUniforms = blurMaterial.uniforms;
|
||||
|
||||
const pixels = this._sizeLods[ lodIn ] - 1;
|
||||
const radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 );
|
||||
const sigmaPixels = sigmaRadians / radiansPerPixel;
|
||||
const samples = isFinite( sigmaRadians ) ? 1 + Math.floor( STANDARD_DEVIATIONS * sigmaPixels ) : MAX_SAMPLES;
|
||||
|
||||
if ( samples > MAX_SAMPLES ) {
|
||||
|
||||
console.warn( `sigmaRadians, ${
|
||||
sigmaRadians}, is too large and will clip, as it requested ${
|
||||
samples} samples when the maximum is set to ${MAX_SAMPLES}` );
|
||||
|
||||
}
|
||||
|
||||
const weights = [];
|
||||
let sum = 0;
|
||||
|
||||
for ( let i = 0; i < MAX_SAMPLES; ++ i ) {
|
||||
|
||||
const x = i / sigmaPixels;
|
||||
const weight = Math.exp( - x * x / 2 );
|
||||
weights.push( weight );
|
||||
|
||||
if ( i === 0 ) {
|
||||
|
||||
sum += weight;
|
||||
|
||||
} else if ( i < samples ) {
|
||||
|
||||
sum += 2 * weight;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for ( let i = 0; i < weights.length; i ++ ) {
|
||||
|
||||
weights[ i ] = weights[ i ] / sum;
|
||||
|
||||
}
|
||||
|
||||
blurUniforms[ 'envMap' ].value = targetIn.texture;
|
||||
blurUniforms[ 'samples' ].value = samples;
|
||||
blurUniforms[ 'weights' ].value = weights;
|
||||
blurUniforms[ 'latitudinal' ].value = direction === 'latitudinal';
|
||||
|
||||
if ( poleAxis ) {
|
||||
|
||||
blurUniforms[ 'poleAxis' ].value = poleAxis;
|
||||
|
||||
}
|
||||
|
||||
const { _lodMax } = this;
|
||||
blurUniforms[ 'dTheta' ].value = radiansPerPixel;
|
||||
blurUniforms[ 'mipInt' ].value = _lodMax - lodIn;
|
||||
|
||||
const outputSize = this._sizeLods[ lodOut ];
|
||||
const x = 3 * outputSize * ( lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0 );
|
||||
const y = 4 * ( this._cubeSize - outputSize );
|
||||
|
||||
_setViewport( targetOut, x, y, 3 * outputSize, 2 * outputSize );
|
||||
renderer.setRenderTarget( targetOut );
|
||||
renderer.render( blurMesh, _flatCamera );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function _createPlanes( lodMax ) {
|
||||
|
||||
const lodPlanes = [];
|
||||
const sizeLods = [];
|
||||
const sigmas = [];
|
||||
|
||||
let lod = lodMax;
|
||||
|
||||
const totalLods = lodMax - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length;
|
||||
|
||||
for ( let i = 0; i < totalLods; i ++ ) {
|
||||
|
||||
const sizeLod = Math.pow( 2, lod );
|
||||
sizeLods.push( sizeLod );
|
||||
let sigma = 1.0 / sizeLod;
|
||||
|
||||
if ( i > lodMax - LOD_MIN ) {
|
||||
|
||||
sigma = EXTRA_LOD_SIGMA[ i - lodMax + LOD_MIN - 1 ];
|
||||
|
||||
} else if ( i === 0 ) {
|
||||
|
||||
sigma = 0;
|
||||
|
||||
}
|
||||
|
||||
sigmas.push( sigma );
|
||||
|
||||
const texelSize = 1.0 / ( sizeLod - 2 );
|
||||
const min = - texelSize;
|
||||
const max = 1 + texelSize;
|
||||
const uv1 = [ min, min, max, min, max, max, min, min, max, max, min, max ];
|
||||
|
||||
const cubeFaces = 6;
|
||||
const vertices = 6;
|
||||
const positionSize = 3;
|
||||
const uvSize = 2;
|
||||
const faceIndexSize = 1;
|
||||
|
||||
const position = new Float32Array( positionSize * vertices * cubeFaces );
|
||||
const uv = new Float32Array( uvSize * vertices * cubeFaces );
|
||||
const faceIndex = new Float32Array( faceIndexSize * vertices * cubeFaces );
|
||||
|
||||
for ( let face = 0; face < cubeFaces; face ++ ) {
|
||||
|
||||
const x = ( face % 3 ) * 2 / 3 - 1;
|
||||
const y = face > 2 ? 0 : - 1;
|
||||
const coordinates = [
|
||||
x, y, 0,
|
||||
x + 2 / 3, y, 0,
|
||||
x + 2 / 3, y + 1, 0,
|
||||
x, y, 0,
|
||||
x + 2 / 3, y + 1, 0,
|
||||
x, y + 1, 0
|
||||
];
|
||||
position.set( coordinates, positionSize * vertices * face );
|
||||
uv.set( uv1, uvSize * vertices * face );
|
||||
const fill = [ face, face, face, face, face, face ];
|
||||
faceIndex.set( fill, faceIndexSize * vertices * face );
|
||||
|
||||
}
|
||||
|
||||
const planes = new BufferGeometry();
|
||||
planes.setAttribute( 'position', new BufferAttribute( position, positionSize ) );
|
||||
planes.setAttribute( 'uv', new BufferAttribute( uv, uvSize ) );
|
||||
planes.setAttribute( 'faceIndex', new BufferAttribute( faceIndex, faceIndexSize ) );
|
||||
lodPlanes.push( planes );
|
||||
|
||||
if ( lod > LOD_MIN ) {
|
||||
|
||||
lod --;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return { lodPlanes, sizeLods, sigmas };
|
||||
|
||||
}
|
||||
|
||||
function _createRenderTarget( width, height, params ) {
|
||||
|
||||
const cubeUVRenderTarget = new WebGLRenderTarget( width, height, params );
|
||||
cubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping;
|
||||
cubeUVRenderTarget.texture.name = 'PMREM.cubeUv';
|
||||
cubeUVRenderTarget.scissorTest = true;
|
||||
return cubeUVRenderTarget;
|
||||
|
||||
}
|
||||
|
||||
function _setViewport( target, x, y, width, height ) {
|
||||
|
||||
target.viewport.set( x, y, width, height );
|
||||
target.scissor.set( x, y, width, height );
|
||||
|
||||
}
|
||||
|
||||
function _getBlurShader( lodMax, width, height ) {
|
||||
|
||||
const weights = new Float32Array( MAX_SAMPLES );
|
||||
const poleAxis = new Vector3( 0, 1, 0 );
|
||||
const shaderMaterial = new ShaderMaterial( {
|
||||
|
||||
name: 'SphericalGaussianBlur',
|
||||
|
||||
defines: {
|
||||
'n': MAX_SAMPLES,
|
||||
'CUBEUV_TEXEL_WIDTH': 1.0 / width,
|
||||
'CUBEUV_TEXEL_HEIGHT': 1.0 / height,
|
||||
'CUBEUV_MAX_MIP': `${lodMax}.0`,
|
||||
},
|
||||
|
||||
uniforms: {
|
||||
'envMap': { value: null },
|
||||
'samples': { value: 1 },
|
||||
'weights': { value: weights },
|
||||
'latitudinal': { value: false },
|
||||
'dTheta': { value: 0 },
|
||||
'mipInt': { value: 0 },
|
||||
'poleAxis': { value: poleAxis }
|
||||
},
|
||||
|
||||
vertexShader: _getCommonVertexShader(),
|
||||
|
||||
fragmentShader: /* glsl */`
|
||||
|
||||
precision mediump float;
|
||||
precision mediump int;
|
||||
|
||||
varying vec3 vOutputDirection;
|
||||
|
||||
uniform sampler2D envMap;
|
||||
uniform int samples;
|
||||
uniform float weights[ n ];
|
||||
uniform bool latitudinal;
|
||||
uniform float dTheta;
|
||||
uniform float mipInt;
|
||||
uniform vec3 poleAxis;
|
||||
|
||||
#define ENVMAP_TYPE_CUBE_UV
|
||||
#include <cube_uv_reflection_fragment>
|
||||
|
||||
vec3 getSample( float theta, vec3 axis ) {
|
||||
|
||||
float cosTheta = cos( theta );
|
||||
// Rodrigues' axis-angle rotation
|
||||
vec3 sampleDirection = vOutputDirection * cosTheta
|
||||
+ cross( axis, vOutputDirection ) * sin( theta )
|
||||
+ axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta );
|
||||
|
||||
return bilinearCubeUV( envMap, sampleDirection, mipInt );
|
||||
|
||||
}
|
||||
|
||||
void main() {
|
||||
|
||||
vec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection );
|
||||
|
||||
if ( all( equal( axis, vec3( 0.0 ) ) ) ) {
|
||||
|
||||
axis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x );
|
||||
|
||||
}
|
||||
|
||||
axis = normalize( axis );
|
||||
|
||||
gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );
|
||||
gl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis );
|
||||
|
||||
for ( int i = 1; i < n; i++ ) {
|
||||
|
||||
if ( i >= samples ) {
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
float theta = dTheta * float( i );
|
||||
gl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis );
|
||||
gl_FragColor.rgb += weights[ i ] * getSample( theta, axis );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
`,
|
||||
|
||||
blending: NoBlending,
|
||||
depthTest: false,
|
||||
depthWrite: false
|
||||
|
||||
} );
|
||||
|
||||
return shaderMaterial;
|
||||
|
||||
}
|
||||
|
||||
function _getEquirectMaterial() {
|
||||
|
||||
return new ShaderMaterial( {
|
||||
|
||||
name: 'EquirectangularToCubeUV',
|
||||
|
||||
uniforms: {
|
||||
'envMap': { value: null }
|
||||
},
|
||||
|
||||
vertexShader: _getCommonVertexShader(),
|
||||
|
||||
fragmentShader: /* glsl */`
|
||||
|
||||
precision mediump float;
|
||||
precision mediump int;
|
||||
|
||||
varying vec3 vOutputDirection;
|
||||
|
||||
uniform sampler2D envMap;
|
||||
|
||||
#include <common>
|
||||
|
||||
void main() {
|
||||
|
||||
vec3 outputDirection = normalize( vOutputDirection );
|
||||
vec2 uv = equirectUv( outputDirection );
|
||||
|
||||
gl_FragColor = vec4( texture2D ( envMap, uv ).rgb, 1.0 );
|
||||
|
||||
}
|
||||
`,
|
||||
|
||||
blending: NoBlending,
|
||||
depthTest: false,
|
||||
depthWrite: false
|
||||
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
function _getCubemapMaterial() {
|
||||
|
||||
return new ShaderMaterial( {
|
||||
|
||||
name: 'CubemapToCubeUV',
|
||||
|
||||
uniforms: {
|
||||
'envMap': { value: null },
|
||||
'flipEnvMap': { value: - 1 }
|
||||
},
|
||||
|
||||
vertexShader: _getCommonVertexShader(),
|
||||
|
||||
fragmentShader: /* glsl */`
|
||||
|
||||
precision mediump float;
|
||||
precision mediump int;
|
||||
|
||||
uniform float flipEnvMap;
|
||||
|
||||
varying vec3 vOutputDirection;
|
||||
|
||||
uniform samplerCube envMap;
|
||||
|
||||
void main() {
|
||||
|
||||
gl_FragColor = textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) );
|
||||
|
||||
}
|
||||
`,
|
||||
|
||||
blending: NoBlending,
|
||||
depthTest: false,
|
||||
depthWrite: false
|
||||
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
function _getCommonVertexShader() {
|
||||
|
||||
return /* glsl */`
|
||||
|
||||
precision mediump float;
|
||||
precision mediump int;
|
||||
|
||||
attribute float faceIndex;
|
||||
|
||||
varying vec3 vOutputDirection;
|
||||
|
||||
// RH coordinate system; PMREM face-indexing convention
|
||||
vec3 getDirection( vec2 uv, float face ) {
|
||||
|
||||
uv = 2.0 * uv - 1.0;
|
||||
|
||||
vec3 direction = vec3( uv, 1.0 );
|
||||
|
||||
if ( face == 0.0 ) {
|
||||
|
||||
direction = direction.zyx; // ( 1, v, u ) pos x
|
||||
|
||||
} else if ( face == 1.0 ) {
|
||||
|
||||
direction = direction.xzy;
|
||||
direction.xz *= -1.0; // ( -u, 1, -v ) pos y
|
||||
|
||||
} else if ( face == 2.0 ) {
|
||||
|
||||
direction.x *= -1.0; // ( -u, v, 1 ) pos z
|
||||
|
||||
} else if ( face == 3.0 ) {
|
||||
|
||||
direction = direction.zyx;
|
||||
direction.xz *= -1.0; // ( -1, v, -u ) neg x
|
||||
|
||||
} else if ( face == 4.0 ) {
|
||||
|
||||
direction = direction.xzy;
|
||||
direction.xy *= -1.0; // ( -u, -1, v ) neg y
|
||||
|
||||
} else if ( face == 5.0 ) {
|
||||
|
||||
direction.z *= -1.0; // ( u, v, -1 ) neg z
|
||||
|
||||
}
|
||||
|
||||
return direction;
|
||||
|
||||
}
|
||||
|
||||
void main() {
|
||||
|
||||
vOutputDirection = getDirection( uv, faceIndex );
|
||||
gl_Position = vec4( position, 1.0 );
|
||||
|
||||
}
|
||||
`;
|
||||
|
||||
}
|
||||
|
||||
export { PMREMGenerator };
|
92
site/real_game/node_modules/three/src/extras/ShapeUtils.js
generated
vendored
Normal file
92
site/real_game/node_modules/three/src/extras/ShapeUtils.js
generated
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
import { Earcut } from './Earcut.js';
|
||||
|
||||
class ShapeUtils {
|
||||
|
||||
// calculate area of the contour polygon
|
||||
|
||||
static area( contour ) {
|
||||
|
||||
const n = contour.length;
|
||||
let a = 0.0;
|
||||
|
||||
for ( let p = n - 1, q = 0; q < n; p = q ++ ) {
|
||||
|
||||
a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;
|
||||
|
||||
}
|
||||
|
||||
return a * 0.5;
|
||||
|
||||
}
|
||||
|
||||
static isClockWise( pts ) {
|
||||
|
||||
return ShapeUtils.area( pts ) < 0;
|
||||
|
||||
}
|
||||
|
||||
static triangulateShape( contour, holes ) {
|
||||
|
||||
const vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ]
|
||||
const holeIndices = []; // array of hole indices
|
||||
const faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ]
|
||||
|
||||
removeDupEndPts( contour );
|
||||
addContour( vertices, contour );
|
||||
|
||||
//
|
||||
|
||||
let holeIndex = contour.length;
|
||||
|
||||
holes.forEach( removeDupEndPts );
|
||||
|
||||
for ( let i = 0; i < holes.length; i ++ ) {
|
||||
|
||||
holeIndices.push( holeIndex );
|
||||
holeIndex += holes[ i ].length;
|
||||
addContour( vertices, holes[ i ] );
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
const triangles = Earcut.triangulate( vertices, holeIndices );
|
||||
|
||||
//
|
||||
|
||||
for ( let i = 0; i < triangles.length; i += 3 ) {
|
||||
|
||||
faces.push( triangles.slice( i, i + 3 ) );
|
||||
|
||||
}
|
||||
|
||||
return faces;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function removeDupEndPts( points ) {
|
||||
|
||||
const l = points.length;
|
||||
|
||||
if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) {
|
||||
|
||||
points.pop();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function addContour( vertices, contour ) {
|
||||
|
||||
for ( let i = 0; i < contour.length; i ++ ) {
|
||||
|
||||
vertices.push( contour[ i ].x );
|
||||
vertices.push( contour[ i ].y );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { ShapeUtils };
|
210
site/real_game/node_modules/three/src/extras/TextureUtils.js
generated
vendored
Normal file
210
site/real_game/node_modules/three/src/extras/TextureUtils.js
generated
vendored
Normal file
@ -0,0 +1,210 @@
|
||||
import { AlphaFormat, LuminanceFormat, LuminanceAlphaFormat, RedFormat, RedIntegerFormat, RGFormat, RGIntegerFormat, RGBFormat, RGBAFormat, RGBAIntegerFormat, RGB_S3TC_DXT1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGB_PVRTC_2BPPV1_Format, RGBA_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGBA_ETC2_EAC_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_10x10_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_BPTC_Format, RGB_BPTC_SIGNED_Format, RGB_BPTC_UNSIGNED_Format, RED_RGTC1_Format, SIGNED_RED_RGTC1_Format, RED_GREEN_RGTC2_Format, SIGNED_RED_GREEN_RGTC2_Format, UnsignedByteType, ByteType, UnsignedShortType, ShortType, HalfFloatType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedIntType, IntType, FloatType, UnsignedInt5999Type } from '../constants.js';
|
||||
|
||||
function contain( texture, aspect ) {
|
||||
|
||||
const imageAspect = ( texture.image && texture.image.width ) ? texture.image.width / texture.image.height : 1;
|
||||
|
||||
if ( imageAspect > aspect ) {
|
||||
|
||||
texture.repeat.x = 1;
|
||||
texture.repeat.y = imageAspect / aspect;
|
||||
|
||||
texture.offset.x = 0;
|
||||
texture.offset.y = ( 1 - texture.repeat.y ) / 2;
|
||||
|
||||
} else {
|
||||
|
||||
texture.repeat.x = aspect / imageAspect;
|
||||
texture.repeat.y = 1;
|
||||
|
||||
texture.offset.x = ( 1 - texture.repeat.x ) / 2;
|
||||
texture.offset.y = 0;
|
||||
|
||||
}
|
||||
|
||||
return texture;
|
||||
|
||||
}
|
||||
|
||||
function cover( texture, aspect ) {
|
||||
|
||||
const imageAspect = ( texture.image && texture.image.width ) ? texture.image.width / texture.image.height : 1;
|
||||
|
||||
if ( imageAspect > aspect ) {
|
||||
|
||||
texture.repeat.x = aspect / imageAspect;
|
||||
texture.repeat.y = 1;
|
||||
|
||||
texture.offset.x = ( 1 - texture.repeat.x ) / 2;
|
||||
texture.offset.y = 0;
|
||||
|
||||
} else {
|
||||
|
||||
texture.repeat.x = 1;
|
||||
texture.repeat.y = imageAspect / aspect;
|
||||
|
||||
texture.offset.x = 0;
|
||||
texture.offset.y = ( 1 - texture.repeat.y ) / 2;
|
||||
|
||||
}
|
||||
|
||||
return texture;
|
||||
|
||||
}
|
||||
|
||||
function fill( texture ) {
|
||||
|
||||
texture.repeat.x = 1;
|
||||
texture.repeat.y = 1;
|
||||
|
||||
texture.offset.x = 0;
|
||||
texture.offset.y = 0;
|
||||
|
||||
return texture;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Given the width, height, format, and type of a texture. Determines how many
|
||||
* bytes must be used to represent the texture.
|
||||
*/
|
||||
function getByteLength( width, height, format, type ) {
|
||||
|
||||
const typeByteLength = getTextureTypeByteLength( type );
|
||||
|
||||
switch ( format ) {
|
||||
|
||||
// https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml
|
||||
case AlphaFormat:
|
||||
return width * height;
|
||||
case LuminanceFormat:
|
||||
return width * height;
|
||||
case LuminanceAlphaFormat:
|
||||
return width * height * 2;
|
||||
case RedFormat:
|
||||
return ( ( width * height ) / typeByteLength.components ) * typeByteLength.byteLength;
|
||||
case RedIntegerFormat:
|
||||
return ( ( width * height ) / typeByteLength.components ) * typeByteLength.byteLength;
|
||||
case RGFormat:
|
||||
return ( ( width * height * 2 ) / typeByteLength.components ) * typeByteLength.byteLength;
|
||||
case RGIntegerFormat:
|
||||
return ( ( width * height * 2 ) / typeByteLength.components ) * typeByteLength.byteLength;
|
||||
case RGBFormat:
|
||||
return ( ( width * height * 3 ) / typeByteLength.components ) * typeByteLength.byteLength;
|
||||
case RGBAFormat:
|
||||
return ( ( width * height * 4 ) / typeByteLength.components ) * typeByteLength.byteLength;
|
||||
case RGBAIntegerFormat:
|
||||
return ( ( width * height * 4 ) / typeByteLength.components ) * typeByteLength.byteLength;
|
||||
|
||||
// https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_s3tc_srgb/
|
||||
case RGB_S3TC_DXT1_Format:
|
||||
case RGBA_S3TC_DXT1_Format:
|
||||
return Math.floor( ( width + 3 ) / 4 ) * Math.floor( ( height + 3 ) / 4 ) * 8;
|
||||
case RGBA_S3TC_DXT3_Format:
|
||||
case RGBA_S3TC_DXT5_Format:
|
||||
return Math.floor( ( width + 3 ) / 4 ) * Math.floor( ( height + 3 ) / 4 ) * 16;
|
||||
|
||||
// https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_pvrtc/
|
||||
case RGB_PVRTC_2BPPV1_Format:
|
||||
case RGBA_PVRTC_2BPPV1_Format:
|
||||
return ( Math.max( width, 16 ) * Math.max( height, 8 ) ) / 4;
|
||||
case RGB_PVRTC_4BPPV1_Format:
|
||||
case RGBA_PVRTC_4BPPV1_Format:
|
||||
return ( Math.max( width, 8 ) * Math.max( height, 8 ) ) / 2;
|
||||
|
||||
// https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_etc/
|
||||
case RGB_ETC1_Format:
|
||||
case RGB_ETC2_Format:
|
||||
return Math.floor( ( width + 3 ) / 4 ) * Math.floor( ( height + 3 ) / 4 ) * 8;
|
||||
case RGBA_ETC2_EAC_Format:
|
||||
return Math.floor( ( width + 3 ) / 4 ) * Math.floor( ( height + 3 ) / 4 ) * 16;
|
||||
|
||||
// https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_astc/
|
||||
case RGBA_ASTC_4x4_Format:
|
||||
return Math.floor( ( width + 3 ) / 4 ) * Math.floor( ( height + 3 ) / 4 ) * 16;
|
||||
case RGBA_ASTC_5x4_Format:
|
||||
return Math.floor( ( width + 4 ) / 5 ) * Math.floor( ( height + 3 ) / 4 ) * 16;
|
||||
case RGBA_ASTC_5x5_Format:
|
||||
return Math.floor( ( width + 4 ) / 5 ) * Math.floor( ( height + 4 ) / 5 ) * 16;
|
||||
case RGBA_ASTC_6x5_Format:
|
||||
return Math.floor( ( width + 5 ) / 6 ) * Math.floor( ( height + 4 ) / 5 ) * 16;
|
||||
case RGBA_ASTC_6x6_Format:
|
||||
return Math.floor( ( width + 5 ) / 6 ) * Math.floor( ( height + 5 ) / 6 ) * 16;
|
||||
case RGBA_ASTC_8x5_Format:
|
||||
return Math.floor( ( width + 7 ) / 8 ) * Math.floor( ( height + 4 ) / 5 ) * 16;
|
||||
case RGBA_ASTC_8x6_Format:
|
||||
return Math.floor( ( width + 7 ) / 8 ) * Math.floor( ( height + 5 ) / 6 ) * 16;
|
||||
case RGBA_ASTC_8x8_Format:
|
||||
return Math.floor( ( width + 7 ) / 8 ) * Math.floor( ( height + 7 ) / 8 ) * 16;
|
||||
case RGBA_ASTC_10x5_Format:
|
||||
return Math.floor( ( width + 9 ) / 10 ) * Math.floor( ( height + 4 ) / 5 ) * 16;
|
||||
case RGBA_ASTC_10x6_Format:
|
||||
return Math.floor( ( width + 9 ) / 10 ) * Math.floor( ( height + 5 ) / 6 ) * 16;
|
||||
case RGBA_ASTC_10x8_Format:
|
||||
return Math.floor( ( width + 9 ) / 10 ) * Math.floor( ( height + 7 ) / 8 ) * 16;
|
||||
case RGBA_ASTC_10x10_Format:
|
||||
return Math.floor( ( width + 9 ) / 10 ) * Math.floor( ( height + 9 ) / 10 ) * 16;
|
||||
case RGBA_ASTC_12x10_Format:
|
||||
return Math.floor( ( width + 11 ) / 12 ) * Math.floor( ( height + 9 ) / 10 ) * 16;
|
||||
case RGBA_ASTC_12x12_Format:
|
||||
return Math.floor( ( width + 11 ) / 12 ) * Math.floor( ( height + 11 ) / 12 ) * 16;
|
||||
|
||||
// https://registry.khronos.org/webgl/extensions/EXT_texture_compression_bptc/
|
||||
case RGBA_BPTC_Format:
|
||||
case RGB_BPTC_SIGNED_Format:
|
||||
case RGB_BPTC_UNSIGNED_Format:
|
||||
return Math.ceil( width / 4 ) * Math.ceil( height / 4 ) * 16;
|
||||
|
||||
// https://registry.khronos.org/webgl/extensions/EXT_texture_compression_rgtc/
|
||||
case RED_RGTC1_Format:
|
||||
case SIGNED_RED_RGTC1_Format:
|
||||
return Math.ceil( width / 4 ) * Math.ceil( height / 4 ) * 8;
|
||||
case RED_GREEN_RGTC2_Format:
|
||||
case SIGNED_RED_GREEN_RGTC2_Format:
|
||||
return Math.ceil( width / 4 ) * Math.ceil( height / 4 ) * 16;
|
||||
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Unable to determine texture byte length for ${format} format.`,
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function getTextureTypeByteLength( type ) {
|
||||
|
||||
switch ( type ) {
|
||||
|
||||
case UnsignedByteType:
|
||||
case ByteType:
|
||||
return { byteLength: 1, components: 1 };
|
||||
case UnsignedShortType:
|
||||
case ShortType:
|
||||
case HalfFloatType:
|
||||
return { byteLength: 2, components: 1 };
|
||||
case UnsignedShort4444Type:
|
||||
case UnsignedShort5551Type:
|
||||
return { byteLength: 2, components: 4 };
|
||||
case UnsignedIntType:
|
||||
case IntType:
|
||||
case FloatType:
|
||||
return { byteLength: 4, components: 1 };
|
||||
case UnsignedInt5999Type:
|
||||
return { byteLength: 4, components: 3 };
|
||||
|
||||
}
|
||||
|
||||
throw new Error( `Unknown texture type ${type}.` );
|
||||
|
||||
}
|
||||
|
||||
const TextureUtils = {
|
||||
contain,
|
||||
cover,
|
||||
fill,
|
||||
getByteLength
|
||||
};
|
||||
|
||||
export { contain, cover, fill, getByteLength, TextureUtils };
|
416
site/real_game/node_modules/three/src/extras/core/Curve.js
generated
vendored
Normal file
416
site/real_game/node_modules/three/src/extras/core/Curve.js
generated
vendored
Normal file
@ -0,0 +1,416 @@
|
||||
import * as MathUtils from '../../math/MathUtils.js';
|
||||
import { Vector2 } from '../../math/Vector2.js';
|
||||
import { Vector3 } from '../../math/Vector3.js';
|
||||
import { Matrix4 } from '../../math/Matrix4.js';
|
||||
|
||||
/**
|
||||
* Extensible curve object.
|
||||
*
|
||||
* Some common of curve methods:
|
||||
* .getPoint( t, optionalTarget ), .getTangent( t, optionalTarget )
|
||||
* .getPointAt( u, optionalTarget ), .getTangentAt( u, optionalTarget )
|
||||
* .getPoints(), .getSpacedPoints()
|
||||
* .getLength()
|
||||
* .updateArcLengths()
|
||||
*
|
||||
* This following curves inherit from THREE.Curve:
|
||||
*
|
||||
* -- 2D curves --
|
||||
* THREE.ArcCurve
|
||||
* THREE.CubicBezierCurve
|
||||
* THREE.EllipseCurve
|
||||
* THREE.LineCurve
|
||||
* THREE.QuadraticBezierCurve
|
||||
* THREE.SplineCurve
|
||||
*
|
||||
* -- 3D curves --
|
||||
* THREE.CatmullRomCurve3
|
||||
* THREE.CubicBezierCurve3
|
||||
* THREE.LineCurve3
|
||||
* THREE.QuadraticBezierCurve3
|
||||
*
|
||||
* A series of curves can be represented as a THREE.CurvePath.
|
||||
*
|
||||
**/
|
||||
|
||||
class Curve {
|
||||
|
||||
constructor() {
|
||||
|
||||
this.type = 'Curve';
|
||||
|
||||
this.arcLengthDivisions = 200;
|
||||
|
||||
}
|
||||
|
||||
// Virtual base class method to overwrite and implement in subclasses
|
||||
// - t [0 .. 1]
|
||||
|
||||
getPoint( /* t, optionalTarget */ ) {
|
||||
|
||||
console.warn( 'THREE.Curve: .getPoint() not implemented.' );
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
// Get point at relative position in curve according to arc length
|
||||
// - u [0 .. 1]
|
||||
|
||||
getPointAt( u, optionalTarget ) {
|
||||
|
||||
const t = this.getUtoTmapping( u );
|
||||
return this.getPoint( t, optionalTarget );
|
||||
|
||||
}
|
||||
|
||||
// Get sequence of points using getPoint( t )
|
||||
|
||||
getPoints( divisions = 5 ) {
|
||||
|
||||
const points = [];
|
||||
|
||||
for ( let d = 0; d <= divisions; d ++ ) {
|
||||
|
||||
points.push( this.getPoint( d / divisions ) );
|
||||
|
||||
}
|
||||
|
||||
return points;
|
||||
|
||||
}
|
||||
|
||||
// Get sequence of points using getPointAt( u )
|
||||
|
||||
getSpacedPoints( divisions = 5 ) {
|
||||
|
||||
const points = [];
|
||||
|
||||
for ( let d = 0; d <= divisions; d ++ ) {
|
||||
|
||||
points.push( this.getPointAt( d / divisions ) );
|
||||
|
||||
}
|
||||
|
||||
return points;
|
||||
|
||||
}
|
||||
|
||||
// Get total curve arc length
|
||||
|
||||
getLength() {
|
||||
|
||||
const lengths = this.getLengths();
|
||||
return lengths[ lengths.length - 1 ];
|
||||
|
||||
}
|
||||
|
||||
// Get list of cumulative segment lengths
|
||||
|
||||
getLengths( divisions = this.arcLengthDivisions ) {
|
||||
|
||||
if ( this.cacheArcLengths &&
|
||||
( this.cacheArcLengths.length === divisions + 1 ) &&
|
||||
! this.needsUpdate ) {
|
||||
|
||||
return this.cacheArcLengths;
|
||||
|
||||
}
|
||||
|
||||
this.needsUpdate = false;
|
||||
|
||||
const cache = [];
|
||||
let current, last = this.getPoint( 0 );
|
||||
let sum = 0;
|
||||
|
||||
cache.push( 0 );
|
||||
|
||||
for ( let p = 1; p <= divisions; p ++ ) {
|
||||
|
||||
current = this.getPoint( p / divisions );
|
||||
sum += current.distanceTo( last );
|
||||
cache.push( sum );
|
||||
last = current;
|
||||
|
||||
}
|
||||
|
||||
this.cacheArcLengths = cache;
|
||||
|
||||
return cache; // { sums: cache, sum: sum }; Sum is in the last element.
|
||||
|
||||
}
|
||||
|
||||
updateArcLengths() {
|
||||
|
||||
this.needsUpdate = true;
|
||||
this.getLengths();
|
||||
|
||||
}
|
||||
|
||||
// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant
|
||||
|
||||
getUtoTmapping( u, distance ) {
|
||||
|
||||
const arcLengths = this.getLengths();
|
||||
|
||||
let i = 0;
|
||||
const il = arcLengths.length;
|
||||
|
||||
let targetArcLength; // The targeted u distance value to get
|
||||
|
||||
if ( distance ) {
|
||||
|
||||
targetArcLength = distance;
|
||||
|
||||
} else {
|
||||
|
||||
targetArcLength = u * arcLengths[ il - 1 ];
|
||||
|
||||
}
|
||||
|
||||
// binary search for the index with largest value smaller than target u distance
|
||||
|
||||
let low = 0, high = il - 1, comparison;
|
||||
|
||||
while ( low <= high ) {
|
||||
|
||||
i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats
|
||||
|
||||
comparison = arcLengths[ i ] - targetArcLength;
|
||||
|
||||
if ( comparison < 0 ) {
|
||||
|
||||
low = i + 1;
|
||||
|
||||
} else if ( comparison > 0 ) {
|
||||
|
||||
high = i - 1;
|
||||
|
||||
} else {
|
||||
|
||||
high = i;
|
||||
break;
|
||||
|
||||
// DONE
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
i = high;
|
||||
|
||||
if ( arcLengths[ i ] === targetArcLength ) {
|
||||
|
||||
return i / ( il - 1 );
|
||||
|
||||
}
|
||||
|
||||
// we could get finer grain at lengths, or use simple interpolation between two points
|
||||
|
||||
const lengthBefore = arcLengths[ i ];
|
||||
const lengthAfter = arcLengths[ i + 1 ];
|
||||
|
||||
const segmentLength = lengthAfter - lengthBefore;
|
||||
|
||||
// determine where we are between the 'before' and 'after' points
|
||||
|
||||
const segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;
|
||||
|
||||
// add that fractional amount to t
|
||||
|
||||
const t = ( i + segmentFraction ) / ( il - 1 );
|
||||
|
||||
return t;
|
||||
|
||||
}
|
||||
|
||||
// Returns a unit vector tangent at t
|
||||
// In case any sub curve does not implement its tangent derivation,
|
||||
// 2 points a small delta apart will be used to find its gradient
|
||||
// which seems to give a reasonable approximation
|
||||
|
||||
getTangent( t, optionalTarget ) {
|
||||
|
||||
const delta = 0.0001;
|
||||
let t1 = t - delta;
|
||||
let t2 = t + delta;
|
||||
|
||||
// Capping in case of danger
|
||||
|
||||
if ( t1 < 0 ) t1 = 0;
|
||||
if ( t2 > 1 ) t2 = 1;
|
||||
|
||||
const pt1 = this.getPoint( t1 );
|
||||
const pt2 = this.getPoint( t2 );
|
||||
|
||||
const tangent = optionalTarget || ( ( pt1.isVector2 ) ? new Vector2() : new Vector3() );
|
||||
|
||||
tangent.copy( pt2 ).sub( pt1 ).normalize();
|
||||
|
||||
return tangent;
|
||||
|
||||
}
|
||||
|
||||
getTangentAt( u, optionalTarget ) {
|
||||
|
||||
const t = this.getUtoTmapping( u );
|
||||
return this.getTangent( t, optionalTarget );
|
||||
|
||||
}
|
||||
|
||||
computeFrenetFrames( segments, closed ) {
|
||||
|
||||
// see http://www.cs.indiana.edu/pub/techreports/TR425.pdf
|
||||
|
||||
const normal = new Vector3();
|
||||
|
||||
const tangents = [];
|
||||
const normals = [];
|
||||
const binormals = [];
|
||||
|
||||
const vec = new Vector3();
|
||||
const mat = new Matrix4();
|
||||
|
||||
// compute the tangent vectors for each segment on the curve
|
||||
|
||||
for ( let i = 0; i <= segments; i ++ ) {
|
||||
|
||||
const u = i / segments;
|
||||
|
||||
tangents[ i ] = this.getTangentAt( u, new Vector3() );
|
||||
|
||||
}
|
||||
|
||||
// select an initial normal vector perpendicular to the first tangent vector,
|
||||
// and in the direction of the minimum tangent xyz component
|
||||
|
||||
normals[ 0 ] = new Vector3();
|
||||
binormals[ 0 ] = new Vector3();
|
||||
let min = Number.MAX_VALUE;
|
||||
const tx = Math.abs( tangents[ 0 ].x );
|
||||
const ty = Math.abs( tangents[ 0 ].y );
|
||||
const tz = Math.abs( tangents[ 0 ].z );
|
||||
|
||||
if ( tx <= min ) {
|
||||
|
||||
min = tx;
|
||||
normal.set( 1, 0, 0 );
|
||||
|
||||
}
|
||||
|
||||
if ( ty <= min ) {
|
||||
|
||||
min = ty;
|
||||
normal.set( 0, 1, 0 );
|
||||
|
||||
}
|
||||
|
||||
if ( tz <= min ) {
|
||||
|
||||
normal.set( 0, 0, 1 );
|
||||
|
||||
}
|
||||
|
||||
vec.crossVectors( tangents[ 0 ], normal ).normalize();
|
||||
|
||||
normals[ 0 ].crossVectors( tangents[ 0 ], vec );
|
||||
binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] );
|
||||
|
||||
|
||||
// compute the slowly-varying normal and binormal vectors for each segment on the curve
|
||||
|
||||
for ( let i = 1; i <= segments; i ++ ) {
|
||||
|
||||
normals[ i ] = normals[ i - 1 ].clone();
|
||||
|
||||
binormals[ i ] = binormals[ i - 1 ].clone();
|
||||
|
||||
vec.crossVectors( tangents[ i - 1 ], tangents[ i ] );
|
||||
|
||||
if ( vec.length() > Number.EPSILON ) {
|
||||
|
||||
vec.normalize();
|
||||
|
||||
const theta = Math.acos( MathUtils.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors
|
||||
|
||||
normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) );
|
||||
|
||||
}
|
||||
|
||||
binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
|
||||
|
||||
}
|
||||
|
||||
// if the curve is closed, postprocess the vectors so the first and last normal vectors are the same
|
||||
|
||||
if ( closed === true ) {
|
||||
|
||||
let theta = Math.acos( MathUtils.clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) );
|
||||
theta /= segments;
|
||||
|
||||
if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) {
|
||||
|
||||
theta = - theta;
|
||||
|
||||
}
|
||||
|
||||
for ( let i = 1; i <= segments; i ++ ) {
|
||||
|
||||
// twist a little...
|
||||
normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) );
|
||||
binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
tangents: tangents,
|
||||
normals: normals,
|
||||
binormals: binormals
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
clone() {
|
||||
|
||||
return new this.constructor().copy( this );
|
||||
|
||||
}
|
||||
|
||||
copy( source ) {
|
||||
|
||||
this.arcLengthDivisions = source.arcLengthDivisions;
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
|
||||
const data = {
|
||||
metadata: {
|
||||
version: 4.6,
|
||||
type: 'Curve',
|
||||
generator: 'Curve.toJSON'
|
||||
}
|
||||
};
|
||||
|
||||
data.arcLengthDivisions = this.arcLengthDivisions;
|
||||
data.type = this.type;
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
fromJSON( json ) {
|
||||
|
||||
this.arcLengthDivisions = json.arcLengthDivisions;
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
export { Curve };
|
255
site/real_game/node_modules/three/src/extras/core/CurvePath.js
generated
vendored
Normal file
255
site/real_game/node_modules/three/src/extras/core/CurvePath.js
generated
vendored
Normal file
@ -0,0 +1,255 @@
|
||||
import { Curve } from './Curve.js';
|
||||
import * as Curves from '../curves/Curves.js';
|
||||
|
||||
/**************************************************************
|
||||
* Curved Path - a curve path is simply a array of connected
|
||||
* curves, but retains the api of a curve
|
||||
**************************************************************/
|
||||
|
||||
class CurvePath extends Curve {
|
||||
|
||||
constructor() {
|
||||
|
||||
super();
|
||||
|
||||
this.type = 'CurvePath';
|
||||
|
||||
this.curves = [];
|
||||
this.autoClose = false; // Automatically closes the path
|
||||
|
||||
}
|
||||
|
||||
add( curve ) {
|
||||
|
||||
this.curves.push( curve );
|
||||
|
||||
}
|
||||
|
||||
closePath() {
|
||||
|
||||
// Add a line curve if start and end of lines are not connected
|
||||
const startPoint = this.curves[ 0 ].getPoint( 0 );
|
||||
const endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 );
|
||||
|
||||
if ( ! startPoint.equals( endPoint ) ) {
|
||||
|
||||
const lineType = ( startPoint.isVector2 === true ) ? 'LineCurve' : 'LineCurve3';
|
||||
this.curves.push( new Curves[ lineType ]( endPoint, startPoint ) );
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
// To get accurate point with reference to
|
||||
// entire path distance at time t,
|
||||
// following has to be done:
|
||||
|
||||
// 1. Length of each sub path have to be known
|
||||
// 2. Locate and identify type of curve
|
||||
// 3. Get t for the curve
|
||||
// 4. Return curve.getPointAt(t')
|
||||
|
||||
getPoint( t, optionalTarget ) {
|
||||
|
||||
const d = t * this.getLength();
|
||||
const curveLengths = this.getCurveLengths();
|
||||
let i = 0;
|
||||
|
||||
// To think about boundaries points.
|
||||
|
||||
while ( i < curveLengths.length ) {
|
||||
|
||||
if ( curveLengths[ i ] >= d ) {
|
||||
|
||||
const diff = curveLengths[ i ] - d;
|
||||
const curve = this.curves[ i ];
|
||||
|
||||
const segmentLength = curve.getLength();
|
||||
const u = segmentLength === 0 ? 0 : 1 - diff / segmentLength;
|
||||
|
||||
return curve.getPointAt( u, optionalTarget );
|
||||
|
||||
}
|
||||
|
||||
i ++;
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
// loop where sum != 0, sum > d , sum+1 <d
|
||||
|
||||
}
|
||||
|
||||
// We cannot use the default THREE.Curve getPoint() with getLength() because in
|
||||
// THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath
|
||||
// getPoint() depends on getLength
|
||||
|
||||
getLength() {
|
||||
|
||||
const lens = this.getCurveLengths();
|
||||
return lens[ lens.length - 1 ];
|
||||
|
||||
}
|
||||
|
||||
// cacheLengths must be recalculated.
|
||||
updateArcLengths() {
|
||||
|
||||
this.needsUpdate = true;
|
||||
this.cacheLengths = null;
|
||||
this.getCurveLengths();
|
||||
|
||||
}
|
||||
|
||||
// Compute lengths and cache them
|
||||
// We cannot overwrite getLengths() because UtoT mapping uses it.
|
||||
|
||||
getCurveLengths() {
|
||||
|
||||
// We use cache values if curves and cache array are same length
|
||||
|
||||
if ( this.cacheLengths && this.cacheLengths.length === this.curves.length ) {
|
||||
|
||||
return this.cacheLengths;
|
||||
|
||||
}
|
||||
|
||||
// Get length of sub-curve
|
||||
// Push sums into cached array
|
||||
|
||||
const lengths = [];
|
||||
let sums = 0;
|
||||
|
||||
for ( let i = 0, l = this.curves.length; i < l; i ++ ) {
|
||||
|
||||
sums += this.curves[ i ].getLength();
|
||||
lengths.push( sums );
|
||||
|
||||
}
|
||||
|
||||
this.cacheLengths = lengths;
|
||||
|
||||
return lengths;
|
||||
|
||||
}
|
||||
|
||||
getSpacedPoints( divisions = 40 ) {
|
||||
|
||||
const points = [];
|
||||
|
||||
for ( let i = 0; i <= divisions; i ++ ) {
|
||||
|
||||
points.push( this.getPoint( i / divisions ) );
|
||||
|
||||
}
|
||||
|
||||
if ( this.autoClose ) {
|
||||
|
||||
points.push( points[ 0 ] );
|
||||
|
||||
}
|
||||
|
||||
return points;
|
||||
|
||||
}
|
||||
|
||||
getPoints( divisions = 12 ) {
|
||||
|
||||
const points = [];
|
||||
let last;
|
||||
|
||||
for ( let i = 0, curves = this.curves; i < curves.length; i ++ ) {
|
||||
|
||||
const curve = curves[ i ];
|
||||
const resolution = curve.isEllipseCurve ? divisions * 2
|
||||
: ( curve.isLineCurve || curve.isLineCurve3 ) ? 1
|
||||
: curve.isSplineCurve ? divisions * curve.points.length
|
||||
: divisions;
|
||||
|
||||
const pts = curve.getPoints( resolution );
|
||||
|
||||
for ( let j = 0; j < pts.length; j ++ ) {
|
||||
|
||||
const point = pts[ j ];
|
||||
|
||||
if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates
|
||||
|
||||
points.push( point );
|
||||
last = point;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( this.autoClose && points.length > 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) {
|
||||
|
||||
points.push( points[ 0 ] );
|
||||
|
||||
}
|
||||
|
||||
return points;
|
||||
|
||||
}
|
||||
|
||||
copy( source ) {
|
||||
|
||||
super.copy( source );
|
||||
|
||||
this.curves = [];
|
||||
|
||||
for ( let i = 0, l = source.curves.length; i < l; i ++ ) {
|
||||
|
||||
const curve = source.curves[ i ];
|
||||
|
||||
this.curves.push( curve.clone() );
|
||||
|
||||
}
|
||||
|
||||
this.autoClose = source.autoClose;
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
|
||||
const data = super.toJSON();
|
||||
|
||||
data.autoClose = this.autoClose;
|
||||
data.curves = [];
|
||||
|
||||
for ( let i = 0, l = this.curves.length; i < l; i ++ ) {
|
||||
|
||||
const curve = this.curves[ i ];
|
||||
data.curves.push( curve.toJSON() );
|
||||
|
||||
}
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
fromJSON( json ) {
|
||||
|
||||
super.fromJSON( json );
|
||||
|
||||
this.autoClose = json.autoClose;
|
||||
this.curves = [];
|
||||
|
||||
for ( let i = 0, l = json.curves.length; i < l; i ++ ) {
|
||||
|
||||
const curve = json.curves[ i ];
|
||||
this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) );
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
export { CurvePath };
|
79
site/real_game/node_modules/three/src/extras/core/Interpolations.js
generated
vendored
Normal file
79
site/real_game/node_modules/three/src/extras/core/Interpolations.js
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Bezier Curves formulas obtained from
|
||||
* https://en.wikipedia.org/wiki/B%C3%A9zier_curve
|
||||
*/
|
||||
|
||||
function CatmullRom( t, p0, p1, p2, p3 ) {
|
||||
|
||||
const v0 = ( p2 - p0 ) * 0.5;
|
||||
const v1 = ( p3 - p1 ) * 0.5;
|
||||
const t2 = t * t;
|
||||
const t3 = t * t2;
|
||||
return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
function QuadraticBezierP0( t, p ) {
|
||||
|
||||
const k = 1 - t;
|
||||
return k * k * p;
|
||||
|
||||
}
|
||||
|
||||
function QuadraticBezierP1( t, p ) {
|
||||
|
||||
return 2 * ( 1 - t ) * t * p;
|
||||
|
||||
}
|
||||
|
||||
function QuadraticBezierP2( t, p ) {
|
||||
|
||||
return t * t * p;
|
||||
|
||||
}
|
||||
|
||||
function QuadraticBezier( t, p0, p1, p2 ) {
|
||||
|
||||
return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) +
|
||||
QuadraticBezierP2( t, p2 );
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
function CubicBezierP0( t, p ) {
|
||||
|
||||
const k = 1 - t;
|
||||
return k * k * k * p;
|
||||
|
||||
}
|
||||
|
||||
function CubicBezierP1( t, p ) {
|
||||
|
||||
const k = 1 - t;
|
||||
return 3 * k * k * t * p;
|
||||
|
||||
}
|
||||
|
||||
function CubicBezierP2( t, p ) {
|
||||
|
||||
return 3 * ( 1 - t ) * t * t * p;
|
||||
|
||||
}
|
||||
|
||||
function CubicBezierP3( t, p ) {
|
||||
|
||||
return t * t * t * p;
|
||||
|
||||
}
|
||||
|
||||
function CubicBezier( t, p0, p1, p2, p3 ) {
|
||||
|
||||
return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) +
|
||||
CubicBezierP3( t, p3 );
|
||||
|
||||
}
|
||||
|
||||
export { CatmullRom, QuadraticBezier, CubicBezier };
|
196
site/real_game/node_modules/three/src/extras/core/Path.js
generated
vendored
Normal file
196
site/real_game/node_modules/three/src/extras/core/Path.js
generated
vendored
Normal file
@ -0,0 +1,196 @@
|
||||
import { Vector2 } from '../../math/Vector2.js';
|
||||
import { CurvePath } from './CurvePath.js';
|
||||
import { EllipseCurve } from '../curves/EllipseCurve.js';
|
||||
import { SplineCurve } from '../curves/SplineCurve.js';
|
||||
import { CubicBezierCurve } from '../curves/CubicBezierCurve.js';
|
||||
import { QuadraticBezierCurve } from '../curves/QuadraticBezierCurve.js';
|
||||
import { LineCurve } from '../curves/LineCurve.js';
|
||||
|
||||
class Path extends CurvePath {
|
||||
|
||||
constructor( points ) {
|
||||
|
||||
super();
|
||||
|
||||
this.type = 'Path';
|
||||
|
||||
this.currentPoint = new Vector2();
|
||||
|
||||
if ( points ) {
|
||||
|
||||
this.setFromPoints( points );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setFromPoints( points ) {
|
||||
|
||||
this.moveTo( points[ 0 ].x, points[ 0 ].y );
|
||||
|
||||
for ( let i = 1, l = points.length; i < l; i ++ ) {
|
||||
|
||||
this.lineTo( points[ i ].x, points[ i ].y );
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
moveTo( x, y ) {
|
||||
|
||||
this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying?
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
lineTo( x, y ) {
|
||||
|
||||
const curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) );
|
||||
this.curves.push( curve );
|
||||
|
||||
this.currentPoint.set( x, y );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
quadraticCurveTo( aCPx, aCPy, aX, aY ) {
|
||||
|
||||
const curve = new QuadraticBezierCurve(
|
||||
this.currentPoint.clone(),
|
||||
new Vector2( aCPx, aCPy ),
|
||||
new Vector2( aX, aY )
|
||||
);
|
||||
|
||||
this.curves.push( curve );
|
||||
|
||||
this.currentPoint.set( aX, aY );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
|
||||
|
||||
const curve = new CubicBezierCurve(
|
||||
this.currentPoint.clone(),
|
||||
new Vector2( aCP1x, aCP1y ),
|
||||
new Vector2( aCP2x, aCP2y ),
|
||||
new Vector2( aX, aY )
|
||||
);
|
||||
|
||||
this.curves.push( curve );
|
||||
|
||||
this.currentPoint.set( aX, aY );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
splineThru( pts /*Array of Vector*/ ) {
|
||||
|
||||
const npts = [ this.currentPoint.clone() ].concat( pts );
|
||||
|
||||
const curve = new SplineCurve( npts );
|
||||
this.curves.push( curve );
|
||||
|
||||
this.currentPoint.copy( pts[ pts.length - 1 ] );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
arc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
|
||||
|
||||
const x0 = this.currentPoint.x;
|
||||
const y0 = this.currentPoint.y;
|
||||
|
||||
this.absarc( aX + x0, aY + y0, aRadius,
|
||||
aStartAngle, aEndAngle, aClockwise );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
absarc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
|
||||
|
||||
this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
ellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
|
||||
|
||||
const x0 = this.currentPoint.x;
|
||||
const y0 = this.currentPoint.y;
|
||||
|
||||
this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
absellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
|
||||
|
||||
const curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
|
||||
|
||||
if ( this.curves.length > 0 ) {
|
||||
|
||||
// if a previous curve is present, attempt to join
|
||||
const firstPoint = curve.getPoint( 0 );
|
||||
|
||||
if ( ! firstPoint.equals( this.currentPoint ) ) {
|
||||
|
||||
this.lineTo( firstPoint.x, firstPoint.y );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.curves.push( curve );
|
||||
|
||||
const lastPoint = curve.getPoint( 1 );
|
||||
this.currentPoint.copy( lastPoint );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
copy( source ) {
|
||||
|
||||
super.copy( source );
|
||||
|
||||
this.currentPoint.copy( source.currentPoint );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
|
||||
const data = super.toJSON();
|
||||
|
||||
data.currentPoint = this.currentPoint.toArray();
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
fromJSON( json ) {
|
||||
|
||||
super.fromJSON( json );
|
||||
|
||||
this.currentPoint.fromArray( json.currentPoint );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
export { Path };
|
102
site/real_game/node_modules/three/src/extras/core/Shape.js
generated
vendored
Normal file
102
site/real_game/node_modules/three/src/extras/core/Shape.js
generated
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
import { Path } from './Path.js';
|
||||
import * as MathUtils from '../../math/MathUtils.js';
|
||||
|
||||
class Shape extends Path {
|
||||
|
||||
constructor( points ) {
|
||||
|
||||
super( points );
|
||||
|
||||
this.uuid = MathUtils.generateUUID();
|
||||
|
||||
this.type = 'Shape';
|
||||
|
||||
this.holes = [];
|
||||
|
||||
}
|
||||
|
||||
getPointsHoles( divisions ) {
|
||||
|
||||
const holesPts = [];
|
||||
|
||||
for ( let i = 0, l = this.holes.length; i < l; i ++ ) {
|
||||
|
||||
holesPts[ i ] = this.holes[ i ].getPoints( divisions );
|
||||
|
||||
}
|
||||
|
||||
return holesPts;
|
||||
|
||||
}
|
||||
|
||||
// get points of shape and holes (keypoints based on segments parameter)
|
||||
|
||||
extractPoints( divisions ) {
|
||||
|
||||
return {
|
||||
|
||||
shape: this.getPoints( divisions ),
|
||||
holes: this.getPointsHoles( divisions )
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
copy( source ) {
|
||||
|
||||
super.copy( source );
|
||||
|
||||
this.holes = [];
|
||||
|
||||
for ( let i = 0, l = source.holes.length; i < l; i ++ ) {
|
||||
|
||||
const hole = source.holes[ i ];
|
||||
|
||||
this.holes.push( hole.clone() );
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
|
||||
const data = super.toJSON();
|
||||
|
||||
data.uuid = this.uuid;
|
||||
data.holes = [];
|
||||
|
||||
for ( let i = 0, l = this.holes.length; i < l; i ++ ) {
|
||||
|
||||
const hole = this.holes[ i ];
|
||||
data.holes.push( hole.toJSON() );
|
||||
|
||||
}
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
fromJSON( json ) {
|
||||
|
||||
super.fromJSON( json );
|
||||
|
||||
this.uuid = json.uuid;
|
||||
this.holes = [];
|
||||
|
||||
for ( let i = 0, l = json.holes.length; i < l; i ++ ) {
|
||||
|
||||
const hole = json.holes[ i ];
|
||||
this.holes.push( new Path().fromJSON( hole ) );
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
export { Shape };
|
291
site/real_game/node_modules/three/src/extras/core/ShapePath.js
generated
vendored
Normal file
291
site/real_game/node_modules/three/src/extras/core/ShapePath.js
generated
vendored
Normal file
@ -0,0 +1,291 @@
|
||||
import { Color } from '../../math/Color.js';
|
||||
import { Path } from './Path.js';
|
||||
import { Shape } from './Shape.js';
|
||||
import { ShapeUtils } from '../ShapeUtils.js';
|
||||
|
||||
class ShapePath {
|
||||
|
||||
constructor() {
|
||||
|
||||
this.type = 'ShapePath';
|
||||
|
||||
this.color = new Color();
|
||||
|
||||
this.subPaths = [];
|
||||
this.currentPath = null;
|
||||
|
||||
}
|
||||
|
||||
moveTo( x, y ) {
|
||||
|
||||
this.currentPath = new Path();
|
||||
this.subPaths.push( this.currentPath );
|
||||
this.currentPath.moveTo( x, y );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
lineTo( x, y ) {
|
||||
|
||||
this.currentPath.lineTo( x, y );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
quadraticCurveTo( aCPx, aCPy, aX, aY ) {
|
||||
|
||||
this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
|
||||
|
||||
this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
splineThru( pts ) {
|
||||
|
||||
this.currentPath.splineThru( pts );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
toShapes( isCCW ) {
|
||||
|
||||
function toShapesNoHoles( inSubpaths ) {
|
||||
|
||||
const shapes = [];
|
||||
|
||||
for ( let i = 0, l = inSubpaths.length; i < l; i ++ ) {
|
||||
|
||||
const tmpPath = inSubpaths[ i ];
|
||||
|
||||
const tmpShape = new Shape();
|
||||
tmpShape.curves = tmpPath.curves;
|
||||
|
||||
shapes.push( tmpShape );
|
||||
|
||||
}
|
||||
|
||||
return shapes;
|
||||
|
||||
}
|
||||
|
||||
function isPointInsidePolygon( inPt, inPolygon ) {
|
||||
|
||||
const polyLen = inPolygon.length;
|
||||
|
||||
// inPt on polygon contour => immediate success or
|
||||
// toggling of inside/outside at every single! intersection point of an edge
|
||||
// with the horizontal line through inPt, left of inPt
|
||||
// not counting lowerY endpoints of edges and whole edges on that line
|
||||
let inside = false;
|
||||
for ( let p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) {
|
||||
|
||||
let edgeLowPt = inPolygon[ p ];
|
||||
let edgeHighPt = inPolygon[ q ];
|
||||
|
||||
let edgeDx = edgeHighPt.x - edgeLowPt.x;
|
||||
let edgeDy = edgeHighPt.y - edgeLowPt.y;
|
||||
|
||||
if ( Math.abs( edgeDy ) > Number.EPSILON ) {
|
||||
|
||||
// not parallel
|
||||
if ( edgeDy < 0 ) {
|
||||
|
||||
edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx;
|
||||
edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy;
|
||||
|
||||
}
|
||||
|
||||
if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue;
|
||||
|
||||
if ( inPt.y === edgeLowPt.y ) {
|
||||
|
||||
if ( inPt.x === edgeLowPt.x ) return true; // inPt is on contour ?
|
||||
// continue; // no intersection or edgeLowPt => doesn't count !!!
|
||||
|
||||
} else {
|
||||
|
||||
const perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y );
|
||||
if ( perpEdge === 0 ) return true; // inPt is on contour ?
|
||||
if ( perpEdge < 0 ) continue;
|
||||
inside = ! inside; // true intersection left of inPt
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// parallel or collinear
|
||||
if ( inPt.y !== edgeLowPt.y ) continue; // parallel
|
||||
// edge lies on the same horizontal line as inPt
|
||||
if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) ||
|
||||
( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour !
|
||||
// continue;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return inside;
|
||||
|
||||
}
|
||||
|
||||
const isClockWise = ShapeUtils.isClockWise;
|
||||
|
||||
const subPaths = this.subPaths;
|
||||
if ( subPaths.length === 0 ) return [];
|
||||
|
||||
let solid, tmpPath, tmpShape;
|
||||
const shapes = [];
|
||||
|
||||
if ( subPaths.length === 1 ) {
|
||||
|
||||
tmpPath = subPaths[ 0 ];
|
||||
tmpShape = new Shape();
|
||||
tmpShape.curves = tmpPath.curves;
|
||||
shapes.push( tmpShape );
|
||||
return shapes;
|
||||
|
||||
}
|
||||
|
||||
let holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() );
|
||||
holesFirst = isCCW ? ! holesFirst : holesFirst;
|
||||
|
||||
// console.log("Holes first", holesFirst);
|
||||
|
||||
const betterShapeHoles = [];
|
||||
const newShapes = [];
|
||||
let newShapeHoles = [];
|
||||
let mainIdx = 0;
|
||||
let tmpPoints;
|
||||
|
||||
newShapes[ mainIdx ] = undefined;
|
||||
newShapeHoles[ mainIdx ] = [];
|
||||
|
||||
for ( let i = 0, l = subPaths.length; i < l; i ++ ) {
|
||||
|
||||
tmpPath = subPaths[ i ];
|
||||
tmpPoints = tmpPath.getPoints();
|
||||
solid = isClockWise( tmpPoints );
|
||||
solid = isCCW ? ! solid : solid;
|
||||
|
||||
if ( solid ) {
|
||||
|
||||
if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) ) mainIdx ++;
|
||||
|
||||
newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints };
|
||||
newShapes[ mainIdx ].s.curves = tmpPath.curves;
|
||||
|
||||
if ( holesFirst ) mainIdx ++;
|
||||
newShapeHoles[ mainIdx ] = [];
|
||||
|
||||
//console.log('cw', i);
|
||||
|
||||
} else {
|
||||
|
||||
newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } );
|
||||
|
||||
//console.log('ccw', i);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// only Holes? -> probably all Shapes with wrong orientation
|
||||
if ( ! newShapes[ 0 ] ) return toShapesNoHoles( subPaths );
|
||||
|
||||
|
||||
if ( newShapes.length > 1 ) {
|
||||
|
||||
let ambiguous = false;
|
||||
let toChange = 0;
|
||||
|
||||
for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
|
||||
|
||||
betterShapeHoles[ sIdx ] = [];
|
||||
|
||||
}
|
||||
|
||||
for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
|
||||
|
||||
const sho = newShapeHoles[ sIdx ];
|
||||
|
||||
for ( let hIdx = 0; hIdx < sho.length; hIdx ++ ) {
|
||||
|
||||
const ho = sho[ hIdx ];
|
||||
let hole_unassigned = true;
|
||||
|
||||
for ( let s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) {
|
||||
|
||||
if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) {
|
||||
|
||||
if ( sIdx !== s2Idx ) toChange ++;
|
||||
|
||||
if ( hole_unassigned ) {
|
||||
|
||||
hole_unassigned = false;
|
||||
betterShapeHoles[ s2Idx ].push( ho );
|
||||
|
||||
} else {
|
||||
|
||||
ambiguous = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( hole_unassigned ) {
|
||||
|
||||
betterShapeHoles[ sIdx ].push( ho );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( toChange > 0 && ambiguous === false ) {
|
||||
|
||||
newShapeHoles = betterShapeHoles;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let tmpHoles;
|
||||
|
||||
for ( let i = 0, il = newShapes.length; i < il; i ++ ) {
|
||||
|
||||
tmpShape = newShapes[ i ].s;
|
||||
shapes.push( tmpShape );
|
||||
tmpHoles = newShapeHoles[ i ];
|
||||
|
||||
for ( let j = 0, jl = tmpHoles.length; j < jl; j ++ ) {
|
||||
|
||||
tmpShape.holes.push( tmpHoles[ j ].h );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//console.log("shape", shapes);
|
||||
|
||||
return shapes;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
export { ShapePath };
|
17
site/real_game/node_modules/three/src/extras/curves/ArcCurve.js
generated
vendored
Normal file
17
site/real_game/node_modules/three/src/extras/curves/ArcCurve.js
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
import { EllipseCurve } from './EllipseCurve.js';
|
||||
|
||||
class ArcCurve extends EllipseCurve {
|
||||
|
||||
constructor( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
|
||||
|
||||
super( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
|
||||
|
||||
this.isArcCurve = true;
|
||||
|
||||
this.type = 'ArcCurve';
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { ArcCurve };
|
255
site/real_game/node_modules/three/src/extras/curves/CatmullRomCurve3.js
generated
vendored
Normal file
255
site/real_game/node_modules/three/src/extras/curves/CatmullRomCurve3.js
generated
vendored
Normal file
@ -0,0 +1,255 @@
|
||||
import { Vector3 } from '../../math/Vector3.js';
|
||||
import { Curve } from '../core/Curve.js';
|
||||
|
||||
/**
|
||||
* Centripetal CatmullRom Curve - which is useful for avoiding
|
||||
* cusps and self-intersections in non-uniform catmull rom curves.
|
||||
* http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf
|
||||
*
|
||||
* curve.type accepts centripetal(default), chordal and catmullrom
|
||||
* curve.tension is used for catmullrom which defaults to 0.5
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
Based on an optimized c++ solution in
|
||||
- http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/
|
||||
- http://ideone.com/NoEbVM
|
||||
|
||||
This CubicPoly class could be used for reusing some variables and calculations,
|
||||
but for three.js curve use, it could be possible inlined and flatten into a single function call
|
||||
which can be placed in CurveUtils.
|
||||
*/
|
||||
|
||||
function CubicPoly() {
|
||||
|
||||
let c0 = 0, c1 = 0, c2 = 0, c3 = 0;
|
||||
|
||||
/*
|
||||
* Compute coefficients for a cubic polynomial
|
||||
* p(s) = c0 + c1*s + c2*s^2 + c3*s^3
|
||||
* such that
|
||||
* p(0) = x0, p(1) = x1
|
||||
* and
|
||||
* p'(0) = t0, p'(1) = t1.
|
||||
*/
|
||||
function init( x0, x1, t0, t1 ) {
|
||||
|
||||
c0 = x0;
|
||||
c1 = t0;
|
||||
c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1;
|
||||
c3 = 2 * x0 - 2 * x1 + t0 + t1;
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
initCatmullRom: function ( x0, x1, x2, x3, tension ) {
|
||||
|
||||
init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) );
|
||||
|
||||
},
|
||||
|
||||
initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) {
|
||||
|
||||
// compute tangents when parameterized in [t1,t2]
|
||||
let t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1;
|
||||
let t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2;
|
||||
|
||||
// rescale tangents for parametrization in [0,1]
|
||||
t1 *= dt1;
|
||||
t2 *= dt1;
|
||||
|
||||
init( x1, x2, t1, t2 );
|
||||
|
||||
},
|
||||
|
||||
calc: function ( t ) {
|
||||
|
||||
const t2 = t * t;
|
||||
const t3 = t2 * t;
|
||||
return c0 + c1 * t + c2 * t2 + c3 * t3;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
const tmp = /*@__PURE__*/ new Vector3();
|
||||
const px = /*@__PURE__*/ new CubicPoly();
|
||||
const py = /*@__PURE__*/ new CubicPoly();
|
||||
const pz = /*@__PURE__*/ new CubicPoly();
|
||||
|
||||
class CatmullRomCurve3 extends Curve {
|
||||
|
||||
constructor( points = [], closed = false, curveType = 'centripetal', tension = 0.5 ) {
|
||||
|
||||
super();
|
||||
|
||||
this.isCatmullRomCurve3 = true;
|
||||
|
||||
this.type = 'CatmullRomCurve3';
|
||||
|
||||
this.points = points;
|
||||
this.closed = closed;
|
||||
this.curveType = curveType;
|
||||
this.tension = tension;
|
||||
|
||||
}
|
||||
|
||||
getPoint( t, optionalTarget = new Vector3() ) {
|
||||
|
||||
const point = optionalTarget;
|
||||
|
||||
const points = this.points;
|
||||
const l = points.length;
|
||||
|
||||
const p = ( l - ( this.closed ? 0 : 1 ) ) * t;
|
||||
let intPoint = Math.floor( p );
|
||||
let weight = p - intPoint;
|
||||
|
||||
if ( this.closed ) {
|
||||
|
||||
intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l;
|
||||
|
||||
} else if ( weight === 0 && intPoint === l - 1 ) {
|
||||
|
||||
intPoint = l - 2;
|
||||
weight = 1;
|
||||
|
||||
}
|
||||
|
||||
let p0, p3; // 4 points (p1 & p2 defined below)
|
||||
|
||||
if ( this.closed || intPoint > 0 ) {
|
||||
|
||||
p0 = points[ ( intPoint - 1 ) % l ];
|
||||
|
||||
} else {
|
||||
|
||||
// extrapolate first point
|
||||
tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] );
|
||||
p0 = tmp;
|
||||
|
||||
}
|
||||
|
||||
const p1 = points[ intPoint % l ];
|
||||
const p2 = points[ ( intPoint + 1 ) % l ];
|
||||
|
||||
if ( this.closed || intPoint + 2 < l ) {
|
||||
|
||||
p3 = points[ ( intPoint + 2 ) % l ];
|
||||
|
||||
} else {
|
||||
|
||||
// extrapolate last point
|
||||
tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] );
|
||||
p3 = tmp;
|
||||
|
||||
}
|
||||
|
||||
if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) {
|
||||
|
||||
// init Centripetal / Chordal Catmull-Rom
|
||||
const pow = this.curveType === 'chordal' ? 0.5 : 0.25;
|
||||
let dt0 = Math.pow( p0.distanceToSquared( p1 ), pow );
|
||||
let dt1 = Math.pow( p1.distanceToSquared( p2 ), pow );
|
||||
let dt2 = Math.pow( p2.distanceToSquared( p3 ), pow );
|
||||
|
||||
// safety check for repeated points
|
||||
if ( dt1 < 1e-4 ) dt1 = 1.0;
|
||||
if ( dt0 < 1e-4 ) dt0 = dt1;
|
||||
if ( dt2 < 1e-4 ) dt2 = dt1;
|
||||
|
||||
px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 );
|
||||
py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 );
|
||||
pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 );
|
||||
|
||||
} else if ( this.curveType === 'catmullrom' ) {
|
||||
|
||||
px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension );
|
||||
py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension );
|
||||
pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension );
|
||||
|
||||
}
|
||||
|
||||
point.set(
|
||||
px.calc( weight ),
|
||||
py.calc( weight ),
|
||||
pz.calc( weight )
|
||||
);
|
||||
|
||||
return point;
|
||||
|
||||
}
|
||||
|
||||
copy( source ) {
|
||||
|
||||
super.copy( source );
|
||||
|
||||
this.points = [];
|
||||
|
||||
for ( let i = 0, l = source.points.length; i < l; i ++ ) {
|
||||
|
||||
const point = source.points[ i ];
|
||||
|
||||
this.points.push( point.clone() );
|
||||
|
||||
}
|
||||
|
||||
this.closed = source.closed;
|
||||
this.curveType = source.curveType;
|
||||
this.tension = source.tension;
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
|
||||
const data = super.toJSON();
|
||||
|
||||
data.points = [];
|
||||
|
||||
for ( let i = 0, l = this.points.length; i < l; i ++ ) {
|
||||
|
||||
const point = this.points[ i ];
|
||||
data.points.push( point.toArray() );
|
||||
|
||||
}
|
||||
|
||||
data.closed = this.closed;
|
||||
data.curveType = this.curveType;
|
||||
data.tension = this.tension;
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
fromJSON( json ) {
|
||||
|
||||
super.fromJSON( json );
|
||||
|
||||
this.points = [];
|
||||
|
||||
for ( let i = 0, l = json.points.length; i < l; i ++ ) {
|
||||
|
||||
const point = json.points[ i ];
|
||||
this.points.push( new Vector3().fromArray( point ) );
|
||||
|
||||
}
|
||||
|
||||
this.closed = json.closed;
|
||||
this.curveType = json.curveType;
|
||||
this.tension = json.tension;
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { CatmullRomCurve3 };
|
78
site/real_game/node_modules/three/src/extras/curves/CubicBezierCurve.js
generated
vendored
Normal file
78
site/real_game/node_modules/three/src/extras/curves/CubicBezierCurve.js
generated
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
import { Curve } from '../core/Curve.js';
|
||||
import { CubicBezier } from '../core/Interpolations.js';
|
||||
import { Vector2 } from '../../math/Vector2.js';
|
||||
|
||||
class CubicBezierCurve extends Curve {
|
||||
|
||||
constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2(), v3 = new Vector2() ) {
|
||||
|
||||
super();
|
||||
|
||||
this.isCubicBezierCurve = true;
|
||||
|
||||
this.type = 'CubicBezierCurve';
|
||||
|
||||
this.v0 = v0;
|
||||
this.v1 = v1;
|
||||
this.v2 = v2;
|
||||
this.v3 = v3;
|
||||
|
||||
}
|
||||
|
||||
getPoint( t, optionalTarget = new Vector2() ) {
|
||||
|
||||
const point = optionalTarget;
|
||||
|
||||
const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
|
||||
|
||||
point.set(
|
||||
CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
|
||||
CubicBezier( t, v0.y, v1.y, v2.y, v3.y )
|
||||
);
|
||||
|
||||
return point;
|
||||
|
||||
}
|
||||
|
||||
copy( source ) {
|
||||
|
||||
super.copy( source );
|
||||
|
||||
this.v0.copy( source.v0 );
|
||||
this.v1.copy( source.v1 );
|
||||
this.v2.copy( source.v2 );
|
||||
this.v3.copy( source.v3 );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
|
||||
const data = super.toJSON();
|
||||
|
||||
data.v0 = this.v0.toArray();
|
||||
data.v1 = this.v1.toArray();
|
||||
data.v2 = this.v2.toArray();
|
||||
data.v3 = this.v3.toArray();
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
fromJSON( json ) {
|
||||
|
||||
super.fromJSON( json );
|
||||
|
||||
this.v0.fromArray( json.v0 );
|
||||
this.v1.fromArray( json.v1 );
|
||||
this.v2.fromArray( json.v2 );
|
||||
this.v3.fromArray( json.v3 );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { CubicBezierCurve };
|
79
site/real_game/node_modules/three/src/extras/curves/CubicBezierCurve3.js
generated
vendored
Normal file
79
site/real_game/node_modules/three/src/extras/curves/CubicBezierCurve3.js
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
import { Curve } from '../core/Curve.js';
|
||||
import { CubicBezier } from '../core/Interpolations.js';
|
||||
import { Vector3 } from '../../math/Vector3.js';
|
||||
|
||||
class CubicBezierCurve3 extends Curve {
|
||||
|
||||
constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3(), v3 = new Vector3() ) {
|
||||
|
||||
super();
|
||||
|
||||
this.isCubicBezierCurve3 = true;
|
||||
|
||||
this.type = 'CubicBezierCurve3';
|
||||
|
||||
this.v0 = v0;
|
||||
this.v1 = v1;
|
||||
this.v2 = v2;
|
||||
this.v3 = v3;
|
||||
|
||||
}
|
||||
|
||||
getPoint( t, optionalTarget = new Vector3() ) {
|
||||
|
||||
const point = optionalTarget;
|
||||
|
||||
const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
|
||||
|
||||
point.set(
|
||||
CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
|
||||
CubicBezier( t, v0.y, v1.y, v2.y, v3.y ),
|
||||
CubicBezier( t, v0.z, v1.z, v2.z, v3.z )
|
||||
);
|
||||
|
||||
return point;
|
||||
|
||||
}
|
||||
|
||||
copy( source ) {
|
||||
|
||||
super.copy( source );
|
||||
|
||||
this.v0.copy( source.v0 );
|
||||
this.v1.copy( source.v1 );
|
||||
this.v2.copy( source.v2 );
|
||||
this.v3.copy( source.v3 );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
|
||||
const data = super.toJSON();
|
||||
|
||||
data.v0 = this.v0.toArray();
|
||||
data.v1 = this.v1.toArray();
|
||||
data.v2 = this.v2.toArray();
|
||||
data.v3 = this.v3.toArray();
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
fromJSON( json ) {
|
||||
|
||||
super.fromJSON( json );
|
||||
|
||||
this.v0.fromArray( json.v0 );
|
||||
this.v1.fromArray( json.v1 );
|
||||
this.v2.fromArray( json.v2 );
|
||||
this.v3.fromArray( json.v3 );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { CubicBezierCurve3 };
|
10
site/real_game/node_modules/three/src/extras/curves/Curves.js
generated
vendored
Normal file
10
site/real_game/node_modules/three/src/extras/curves/Curves.js
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
export { ArcCurve } from './ArcCurve.js';
|
||||
export { CatmullRomCurve3 } from './CatmullRomCurve3.js';
|
||||
export { CubicBezierCurve } from './CubicBezierCurve.js';
|
||||
export { CubicBezierCurve3 } from './CubicBezierCurve3.js';
|
||||
export { EllipseCurve } from './EllipseCurve.js';
|
||||
export { LineCurve } from './LineCurve.js';
|
||||
export { LineCurve3 } from './LineCurve3.js';
|
||||
export { QuadraticBezierCurve } from './QuadraticBezierCurve.js';
|
||||
export { QuadraticBezierCurve3 } from './QuadraticBezierCurve3.js';
|
||||
export { SplineCurve } from './SplineCurve.js';
|
156
site/real_game/node_modules/three/src/extras/curves/EllipseCurve.js
generated
vendored
Normal file
156
site/real_game/node_modules/three/src/extras/curves/EllipseCurve.js
generated
vendored
Normal file
@ -0,0 +1,156 @@
|
||||
import { Curve } from '../core/Curve.js';
|
||||
import { Vector2 } from '../../math/Vector2.js';
|
||||
|
||||
class EllipseCurve extends Curve {
|
||||
|
||||
constructor( aX = 0, aY = 0, xRadius = 1, yRadius = 1, aStartAngle = 0, aEndAngle = Math.PI * 2, aClockwise = false, aRotation = 0 ) {
|
||||
|
||||
super();
|
||||
|
||||
this.isEllipseCurve = true;
|
||||
|
||||
this.type = 'EllipseCurve';
|
||||
|
||||
this.aX = aX;
|
||||
this.aY = aY;
|
||||
|
||||
this.xRadius = xRadius;
|
||||
this.yRadius = yRadius;
|
||||
|
||||
this.aStartAngle = aStartAngle;
|
||||
this.aEndAngle = aEndAngle;
|
||||
|
||||
this.aClockwise = aClockwise;
|
||||
|
||||
this.aRotation = aRotation;
|
||||
|
||||
}
|
||||
|
||||
getPoint( t, optionalTarget = new Vector2() ) {
|
||||
|
||||
const point = optionalTarget;
|
||||
|
||||
const twoPi = Math.PI * 2;
|
||||
let deltaAngle = this.aEndAngle - this.aStartAngle;
|
||||
const samePoints = Math.abs( deltaAngle ) < Number.EPSILON;
|
||||
|
||||
// ensures that deltaAngle is 0 .. 2 PI
|
||||
while ( deltaAngle < 0 ) deltaAngle += twoPi;
|
||||
while ( deltaAngle > twoPi ) deltaAngle -= twoPi;
|
||||
|
||||
if ( deltaAngle < Number.EPSILON ) {
|
||||
|
||||
if ( samePoints ) {
|
||||
|
||||
deltaAngle = 0;
|
||||
|
||||
} else {
|
||||
|
||||
deltaAngle = twoPi;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( this.aClockwise === true && ! samePoints ) {
|
||||
|
||||
if ( deltaAngle === twoPi ) {
|
||||
|
||||
deltaAngle = - twoPi;
|
||||
|
||||
} else {
|
||||
|
||||
deltaAngle = deltaAngle - twoPi;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const angle = this.aStartAngle + t * deltaAngle;
|
||||
let x = this.aX + this.xRadius * Math.cos( angle );
|
||||
let y = this.aY + this.yRadius * Math.sin( angle );
|
||||
|
||||
if ( this.aRotation !== 0 ) {
|
||||
|
||||
const cos = Math.cos( this.aRotation );
|
||||
const sin = Math.sin( this.aRotation );
|
||||
|
||||
const tx = x - this.aX;
|
||||
const ty = y - this.aY;
|
||||
|
||||
// Rotate the point about the center of the ellipse.
|
||||
x = tx * cos - ty * sin + this.aX;
|
||||
y = tx * sin + ty * cos + this.aY;
|
||||
|
||||
}
|
||||
|
||||
return point.set( x, y );
|
||||
|
||||
}
|
||||
|
||||
copy( source ) {
|
||||
|
||||
super.copy( source );
|
||||
|
||||
this.aX = source.aX;
|
||||
this.aY = source.aY;
|
||||
|
||||
this.xRadius = source.xRadius;
|
||||
this.yRadius = source.yRadius;
|
||||
|
||||
this.aStartAngle = source.aStartAngle;
|
||||
this.aEndAngle = source.aEndAngle;
|
||||
|
||||
this.aClockwise = source.aClockwise;
|
||||
|
||||
this.aRotation = source.aRotation;
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
|
||||
const data = super.toJSON();
|
||||
|
||||
data.aX = this.aX;
|
||||
data.aY = this.aY;
|
||||
|
||||
data.xRadius = this.xRadius;
|
||||
data.yRadius = this.yRadius;
|
||||
|
||||
data.aStartAngle = this.aStartAngle;
|
||||
data.aEndAngle = this.aEndAngle;
|
||||
|
||||
data.aClockwise = this.aClockwise;
|
||||
|
||||
data.aRotation = this.aRotation;
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
fromJSON( json ) {
|
||||
|
||||
super.fromJSON( json );
|
||||
|
||||
this.aX = json.aX;
|
||||
this.aY = json.aY;
|
||||
|
||||
this.xRadius = json.xRadius;
|
||||
this.yRadius = json.yRadius;
|
||||
|
||||
this.aStartAngle = json.aStartAngle;
|
||||
this.aEndAngle = json.aEndAngle;
|
||||
|
||||
this.aClockwise = json.aClockwise;
|
||||
|
||||
this.aRotation = json.aRotation;
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { EllipseCurve };
|
92
site/real_game/node_modules/three/src/extras/curves/LineCurve.js
generated
vendored
Normal file
92
site/real_game/node_modules/three/src/extras/curves/LineCurve.js
generated
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
import { Vector2 } from '../../math/Vector2.js';
|
||||
import { Curve } from '../core/Curve.js';
|
||||
|
||||
class LineCurve extends Curve {
|
||||
|
||||
constructor( v1 = new Vector2(), v2 = new Vector2() ) {
|
||||
|
||||
super();
|
||||
|
||||
this.isLineCurve = true;
|
||||
|
||||
this.type = 'LineCurve';
|
||||
|
||||
this.v1 = v1;
|
||||
this.v2 = v2;
|
||||
|
||||
}
|
||||
|
||||
getPoint( t, optionalTarget = new Vector2() ) {
|
||||
|
||||
const point = optionalTarget;
|
||||
|
||||
if ( t === 1 ) {
|
||||
|
||||
point.copy( this.v2 );
|
||||
|
||||
} else {
|
||||
|
||||
point.copy( this.v2 ).sub( this.v1 );
|
||||
point.multiplyScalar( t ).add( this.v1 );
|
||||
|
||||
}
|
||||
|
||||
return point;
|
||||
|
||||
}
|
||||
|
||||
// Line curve is linear, so we can overwrite default getPointAt
|
||||
getPointAt( u, optionalTarget ) {
|
||||
|
||||
return this.getPoint( u, optionalTarget );
|
||||
|
||||
}
|
||||
|
||||
getTangent( t, optionalTarget = new Vector2() ) {
|
||||
|
||||
return optionalTarget.subVectors( this.v2, this.v1 ).normalize();
|
||||
|
||||
}
|
||||
|
||||
getTangentAt( u, optionalTarget ) {
|
||||
|
||||
return this.getTangent( u, optionalTarget );
|
||||
|
||||
}
|
||||
|
||||
copy( source ) {
|
||||
|
||||
super.copy( source );
|
||||
|
||||
this.v1.copy( source.v1 );
|
||||
this.v2.copy( source.v2 );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
|
||||
const data = super.toJSON();
|
||||
|
||||
data.v1 = this.v1.toArray();
|
||||
data.v2 = this.v2.toArray();
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
fromJSON( json ) {
|
||||
|
||||
super.fromJSON( json );
|
||||
|
||||
this.v1.fromArray( json.v1 );
|
||||
this.v2.fromArray( json.v2 );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { LineCurve };
|
92
site/real_game/node_modules/three/src/extras/curves/LineCurve3.js
generated
vendored
Normal file
92
site/real_game/node_modules/three/src/extras/curves/LineCurve3.js
generated
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
import { Vector3 } from '../../math/Vector3.js';
|
||||
import { Curve } from '../core/Curve.js';
|
||||
|
||||
class LineCurve3 extends Curve {
|
||||
|
||||
constructor( v1 = new Vector3(), v2 = new Vector3() ) {
|
||||
|
||||
super();
|
||||
|
||||
this.isLineCurve3 = true;
|
||||
|
||||
this.type = 'LineCurve3';
|
||||
|
||||
this.v1 = v1;
|
||||
this.v2 = v2;
|
||||
|
||||
}
|
||||
|
||||
getPoint( t, optionalTarget = new Vector3() ) {
|
||||
|
||||
const point = optionalTarget;
|
||||
|
||||
if ( t === 1 ) {
|
||||
|
||||
point.copy( this.v2 );
|
||||
|
||||
} else {
|
||||
|
||||
point.copy( this.v2 ).sub( this.v1 );
|
||||
point.multiplyScalar( t ).add( this.v1 );
|
||||
|
||||
}
|
||||
|
||||
return point;
|
||||
|
||||
}
|
||||
|
||||
// Line curve is linear, so we can overwrite default getPointAt
|
||||
getPointAt( u, optionalTarget ) {
|
||||
|
||||
return this.getPoint( u, optionalTarget );
|
||||
|
||||
}
|
||||
|
||||
getTangent( t, optionalTarget = new Vector3() ) {
|
||||
|
||||
return optionalTarget.subVectors( this.v2, this.v1 ).normalize();
|
||||
|
||||
}
|
||||
|
||||
getTangentAt( u, optionalTarget ) {
|
||||
|
||||
return this.getTangent( u, optionalTarget );
|
||||
|
||||
}
|
||||
|
||||
copy( source ) {
|
||||
|
||||
super.copy( source );
|
||||
|
||||
this.v1.copy( source.v1 );
|
||||
this.v2.copy( source.v2 );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
|
||||
const data = super.toJSON();
|
||||
|
||||
data.v1 = this.v1.toArray();
|
||||
data.v2 = this.v2.toArray();
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
fromJSON( json ) {
|
||||
|
||||
super.fromJSON( json );
|
||||
|
||||
this.v1.fromArray( json.v1 );
|
||||
this.v2.fromArray( json.v2 );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { LineCurve3 };
|
74
site/real_game/node_modules/three/src/extras/curves/QuadraticBezierCurve.js
generated
vendored
Normal file
74
site/real_game/node_modules/three/src/extras/curves/QuadraticBezierCurve.js
generated
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
import { Curve } from '../core/Curve.js';
|
||||
import { QuadraticBezier } from '../core/Interpolations.js';
|
||||
import { Vector2 } from '../../math/Vector2.js';
|
||||
|
||||
class QuadraticBezierCurve extends Curve {
|
||||
|
||||
constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2() ) {
|
||||
|
||||
super();
|
||||
|
||||
this.isQuadraticBezierCurve = true;
|
||||
|
||||
this.type = 'QuadraticBezierCurve';
|
||||
|
||||
this.v0 = v0;
|
||||
this.v1 = v1;
|
||||
this.v2 = v2;
|
||||
|
||||
}
|
||||
|
||||
getPoint( t, optionalTarget = new Vector2() ) {
|
||||
|
||||
const point = optionalTarget;
|
||||
|
||||
const v0 = this.v0, v1 = this.v1, v2 = this.v2;
|
||||
|
||||
point.set(
|
||||
QuadraticBezier( t, v0.x, v1.x, v2.x ),
|
||||
QuadraticBezier( t, v0.y, v1.y, v2.y )
|
||||
);
|
||||
|
||||
return point;
|
||||
|
||||
}
|
||||
|
||||
copy( source ) {
|
||||
|
||||
super.copy( source );
|
||||
|
||||
this.v0.copy( source.v0 );
|
||||
this.v1.copy( source.v1 );
|
||||
this.v2.copy( source.v2 );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
|
||||
const data = super.toJSON();
|
||||
|
||||
data.v0 = this.v0.toArray();
|
||||
data.v1 = this.v1.toArray();
|
||||
data.v2 = this.v2.toArray();
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
fromJSON( json ) {
|
||||
|
||||
super.fromJSON( json );
|
||||
|
||||
this.v0.fromArray( json.v0 );
|
||||
this.v1.fromArray( json.v1 );
|
||||
this.v2.fromArray( json.v2 );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { QuadraticBezierCurve };
|
75
site/real_game/node_modules/three/src/extras/curves/QuadraticBezierCurve3.js
generated
vendored
Normal file
75
site/real_game/node_modules/three/src/extras/curves/QuadraticBezierCurve3.js
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
import { Curve } from '../core/Curve.js';
|
||||
import { QuadraticBezier } from '../core/Interpolations.js';
|
||||
import { Vector3 } from '../../math/Vector3.js';
|
||||
|
||||
class QuadraticBezierCurve3 extends Curve {
|
||||
|
||||
constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3() ) {
|
||||
|
||||
super();
|
||||
|
||||
this.isQuadraticBezierCurve3 = true;
|
||||
|
||||
this.type = 'QuadraticBezierCurve3';
|
||||
|
||||
this.v0 = v0;
|
||||
this.v1 = v1;
|
||||
this.v2 = v2;
|
||||
|
||||
}
|
||||
|
||||
getPoint( t, optionalTarget = new Vector3() ) {
|
||||
|
||||
const point = optionalTarget;
|
||||
|
||||
const v0 = this.v0, v1 = this.v1, v2 = this.v2;
|
||||
|
||||
point.set(
|
||||
QuadraticBezier( t, v0.x, v1.x, v2.x ),
|
||||
QuadraticBezier( t, v0.y, v1.y, v2.y ),
|
||||
QuadraticBezier( t, v0.z, v1.z, v2.z )
|
||||
);
|
||||
|
||||
return point;
|
||||
|
||||
}
|
||||
|
||||
copy( source ) {
|
||||
|
||||
super.copy( source );
|
||||
|
||||
this.v0.copy( source.v0 );
|
||||
this.v1.copy( source.v1 );
|
||||
this.v2.copy( source.v2 );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
|
||||
const data = super.toJSON();
|
||||
|
||||
data.v0 = this.v0.toArray();
|
||||
data.v1 = this.v1.toArray();
|
||||
data.v2 = this.v2.toArray();
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
fromJSON( json ) {
|
||||
|
||||
super.fromJSON( json );
|
||||
|
||||
this.v0.fromArray( json.v0 );
|
||||
this.v1.fromArray( json.v1 );
|
||||
this.v2.fromArray( json.v2 );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { QuadraticBezierCurve3 };
|
97
site/real_game/node_modules/three/src/extras/curves/SplineCurve.js
generated
vendored
Normal file
97
site/real_game/node_modules/three/src/extras/curves/SplineCurve.js
generated
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
import { Curve } from '../core/Curve.js';
|
||||
import { CatmullRom } from '../core/Interpolations.js';
|
||||
import { Vector2 } from '../../math/Vector2.js';
|
||||
|
||||
class SplineCurve extends Curve {
|
||||
|
||||
constructor( points = [] ) {
|
||||
|
||||
super();
|
||||
|
||||
this.isSplineCurve = true;
|
||||
|
||||
this.type = 'SplineCurve';
|
||||
|
||||
this.points = points;
|
||||
|
||||
}
|
||||
|
||||
getPoint( t, optionalTarget = new Vector2() ) {
|
||||
|
||||
const point = optionalTarget;
|
||||
|
||||
const points = this.points;
|
||||
const p = ( points.length - 1 ) * t;
|
||||
|
||||
const intPoint = Math.floor( p );
|
||||
const weight = p - intPoint;
|
||||
|
||||
const p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ];
|
||||
const p1 = points[ intPoint ];
|
||||
const p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ];
|
||||
const p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ];
|
||||
|
||||
point.set(
|
||||
CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ),
|
||||
CatmullRom( weight, p0.y, p1.y, p2.y, p3.y )
|
||||
);
|
||||
|
||||
return point;
|
||||
|
||||
}
|
||||
|
||||
copy( source ) {
|
||||
|
||||
super.copy( source );
|
||||
|
||||
this.points = [];
|
||||
|
||||
for ( let i = 0, l = source.points.length; i < l; i ++ ) {
|
||||
|
||||
const point = source.points[ i ];
|
||||
|
||||
this.points.push( point.clone() );
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
|
||||
const data = super.toJSON();
|
||||
|
||||
data.points = [];
|
||||
|
||||
for ( let i = 0, l = this.points.length; i < l; i ++ ) {
|
||||
|
||||
const point = this.points[ i ];
|
||||
data.points.push( point.toArray() );
|
||||
|
||||
}
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
fromJSON( json ) {
|
||||
|
||||
super.fromJSON( json );
|
||||
|
||||
this.points = [];
|
||||
|
||||
for ( let i = 0, l = json.points.length; i < l; i ++ ) {
|
||||
|
||||
const point = json.points[ i ];
|
||||
this.points.push( new Vector2().fromArray( point ) );
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { SplineCurve };
|
Reference in New Issue
Block a user