Initial commit of ship project
This commit is contained in:
commit
1e74491310
1
.env.example
Normal file
1
.env.example
Normal file
@ -0,0 +1 @@
|
||||
APP_BASE_PATH = /ship
|
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
.env
|
||||
*.log
|
||||
.idea/
|
||||
node_modules/
|
||||
1.bat
|
1689
package-lock.json
generated
Normal file
1689
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
13
package.json
Normal file
13
package.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"canvas": "^2.11.2",
|
||||
"dotenv": "^16.5.0",
|
||||
"ejs": "^3.1.8",
|
||||
"express": "^4.18.2",
|
||||
"mysql2": "^3.2.0",
|
||||
"path": "^0.12.7",
|
||||
"sequelize": "^6.29.1",
|
||||
"socket.io": "^4.6.1",
|
||||
"sweetalert2": "^11.7.3"
|
||||
}
|
||||
}
|
BIN
public/Rock_color.png
Normal file
BIN
public/Rock_color.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 MiB |
BIN
public/Rock_color2.png
Normal file
BIN
public/Rock_color2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.0 MiB |
BIN
public/Walking.fbx
Normal file
BIN
public/Walking.fbx
Normal file
Binary file not shown.
3
public/assets/models.js
Normal file
3
public/assets/models.js
Normal file
File diff suppressed because one or more lines are too long
2
public/assets/models_man.js
Normal file
2
public/assets/models_man.js
Normal file
File diff suppressed because one or more lines are too long
4
public/assets/textures.js
Normal file
4
public/assets/textures.js
Normal file
File diff suppressed because one or more lines are too long
BIN
public/blue_whale.fbx
Normal file
BIN
public/blue_whale.fbx
Normal file
Binary file not shown.
142
public/css/style.css
Normal file
142
public/css/style.css
Normal file
@ -0,0 +1,142 @@
|
||||
html, body {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
}
|
||||
#c {
|
||||
width: 750px;
|
||||
height: 500px;
|
||||
display: block;
|
||||
}
|
||||
#canvas_temp, #canvas_temp2{
|
||||
display: none;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
#canvas_temp{
|
||||
z-index: 1;
|
||||
}
|
||||
.top-div {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
font-family: "Arial";
|
||||
font-size: 10px;
|
||||
background: black;
|
||||
color: white;
|
||||
}
|
||||
.top-div::after {
|
||||
content: "Загрузка";
|
||||
display: flex;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
animation: loading 1s ease-in-out infinite;
|
||||
font-size: 30px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
@keyframes loading{
|
||||
0% {
|
||||
content: "Загрузка\00a0\00a0\00a0";
|
||||
}
|
||||
35% {
|
||||
content: "Загрузка.\00a0\00a0";
|
||||
}
|
||||
65% {
|
||||
content: "Загрузка..\00a0";
|
||||
}
|
||||
100% {
|
||||
content: "Загрузка...";
|
||||
}
|
||||
}
|
||||
a{
|
||||
margin-top: 10px;
|
||||
background: lightgray;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
font-size: 15px;
|
||||
line-height: 15px;
|
||||
border: 2px solid gray;
|
||||
}
|
||||
.container{
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.big_container{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
.menu_ico{
|
||||
width: 21px;
|
||||
height: 21px;
|
||||
position:absolute;
|
||||
top: 10px;
|
||||
right: 22px;
|
||||
z-index: 2;
|
||||
cursor: pointer;
|
||||
}
|
||||
.menu_ico > div:first-child, .menu_ico > div:first-child:after, .menu_ico > div:first-child:before{
|
||||
width: 12px;
|
||||
height: 2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.menu_ico > div:first-child{
|
||||
position:absolute;
|
||||
margin-left: 4px;
|
||||
display: inline;
|
||||
background: darkgray;
|
||||
transform: scale(1.7);
|
||||
}
|
||||
.menu_ico > div:first-child:after{
|
||||
position:absolute;
|
||||
content: "";
|
||||
background: darkgray;
|
||||
top: 4px;
|
||||
left: 0px;
|
||||
}
|
||||
.menu_ico > div:first-child:before{
|
||||
position:absolute;
|
||||
content: "";
|
||||
background: darkgray;
|
||||
top: 8px;
|
||||
left: 0px;
|
||||
}
|
||||
.slidecontainer {
|
||||
display: none;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
background: white;
|
||||
z-index: 1;
|
||||
}
|
||||
.menu_ico:hover .slidecontainer{
|
||||
display: flex;
|
||||
}
|
||||
#checkbox-container{
|
||||
display: grid;
|
||||
columns: 2;
|
||||
row-gap: 10px;
|
||||
padding-left: 20px;
|
||||
}
|
||||
.sheet{
|
||||
width: 400px;
|
||||
}
|
||||
.hide{
|
||||
display: none;
|
||||
}
|
4074
public/scripts/FBXLoader.js
Normal file
4074
public/scripts/FBXLoader.js
Normal file
File diff suppressed because it is too large
Load Diff
4507
public/scripts/GLTFLoader.js
Normal file
4507
public/scripts/GLTFLoader.js
Normal file
File diff suppressed because it is too large
Load Diff
451
public/scripts/NURBSCurve.js
Normal file
451
public/scripts/NURBSCurve.js
Normal file
@ -0,0 +1,451 @@
|
||||
|
||||
function findSpan( p, u, U ) {
|
||||
|
||||
const n = U.length - p - 1;
|
||||
|
||||
if ( u >= U[ n ] ) {
|
||||
|
||||
return n - 1;
|
||||
|
||||
}
|
||||
|
||||
if ( u <= U[ p ] ) {
|
||||
|
||||
return p;
|
||||
|
||||
}
|
||||
|
||||
let low = p;
|
||||
let high = n;
|
||||
let mid = Math.floor( ( low + high ) / 2 );
|
||||
|
||||
while ( u < U[ mid ] || u >= U[ mid + 1 ] ) {
|
||||
|
||||
if ( u < U[ mid ] ) {
|
||||
|
||||
high = mid;
|
||||
|
||||
} else {
|
||||
|
||||
low = mid;
|
||||
|
||||
}
|
||||
|
||||
mid = Math.floor( ( low + high ) / 2 );
|
||||
|
||||
}
|
||||
|
||||
return mid;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Calculate basis functions. See The NURBS Book, page 70, algorithm A2.2
|
||||
|
||||
span : span in which u lies
|
||||
u : parametric point
|
||||
p : degree
|
||||
U : knot vector
|
||||
|
||||
returns array[p+1] with basis functions values.
|
||||
*/
|
||||
function calcBasisFunctions( span, u, p, U ) {
|
||||
|
||||
const N = [];
|
||||
const left = [];
|
||||
const right = [];
|
||||
N[ 0 ] = 1.0;
|
||||
|
||||
for ( let j = 1; j <= p; ++ j ) {
|
||||
|
||||
left[ j ] = u - U[ span + 1 - j ];
|
||||
right[ j ] = U[ span + j ] - u;
|
||||
|
||||
let saved = 0.0;
|
||||
|
||||
for ( let r = 0; r < j; ++ r ) {
|
||||
|
||||
const rv = right[ r + 1 ];
|
||||
const lv = left[ j - r ];
|
||||
const temp = N[ r ] / ( rv + lv );
|
||||
N[ r ] = saved + rv * temp;
|
||||
saved = lv * temp;
|
||||
|
||||
}
|
||||
|
||||
N[ j ] = saved;
|
||||
|
||||
}
|
||||
|
||||
return N;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Calculate B-Spline curve points. See The NURBS Book, page 82, algorithm A3.1.
|
||||
|
||||
p : degree of B-Spline
|
||||
U : knot vector
|
||||
P : control points (x, y, z, w)
|
||||
u : parametric point
|
||||
|
||||
returns point for given u
|
||||
*/
|
||||
function calcBSplinePoint( p, U, P, u ) {
|
||||
|
||||
const span = findSpan( p, u, U );
|
||||
const N = calcBasisFunctions( span, u, p, U );
|
||||
const C = new Vector4( 0, 0, 0, 0 );
|
||||
|
||||
for ( let j = 0; j <= p; ++ j ) {
|
||||
|
||||
const point = P[ span - p + j ];
|
||||
const Nj = N[ j ];
|
||||
const wNj = point.w * Nj;
|
||||
C.x += point.x * wNj;
|
||||
C.y += point.y * wNj;
|
||||
C.z += point.z * wNj;
|
||||
C.w += point.w * Nj;
|
||||
|
||||
}
|
||||
|
||||
return C;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Calculate basis functions derivatives. See The NURBS Book, page 72, algorithm A2.3.
|
||||
|
||||
span : span in which u lies
|
||||
u : parametric point
|
||||
p : degree
|
||||
n : number of derivatives to calculate
|
||||
U : knot vector
|
||||
|
||||
returns array[n+1][p+1] with basis functions derivatives
|
||||
*/
|
||||
function calcBasisFunctionDerivatives( span, u, p, n, U ) {
|
||||
|
||||
const zeroArr = [];
|
||||
for ( let i = 0; i <= p; ++ i )
|
||||
zeroArr[ i ] = 0.0;
|
||||
|
||||
const ders = [];
|
||||
|
||||
for ( let i = 0; i <= n; ++ i )
|
||||
ders[ i ] = zeroArr.slice( 0 );
|
||||
|
||||
const ndu = [];
|
||||
|
||||
for ( let i = 0; i <= p; ++ i )
|
||||
ndu[ i ] = zeroArr.slice( 0 );
|
||||
|
||||
ndu[ 0 ][ 0 ] = 1.0;
|
||||
|
||||
const left = zeroArr.slice( 0 );
|
||||
const right = zeroArr.slice( 0 );
|
||||
|
||||
for ( let j = 1; j <= p; ++ j ) {
|
||||
|
||||
left[ j ] = u - U[ span + 1 - j ];
|
||||
right[ j ] = U[ span + j ] - u;
|
||||
|
||||
let saved = 0.0;
|
||||
|
||||
for ( let r = 0; r < j; ++ r ) {
|
||||
|
||||
const rv = right[ r + 1 ];
|
||||
const lv = left[ j - r ];
|
||||
ndu[ j ][ r ] = rv + lv;
|
||||
|
||||
const temp = ndu[ r ][ j - 1 ] / ndu[ j ][ r ];
|
||||
ndu[ r ][ j ] = saved + rv * temp;
|
||||
saved = lv * temp;
|
||||
|
||||
}
|
||||
|
||||
ndu[ j ][ j ] = saved;
|
||||
|
||||
}
|
||||
|
||||
for ( let j = 0; j <= p; ++ j ) {
|
||||
|
||||
ders[ 0 ][ j ] = ndu[ j ][ p ];
|
||||
|
||||
}
|
||||
|
||||
for ( let r = 0; r <= p; ++ r ) {
|
||||
|
||||
let s1 = 0;
|
||||
let s2 = 1;
|
||||
|
||||
const a = [];
|
||||
for ( let i = 0; i <= p; ++ i ) {
|
||||
|
||||
a[ i ] = zeroArr.slice( 0 );
|
||||
|
||||
}
|
||||
|
||||
a[ 0 ][ 0 ] = 1.0;
|
||||
|
||||
for ( let k = 1; k <= n; ++ k ) {
|
||||
|
||||
let d = 0.0;
|
||||
const rk = r - k;
|
||||
const pk = p - k;
|
||||
|
||||
if ( r >= k ) {
|
||||
|
||||
a[ s2 ][ 0 ] = a[ s1 ][ 0 ] / ndu[ pk + 1 ][ rk ];
|
||||
d = a[ s2 ][ 0 ] * ndu[ rk ][ pk ];
|
||||
|
||||
}
|
||||
|
||||
const j1 = ( rk >= - 1 ) ? 1 : - rk;
|
||||
const j2 = ( r - 1 <= pk ) ? k - 1 : p - r;
|
||||
|
||||
for ( let j = j1; j <= j2; ++ j ) {
|
||||
|
||||
a[ s2 ][ j ] = ( a[ s1 ][ j ] - a[ s1 ][ j - 1 ] ) / ndu[ pk + 1 ][ rk + j ];
|
||||
d += a[ s2 ][ j ] * ndu[ rk + j ][ pk ];
|
||||
|
||||
}
|
||||
|
||||
if ( r <= pk ) {
|
||||
|
||||
a[ s2 ][ k ] = - a[ s1 ][ k - 1 ] / ndu[ pk + 1 ][ r ];
|
||||
d += a[ s2 ][ k ] * ndu[ r ][ pk ];
|
||||
|
||||
}
|
||||
|
||||
ders[ k ][ r ] = d;
|
||||
|
||||
const j = s1;
|
||||
s1 = s2;
|
||||
s2 = j;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let r = p;
|
||||
|
||||
for ( let k = 1; k <= n; ++ k ) {
|
||||
|
||||
for ( let j = 0; j <= p; ++ j ) {
|
||||
|
||||
ders[ k ][ j ] *= r;
|
||||
|
||||
}
|
||||
|
||||
r *= p - k;
|
||||
|
||||
}
|
||||
|
||||
return ders;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Calculate derivatives of a B-Spline. See The NURBS Book, page 93, algorithm A3.2.
|
||||
|
||||
p : degree
|
||||
U : knot vector
|
||||
P : control points
|
||||
u : Parametric points
|
||||
nd : number of derivatives
|
||||
|
||||
returns array[d+1] with derivatives
|
||||
*/
|
||||
function calcBSplineDerivatives( p, U, P, u, nd ) {
|
||||
|
||||
const du = nd < p ? nd : p;
|
||||
const CK = [];
|
||||
const span = findSpan( p, u, U );
|
||||
const nders = calcBasisFunctionDerivatives( span, u, p, du, U );
|
||||
const Pw = [];
|
||||
|
||||
for ( let i = 0; i < P.length; ++ i ) {
|
||||
|
||||
const point = P[ i ].clone();
|
||||
const w = point.w;
|
||||
|
||||
point.x *= w;
|
||||
point.y *= w;
|
||||
point.z *= w;
|
||||
|
||||
Pw[ i ] = point;
|
||||
|
||||
}
|
||||
|
||||
for ( let k = 0; k <= du; ++ k ) {
|
||||
|
||||
const point = Pw[ span - p ].clone().multiplyScalar( nders[ k ][ 0 ] );
|
||||
|
||||
for ( let j = 1; j <= p; ++ j ) {
|
||||
|
||||
point.add( Pw[ span - p + j ].clone().multiplyScalar( nders[ k ][ j ] ) );
|
||||
|
||||
}
|
||||
|
||||
CK[ k ] = point;
|
||||
|
||||
}
|
||||
|
||||
for ( let k = du + 1; k <= nd + 1; ++ k ) {
|
||||
|
||||
CK[ k ] = new Vector4( 0, 0, 0 );
|
||||
|
||||
}
|
||||
|
||||
return CK;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Calculate "K over I"
|
||||
|
||||
returns k!/(i!(k-i)!)
|
||||
*/
|
||||
function calcKoverI( k, i ) {
|
||||
|
||||
let nom = 1;
|
||||
|
||||
for ( let j = 2; j <= k; ++ j ) {
|
||||
|
||||
nom *= j;
|
||||
|
||||
}
|
||||
|
||||
let denom = 1;
|
||||
|
||||
for ( let j = 2; j <= i; ++ j ) {
|
||||
|
||||
denom *= j;
|
||||
|
||||
}
|
||||
|
||||
for ( let j = 2; j <= k - i; ++ j ) {
|
||||
|
||||
denom *= j;
|
||||
|
||||
}
|
||||
|
||||
return nom / denom;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Calculate derivatives (0-nd) of rational curve. See The NURBS Book, page 127, algorithm A4.2.
|
||||
|
||||
Pders : result of function calcBSplineDerivatives
|
||||
|
||||
returns array with derivatives for rational curve.
|
||||
*/
|
||||
function calcRationalCurveDerivatives( Pders ) {
|
||||
|
||||
const nd = Pders.length;
|
||||
const Aders = [];
|
||||
const wders = [];
|
||||
|
||||
for ( let i = 0; i < nd; ++ i ) {
|
||||
|
||||
const point = Pders[ i ];
|
||||
Aders[ i ] = new Vector3( point.x, point.y, point.z );
|
||||
wders[ i ] = point.w;
|
||||
|
||||
}
|
||||
|
||||
const CK = [];
|
||||
|
||||
for ( let k = 0; k < nd; ++ k ) {
|
||||
|
||||
const v = Aders[ k ].clone();
|
||||
|
||||
for ( let i = 1; i <= k; ++ i ) {
|
||||
|
||||
v.sub( CK[ k - i ].clone().multiplyScalar( calcKoverI( k, i ) * wders[ i ] ) );
|
||||
|
||||
}
|
||||
|
||||
CK[ k ] = v.divideScalar( wders[ 0 ] );
|
||||
|
||||
}
|
||||
|
||||
return CK;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Calculate NURBS curve derivatives. See The NURBS Book, page 127, algorithm A4.2.
|
||||
|
||||
p : degree
|
||||
U : knot vector
|
||||
P : control points in homogeneous space
|
||||
u : parametric points
|
||||
nd : number of derivatives
|
||||
|
||||
returns array with derivatives.
|
||||
*/
|
||||
function calcNURBSDerivatives( p, U, P, u, nd ) {
|
||||
|
||||
const Pders = calcBSplineDerivatives( p, U, P, u, nd );
|
||||
return calcRationalCurveDerivatives( Pders );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Calculate rational B-Spline surface point. See The NURBS Book, page 134, algorithm A4.3.
|
||||
|
||||
p1, p2 : degrees of B-Spline surface
|
||||
U1, U2 : knot vectors
|
||||
P : control points (x, y, z, w)
|
||||
u, v : parametric values
|
||||
|
||||
returns point for given (u, v)
|
||||
*/
|
||||
function calcSurfacePoint( p, q, U, V, P, u, v, target ) {
|
||||
|
||||
const uspan = findSpan( p, u, U );
|
||||
const vspan = findSpan( q, v, V );
|
||||
const Nu = calcBasisFunctions( uspan, u, p, U );
|
||||
const Nv = calcBasisFunctions( vspan, v, q, V );
|
||||
const temp = [];
|
||||
|
||||
for ( let l = 0; l <= q; ++ l ) {
|
||||
|
||||
temp[ l ] = new Vector4( 0, 0, 0, 0 );
|
||||
for ( let k = 0; k <= p; ++ k ) {
|
||||
|
||||
const point = P[ uspan - p + k ][ vspan - q + l ].clone();
|
||||
const w = point.w;
|
||||
point.x *= w;
|
||||
point.y *= w;
|
||||
point.z *= w;
|
||||
temp[ l ].add( point.multiplyScalar( Nu[ k ] ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const Sw = new Vector4( 0, 0, 0, 0 );
|
||||
for ( let l = 0; l <= q; ++ l ) {
|
||||
|
||||
Sw.add( temp[ l ].multiplyScalar( Nv[ l ] ) );
|
||||
|
||||
}
|
||||
|
||||
Sw.divideScalar( Sw.w );
|
||||
target.set( Sw.x, Sw.y, Sw.z );
|
||||
|
||||
}
|
||||
|
||||
|
450
public/scripts/NURBSUtils.js
Normal file
450
public/scripts/NURBSUtils.js
Normal file
@ -0,0 +1,450 @@
|
||||
|
||||
function findSpan( p, u, U ) {
|
||||
|
||||
const n = U.length - p - 1;
|
||||
|
||||
if ( u >= U[ n ] ) {
|
||||
|
||||
return n - 1;
|
||||
|
||||
}
|
||||
|
||||
if ( u <= U[ p ] ) {
|
||||
|
||||
return p;
|
||||
|
||||
}
|
||||
|
||||
let low = p;
|
||||
let high = n;
|
||||
let mid = Math.floor( ( low + high ) / 2 );
|
||||
|
||||
while ( u < U[ mid ] || u >= U[ mid + 1 ] ) {
|
||||
|
||||
if ( u < U[ mid ] ) {
|
||||
|
||||
high = mid;
|
||||
|
||||
} else {
|
||||
|
||||
low = mid;
|
||||
|
||||
}
|
||||
|
||||
mid = Math.floor( ( low + high ) / 2 );
|
||||
|
||||
}
|
||||
|
||||
return mid;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Calculate basis functions. See The NURBS Book, page 70, algorithm A2.2
|
||||
|
||||
span : span in which u lies
|
||||
u : parametric point
|
||||
p : degree
|
||||
U : knot vector
|
||||
|
||||
returns array[p+1] with basis functions values.
|
||||
*/
|
||||
function calcBasisFunctions( span, u, p, U ) {
|
||||
|
||||
const N = [];
|
||||
const left = [];
|
||||
const right = [];
|
||||
N[ 0 ] = 1.0;
|
||||
|
||||
for ( let j = 1; j <= p; ++ j ) {
|
||||
|
||||
left[ j ] = u - U[ span + 1 - j ];
|
||||
right[ j ] = U[ span + j ] - u;
|
||||
|
||||
let saved = 0.0;
|
||||
|
||||
for ( let r = 0; r < j; ++ r ) {
|
||||
|
||||
const rv = right[ r + 1 ];
|
||||
const lv = left[ j - r ];
|
||||
const temp = N[ r ] / ( rv + lv );
|
||||
N[ r ] = saved + rv * temp;
|
||||
saved = lv * temp;
|
||||
|
||||
}
|
||||
|
||||
N[ j ] = saved;
|
||||
|
||||
}
|
||||
|
||||
return N;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Calculate B-Spline curve points. See The NURBS Book, page 82, algorithm A3.1.
|
||||
|
||||
p : degree of B-Spline
|
||||
U : knot vector
|
||||
P : control points (x, y, z, w)
|
||||
u : parametric point
|
||||
|
||||
returns point for given u
|
||||
*/
|
||||
function calcBSplinePoint( p, U, P, u ) {
|
||||
|
||||
const span = findSpan( p, u, U );
|
||||
const N = calcBasisFunctions( span, u, p, U );
|
||||
const C = new Vector4( 0, 0, 0, 0 );
|
||||
|
||||
for ( let j = 0; j <= p; ++ j ) {
|
||||
|
||||
const point = P[ span - p + j ];
|
||||
const Nj = N[ j ];
|
||||
const wNj = point.w * Nj;
|
||||
C.x += point.x * wNj;
|
||||
C.y += point.y * wNj;
|
||||
C.z += point.z * wNj;
|
||||
C.w += point.w * Nj;
|
||||
|
||||
}
|
||||
|
||||
return C;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Calculate basis functions derivatives. See The NURBS Book, page 72, algorithm A2.3.
|
||||
|
||||
span : span in which u lies
|
||||
u : parametric point
|
||||
p : degree
|
||||
n : number of derivatives to calculate
|
||||
U : knot vector
|
||||
|
||||
returns array[n+1][p+1] with basis functions derivatives
|
||||
*/
|
||||
function calcBasisFunctionDerivatives( span, u, p, n, U ) {
|
||||
|
||||
const zeroArr = [];
|
||||
for ( let i = 0; i <= p; ++ i )
|
||||
zeroArr[ i ] = 0.0;
|
||||
|
||||
const ders = [];
|
||||
|
||||
for ( let i = 0; i <= n; ++ i )
|
||||
ders[ i ] = zeroArr.slice( 0 );
|
||||
|
||||
const ndu = [];
|
||||
|
||||
for ( let i = 0; i <= p; ++ i )
|
||||
ndu[ i ] = zeroArr.slice( 0 );
|
||||
|
||||
ndu[ 0 ][ 0 ] = 1.0;
|
||||
|
||||
const left = zeroArr.slice( 0 );
|
||||
const right = zeroArr.slice( 0 );
|
||||
|
||||
for ( let j = 1; j <= p; ++ j ) {
|
||||
|
||||
left[ j ] = u - U[ span + 1 - j ];
|
||||
right[ j ] = U[ span + j ] - u;
|
||||
|
||||
let saved = 0.0;
|
||||
|
||||
for ( let r = 0; r < j; ++ r ) {
|
||||
|
||||
const rv = right[ r + 1 ];
|
||||
const lv = left[ j - r ];
|
||||
ndu[ j ][ r ] = rv + lv;
|
||||
|
||||
const temp = ndu[ r ][ j - 1 ] / ndu[ j ][ r ];
|
||||
ndu[ r ][ j ] = saved + rv * temp;
|
||||
saved = lv * temp;
|
||||
|
||||
}
|
||||
|
||||
ndu[ j ][ j ] = saved;
|
||||
|
||||
}
|
||||
|
||||
for ( let j = 0; j <= p; ++ j ) {
|
||||
|
||||
ders[ 0 ][ j ] = ndu[ j ][ p ];
|
||||
|
||||
}
|
||||
|
||||
for ( let r = 0; r <= p; ++ r ) {
|
||||
|
||||
let s1 = 0;
|
||||
let s2 = 1;
|
||||
|
||||
const a = [];
|
||||
for ( let i = 0; i <= p; ++ i ) {
|
||||
|
||||
a[ i ] = zeroArr.slice( 0 );
|
||||
|
||||
}
|
||||
|
||||
a[ 0 ][ 0 ] = 1.0;
|
||||
|
||||
for ( let k = 1; k <= n; ++ k ) {
|
||||
|
||||
let d = 0.0;
|
||||
const rk = r - k;
|
||||
const pk = p - k;
|
||||
|
||||
if ( r >= k ) {
|
||||
|
||||
a[ s2 ][ 0 ] = a[ s1 ][ 0 ] / ndu[ pk + 1 ][ rk ];
|
||||
d = a[ s2 ][ 0 ] * ndu[ rk ][ pk ];
|
||||
|
||||
}
|
||||
|
||||
const j1 = ( rk >= - 1 ) ? 1 : - rk;
|
||||
const j2 = ( r - 1 <= pk ) ? k - 1 : p - r;
|
||||
|
||||
for ( let j = j1; j <= j2; ++ j ) {
|
||||
|
||||
a[ s2 ][ j ] = ( a[ s1 ][ j ] - a[ s1 ][ j - 1 ] ) / ndu[ pk + 1 ][ rk + j ];
|
||||
d += a[ s2 ][ j ] * ndu[ rk + j ][ pk ];
|
||||
|
||||
}
|
||||
|
||||
if ( r <= pk ) {
|
||||
|
||||
a[ s2 ][ k ] = - a[ s1 ][ k - 1 ] / ndu[ pk + 1 ][ r ];
|
||||
d += a[ s2 ][ k ] * ndu[ r ][ pk ];
|
||||
|
||||
}
|
||||
|
||||
ders[ k ][ r ] = d;
|
||||
|
||||
const j = s1;
|
||||
s1 = s2;
|
||||
s2 = j;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let r = p;
|
||||
|
||||
for ( let k = 1; k <= n; ++ k ) {
|
||||
|
||||
for ( let j = 0; j <= p; ++ j ) {
|
||||
|
||||
ders[ k ][ j ] *= r;
|
||||
|
||||
}
|
||||
|
||||
r *= p - k;
|
||||
|
||||
}
|
||||
|
||||
return ders;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Calculate derivatives of a B-Spline. See The NURBS Book, page 93, algorithm A3.2.
|
||||
|
||||
p : degree
|
||||
U : knot vector
|
||||
P : control points
|
||||
u : Parametric points
|
||||
nd : number of derivatives
|
||||
|
||||
returns array[d+1] with derivatives
|
||||
*/
|
||||
function calcBSplineDerivatives( p, U, P, u, nd ) {
|
||||
|
||||
const du = nd < p ? nd : p;
|
||||
const CK = [];
|
||||
const span = findSpan( p, u, U );
|
||||
const nders = calcBasisFunctionDerivatives( span, u, p, du, U );
|
||||
const Pw = [];
|
||||
|
||||
for ( let i = 0; i < P.length; ++ i ) {
|
||||
|
||||
const point = P[ i ].clone();
|
||||
const w = point.w;
|
||||
|
||||
point.x *= w;
|
||||
point.y *= w;
|
||||
point.z *= w;
|
||||
|
||||
Pw[ i ] = point;
|
||||
|
||||
}
|
||||
|
||||
for ( let k = 0; k <= du; ++ k ) {
|
||||
|
||||
const point = Pw[ span - p ].clone().multiplyScalar( nders[ k ][ 0 ] );
|
||||
|
||||
for ( let j = 1; j <= p; ++ j ) {
|
||||
|
||||
point.add( Pw[ span - p + j ].clone().multiplyScalar( nders[ k ][ j ] ) );
|
||||
|
||||
}
|
||||
|
||||
CK[ k ] = point;
|
||||
|
||||
}
|
||||
|
||||
for ( let k = du + 1; k <= nd + 1; ++ k ) {
|
||||
|
||||
CK[ k ] = new Vector4( 0, 0, 0 );
|
||||
|
||||
}
|
||||
|
||||
return CK;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Calculate "K over I"
|
||||
|
||||
returns k!/(i!(k-i)!)
|
||||
*/
|
||||
function calcKoverI( k, i ) {
|
||||
|
||||
let nom = 1;
|
||||
|
||||
for ( let j = 2; j <= k; ++ j ) {
|
||||
|
||||
nom *= j;
|
||||
|
||||
}
|
||||
|
||||
let denom = 1;
|
||||
|
||||
for ( let j = 2; j <= i; ++ j ) {
|
||||
|
||||
denom *= j;
|
||||
|
||||
}
|
||||
|
||||
for ( let j = 2; j <= k - i; ++ j ) {
|
||||
|
||||
denom *= j;
|
||||
|
||||
}
|
||||
|
||||
return nom / denom;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Calculate derivatives (0-nd) of rational curve. See The NURBS Book, page 127, algorithm A4.2.
|
||||
|
||||
Pders : result of function calcBSplineDerivatives
|
||||
|
||||
returns array with derivatives for rational curve.
|
||||
*/
|
||||
function calcRationalCurveDerivatives( Pders ) {
|
||||
|
||||
const nd = Pders.length;
|
||||
const Aders = [];
|
||||
const wders = [];
|
||||
|
||||
for ( let i = 0; i < nd; ++ i ) {
|
||||
|
||||
const point = Pders[ i ];
|
||||
Aders[ i ] = new Vector3( point.x, point.y, point.z );
|
||||
wders[ i ] = point.w;
|
||||
|
||||
}
|
||||
|
||||
const CK = [];
|
||||
|
||||
for ( let k = 0; k < nd; ++ k ) {
|
||||
|
||||
const v = Aders[ k ].clone();
|
||||
|
||||
for ( let i = 1; i <= k; ++ i ) {
|
||||
|
||||
v.sub( CK[ k - i ].clone().multiplyScalar( calcKoverI( k, i ) * wders[ i ] ) );
|
||||
|
||||
}
|
||||
|
||||
CK[ k ] = v.divideScalar( wders[ 0 ] );
|
||||
|
||||
}
|
||||
|
||||
return CK;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Calculate NURBS curve derivatives. See The NURBS Book, page 127, algorithm A4.2.
|
||||
|
||||
p : degree
|
||||
U : knot vector
|
||||
P : control points in homogeneous space
|
||||
u : parametric points
|
||||
nd : number of derivatives
|
||||
|
||||
returns array with derivatives.
|
||||
*/
|
||||
function calcNURBSDerivatives( p, U, P, u, nd ) {
|
||||
|
||||
const Pders = calcBSplineDerivatives( p, U, P, u, nd );
|
||||
return calcRationalCurveDerivatives( Pders );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Calculate rational B-Spline surface point. See The NURBS Book, page 134, algorithm A4.3.
|
||||
|
||||
p1, p2 : degrees of B-Spline surface
|
||||
U1, U2 : knot vectors
|
||||
P : control points (x, y, z, w)
|
||||
u, v : parametric values
|
||||
|
||||
returns point for given (u, v)
|
||||
*/
|
||||
function calcSurfacePoint( p, q, U, V, P, u, v, target ) {
|
||||
|
||||
const uspan = findSpan( p, u, U );
|
||||
const vspan = findSpan( q, v, V );
|
||||
const Nu = calcBasisFunctions( uspan, u, p, U );
|
||||
const Nv = calcBasisFunctions( vspan, v, q, V );
|
||||
const temp = [];
|
||||
|
||||
for ( let l = 0; l <= q; ++ l ) {
|
||||
|
||||
temp[ l ] = new Vector4( 0, 0, 0, 0 );
|
||||
for ( let k = 0; k <= p; ++ k ) {
|
||||
|
||||
const point = P[ uspan - p + k ][ vspan - q + l ].clone();
|
||||
const w = point.w;
|
||||
point.x *= w;
|
||||
point.y *= w;
|
||||
point.z *= w;
|
||||
temp[ l ].add( point.multiplyScalar( Nu[ k ] ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const Sw = new Vector4( 0, 0, 0, 0 );
|
||||
for ( let l = 0; l <= q; ++ l ) {
|
||||
|
||||
Sw.add( temp[ l ].multiplyScalar( Nv[ l ] ) );
|
||||
|
||||
}
|
||||
|
||||
Sw.divideScalar( Sw.w );
|
||||
target.set( Sw.x, Sw.y, Sw.z );
|
||||
|
||||
}
|
||||
|
1079
public/scripts/OrbitControls.js
Normal file
1079
public/scripts/OrbitControls.js
Normal file
File diff suppressed because it is too large
Load Diff
230
public/scripts/ShadowMapViewer.js
Normal file
230
public/scripts/ShadowMapViewer.js
Normal file
@ -0,0 +1,230 @@
|
||||
const UnpackDepthRGBAShader = {
|
||||
|
||||
name: 'UnpackDepthRGBAShader',
|
||||
|
||||
uniforms: {
|
||||
|
||||
'tDiffuse': { value: null },
|
||||
'opacity': { value: 1.0 }
|
||||
|
||||
},
|
||||
|
||||
vertexShader: /* glsl */`
|
||||
|
||||
varying vec2 vUv;
|
||||
|
||||
void main() {
|
||||
|
||||
vUv = uv;
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
||||
|
||||
}`,
|
||||
|
||||
fragmentShader: /* glsl */`
|
||||
|
||||
uniform float opacity;
|
||||
|
||||
uniform sampler2D tDiffuse;
|
||||
|
||||
varying vec2 vUv;
|
||||
|
||||
#include <packing>
|
||||
|
||||
void main() {
|
||||
|
||||
float depth = 1.0 - unpackRGBAToDepth( texture2D( tDiffuse, vUv ) );
|
||||
gl_FragColor = vec4( vec3( depth ), opacity );
|
||||
|
||||
}`
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a helper for visualising a given light's shadow map.
|
||||
* It works for shadow casting lights: DirectionalLight and SpotLight.
|
||||
* It renders out the shadow map and displays it on a HUD.
|
||||
*
|
||||
* Example usage:
|
||||
* 1) Import ShadowMapViewer into your app.
|
||||
*
|
||||
* 2) Create a shadow casting light and name it optionally:
|
||||
* let light = new DirectionalLight( 0xffffff, 1 );
|
||||
* light.castShadow = true;
|
||||
* light.name = 'Sun';
|
||||
*
|
||||
* 3) Create a shadow map viewer for that light and set its size and position optionally:
|
||||
* let shadowMapViewer = new ShadowMapViewer( light );
|
||||
* shadowMapViewer.size.set( 128, 128 ); //width, height default: 256, 256
|
||||
* shadowMapViewer.position.set( 10, 10 ); //x, y in pixel default: 0, 0 (top left corner)
|
||||
*
|
||||
* 4) Render the shadow map viewer in your render loop:
|
||||
* shadowMapViewer.render( renderer );
|
||||
*
|
||||
* 5) Optionally: Update the shadow map viewer on window resize:
|
||||
* shadowMapViewer.updateForWindowResize();
|
||||
*
|
||||
* 6) If you set the position or size members directly, you need to call shadowMapViewer.update();
|
||||
*/
|
||||
|
||||
class ShadowMapViewer {
|
||||
|
||||
constructor( light ) {
|
||||
|
||||
//- Internals
|
||||
const scope = this;
|
||||
const doRenderLabel = ( light.name !== undefined && light.name !== '' );
|
||||
let userAutoClearSetting;
|
||||
|
||||
//Holds the initial position and dimension of the HUD
|
||||
const frame = {
|
||||
x: 10,
|
||||
y: 10,
|
||||
width: 256,
|
||||
height: 256
|
||||
};
|
||||
|
||||
const camera = new OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, 1, 10 );
|
||||
camera.position.set( 0, 0, 2 );
|
||||
const scene = new Scene();
|
||||
|
||||
//HUD for shadow map
|
||||
const shader = UnpackDepthRGBAShader;
|
||||
|
||||
const uniforms = UniformsUtils.clone( shader.uniforms );
|
||||
const material = new ShaderMaterial( {
|
||||
uniforms: uniforms,
|
||||
vertexShader: shader.vertexShader,
|
||||
fragmentShader: shader.fragmentShader
|
||||
} );
|
||||
const plane = new PlaneGeometry( frame.width, frame.height );
|
||||
window.mesh = new Mesh( plane, material );
|
||||
|
||||
scene.add( mesh );
|
||||
|
||||
|
||||
//Label for light's name
|
||||
let labelCanvas, labelMesh;
|
||||
|
||||
if ( doRenderLabel ) {
|
||||
|
||||
labelCanvas = document.createElement( 'canvas' );
|
||||
|
||||
const context = labelCanvas.getContext( '2d' );
|
||||
context.font = 'Bold 20px Arial';
|
||||
|
||||
const labelWidth = context.measureText( light.name ).width;
|
||||
labelCanvas.width = labelWidth;
|
||||
labelCanvas.height = 25; //25 to account for g, p, etc.
|
||||
|
||||
context.font = 'Bold 20px Arial';
|
||||
context.fillStyle = 'rgba( 255, 0, 0, 1 )';
|
||||
context.fillText( light.name, 0, 20 );
|
||||
|
||||
const labelTexture = new CanvasTexture( labelCanvas );
|
||||
|
||||
const labelMaterial = new MeshBasicMaterial( { map: labelTexture, side: DoubleSide, transparent: true } );
|
||||
|
||||
const labelPlane = new PlaneGeometry( labelCanvas.width, labelCanvas.height );
|
||||
labelMesh = new Mesh( labelPlane, labelMaterial );
|
||||
|
||||
scene.add( labelMesh );
|
||||
|
||||
}
|
||||
|
||||
|
||||
function resetPosition() {
|
||||
|
||||
scope.position.set( scope.position.x, scope.position.y );
|
||||
|
||||
}
|
||||
|
||||
//- API
|
||||
// Set to false to disable displaying this shadow map
|
||||
this.enabled = true;
|
||||
|
||||
// Set the size of the displayed shadow map on the HUD
|
||||
this.size = {
|
||||
width: frame.width,
|
||||
height: frame.height,
|
||||
set: function ( width, height ) {
|
||||
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
|
||||
mesh.scale.set( this.width / frame.width, this.height / frame.height, 1 );
|
||||
|
||||
//Reset the position as it is off when we scale stuff
|
||||
resetPosition();
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// Set the position of the displayed shadow map on the HUD
|
||||
this.position = {
|
||||
x: frame.x,
|
||||
y: frame.y,
|
||||
set: function ( x, y ) {
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
const width = scope.size.width;
|
||||
const height = scope.size.height;
|
||||
|
||||
mesh.position.set( - window.innerWidth / 2 + width / 2 + this.x, window.innerHeight / 2 - height / 2 - this.y, 0 );
|
||||
|
||||
if ( doRenderLabel ) labelMesh.position.set( mesh.position.x, mesh.position.y - scope.size.height / 2 + labelCanvas.height / 2, 0 );
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
this.render = function ( renderer ) {
|
||||
|
||||
if ( this.enabled ) {
|
||||
|
||||
//Because a light's .shadowMap is only initialised after the first render pass
|
||||
//we have to make sure the correct map is sent into the shader, otherwise we
|
||||
//always end up with the scene's first added shadow casting light's shadowMap
|
||||
//in the shader
|
||||
//See: https://github.com/mrdoob/three.js/issues/5932
|
||||
uniforms.tDiffuse.value = light.shadow.map.texture;
|
||||
|
||||
userAutoClearSetting = renderer.autoClear;
|
||||
renderer.autoClear = false; // To allow render overlay
|
||||
renderer.clearDepth();
|
||||
renderer.render( scene, camera );
|
||||
renderer.autoClear = userAutoClearSetting; //Restore user's setting
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.updateForWindowResize = function () {
|
||||
|
||||
if ( this.enabled ) {
|
||||
|
||||
camera.left = window.innerWidth / - 2;
|
||||
camera.right = window.innerWidth / 2;
|
||||
camera.top = window.innerHeight / 2;
|
||||
camera.bottom = window.innerHeight / - 2;
|
||||
camera.updateProjectionMatrix();
|
||||
|
||||
this.update();
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.update = function () {
|
||||
|
||||
this.position.set( this.position.x, this.position.y );
|
||||
this.size.set( this.size.width, this.size.height );
|
||||
|
||||
};
|
||||
|
||||
//Force an update to set position/size
|
||||
this.update();
|
||||
|
||||
}
|
||||
|
||||
}
|
441
public/scripts/SkeletonUtils.js
Normal file
441
public/scripts/SkeletonUtils.js
Normal file
@ -0,0 +1,441 @@
|
||||
|
||||
var AnimationClip = THREE.AnimationClip;
|
||||
var AnimationMixer = THREE.AnimationMixer;
|
||||
var Matrix4 = THREE.Matrix4;
|
||||
var Quaternion = THREE.Quaternion;
|
||||
var QuaternionKeyframeTrack = THREE.QuaternionKeyframeTrack;
|
||||
var SkeletonHelper = THREE.SkeletonHelper;
|
||||
var Vector3 = THREE.Vector3;
|
||||
var VectorKeyframeTrack = THREE.VectorKeyframeTrack;
|
||||
|
||||
function getBoneName( bone, options ) {
|
||||
|
||||
if ( options.getBoneName !== undefined ) {
|
||||
|
||||
return options.getBoneName( bone );
|
||||
|
||||
}
|
||||
|
||||
return options.names[ bone.name ];
|
||||
|
||||
}
|
||||
|
||||
function retarget( target, source, options = {} ) {
|
||||
|
||||
const quat = new Quaternion(),
|
||||
scale = new Vector3(),
|
||||
relativeMatrix = new Matrix4(),
|
||||
globalMatrix = new Matrix4();
|
||||
|
||||
options.preserveBoneMatrix = options.preserveBoneMatrix !== undefined ? options.preserveBoneMatrix : true;
|
||||
options.preserveBonePositions = options.preserveBonePositions !== undefined ? options.preserveBonePositions : true;
|
||||
options.useTargetMatrix = options.useTargetMatrix !== undefined ? options.useTargetMatrix : false;
|
||||
options.hip = options.hip !== undefined ? options.hip : 'hip';
|
||||
options.hipInfluence = options.hipInfluence !== undefined ? options.hipInfluence : new Vector3( 1, 1, 1 );
|
||||
options.scale = options.scale !== undefined ? options.scale : 1;
|
||||
options.names = options.names || {};
|
||||
|
||||
const sourceBones = source.isObject3D ? source.skeleton.bones : getBones( source ),
|
||||
bones = target.isObject3D ? target.skeleton.bones : getBones( target );
|
||||
|
||||
let bone, name, boneTo,
|
||||
bonesPosition;
|
||||
|
||||
// reset bones
|
||||
|
||||
if ( target.isObject3D ) {
|
||||
|
||||
target.skeleton.pose();
|
||||
|
||||
} else {
|
||||
|
||||
options.useTargetMatrix = true;
|
||||
options.preserveBoneMatrix = false;
|
||||
|
||||
}
|
||||
|
||||
if ( options.preserveBonePositions ) {
|
||||
|
||||
bonesPosition = [];
|
||||
|
||||
for ( let i = 0; i < bones.length; i ++ ) {
|
||||
|
||||
bonesPosition.push( bones[ i ].position.clone() );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( options.preserveBoneMatrix ) {
|
||||
|
||||
// reset matrix
|
||||
|
||||
target.updateMatrixWorld();
|
||||
|
||||
target.matrixWorld.identity();
|
||||
|
||||
// reset children matrix
|
||||
|
||||
for ( let i = 0; i < target.children.length; ++ i ) {
|
||||
|
||||
target.children[ i ].updateMatrixWorld( true );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for ( let i = 0; i < bones.length; ++ i ) {
|
||||
|
||||
bone = bones[ i ];
|
||||
name = getBoneName( bone, options );
|
||||
|
||||
boneTo = getBoneByName( name, sourceBones );
|
||||
|
||||
globalMatrix.copy( bone.matrixWorld );
|
||||
|
||||
if ( boneTo ) {
|
||||
|
||||
boneTo.updateMatrixWorld();
|
||||
|
||||
if ( options.useTargetMatrix ) {
|
||||
|
||||
relativeMatrix.copy( boneTo.matrixWorld );
|
||||
|
||||
} else {
|
||||
|
||||
relativeMatrix.copy( target.matrixWorld ).invert();
|
||||
relativeMatrix.multiply( boneTo.matrixWorld );
|
||||
|
||||
}
|
||||
|
||||
// ignore scale to extract rotation
|
||||
|
||||
scale.setFromMatrixScale( relativeMatrix );
|
||||
relativeMatrix.scale( scale.set( 1 / scale.x, 1 / scale.y, 1 / scale.z ) );
|
||||
|
||||
// apply to global matrix
|
||||
|
||||
globalMatrix.makeRotationFromQuaternion( quat.setFromRotationMatrix( relativeMatrix ) );
|
||||
|
||||
if ( target.isObject3D ) {
|
||||
|
||||
if ( options.localOffsets ) {
|
||||
|
||||
if ( options.localOffsets[ bone.name ] ) {
|
||||
|
||||
globalMatrix.multiply( options.localOffsets[ bone.name ] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
globalMatrix.copyPosition( relativeMatrix );
|
||||
|
||||
}
|
||||
|
||||
if ( name === options.hip ) {
|
||||
|
||||
globalMatrix.elements[ 12 ] *= options.scale * options.hipInfluence.x;
|
||||
globalMatrix.elements[ 13 ] *= options.scale * options.hipInfluence.y;
|
||||
globalMatrix.elements[ 14 ] *= options.scale * options.hipInfluence.z;
|
||||
|
||||
if ( options.hipPosition !== undefined ) {
|
||||
|
||||
globalMatrix.elements[ 12 ] += options.hipPosition.x * options.scale;
|
||||
globalMatrix.elements[ 13 ] += options.hipPosition.y * options.scale;
|
||||
globalMatrix.elements[ 14 ] += options.hipPosition.z * options.scale;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( bone.parent ) {
|
||||
|
||||
bone.matrix.copy( bone.parent.matrixWorld ).invert();
|
||||
bone.matrix.multiply( globalMatrix );
|
||||
|
||||
} else {
|
||||
|
||||
bone.matrix.copy( globalMatrix );
|
||||
|
||||
}
|
||||
|
||||
bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
|
||||
|
||||
bone.updateMatrixWorld();
|
||||
|
||||
}
|
||||
|
||||
if ( options.preserveBonePositions ) {
|
||||
|
||||
for ( let i = 0; i < bones.length; ++ i ) {
|
||||
|
||||
bone = bones[ i ];
|
||||
name = getBoneName( bone, options ) || bone.name;
|
||||
|
||||
if ( name !== options.hip ) {
|
||||
|
||||
bone.position.copy( bonesPosition[ i ] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( options.preserveBoneMatrix ) {
|
||||
|
||||
// restore matrix
|
||||
|
||||
target.updateMatrixWorld( true );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function retargetClip( target, source, clip, options = {} ) {
|
||||
|
||||
options.useFirstFramePosition = options.useFirstFramePosition !== undefined ? options.useFirstFramePosition : false;
|
||||
|
||||
// Calculate the fps from the source clip based on the track with the most frames, unless fps is already provided.
|
||||
options.fps = options.fps !== undefined ? options.fps : ( Math.max( ...clip.tracks.map( track => track.times.length ) ) / clip.duration );
|
||||
options.names = options.names || [];
|
||||
|
||||
if ( ! source.isObject3D ) {
|
||||
|
||||
source = getHelperFromSkeleton( source );
|
||||
|
||||
}
|
||||
|
||||
const numFrames = Math.round( clip.duration * ( options.fps / 1000 ) * 1000 ),
|
||||
delta = clip.duration / ( numFrames - 1 ),
|
||||
convertedTracks = [],
|
||||
mixer = new AnimationMixer( source ),
|
||||
bones = getBones( target.skeleton ),
|
||||
boneDatas = [];
|
||||
|
||||
let positionOffset,
|
||||
bone, boneTo, boneData,
|
||||
name;
|
||||
|
||||
mixer.clipAction( clip ).play();
|
||||
|
||||
// trim
|
||||
|
||||
let start = 0, end = numFrames;
|
||||
|
||||
if ( options.trim !== undefined ) {
|
||||
|
||||
start = Math.round( options.trim[ 0 ] * options.fps );
|
||||
end = Math.min( Math.round( options.trim[ 1 ] * options.fps ), numFrames ) - start;
|
||||
|
||||
mixer.update( options.trim[ 0 ] );
|
||||
|
||||
} else {
|
||||
|
||||
mixer.update( 0 );
|
||||
|
||||
}
|
||||
|
||||
source.updateMatrixWorld();
|
||||
|
||||
//
|
||||
|
||||
for ( let frame = 0; frame < end; ++ frame ) {
|
||||
|
||||
const time = frame * delta;
|
||||
|
||||
retarget( target, source, options );
|
||||
|
||||
for ( let j = 0; j < bones.length; ++ j ) {
|
||||
|
||||
bone = bones[ j ];
|
||||
name = getBoneName( bone, options ) || bone.name;
|
||||
boneTo = getBoneByName( name, source.skeleton );
|
||||
|
||||
if ( boneTo ) {
|
||||
|
||||
boneData = boneDatas[ j ] = boneDatas[ j ] || { bone: bone };
|
||||
|
||||
if ( options.hip === name ) {
|
||||
|
||||
if ( ! boneData.pos ) {
|
||||
|
||||
boneData.pos = {
|
||||
times: new Float32Array( end ),
|
||||
values: new Float32Array( end * 3 )
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
if ( options.useFirstFramePosition ) {
|
||||
|
||||
if ( frame === 0 ) {
|
||||
|
||||
positionOffset = bone.position.clone();
|
||||
|
||||
}
|
||||
|
||||
bone.position.sub( positionOffset );
|
||||
|
||||
}
|
||||
|
||||
boneData.pos.times[ frame ] = time;
|
||||
|
||||
bone.position.toArray( boneData.pos.values, frame * 3 );
|
||||
|
||||
}
|
||||
|
||||
if ( ! boneData.quat ) {
|
||||
|
||||
boneData.quat = {
|
||||
times: new Float32Array( end ),
|
||||
values: new Float32Array( end * 4 )
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
boneData.quat.times[ frame ] = time;
|
||||
|
||||
bone.quaternion.toArray( boneData.quat.values, frame * 4 );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( frame === end - 2 ) {
|
||||
|
||||
// last mixer update before final loop iteration
|
||||
// make sure we do not go over or equal to clip duration
|
||||
mixer.update( delta - 0.0000001 );
|
||||
|
||||
} else {
|
||||
|
||||
mixer.update( delta );
|
||||
|
||||
}
|
||||
|
||||
source.updateMatrixWorld();
|
||||
|
||||
}
|
||||
|
||||
for ( let i = 0; i < boneDatas.length; ++ i ) {
|
||||
|
||||
boneData = boneDatas[ i ];
|
||||
|
||||
if ( boneData ) {
|
||||
|
||||
if ( boneData.pos ) {
|
||||
|
||||
convertedTracks.push( new VectorKeyframeTrack(
|
||||
'.bones[' + boneData.bone.name + '].position',
|
||||
boneData.pos.times,
|
||||
boneData.pos.values
|
||||
) );
|
||||
|
||||
}
|
||||
|
||||
convertedTracks.push( new QuaternionKeyframeTrack(
|
||||
'.bones[' + boneData.bone.name + '].quaternion',
|
||||
boneData.quat.times,
|
||||
boneData.quat.values
|
||||
) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mixer.uncacheAction( clip );
|
||||
|
||||
return new AnimationClip( clip.name, - 1, convertedTracks );
|
||||
|
||||
}
|
||||
|
||||
function clone( source ) {
|
||||
|
||||
const sourceLookup = new Map();
|
||||
const cloneLookup = new Map();
|
||||
|
||||
const clone = source.clone();
|
||||
|
||||
parallelTraverse( source, clone, function ( sourceNode, clonedNode ) {
|
||||
|
||||
sourceLookup.set( clonedNode, sourceNode );
|
||||
cloneLookup.set( sourceNode, clonedNode );
|
||||
|
||||
} );
|
||||
|
||||
clone.traverse( function ( node ) {
|
||||
|
||||
if ( ! node.isSkinnedMesh ) return;
|
||||
|
||||
const clonedMesh = node;
|
||||
const sourceMesh = sourceLookup.get( node );
|
||||
const sourceBones = sourceMesh.skeleton.bones;
|
||||
|
||||
clonedMesh.skeleton = sourceMesh.skeleton.clone();
|
||||
clonedMesh.bindMatrix.copy( sourceMesh.bindMatrix );
|
||||
|
||||
clonedMesh.skeleton.bones = sourceBones.map( function ( bone ) {
|
||||
|
||||
return cloneLookup.get( bone );
|
||||
|
||||
} );
|
||||
|
||||
clonedMesh.bind( clonedMesh.skeleton, clonedMesh.bindMatrix );
|
||||
|
||||
} );
|
||||
|
||||
return clone;
|
||||
|
||||
}
|
||||
|
||||
// internal helper
|
||||
|
||||
function getBoneByName( name, skeleton ) {
|
||||
|
||||
for ( let i = 0, bones = getBones( skeleton ); i < bones.length; i ++ ) {
|
||||
|
||||
if ( name === bones[ i ].name )
|
||||
|
||||
return bones[ i ];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function getBones( skeleton ) {
|
||||
|
||||
return Array.isArray( skeleton ) ? skeleton : skeleton.bones;
|
||||
|
||||
}
|
||||
|
||||
|
||||
function getHelperFromSkeleton( skeleton ) {
|
||||
|
||||
const source = new SkeletonHelper( skeleton.bones[ 0 ] );
|
||||
source.skeleton = skeleton;
|
||||
|
||||
return source;
|
||||
|
||||
}
|
||||
|
||||
function parallelTraverse( a, b, callback ) {
|
||||
|
||||
callback( a, b );
|
||||
|
||||
for ( let i = 0; i < a.children.length; i ++ ) {
|
||||
|
||||
parallelTraverse( a.children[ i ], b.children[ i ], callback );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export {
|
||||
retarget,
|
||||
retargetClip,
|
||||
clone,
|
||||
};
|
2474
public/scripts/fflate.module.js
Normal file
2474
public/scripts/fflate.module.js
Normal file
File diff suppressed because it is too large
Load Diff
1700
public/scripts/main.js
Normal file
1700
public/scripts/main.js
Normal file
File diff suppressed because it is too large
Load Diff
35459
public/scripts/three.js
Normal file
35459
public/scripts/three.js
Normal file
File diff suppressed because one or more lines are too long
51464
public/scripts/three.module.js
Normal file
51464
public/scripts/three.module.js
Normal file
File diff suppressed because one or more lines are too long
395
public/scripts/water.js
Normal file
395
public/scripts/water.js
Normal file
@ -0,0 +1,395 @@
|
||||
( function () {
|
||||
|
||||
/**
|
||||
* Work based on :
|
||||
* https://github.com/Slayvin: Flat mirror for three.js
|
||||
* https://home.adelphi.edu/~stemkoski/ : An implementation of water shader based on the flat mirror
|
||||
* http://29a.ch/ && http://29a.ch/slides/2012/webglwater/ : Water shader explanations in WebGL
|
||||
*/
|
||||
|
||||
class Water extends THREE.Mesh {
|
||||
|
||||
constructor( geometry, options = {} ) {
|
||||
|
||||
super( geometry );
|
||||
this.isWater = true;
|
||||
const scope = this;
|
||||
const textureWidth = options.textureWidth !== undefined ? options.textureWidth : 512;
|
||||
const textureHeight = options.textureHeight !== undefined ? options.textureHeight : 512;
|
||||
const clipBias = options.clipBias !== undefined ? options.clipBias : 0.0;
|
||||
const alpha = options.alpha !== undefined ? options.alpha : 1.0;
|
||||
const time = options.time !== undefined ? options.time : 0.0;
|
||||
const wave_time = options.wave_time !== undefined ? options.wave_time : 0.0;
|
||||
const normalSampler = options.waterNormals !== undefined ? options.waterNormals : null;
|
||||
const sunDirection = options.sunDirection !== undefined ? options.sunDirection : new THREE.Vector3( 0.70707, 0.70707, 0.0 );
|
||||
const sunColor = new THREE.Color( options.sunColor !== undefined ? options.sunColor : 0xffffff );
|
||||
const waterColor = new THREE.Color( options.waterColor !== undefined ? options.waterColor : 0x7F7F7F );
|
||||
const eye = options.eye !== undefined ? options.eye : new THREE.Vector3( 0, 0, 0 );
|
||||
const distortionScale = options.distortionScale !== undefined ? options.distortionScale : 20.0;
|
||||
const side = options.side !== undefined ? options.side : THREE.FrontSide;
|
||||
const fog = options.fog !== undefined ? options.fog : false; //
|
||||
|
||||
const mirrorPlane = new THREE.Plane();
|
||||
const normal = new THREE.Vector3();
|
||||
const mirrorWorldPosition = new THREE.Vector3();
|
||||
const cameraWorldPosition = new THREE.Vector3();
|
||||
const rotationMatrix = new THREE.Matrix4();
|
||||
const lookAtPosition = new THREE.Vector3( 0, 0, - 1 );
|
||||
const clipPlane = new THREE.Vector4();
|
||||
const view = new THREE.Vector3();
|
||||
const target = new THREE.Vector3();
|
||||
const q = new THREE.Vector4();
|
||||
const textureMatrix = new THREE.Matrix4();
|
||||
const mirrorCamera = new THREE.PerspectiveCamera();
|
||||
const renderTarget = new THREE.WebGLRenderTarget( textureWidth, textureHeight );
|
||||
window.mirrorShader = {
|
||||
uniforms: THREE.UniformsUtils.merge( [ THREE.UniformsLib[ 'fog' ], THREE.UniformsLib[ 'lights' ], {
|
||||
'normalSampler': {
|
||||
value: null
|
||||
},
|
||||
'mirrorSampler': {
|
||||
value: null
|
||||
},
|
||||
'alpha': {
|
||||
value: 1.0
|
||||
},
|
||||
'time': {
|
||||
value: 0.0
|
||||
},
|
||||
'wave_time': {
|
||||
value: 0.0
|
||||
},
|
||||
'size': {
|
||||
value: 1.0
|
||||
},
|
||||
'distortionScale': {
|
||||
value: 20.0
|
||||
},
|
||||
'textureMatrix': {
|
||||
value: new THREE.Matrix4()
|
||||
},
|
||||
'sunColor': {
|
||||
value: new THREE.Color( 0x7F7F7F )
|
||||
},
|
||||
'sunDirection': {
|
||||
value: new THREE.Vector3( 0.70707, 0.70707, 0 )
|
||||
},
|
||||
'eye': {
|
||||
value: new THREE.Vector3()
|
||||
},
|
||||
'waterColor': {
|
||||
value: new THREE.Color( 0x555555 )
|
||||
}
|
||||
} ] ),
|
||||
vertexShader:
|
||||
/* glsl */
|
||||
`
|
||||
uniform mat4 textureMatrix;
|
||||
uniform float time;
|
||||
uniform float wave_time;
|
||||
|
||||
varying vec4 mirrorCoord;
|
||||
varying vec4 worldPosition;
|
||||
varying vec2 vUv;
|
||||
|
||||
#include <common>
|
||||
#include <fog_pars_vertex>
|
||||
#include <shadowmap_pars_vertex>
|
||||
#include <logdepthbuf_pars_vertex>
|
||||
|
||||
vec3 mod289(vec3 x) {
|
||||
return x - floor(x * (1.0 / 289.0)) * 289.0;
|
||||
}
|
||||
|
||||
vec4 mod289(vec4 x) {
|
||||
return x - floor(x * (1.0 / 289.0)) * 289.0;
|
||||
}
|
||||
|
||||
vec4 permute(vec4 x) {
|
||||
return mod289(((x*34.0)+1.0)*x);
|
||||
}
|
||||
|
||||
vec4 taylorInvSqrt(vec4 r)
|
||||
{
|
||||
return 1.79284291400159 - 0.85373472095314 * r;
|
||||
}
|
||||
|
||||
float snoise(vec3 v) {
|
||||
const vec2 C = vec2(1.0/6.0, 1.0/3.0) ;
|
||||
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
|
||||
|
||||
// First corner
|
||||
vec3 i = floor(v + dot(v, C.yyy) );
|
||||
vec3 x0 = v - i + dot(i, C.xxx) ;
|
||||
|
||||
// Other corners
|
||||
vec3 g = step(x0.yzx, x0.xyz);
|
||||
vec3 l = 1.0 - g;
|
||||
vec3 i1 = min( g.xyz, l.zxy );
|
||||
vec3 i2 = max( g.xyz, l.zxy );
|
||||
|
||||
// x0 = x0 - 0.0 + 0.0 * C.xxx;
|
||||
// x1 = x0 - i1 + 1.0 * C.xxx;
|
||||
// x2 = x0 - i2 + 2.0 * C.xxx;
|
||||
// x3 = x0 - 1.0 + 3.0 * C.xxx;
|
||||
vec3 x1 = x0 - i1 + C.xxx;
|
||||
vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
|
||||
vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y
|
||||
|
||||
// Permutations
|
||||
i = mod289(i);
|
||||
vec4 p = permute( permute( permute(
|
||||
i.z + vec4(0.0, i1.z, i2.z, 1.0 ))
|
||||
+ i.y + vec4(0.0, i1.y, i2.y, 1.0 ))
|
||||
+ i.x + vec4(0.0, i1.x, i2.x, 1.0 ));
|
||||
|
||||
// Gradients: 7x7 points over a square, mapped onto an octahedron.
|
||||
// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
|
||||
float n_ = 0.142857142857; // 1.0/7.0
|
||||
vec3 ns = n_ * D.wyz - D.xzx;
|
||||
|
||||
vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7)
|
||||
|
||||
vec4 x_ = floor(j * ns.z);
|
||||
vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N)
|
||||
|
||||
vec4 x = x_ *ns.x + ns.yyyy;
|
||||
vec4 y = y_ *ns.x + ns.yyyy;
|
||||
vec4 h = 1.0 - abs(x) - abs(y);
|
||||
|
||||
vec4 b0 = vec4( x.xy, y.xy );
|
||||
vec4 b1 = vec4( x.zw, y.zw );
|
||||
|
||||
//vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
|
||||
//vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
|
||||
vec4 s0 = floor(b0)*2.0 + 1.0;
|
||||
vec4 s1 = floor(b1)*2.0 + 1.0;
|
||||
vec4 sh = -step(h, vec4(0.0));
|
||||
|
||||
vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;
|
||||
vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;
|
||||
|
||||
vec3 p0 = vec3(a0.xy,h.x);
|
||||
vec3 p1 = vec3(a0.zw,h.y);
|
||||
vec3 p2 = vec3(a1.xy,h.z);
|
||||
vec3 p3 = vec3(a1.zw,h.w);
|
||||
|
||||
// Normalise gradients
|
||||
vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
|
||||
p0 *= norm.x;
|
||||
p1 *= norm.y;
|
||||
p2 *= norm.z;
|
||||
p3 *= norm.w;
|
||||
|
||||
// Mix final noise value
|
||||
vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
|
||||
m = m * m;
|
||||
return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1),
|
||||
dot(p2,x2), dot(p3,x3) ) );
|
||||
}
|
||||
|
||||
void main() {
|
||||
mirrorCoord = modelMatrix * vec4( position, 1.0 );
|
||||
worldPosition = mirrorCoord.xyzw;
|
||||
mirrorCoord = textureMatrix * mirrorCoord;
|
||||
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
|
||||
gl_Position = projectionMatrix * mvPosition;
|
||||
|
||||
vUv = uv;
|
||||
|
||||
vec3 pos = position;
|
||||
float noiseFreq = 3.5;
|
||||
float noiseAmp = 0.45;
|
||||
vec3 noisePos = vec3(pos.x * noiseFreq + time, pos.y, pos.z);
|
||||
pos.z += snoise(noisePos) * noiseAmp;
|
||||
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.);
|
||||
|
||||
#include <beginnormal_vertex>
|
||||
#include <defaultnormal_vertex>
|
||||
#include <logdepthbuf_vertex>
|
||||
#include <fog_vertex>
|
||||
#include <shadowmap_vertex>
|
||||
}`,
|
||||
fragmentShader:
|
||||
/* glsl */
|
||||
`
|
||||
uniform sampler2D mirrorSampler;
|
||||
uniform float alpha;
|
||||
uniform float time;
|
||||
uniform float size;
|
||||
uniform float distortionScale;
|
||||
uniform sampler2D normalSampler;
|
||||
uniform vec3 sunColor;
|
||||
uniform vec3 sunDirection;
|
||||
uniform vec3 eye;
|
||||
uniform vec3 waterColor;
|
||||
|
||||
varying vec4 mirrorCoord;
|
||||
varying vec4 worldPosition;
|
||||
|
||||
vec4 getNoise( vec2 uv ) {
|
||||
vec2 uv0 = ( uv / 103.0 ) + vec2(time / 17.0, time / 29.0);
|
||||
vec2 uv1 = uv / 107.0-vec2( time / -19.0, time / 31.0 );
|
||||
vec2 uv2 = uv / vec2( 8907.0, 9803.0 ) + vec2( time / 101.0, time / 97.0 );
|
||||
vec2 uv3 = uv / vec2( 1091.0, 1027.0 ) - vec2( time / 109.0, time / -113.0 );
|
||||
vec4 noise = texture2D( normalSampler, uv0 ) +
|
||||
texture2D( normalSampler, uv1 ) +
|
||||
texture2D( normalSampler, uv2 ) +
|
||||
texture2D( normalSampler, uv3 );
|
||||
return noise * 0.5 - 1.0;
|
||||
}
|
||||
|
||||
void sunLight( const vec3 surfaceNormal, const vec3 eyeDirection, float shiny, float spec, float diffuse, inout vec3 diffuseColor, inout vec3 specularColor ) {
|
||||
vec3 reflection = normalize( reflect( -sunDirection, surfaceNormal ) );
|
||||
float direction = max( 0.0, dot( eyeDirection, reflection ) );
|
||||
specularColor += pow( direction, shiny ) * sunColor * spec;
|
||||
diffuseColor += max( dot( sunDirection, surfaceNormal ), 0.0 ) * sunColor * diffuse;
|
||||
}
|
||||
|
||||
#include <common>
|
||||
#include <packing>
|
||||
#include <bsdfs>
|
||||
#include <fog_pars_fragment>
|
||||
#include <logdepthbuf_pars_fragment>
|
||||
#include <lights_pars_begin>
|
||||
#include <shadowmap_pars_fragment>
|
||||
#include <shadowmask_pars_fragment>
|
||||
|
||||
void main() {
|
||||
|
||||
#include <logdepthbuf_fragment>
|
||||
vec4 noise = getNoise( worldPosition.xz * size );
|
||||
vec3 surfaceNormal = normalize( noise.xzy * vec3( 1.5, 1.0, 1.5 ) );
|
||||
|
||||
vec3 diffuseLight = vec3(0.0);
|
||||
vec3 specularLight = vec3(0.0);
|
||||
|
||||
vec3 worldToEye = eye-worldPosition.xyz;
|
||||
vec3 eyeDirection = normalize( worldToEye );
|
||||
sunLight( surfaceNormal, eyeDirection, 100.0, 2.0, 0.5, diffuseLight, specularLight );
|
||||
|
||||
float distance = length(worldToEye);
|
||||
|
||||
vec2 distortion = surfaceNormal.xz * ( 0.001 + 1.0 / distance ) * distortionScale;
|
||||
vec3 reflectionSample = vec3( texture2D( mirrorSampler, mirrorCoord.xy / mirrorCoord.w + distortion ) );
|
||||
|
||||
float theta = max( dot( eyeDirection, surfaceNormal ), 0.0 );
|
||||
float rf0 = 0.3;
|
||||
float reflectance = rf0 + ( 1.0 - rf0 ) * pow( ( 1.0 - theta ), 5.0 );
|
||||
vec3 scatter = max( 0.0, dot( surfaceNormal, eyeDirection ) ) * waterColor;
|
||||
vec3 albedo = mix( ( sunColor * diffuseLight * 0.3 + scatter ) * getShadowMask(), ( vec3( 0.1 ) + reflectionSample * 0.9 + reflectionSample * specularLight ), reflectance);
|
||||
vec3 outgoingLight = albedo;
|
||||
gl_FragColor = vec4( outgoingLight, alpha );
|
||||
|
||||
#include <tonemapping_fragment>
|
||||
#include <fog_fragment>
|
||||
}`
|
||||
};
|
||||
const material = new THREE.ShaderMaterial( {
|
||||
fragmentShader: mirrorShader.fragmentShader,
|
||||
vertexShader: mirrorShader.vertexShader,
|
||||
uniforms: THREE.UniformsUtils.clone( mirrorShader.uniforms ),
|
||||
lights: true,
|
||||
side: side,
|
||||
fog: fog
|
||||
} );
|
||||
material.uniforms[ 'mirrorSampler' ].value = renderTarget.texture;
|
||||
material.uniforms[ 'textureMatrix' ].value = textureMatrix;
|
||||
material.uniforms[ 'alpha' ].value = alpha;
|
||||
material.uniforms[ 'time' ].value = time;
|
||||
material.uniforms[ 'wave_time' ].value = time;
|
||||
material.uniforms[ 'normalSampler' ].value = normalSampler;
|
||||
material.uniforms[ 'sunColor' ].value = sunColor;
|
||||
material.uniforms[ 'waterColor' ].value = waterColor;
|
||||
material.uniforms[ 'sunDirection' ].value = sunDirection;
|
||||
material.uniforms[ 'distortionScale' ].value = distortionScale;
|
||||
material.uniforms[ 'eye' ].value = eye;
|
||||
scope.material = material;
|
||||
|
||||
scope.onBeforeRender = function ( renderer, scene, camera ) {
|
||||
|
||||
mirrorWorldPosition.setFromMatrixPosition( scope.matrixWorld );
|
||||
cameraWorldPosition.setFromMatrixPosition( camera.matrixWorld );
|
||||
rotationMatrix.extractRotation( scope.matrixWorld );
|
||||
normal.set( 0, 0, 1 );
|
||||
normal.applyMatrix4( rotationMatrix );
|
||||
view.subVectors( mirrorWorldPosition, cameraWorldPosition ); // Avoid rendering when mirror is facing away
|
||||
|
||||
if ( view.dot( normal ) > 0 ) return;
|
||||
view.reflect( normal ).negate();
|
||||
view.add( mirrorWorldPosition );
|
||||
rotationMatrix.extractRotation( camera.matrixWorld );
|
||||
lookAtPosition.set( 0, 0, - 1 );
|
||||
lookAtPosition.applyMatrix4( rotationMatrix );
|
||||
lookAtPosition.add( cameraWorldPosition );
|
||||
target.subVectors( mirrorWorldPosition, lookAtPosition );
|
||||
target.reflect( normal ).negate();
|
||||
target.add( mirrorWorldPosition );
|
||||
mirrorCamera.position.copy( view );
|
||||
mirrorCamera.up.set( 0, 1, 0 );
|
||||
mirrorCamera.up.applyMatrix4( rotationMatrix );
|
||||
mirrorCamera.up.reflect( normal );
|
||||
mirrorCamera.lookAt( target );
|
||||
mirrorCamera.far = camera.far; // Used in WebGLBackground
|
||||
|
||||
mirrorCamera.updateMatrixWorld();
|
||||
mirrorCamera.projectionMatrix.copy( camera.projectionMatrix ); // Update the texture matrix
|
||||
|
||||
textureMatrix.set( 0.5, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 1.0 );
|
||||
textureMatrix.multiply( mirrorCamera.projectionMatrix );
|
||||
textureMatrix.multiply( mirrorCamera.matrixWorldInverse ); // Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html
|
||||
// Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
|
||||
|
||||
mirrorPlane.setFromNormalAndCoplanarPoint( normal, mirrorWorldPosition );
|
||||
mirrorPlane.applyMatrix4( mirrorCamera.matrixWorldInverse );
|
||||
clipPlane.set( mirrorPlane.normal.x, mirrorPlane.normal.y, mirrorPlane.normal.z, mirrorPlane.constant );
|
||||
const projectionMatrix = mirrorCamera.projectionMatrix;
|
||||
q.x = ( Math.sign( clipPlane.x ) + projectionMatrix.elements[ 8 ] ) / projectionMatrix.elements[ 0 ];
|
||||
q.y = ( Math.sign( clipPlane.y ) + projectionMatrix.elements[ 9 ] ) / projectionMatrix.elements[ 5 ];
|
||||
q.z = - 1.0;
|
||||
q.w = ( 1.0 + projectionMatrix.elements[ 10 ] ) / projectionMatrix.elements[ 14 ]; // Calculate the scaled plane vector
|
||||
|
||||
clipPlane.multiplyScalar( 2.0 / clipPlane.dot( q ) ); // Replacing the third row of the projection matrix
|
||||
|
||||
projectionMatrix.elements[ 2 ] = clipPlane.x;
|
||||
projectionMatrix.elements[ 6 ] = clipPlane.y;
|
||||
projectionMatrix.elements[ 10 ] = clipPlane.z + 1.0 - clipBias;
|
||||
projectionMatrix.elements[ 14 ] = clipPlane.w;
|
||||
eye.setFromMatrixPosition( camera.matrixWorld ); // Render
|
||||
|
||||
const currentRenderTarget = renderer.getRenderTarget();
|
||||
const currentXrEnabled = renderer.xr.enabled;
|
||||
const currentShadowAutoUpdate = renderer.shadowMap.autoUpdate;
|
||||
scope.visible = false;
|
||||
renderer.xr.enabled = false; // Avoid camera modification and recursion
|
||||
|
||||
renderer.shadowMap.autoUpdate = false; // Avoid re-computing shadows
|
||||
|
||||
renderer.setRenderTarget( renderTarget );
|
||||
renderer.state.buffers.depth.setMask( true ); // make sure the depth buffer is writable so it can be properly cleared, see #18897
|
||||
|
||||
if ( renderer.autoClear === false ) renderer.clear();
|
||||
renderer.render( scene, mirrorCamera );
|
||||
scope.visible = true;
|
||||
renderer.xr.enabled = currentXrEnabled;
|
||||
renderer.shadowMap.autoUpdate = currentShadowAutoUpdate;
|
||||
renderer.setRenderTarget( currentRenderTarget ); // Restore viewport
|
||||
|
||||
const viewport = camera.viewport;
|
||||
|
||||
if ( viewport !== undefined ) {
|
||||
|
||||
renderer.state.viewport( viewport );
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
THREE.Water = Water;
|
||||
|
||||
} )();
|
BIN
public/seagull.glb
Normal file
BIN
public/seagull.glb
Normal file
Binary file not shown.
435
public/shaders/shaders.js
Normal file
435
public/shaders/shaders.js
Normal file
@ -0,0 +1,435 @@
|
||||
const island_vertecies = `
|
||||
#include <common>
|
||||
#include <shadowmap_pars_vertex>
|
||||
|
||||
varying vec3 vNormal;
|
||||
varying vec3 vViewDir;
|
||||
varying vec2 vUv;
|
||||
varying vec3 FragPos;
|
||||
|
||||
void main() {
|
||||
vUv = uv;
|
||||
#include <beginnormal_vertex>
|
||||
#include <defaultnormal_vertex>
|
||||
|
||||
#include <begin_vertex>
|
||||
|
||||
#include <worldpos_vertex>
|
||||
#include <shadowmap_vertex>
|
||||
|
||||
vec4 modelPosition = modelMatrix * vec4(position, 1.0);
|
||||
vec4 viewPosition = viewMatrix * modelPosition;
|
||||
vec4 clipPosition = projectionMatrix * viewPosition;
|
||||
|
||||
vNormal = normalize(normal);
|
||||
// vNormal = normalize(normalMatrix * normal);
|
||||
vViewDir = normalize(-viewPosition.xyz);
|
||||
|
||||
FragPos = vec3(modelMatrix * vec4(position, 1.0));
|
||||
|
||||
gl_Position = clipPosition;
|
||||
|
||||
}
|
||||
`;
|
||||
const island_fragments = `
|
||||
#include <common>
|
||||
#include <packing>
|
||||
#include <lights_pars_begin>
|
||||
#include <shadowmap_pars_fragment>
|
||||
#include <shadowmask_pars_fragment>
|
||||
|
||||
uniform sampler2D texture1;
|
||||
uniform sampler2D texture2;
|
||||
uniform sampler2D texture3;
|
||||
uniform float intensity;
|
||||
uniform float pointLightsPosX;
|
||||
uniform float pointLightsPosY;
|
||||
uniform float pointLightsPosZ;
|
||||
|
||||
varying vec3 vNormal;
|
||||
varying vec3 FragPos;
|
||||
varying vec2 vUv;
|
||||
|
||||
void main() {
|
||||
vec3 pointLightsPos = vec3(9.0, 10.0, -16.0);
|
||||
vec3 pointLightsColor = pointLights[0].color;
|
||||
|
||||
|
||||
vec4 t1 = texture2D( texture1, vUv );
|
||||
vec4 t2 = texture2D( texture2, vUv );
|
||||
vec4 t3 = texture2D( texture3, vUv );
|
||||
|
||||
vec4 interrim = mix( t1, t2, t2.a );
|
||||
vec4 interrim2 = mix( interrim, t3, t3.a );
|
||||
|
||||
// vec3 lightDir = normalize(pointLightsPos - FragPos);
|
||||
vec3 lightDir = normalize(pointLightsPos);
|
||||
|
||||
float diff = max(dot(vNormal, -lightDir), 0.0);
|
||||
vec3 diffuse = diff * pointLightsColor * interrim2.rgb;
|
||||
|
||||
vec3 result = ( (ambientLightColor + diffuse) / 14.0);
|
||||
vec4 color = vec4(result, 1.0);
|
||||
|
||||
gl_FragColor = vec4(color);
|
||||
}
|
||||
`;
|
||||
|
||||
const palm_vertecies = `
|
||||
#define STANDARD
|
||||
uniform float uTime;
|
||||
varying vec3 vViewPosition;
|
||||
#ifdef USE_TRANSMISSION
|
||||
varying vec3 vWorldPosition;
|
||||
#endif
|
||||
#include <common>
|
||||
#include <uv_pars_vertex>
|
||||
#include <uv2_pars_vertex>
|
||||
#include <displacementmap_pars_vertex>
|
||||
#include <color_pars_vertex>
|
||||
#include <fog_pars_vertex>
|
||||
#include <normal_pars_vertex>
|
||||
#include <morphtarget_pars_vertex>
|
||||
#include <skinning_pars_vertex>
|
||||
#include <shadowmap_pars_vertex>
|
||||
#include <logdepthbuf_pars_vertex>
|
||||
#include <clipping_planes_pars_vertex>
|
||||
|
||||
|
||||
void main() {
|
||||
#include <uv_vertex>
|
||||
#include <uv2_vertex>
|
||||
#include <color_vertex>
|
||||
#include <morphcolor_vertex>
|
||||
#include <beginnormal_vertex>
|
||||
#include <morphnormal_vertex>
|
||||
#include <skinbase_vertex>
|
||||
#include <skinnormal_vertex>
|
||||
#include <defaultnormal_vertex>
|
||||
#include <normal_vertex>
|
||||
#include <begin_vertex>
|
||||
#include <morphtarget_vertex>
|
||||
#include <skinning_vertex>
|
||||
#include <displacementmap_vertex>
|
||||
#include <project_vertex>
|
||||
#include <logdepthbuf_vertex>
|
||||
#include <clipping_planes_vertex>
|
||||
vViewPosition = - mvPosition.xyz;
|
||||
#include <worldpos_vertex>
|
||||
#include <shadowmap_vertex>
|
||||
#include <fog_vertex>
|
||||
|
||||
vUv = uv;
|
||||
|
||||
vec3 delta = normal * sin(position.x * position.y * uTime * 0.0001) * 10.0;
|
||||
vec3 newPosition = position + delta;
|
||||
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0);
|
||||
|
||||
#ifdef USE_TRANSMISSION
|
||||
vWorldPosition = worldPosition.xyz;
|
||||
#endif
|
||||
}`;
|
||||
const palm_fragments = `
|
||||
#define STANDARD
|
||||
#ifdef PHYSICAL
|
||||
#define IOR
|
||||
#define SPECULAR
|
||||
#endif
|
||||
uniform vec3 diffuse;
|
||||
uniform vec3 emissive;
|
||||
uniform float roughness;
|
||||
uniform float metalness;
|
||||
uniform float opacity;
|
||||
#ifdef IOR
|
||||
uniform float ior;
|
||||
#endif
|
||||
#ifdef SPECULAR
|
||||
uniform float specularIntensity;
|
||||
uniform vec3 specularColor;
|
||||
#ifdef USE_SPECULARINTENSITYMAP
|
||||
uniform sampler2D specularIntensityMap;
|
||||
#endif
|
||||
#ifdef USE_SPECULARCOLORMAP
|
||||
uniform sampler2D specularColorMap;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef USE_CLEARCOAT
|
||||
uniform float clearcoat;
|
||||
uniform float clearcoatRoughness;
|
||||
#endif
|
||||
#ifdef USE_IRIDESCENCE
|
||||
uniform float iridescence;
|
||||
uniform float iridescenceIOR;
|
||||
uniform float iridescenceThicknessMinimum;
|
||||
uniform float iridescenceThicknessMaximum;
|
||||
#endif
|
||||
#ifdef USE_SHEEN
|
||||
uniform vec3 sheenColor;
|
||||
uniform float sheenRoughness;
|
||||
#ifdef USE_SHEENCOLORMAP
|
||||
uniform sampler2D sheenColorMap;
|
||||
#endif
|
||||
#ifdef USE_SHEENROUGHNESSMAP
|
||||
uniform sampler2D sheenRoughnessMap;
|
||||
#endif
|
||||
#endif
|
||||
varying vec3 vViewPosition;
|
||||
#include <common>
|
||||
#include <packing>
|
||||
#include <dithering_pars_fragment>
|
||||
#include <color_pars_fragment>
|
||||
#include <uv_pars_fragment>
|
||||
#include <uv2_pars_fragment>
|
||||
#include <map_pars_fragment>
|
||||
#include <alphamap_pars_fragment>
|
||||
#include <alphatest_pars_fragment>
|
||||
#include <aomap_pars_fragment>
|
||||
#include <lightmap_pars_fragment>
|
||||
#include <emissivemap_pars_fragment>
|
||||
#include <bsdfs>
|
||||
#include <iridescence_fragment>
|
||||
#include <cube_uv_reflection_fragment>
|
||||
#include <envmap_common_pars_fragment>
|
||||
#include <envmap_physical_pars_fragment>
|
||||
#include <fog_pars_fragment>
|
||||
#include <lights_pars_begin>
|
||||
#include <normal_pars_fragment>
|
||||
#include <lights_physical_pars_fragment>
|
||||
#include <transmission_pars_fragment>
|
||||
#include <shadowmap_pars_fragment>
|
||||
#include <bumpmap_pars_fragment>
|
||||
#include <normalmap_pars_fragment>
|
||||
#include <clearcoat_pars_fragment>
|
||||
#include <iridescence_pars_fragment>
|
||||
#include <roughnessmap_pars_fragment>
|
||||
#include <metalnessmap_pars_fragment>
|
||||
#include <logdepthbuf_pars_fragment>
|
||||
#include <clipping_planes_pars_fragment>
|
||||
void main() {
|
||||
#include <clipping_planes_fragment>
|
||||
vec4 diffuseColor = vec4( diffuse, opacity );
|
||||
ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );
|
||||
vec3 totalEmissiveRadiance = emissive;
|
||||
#include <logdepthbuf_fragment>
|
||||
#include <map_fragment>
|
||||
#include <color_fragment>
|
||||
#include <alphamap_fragment>
|
||||
#include <alphatest_fragment>
|
||||
#include <roughnessmap_fragment>
|
||||
#include <metalnessmap_fragment>
|
||||
#include <normal_fragment_begin>
|
||||
#include <normal_fragment_maps>
|
||||
#include <clearcoat_normal_fragment_begin>
|
||||
#include <clearcoat_normal_fragment_maps>
|
||||
#include <emissivemap_fragment>
|
||||
#include <lights_physical_fragment>
|
||||
#include <lights_fragment_begin>
|
||||
#include <lights_fragment_maps>
|
||||
#include <lights_fragment_end>
|
||||
#include <aomap_fragment>
|
||||
vec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;
|
||||
vec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular;
|
||||
#include <transmission_fragment>
|
||||
vec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance;
|
||||
#ifdef USE_SHEEN
|
||||
float sheenEnergyComp = 1.0 - 0.157 * max3( material.sheenColor );
|
||||
outgoingLight = outgoingLight * sheenEnergyComp + sheenSpecular;
|
||||
#endif
|
||||
#ifdef USE_CLEARCOAT
|
||||
float dotNVcc = saturate( dot( geometry.clearcoatNormal, geometry.viewDir ) );
|
||||
vec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc );
|
||||
outgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + clearcoatSpecular * material.clearcoat;
|
||||
#endif
|
||||
#include <output_fragment>
|
||||
#include <tonemapping_fragment>
|
||||
#include <encodings_fragment>
|
||||
#include <fog_fragment>
|
||||
#include <premultiplied_alpha_fragment>
|
||||
#include <dithering_fragment>
|
||||
}
|
||||
`;
|
||||
const particle_vertecies = `
|
||||
attribute float rots;
|
||||
varying float vRots;
|
||||
varying vec3 pos;
|
||||
varying vec2 vUv;
|
||||
uniform float time;
|
||||
attribute float size;
|
||||
uniform float scale;
|
||||
#include <common>
|
||||
#include <color_pars_vertex>
|
||||
#include <fog_pars_vertex>
|
||||
#include <morphtarget_pars_vertex>
|
||||
#include <logdepthbuf_pars_vertex>
|
||||
#include <clipping_planes_pars_vertex>
|
||||
|
||||
vec3 mod289(vec3 x) {
|
||||
return x - floor(x * (1.0 / 289.0)) * 289.0;
|
||||
}
|
||||
|
||||
vec4 mod289(vec4 x) {
|
||||
return x - floor(x * (1.0 / 289.0)) * 289.0;
|
||||
}
|
||||
|
||||
vec4 permute(vec4 x) {
|
||||
return mod289(((x*34.0)+1.0)*x);
|
||||
}
|
||||
|
||||
vec4 taylorInvSqrt(vec4 r)
|
||||
{
|
||||
return 1.79284291400159 - 0.85373472095314 * r;
|
||||
}
|
||||
|
||||
float snoise(vec3 v) {
|
||||
const vec2 C = vec2(1.0/6.0, 1.0/3.0) ;
|
||||
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
|
||||
|
||||
// First corner
|
||||
vec3 i = floor(v + dot(v, C.yyy) );
|
||||
vec3 x0 = v - i + dot(i, C.xxx) ;
|
||||
|
||||
// Other corners
|
||||
vec3 g = step(x0.yzx, x0.xyz);
|
||||
vec3 l = 1.0 - g;
|
||||
vec3 i1 = min( g.xyz, l.zxy );
|
||||
vec3 i2 = max( g.xyz, l.zxy );
|
||||
|
||||
// x0 = x0 - 0.0 + 0.0 * C.xxx;
|
||||
// x1 = x0 - i1 + 1.0 * C.xxx;
|
||||
// x2 = x0 - i2 + 2.0 * C.xxx;
|
||||
// x3 = x0 - 1.0 + 3.0 * C.xxx;
|
||||
vec3 x1 = x0 - i1 + C.xxx;
|
||||
vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
|
||||
vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y
|
||||
|
||||
// Permutations
|
||||
i = mod289(i);
|
||||
vec4 p = permute( permute( permute(
|
||||
i.z + vec4(0.0, i1.z, i2.z, 1.0 ))
|
||||
+ i.y + vec4(0.0, i1.y, i2.y, 1.0 ))
|
||||
+ i.x + vec4(0.0, i1.x, i2.x, 1.0 ));
|
||||
|
||||
// Gradients: 7x7 points over a square, mapped onto an octahedron.
|
||||
// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
|
||||
float n_ = 0.142857142857; // 1.0/7.0
|
||||
vec3 ns = n_ * D.wyz - D.xzx;
|
||||
|
||||
vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7)
|
||||
|
||||
vec4 x_ = floor(j * ns.z);
|
||||
vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N)
|
||||
|
||||
vec4 x = x_ *ns.x + ns.yyyy;
|
||||
vec4 y = y_ *ns.x + ns.yyyy;
|
||||
vec4 h = 1.0 - abs(x) - abs(y);
|
||||
|
||||
vec4 b0 = vec4( x.xy, y.xy );
|
||||
vec4 b1 = vec4( x.zw, y.zw );
|
||||
|
||||
//vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
|
||||
//vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
|
||||
vec4 s0 = floor(b0)*2.0 + 1.0;
|
||||
vec4 s1 = floor(b1)*2.0 + 1.0;
|
||||
vec4 sh = -step(h, vec4(0.0));
|
||||
|
||||
vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;
|
||||
vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;
|
||||
|
||||
vec3 p0 = vec3(a0.xy,h.x);
|
||||
vec3 p1 = vec3(a0.zw,h.y);
|
||||
vec3 p2 = vec3(a1.xy,h.z);
|
||||
vec3 p3 = vec3(a1.zw,h.w);
|
||||
|
||||
// Normalise gradients
|
||||
vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
|
||||
p0 *= norm.x;
|
||||
p1 *= norm.y;
|
||||
p2 *= norm.z;
|
||||
p3 *= norm.w;
|
||||
|
||||
// Mix final noise value
|
||||
vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
|
||||
m = m * m;
|
||||
return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1),
|
||||
dot(p2,x2), dot(p3,x3) ) );
|
||||
}
|
||||
|
||||
void main() {
|
||||
#include <color_vertex>
|
||||
#include <morphcolor_vertex>
|
||||
#include <begin_vertex>
|
||||
#include <morphtarget_vertex>
|
||||
#include <project_vertex>
|
||||
gl_PointSize = size;
|
||||
pos = position;
|
||||
float noiseFreq = 3.5;
|
||||
float noiseAmp = 0.15;
|
||||
vec3 noisePos = vec3(pos.x * noiseFreq + ${Math.random() * 0.5 + 0.1}, pos.y, pos.z);
|
||||
gl_Position.x += snoise(noisePos) * noiseAmp * 10.0;
|
||||
gl_Position.y += snoise(noisePos) * noiseAmp * 1.0;
|
||||
#ifdef USE_SIZEATTENUATION
|
||||
bool isPerspective = isPerspectiveMatrix( projectionMatrix );
|
||||
if ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );
|
||||
#endif
|
||||
#include <logdepthbuf_vertex>
|
||||
#include <clipping_planes_vertex>
|
||||
#include <worldpos_vertex>
|
||||
#include <fog_vertex>
|
||||
vRots = rots;
|
||||
}
|
||||
`;
|
||||
const particle_fragments = `
|
||||
varying float vRots;
|
||||
uniform sampler2D tDiffuse;
|
||||
varying vec2 vUv;
|
||||
uniform vec3 diffuse;
|
||||
uniform float opacity;
|
||||
varying vec3 pos;
|
||||
|
||||
#include <common>
|
||||
#include <color_pars_fragment>
|
||||
#include <map_particle_pars_fragment>
|
||||
#include <alphatest_pars_fragment>
|
||||
#include <fog_pars_fragment>
|
||||
#include <logdepthbuf_pars_fragment>
|
||||
#include <clipping_planes_pars_fragment>
|
||||
|
||||
// float rand(vec2 co)
|
||||
// {
|
||||
// float a = 12.9898;
|
||||
// float b = 78.233;
|
||||
// float c = 43758.5453;
|
||||
// float dt= dot(co.xy ,vec2(a,b));
|
||||
// float sn= mod(dt,3.14);
|
||||
// return fract(sin(sn) * c);
|
||||
// }
|
||||
|
||||
void main() {
|
||||
#include <clipping_planes_fragment>
|
||||
vec3 outgoingLight = vec3( 0.0 );
|
||||
vec4 diffuseColor = vec4( diffuse, opacity );
|
||||
|
||||
if ( length( gl_PointCoord - vec2( 0.5, 0.5 ) ) > 0.475 ) discard;
|
||||
|
||||
// outgoingLight = diffuseColor.rgb + sin(rand(vec2( time, time) ) );
|
||||
// gl_FragColor.a = 0.1;
|
||||
// gl_FragColor = texture2D(tDiffuse, vUv);
|
||||
// gl_FragColor.r = 256.0;
|
||||
// gl_FragColor.g = 256.0;
|
||||
// gl_FragColor = diffuseColor;
|
||||
|
||||
#include <logdepthbuf_fragment>
|
||||
#include <map_particle_fragment>
|
||||
#include <color_fragment>
|
||||
#include <alphatest_fragment>
|
||||
|
||||
outgoingLight = diffuseColor.rgb + rand(vec2( pos.x, pos.y) ) ;
|
||||
|
||||
#include <output_fragment>
|
||||
#include <tonemapping_fragment>
|
||||
#include <encodings_fragment>
|
||||
#include <fog_fragment>
|
||||
#include <premultiplied_alpha_fragment>
|
||||
}
|
||||
`
|
47
ship.js
Normal file
47
ship.js
Normal file
@ -0,0 +1,47 @@
|
||||
// const {sequelize, DataTypes} = require('./db/sql_connection');
|
||||
require('dotenv').config({ path: require('node:path').resolve(process.cwd(), '.env') });
|
||||
const APP_BASE_PATH = process.env.APP_BASE_PATH || "";
|
||||
const express = require("express");
|
||||
const app = express(); //
|
||||
// const fs = require("fs");
|
||||
const http = require("http").createServer(app);
|
||||
const io = require("socket.io")(http);
|
||||
// const path = require("path");
|
||||
|
||||
var id = [];
|
||||
var obj_collection = {};
|
||||
|
||||
http.listen(process.env.PORT, process.env.HOST, function () {
|
||||
console.log("game server is started");
|
||||
})
|
||||
|
||||
io.on("connection", function (socket) {
|
||||
console.log("user " + socket.id + " is connected");
|
||||
socket.on("mouseclick", (coords) => {
|
||||
console.log("coords");
|
||||
console.log(coords);
|
||||
socket.broadcast.emit("coords", coords);
|
||||
id[socket.id] = coords.id;
|
||||
obj_collection[coords.id] = coords;
|
||||
})
|
||||
socket.on("disconnect", () => {
|
||||
console.log("user " + socket.id + " is disconnected");
|
||||
socket.broadcast.emit("remove", id[socket.id]);
|
||||
|
||||
delete obj_collection[id[socket.id]];
|
||||
delete id[socket.id];
|
||||
})
|
||||
socket.on("loaded", () => {
|
||||
console.log("loaded");
|
||||
io.emit("send_objects", obj_collection);
|
||||
})
|
||||
})
|
||||
|
||||
app.set("view engine", "ejs");
|
||||
app.use(express.static("public"));
|
||||
app.use(express.json({extended: false}));
|
||||
app.get("/", (req, res) => {
|
||||
res.render("game", {
|
||||
base_path: APP_BASE_PATH,
|
||||
});
|
||||
});
|
0
tmp/restart.txt
Normal file
0
tmp/restart.txt
Normal file
108
views/game.ejs
Normal file
108
views/game.ejs
Normal file
@ -0,0 +1,108 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta Content-Type: application/javascript; charset=UTF-8>
|
||||
<link rel="stylesheet" type="text/css" href="./css/style.css">
|
||||
<body>
|
||||
<div class="big_container">
|
||||
<div class="menu_ico">
|
||||
<div>
|
||||
</div>
|
||||
<div class="slidecontainer">
|
||||
<div id="sheet1" class="sheet">
|
||||
<small>Поворот сцены — мышь + зажата левая нопка</small>
|
||||
<br>
|
||||
<small>Перемещение сцены — мышь + левая кнопка + shift</small>
|
||||
<br>
|
||||
<small>Масштаб — прокрутка или зажатие колесика</small>
|
||||
<br>
|
||||
<br>
|
||||
<div>Море</div>
|
||||
<input id="range" type="range" min="1" max="50" value="1" class="slider">
|
||||
</div>
|
||||
<div id="sheet2" class="sheet hide">
|
||||
<small>Клик выделяет кубик — точку границы коллизии</small>
|
||||
<br>
|
||||
<small>Мышь + зажатая левая кнопка — перемещение кубика</small>
|
||||
<br>
|
||||
<small>Кнопка "Проверить" активирует движение корабля</small>
|
||||
<br>
|
||||
<br>
|
||||
<div>Море</div>
|
||||
<input id="range" type="range" min="1" max="50" value="1" class="slider">
|
||||
</div>
|
||||
|
||||
<div id="checkbox-container">
|
||||
<div>
|
||||
<input type="checkbox" id="map" name="map" />
|
||||
<label for="map">Карта</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" id="collision_edit" name="collision_edit" />
|
||||
<label for="collision_edit">Редактировать коллизию</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" id="collision_edit2" name="collision_edit" disabled = "true" checked />
|
||||
<label for="collision_edit2">Обход по кривой Лагранжа</label>
|
||||
<button id="lagr_test" disabled = "true">Проверить путь</button>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" id="border_left" name="border" value="left" />
|
||||
<label for="border_left">Левая граница</label>
|
||||
|
||||
<input type="radio" id="border_right" name="border" value="right" checked/>
|
||||
<label for="border_right">Правая граница</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<canvas id="c"></canvas>
|
||||
<canvas id="canvas_temp"></canvas>
|
||||
<canvas id="canvas_temp2"></canvas>
|
||||
<div class="top-div"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
window.container = document.querySelector(".container");
|
||||
window.canvas = document.querySelector('#c');
|
||||
window.canvas2 = document.querySelector('#canvas_temp');
|
||||
window.ctx2 = canvas2.getContext("2d");
|
||||
canvas2.width = 750;
|
||||
canvas2.height = 500;
|
||||
|
||||
window.canvas3 = document.querySelector('#canvas_temp2');
|
||||
window.ctx3 = canvas3.getContext("2d");
|
||||
canvas3.width = 750;
|
||||
canvas3.height = 500;
|
||||
// container.appendChild(canvas2);
|
||||
window.loading_text = document.querySelector('.top-div');
|
||||
|
||||
const base_path = "<%=base_path%>";
|
||||
</script>
|
||||
<script src="./scripts/three.js"></script>
|
||||
|
||||
<script src="<%=base_path%>/socket.io/socket.io.js"></script>
|
||||
<script src="./scripts/three.module.js"></script>
|
||||
<script src="./scripts/OrbitControls.js"></script>
|
||||
<script src="./scripts/GLTFLoader.js"></script>
|
||||
<script src="./scripts/fflate.module.js"></script>
|
||||
<script src="./scripts/NURBSUtils.js"></script>
|
||||
<script src="./scripts/NURBSCurve.js"></script>
|
||||
<script src="./scripts/FBXLoader.js"></script>
|
||||
<script src="./assets/textures.js"></script>
|
||||
<script src="./assets/models.js"></script>
|
||||
<script src="./assets/models_man.js"></script>
|
||||
<script src="./scripts/water.js"></script>
|
||||
|
||||
<script src='./shaders/shaders.js'>
|
||||
|
||||
</script>
|
||||
|
||||
<script type='module'>
|
||||
import * as SkeletonUtils from './scripts/SkeletonUtils.js';
|
||||
window.SkeletonUtils = SkeletonUtils;
|
||||
</script>
|
||||
|
||||
<script src="./scripts/main.js"></script>
|
||||
</body>
|
||||
</html>
|
Loading…
x
Reference in New Issue
Block a user