@mml-io/3d-web-client-core 0.10.1 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/camera/CameraManager.d.ts +1 -1
- package/build/character/Character.d.ts +9 -18
- package/build/character/CharacterManager.d.ts +6 -5
- package/build/character/CharacterModel.d.ts +2 -4
- package/build/character/CharacterModelLoader.d.ts +2 -5
- package/build/character/CharacterTooltip.d.ts +4 -6
- package/build/character/LocalController.d.ts +3 -4
- package/build/character/RemoteController.d.ts +1 -9
- package/build/character/url-position.d.ts +12 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +1705 -512
- package/build/index.js.map +4 -4
- package/build/mml/MMLCompositionScene.d.ts +1 -0
- package/build/rendering/post-effects/n8-ssao/BlueNoise.d.ts +1 -0
- package/build/rendering/post-effects/n8-ssao/DepthDownSample.d.ts +17 -0
- package/build/rendering/post-effects/n8-ssao/EffectCompositer.d.ts +39 -0
- package/build/rendering/post-effects/n8-ssao/EffectShader.d.ts +31 -0
- package/build/rendering/post-effects/n8-ssao/FullScreenTriangle.d.ts +11 -0
- package/build/rendering/post-effects/n8-ssao/N8SSAOPass.d.ts +65 -0
- package/build/rendering/post-effects/n8-ssao/PoissionBlur.d.ts +30 -0
- package/build/tweakpane/blades/ssaoFolder.d.ts +21 -0
- package/package.json +3 -4
package/build/index.js
CHANGED
@@ -34,6 +34,9 @@ var round = (n, digits) => {
|
|
34
34
|
var ease = (target, n, factor) => {
|
35
35
|
return round((target - n) * factor, 5);
|
36
36
|
};
|
37
|
+
function clamp(value, min, max) {
|
38
|
+
return Math.min(Math.max(value, min), max);
|
39
|
+
}
|
37
40
|
var remap = (value, minValue, maxValue, minScaledValue, maxScaledValue) => {
|
38
41
|
return minScaledValue + (maxScaledValue - minScaledValue) * (value - minValue) / (maxValue - minValue);
|
39
42
|
};
|
@@ -106,6 +109,8 @@ var CameraManager = class {
|
|
106
109
|
this.targetDistance = this.initialDistance;
|
107
110
|
this.distance = this.initialDistance;
|
108
111
|
this.desiredDistance = this.initialDistance;
|
112
|
+
this.phi = Math.PI / 2;
|
113
|
+
this.theta = Math.PI / 2;
|
109
114
|
this.dragging = false;
|
110
115
|
this.target = new Vector32(0, 1.55, 0);
|
111
116
|
this.hadTarget = false;
|
@@ -174,17 +179,24 @@ var CameraManager = class {
|
|
174
179
|
this.setTarget(target);
|
175
180
|
}
|
176
181
|
reverseUpdateFromPositions() {
|
177
|
-
if (this.phi === null || this.theta == null)
|
178
|
-
return;
|
179
182
|
const dx = this.camera.position.x - this.target.x;
|
180
183
|
const dy = this.camera.position.y - this.target.y;
|
181
184
|
const dz = this.camera.position.z - this.target.z;
|
182
185
|
this.targetDistance = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
183
|
-
this.targetTheta =
|
184
|
-
this.targetPhi = Math.
|
186
|
+
this.targetTheta = Math.atan2(dz, dx);
|
187
|
+
this.targetPhi = Math.acos(dy / this.targetDistance);
|
185
188
|
this.phi = this.targetPhi;
|
186
189
|
this.theta = this.targetTheta;
|
187
190
|
this.distance = this.targetDistance;
|
191
|
+
this.desiredDistance = this.targetDistance;
|
192
|
+
this.targetFOV = remap(
|
193
|
+
this.targetDistance,
|
194
|
+
this.minDistance,
|
195
|
+
this.maxDistance,
|
196
|
+
this.minFOV,
|
197
|
+
this.maxFOV
|
198
|
+
);
|
199
|
+
this.fov = this.targetFOV;
|
188
200
|
}
|
189
201
|
adjustCameraPosition() {
|
190
202
|
this.rayCaster.set(
|
@@ -244,14 +256,13 @@ var CameraManager = class {
|
|
244
256
|
};
|
245
257
|
|
246
258
|
// src/character/Character.ts
|
247
|
-
import { Color as Color3, Vector3 as
|
259
|
+
import { Color as Color3, Group, Vector3 as Vector34 } from "three";
|
248
260
|
|
249
261
|
// src/character/CharacterModel.ts
|
250
262
|
import {
|
251
263
|
AnimationClip,
|
252
264
|
AnimationMixer,
|
253
265
|
LoopRepeat,
|
254
|
-
MeshStandardMaterial,
|
255
266
|
Object3D
|
256
267
|
} from "three";
|
257
268
|
|
@@ -659,36 +670,10 @@ var CharacterModel = class {
|
|
659
670
|
);
|
660
671
|
this.applyMaterialToAllSkinnedMeshes(this.material);
|
661
672
|
}
|
662
|
-
updateAnimation(targetAnimation
|
663
|
-
var _a;
|
673
|
+
updateAnimation(targetAnimation) {
|
664
674
|
if (this.currentAnimation !== targetAnimation) {
|
665
675
|
this.transitionToAnimation(targetAnimation);
|
666
676
|
}
|
667
|
-
(_a = this.animationMixer) == null ? void 0 : _a.update(deltaTime);
|
668
|
-
}
|
669
|
-
hideMaterialByMeshName(meshName) {
|
670
|
-
if (!this.mesh)
|
671
|
-
return;
|
672
|
-
this.mesh.traverse((child) => {
|
673
|
-
if (child.type === "Bone" && child.name === "mixamorigHeadTop_End") {
|
674
|
-
this.headBone = child;
|
675
|
-
}
|
676
|
-
if (child.type === "SkinnedMesh" && child.name === meshName) {
|
677
|
-
child.material = new MeshStandardMaterial({
|
678
|
-
color: 16711680,
|
679
|
-
transparent: true,
|
680
|
-
opacity: 0
|
681
|
-
});
|
682
|
-
}
|
683
|
-
});
|
684
|
-
}
|
685
|
-
setShadows(mesh, castShadow = true, receiveShadow = true) {
|
686
|
-
mesh.traverse((child) => {
|
687
|
-
if (child.type === "SkinnedMesh") {
|
688
|
-
child.castShadow = castShadow;
|
689
|
-
child.receiveShadow = receiveShadow;
|
690
|
-
}
|
691
|
-
});
|
692
677
|
}
|
693
678
|
applyMaterialToAllSkinnedMeshes(material) {
|
694
679
|
if (!this.mesh)
|
@@ -699,11 +684,6 @@ var CharacterModel = class {
|
|
699
684
|
}
|
700
685
|
});
|
701
686
|
}
|
702
|
-
initAnimationMixer() {
|
703
|
-
if (this.animationMixer !== null || this.mesh === null)
|
704
|
-
return;
|
705
|
-
this.animationMixer = new AnimationMixer(this.mesh);
|
706
|
-
}
|
707
687
|
async loadMainMesh() {
|
708
688
|
const mainMeshUrl = this.characterDescription.meshFileUrl;
|
709
689
|
const scale = this.characterDescription.modelScale;
|
@@ -717,12 +697,17 @@ var CharacterModel = class {
|
|
717
697
|
this.mesh.add(model);
|
718
698
|
this.mesh.name = name;
|
719
699
|
this.mesh.scale.set(scale, scale, scale);
|
720
|
-
this.
|
700
|
+
this.mesh.traverse((child) => {
|
701
|
+
if (child.type === "SkinnedMesh") {
|
702
|
+
child.castShadow = true;
|
703
|
+
child.receiveShadow = true;
|
704
|
+
}
|
705
|
+
});
|
706
|
+
this.animationMixer = new AnimationMixer(this.mesh);
|
721
707
|
}
|
722
708
|
}
|
723
709
|
async setAnimationFromFile(animationFileUrl, animationType) {
|
724
710
|
return new Promise(async (resolve, reject) => {
|
725
|
-
this.initAnimationMixer();
|
726
711
|
const animation = await this.characterModelLoader.load(animationFileUrl, "animation");
|
727
712
|
if (typeof animation !== "undefined" && animation instanceof AnimationClip) {
|
728
713
|
this.animations[animationType] = this.animationMixer.clipAction(animation);
|
@@ -737,9 +722,10 @@ var CharacterModel = class {
|
|
737
722
|
});
|
738
723
|
}
|
739
724
|
transitionToAnimation(targetAnimation, transitionDuration = 0.15) {
|
740
|
-
if (!this.mesh
|
725
|
+
if (!this.mesh)
|
741
726
|
return;
|
742
727
|
const currentAction = this.animations[this.currentAnimation];
|
728
|
+
this.currentAnimation = targetAnimation;
|
743
729
|
const targetAction = this.animations[targetAnimation];
|
744
730
|
if (!targetAction)
|
745
731
|
return;
|
@@ -752,7 +738,11 @@ var CharacterModel = class {
|
|
752
738
|
targetAction.setLoop(LoopRepeat, Infinity);
|
753
739
|
targetAction.enabled = true;
|
754
740
|
targetAction.fadeIn(transitionDuration);
|
755
|
-
|
741
|
+
}
|
742
|
+
update(time) {
|
743
|
+
if (this.animationMixer) {
|
744
|
+
this.animationMixer.update(time);
|
745
|
+
}
|
756
746
|
}
|
757
747
|
};
|
758
748
|
|
@@ -978,8 +968,10 @@ var defaultLabelPadding = 0;
|
|
978
968
|
var defaultLabelWidth = 0.25;
|
979
969
|
var defaultLabelHeight = 0.125;
|
980
970
|
var defaultLabelCastShadows = true;
|
981
|
-
var
|
982
|
-
|
971
|
+
var tooltipGeometry = new PlaneGeometry(1, 1, 1, 1);
|
972
|
+
var CharacterTooltip = class extends Mesh3 {
|
973
|
+
constructor() {
|
974
|
+
super(tooltipGeometry);
|
983
975
|
this.visibleOpacity = 0.85;
|
984
976
|
this.targetOpacity = 0;
|
985
977
|
this.fadingSpeed = 0.02;
|
@@ -995,25 +987,22 @@ var CharacterTooltip = class {
|
|
995
987
|
fontColor: defaultFontColor,
|
996
988
|
castShadows: defaultLabelCastShadows
|
997
989
|
};
|
998
|
-
this.
|
999
|
-
this.material = new MeshBasicMaterial2({
|
990
|
+
this.tooltipMaterial = new MeshBasicMaterial2({
|
1000
991
|
map: null,
|
1001
992
|
transparent: true,
|
1002
|
-
opacity: 0
|
993
|
+
opacity: 0,
|
994
|
+
side: FrontSide
|
1003
995
|
});
|
1004
|
-
this.material
|
1005
|
-
this.
|
1006
|
-
this.
|
1007
|
-
this.mesh.position.set(0, 1.6, 0);
|
1008
|
-
this.mesh.visible = false;
|
1009
|
-
parentModel.add(this.mesh);
|
996
|
+
this.material = this.tooltipMaterial;
|
997
|
+
this.position.set(0, 1.6, 0);
|
998
|
+
this.visible = false;
|
1010
999
|
}
|
1011
1000
|
redrawText(content) {
|
1012
|
-
if (!this.
|
1001
|
+
if (!this.tooltipMaterial) {
|
1013
1002
|
return;
|
1014
1003
|
}
|
1015
|
-
if (this.
|
1016
|
-
this.
|
1004
|
+
if (this.tooltipMaterial.map) {
|
1005
|
+
this.tooltipMaterial.map.dispose();
|
1017
1006
|
}
|
1018
1007
|
const { texture, width, height } = THREECanvasTextTexture(content, {
|
1019
1008
|
bold: true,
|
@@ -1037,17 +1026,17 @@ var CharacterTooltip = class {
|
|
1037
1026
|
},
|
1038
1027
|
alignment: this.props.alignment
|
1039
1028
|
});
|
1040
|
-
this.
|
1041
|
-
this.
|
1042
|
-
this.
|
1043
|
-
this.
|
1044
|
-
this.
|
1045
|
-
this.
|
1046
|
-
this.
|
1029
|
+
this.tooltipMaterial.map = texture;
|
1030
|
+
this.tooltipMaterial.map.magFilter = LinearFilter2;
|
1031
|
+
this.tooltipMaterial.map.minFilter = LinearFilter2;
|
1032
|
+
this.tooltipMaterial.needsUpdate = true;
|
1033
|
+
this.scale.x = width / (100 * fontScale);
|
1034
|
+
this.scale.y = height / (100 * fontScale);
|
1035
|
+
this.position.y = 1.6;
|
1047
1036
|
}
|
1048
1037
|
setText(text, temporary = false) {
|
1049
1038
|
this.redrawText(text);
|
1050
|
-
this.
|
1039
|
+
this.visible = true;
|
1051
1040
|
this.targetOpacity = this.visibleOpacity;
|
1052
1041
|
if (temporary) {
|
1053
1042
|
setTimeout(() => {
|
@@ -1059,37 +1048,101 @@ var CharacterTooltip = class {
|
|
1059
1048
|
this.targetOpacity = 0;
|
1060
1049
|
}
|
1061
1050
|
update(camera) {
|
1062
|
-
this.
|
1063
|
-
const opacity = this.
|
1051
|
+
this.lookAt(camera.position);
|
1052
|
+
const opacity = this.tooltipMaterial.opacity;
|
1064
1053
|
if (opacity < this.targetOpacity) {
|
1065
|
-
this.
|
1066
|
-
this.
|
1054
|
+
this.tooltipMaterial.opacity = Math.min(
|
1055
|
+
this.tooltipMaterial.opacity + this.fadingSpeed,
|
1067
1056
|
this.targetOpacity
|
1068
1057
|
);
|
1069
1058
|
} else if (opacity > this.targetOpacity) {
|
1070
|
-
this.
|
1071
|
-
this.
|
1059
|
+
this.tooltipMaterial.opacity = Math.max(
|
1060
|
+
this.tooltipMaterial.opacity - this.fadingSpeed,
|
1072
1061
|
this.targetOpacity
|
1073
1062
|
);
|
1074
|
-
if (opacity >= 1 && this.
|
1075
|
-
this.
|
1076
|
-
this.
|
1077
|
-
} else if (opacity > 0 && opacity < 1 && this.
|
1078
|
-
this.
|
1079
|
-
this.
|
1063
|
+
if (opacity >= 1 && this.tooltipMaterial.transparent) {
|
1064
|
+
this.tooltipMaterial.transparent = false;
|
1065
|
+
this.tooltipMaterial.needsUpdate = true;
|
1066
|
+
} else if (opacity > 0 && opacity < 1 && !this.tooltipMaterial.transparent) {
|
1067
|
+
this.tooltipMaterial.transparent = true;
|
1068
|
+
this.tooltipMaterial.needsUpdate = true;
|
1080
1069
|
}
|
1081
|
-
if (this.
|
1082
|
-
this.
|
1070
|
+
if (this.tooltipMaterial.opacity <= 0) {
|
1071
|
+
this.visible = false;
|
1072
|
+
}
|
1073
|
+
}
|
1074
|
+
}
|
1075
|
+
};
|
1076
|
+
|
1077
|
+
// src/character/Character.ts
|
1078
|
+
var Character = class extends Group {
|
1079
|
+
constructor(characterDescription, characterModelLoader, characterId, modelLoadedCallback, cameraManager, composer) {
|
1080
|
+
super();
|
1081
|
+
this.characterDescription = characterDescription;
|
1082
|
+
this.characterModelLoader = characterModelLoader;
|
1083
|
+
this.characterId = characterId;
|
1084
|
+
this.modelLoadedCallback = modelLoadedCallback;
|
1085
|
+
this.cameraManager = cameraManager;
|
1086
|
+
this.composer = composer;
|
1087
|
+
this.model = null;
|
1088
|
+
this.color = new Color3();
|
1089
|
+
this.tooltip = null;
|
1090
|
+
this.speakingIndicator = null;
|
1091
|
+
this.tooltip = new CharacterTooltip();
|
1092
|
+
this.add(this.tooltip);
|
1093
|
+
this.load();
|
1094
|
+
}
|
1095
|
+
async load() {
|
1096
|
+
this.model = new CharacterModel(this.characterDescription, this.characterModelLoader);
|
1097
|
+
await this.model.init();
|
1098
|
+
this.add(this.model.mesh);
|
1099
|
+
if (this.speakingIndicator === null) {
|
1100
|
+
this.speakingIndicator = new CharacterSpeakingIndicator(this.composer.postPostScene);
|
1101
|
+
}
|
1102
|
+
this.color = this.model.material.colorsCube216[this.characterId];
|
1103
|
+
this.modelLoadedCallback();
|
1104
|
+
}
|
1105
|
+
updateAnimation(targetAnimation) {
|
1106
|
+
var _a;
|
1107
|
+
(_a = this.model) == null ? void 0 : _a.updateAnimation(targetAnimation);
|
1108
|
+
}
|
1109
|
+
update(time, deltaTime) {
|
1110
|
+
var _a;
|
1111
|
+
if (!this.model)
|
1112
|
+
return;
|
1113
|
+
if (this.tooltip) {
|
1114
|
+
this.tooltip.update(this.cameraManager.camera);
|
1115
|
+
}
|
1116
|
+
if (this.speakingIndicator) {
|
1117
|
+
this.speakingIndicator.setTime(time);
|
1118
|
+
if (this.model.mesh && this.model.headBone) {
|
1119
|
+
this.speakingIndicator.setBillboarding(
|
1120
|
+
(_a = this.model.headBone) == null ? void 0 : _a.getWorldPosition(new Vector34()),
|
1121
|
+
this.cameraManager.camera
|
1122
|
+
);
|
1083
1123
|
}
|
1084
1124
|
}
|
1125
|
+
if (typeof this.model.material.uniforms.time !== "undefined") {
|
1126
|
+
this.model.material.uniforms.time.value = time;
|
1127
|
+
this.model.material.uniforms.diffuseRandomColor.value = this.color;
|
1128
|
+
this.model.material.update();
|
1129
|
+
}
|
1130
|
+
this.model.update(deltaTime);
|
1131
|
+
}
|
1132
|
+
getCurrentAnimation() {
|
1133
|
+
var _a;
|
1134
|
+
return ((_a = this.model) == null ? void 0 : _a.currentAnimation) || 0 /* idle */;
|
1085
1135
|
}
|
1086
1136
|
};
|
1087
1137
|
|
1138
|
+
// src/character/CharacterManager.ts
|
1139
|
+
import { Euler, Group as Group2, Quaternion as Quaternion5, Vector3 as Vector38 } from "three";
|
1140
|
+
|
1088
1141
|
// src/character/LocalController.ts
|
1089
|
-
import { Line3, Matrix4, Quaternion as Quaternion2, Raycaster as Raycaster2, Vector3 as
|
1142
|
+
import { Line3, Matrix4, Quaternion as Quaternion2, Raycaster as Raycaster2, Vector3 as Vector35 } from "three";
|
1090
1143
|
var LocalController = class {
|
1091
|
-
constructor(
|
1092
|
-
this.
|
1144
|
+
constructor(character, id, collisionsManager, keyInputManager, cameraManager, timeManager) {
|
1145
|
+
this.character = character;
|
1093
1146
|
this.id = id;
|
1094
1147
|
this.collisionsManager = collisionsManager;
|
1095
1148
|
this.keyInputManager = keyInputManager;
|
@@ -1098,7 +1151,7 @@ var LocalController = class {
|
|
1098
1151
|
this.collisionDetectionSteps = 15;
|
1099
1152
|
this.capsuleInfo = {
|
1100
1153
|
radius: 0.4,
|
1101
|
-
segment: new Line3(new
|
1154
|
+
segment: new Line3(new Vector35(), new Vector35(0, 1.05, 0))
|
1102
1155
|
};
|
1103
1156
|
this.maxWalkSpeed = 6;
|
1104
1157
|
this.maxRunSpeed = 8.5;
|
@@ -1111,17 +1164,16 @@ var LocalController = class {
|
|
1111
1164
|
this.characterWasOnGround = false;
|
1112
1165
|
this.characterAirborneSince = 0;
|
1113
1166
|
this.currentHeight = 0;
|
1114
|
-
this.characterVelocity = new
|
1115
|
-
this.vectorUp = new
|
1116
|
-
this.vectorDown = new
|
1167
|
+
this.characterVelocity = new Vector35();
|
1168
|
+
this.vectorUp = new Vector35(0, 1, 0);
|
1169
|
+
this.vectorDown = new Vector35(0, -1, 0);
|
1117
1170
|
this.rotationOffset = 0;
|
1118
1171
|
this.azimuthalAngle = 0;
|
1119
1172
|
this.tempMatrix = new Matrix4();
|
1120
1173
|
this.tempSegment = new Line3();
|
1121
|
-
this.tempVector = new
|
1122
|
-
this.tempVector2 = new
|
1174
|
+
this.tempVector = new Vector35();
|
1175
|
+
this.tempVector2 = new Vector35();
|
1123
1176
|
this.rayCaster = new Raycaster2();
|
1124
|
-
this.thirdPersonCamera = null;
|
1125
1177
|
this.speed = 0;
|
1126
1178
|
this.targetSpeed = 0;
|
1127
1179
|
this.networkState = {
|
@@ -1132,11 +1184,6 @@ var LocalController = class {
|
|
1132
1184
|
};
|
1133
1185
|
}
|
1134
1186
|
update() {
|
1135
|
-
var _a, _b;
|
1136
|
-
if (!((_a = this.model) == null ? void 0 : _a.mesh) || !((_b = this.model) == null ? void 0 : _b.animationMixer))
|
1137
|
-
return;
|
1138
|
-
if (!this.thirdPersonCamera)
|
1139
|
-
this.thirdPersonCamera = this.cameraManager.camera;
|
1140
1187
|
const { forward, backward, left, right, run, jump, anyDirection, conflictingDirection } = this.keyInputManager;
|
1141
1188
|
this.forward = forward;
|
1142
1189
|
this.backward = backward;
|
@@ -1148,28 +1195,28 @@ var LocalController = class {
|
|
1148
1195
|
this.conflictingDirections = conflictingDirection;
|
1149
1196
|
this.targetSpeed = this.run ? this.maxRunSpeed : this.maxWalkSpeed;
|
1150
1197
|
this.speed += ease(this.targetSpeed, this.speed, 0.07);
|
1151
|
-
this.rayCaster.set(this.
|
1198
|
+
this.rayCaster.set(this.character.position, this.vectorDown);
|
1152
1199
|
const minimumDistance = this.collisionsManager.raycastFirstDistance(this.rayCaster.ray);
|
1153
1200
|
if (minimumDistance !== null) {
|
1154
1201
|
this.currentHeight = minimumDistance;
|
1155
1202
|
}
|
1156
1203
|
if (anyDirection || !this.characterOnGround) {
|
1157
1204
|
const targetAnimation = this.getTargetAnimation();
|
1158
|
-
this.
|
1205
|
+
this.character.updateAnimation(targetAnimation);
|
1159
1206
|
} else {
|
1160
|
-
this.
|
1207
|
+
this.character.updateAnimation(0 /* idle */);
|
1161
1208
|
}
|
1162
1209
|
if (this.anyDirection)
|
1163
1210
|
this.updateRotation();
|
1164
1211
|
for (let i = 0; i < this.collisionDetectionSteps; i++) {
|
1165
1212
|
this.updatePosition(this.timeManager.deltaTime / this.collisionDetectionSteps, i);
|
1166
1213
|
}
|
1167
|
-
if (this.
|
1214
|
+
if (this.character.position.y < 0)
|
1168
1215
|
this.resetPosition();
|
1169
1216
|
this.updateNetworkState();
|
1170
1217
|
}
|
1171
1218
|
getTargetAnimation() {
|
1172
|
-
if (!this.
|
1219
|
+
if (!this.character)
|
1173
1220
|
return 0 /* idle */;
|
1174
1221
|
if (this.conflictingDirections)
|
1175
1222
|
return 0 /* idle */;
|
@@ -1201,31 +1248,26 @@ var LocalController = class {
|
|
1201
1248
|
}
|
1202
1249
|
}
|
1203
1250
|
updateAzimuthalAngle() {
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
const camToModelDistance = this.thirdPersonCamera.position.distanceTo(this.model.mesh.position);
|
1251
|
+
const camToModelDistance = this.cameraManager.camera.position.distanceTo(
|
1252
|
+
this.character.position
|
1253
|
+
);
|
1208
1254
|
const isCameraFirstPerson = camToModelDistance < 2;
|
1209
1255
|
if (isCameraFirstPerson) {
|
1210
|
-
const cameraForward = new
|
1256
|
+
const cameraForward = new Vector35(0, 0, 1).applyQuaternion(
|
1257
|
+
this.cameraManager.camera.quaternion
|
1258
|
+
);
|
1211
1259
|
this.azimuthalAngle = Math.atan2(cameraForward.x, cameraForward.z);
|
1212
1260
|
} else {
|
1213
1261
|
this.azimuthalAngle = Math.atan2(
|
1214
|
-
this.
|
1215
|
-
this.
|
1262
|
+
this.cameraManager.camera.position.x - this.character.position.x,
|
1263
|
+
this.cameraManager.camera.position.z - this.character.position.z
|
1216
1264
|
);
|
1217
1265
|
}
|
1218
1266
|
}
|
1219
1267
|
computeAngularDifference(rotationQuaternion) {
|
1220
|
-
|
1221
|
-
if (!((_a = this.model) == null ? void 0 : _a.mesh))
|
1222
|
-
return 0;
|
1223
|
-
return 2 * Math.acos(Math.abs(this.model.mesh.quaternion.dot(rotationQuaternion)));
|
1268
|
+
return 2 * Math.acos(Math.abs(this.character.quaternion.dot(rotationQuaternion)));
|
1224
1269
|
}
|
1225
1270
|
updateRotation() {
|
1226
|
-
var _a;
|
1227
|
-
if (!this.thirdPersonCamera || !((_a = this.model) == null ? void 0 : _a.mesh))
|
1228
|
-
return;
|
1229
1271
|
this.updateRotationOffset();
|
1230
1272
|
this.updateAzimuthalAngle();
|
1231
1273
|
const rotationQuaternion = new Quaternion2();
|
@@ -1234,18 +1276,12 @@ var LocalController = class {
|
|
1234
1276
|
const desiredTime = 0.07;
|
1235
1277
|
const angularSpeed = angularDifference / desiredTime;
|
1236
1278
|
const frameRotation = angularSpeed * this.timeManager.deltaTime;
|
1237
|
-
this.
|
1279
|
+
this.character.quaternion.rotateTowards(rotationQuaternion, frameRotation);
|
1238
1280
|
}
|
1239
1281
|
addScaledVectorToCharacter(deltaTime) {
|
1240
|
-
|
1241
|
-
if (!((_a = this.model) == null ? void 0 : _a.mesh))
|
1242
|
-
return;
|
1243
|
-
this.model.mesh.position.addScaledVector(this.tempVector, this.speed * deltaTime);
|
1282
|
+
this.character.position.addScaledVector(this.tempVector, this.speed * deltaTime);
|
1244
1283
|
}
|
1245
1284
|
updatePosition(deltaTime, _iter) {
|
1246
|
-
var _a;
|
1247
|
-
if (!((_a = this.model) == null ? void 0 : _a.mesh))
|
1248
|
-
return;
|
1249
1285
|
if (this.characterOnGround) {
|
1250
1286
|
if (!this.jump)
|
1251
1287
|
this.canJump = true;
|
@@ -1262,45 +1298,45 @@ var LocalController = class {
|
|
1262
1298
|
this.characterVelocity.y += deltaTime * this.gravity;
|
1263
1299
|
this.canJump = false;
|
1264
1300
|
}
|
1265
|
-
this.
|
1301
|
+
this.character.position.addScaledVector(this.characterVelocity, deltaTime);
|
1266
1302
|
this.tempVector.set(0, 0, 0);
|
1267
1303
|
if (this.forward) {
|
1268
|
-
const forward = new
|
1304
|
+
const forward = new Vector35(0, 0, -1).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
|
1269
1305
|
this.tempVector.add(forward);
|
1270
1306
|
}
|
1271
1307
|
if (this.backward) {
|
1272
|
-
const backward = new
|
1308
|
+
const backward = new Vector35(0, 0, 1).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
|
1273
1309
|
this.tempVector.add(backward);
|
1274
1310
|
}
|
1275
1311
|
if (this.left) {
|
1276
|
-
const left = new
|
1312
|
+
const left = new Vector35(-1, 0, 0).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
|
1277
1313
|
this.tempVector.add(left);
|
1278
1314
|
}
|
1279
1315
|
if (this.right) {
|
1280
|
-
const right = new
|
1316
|
+
const right = new Vector35(1, 0, 0).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
|
1281
1317
|
this.tempVector.add(right);
|
1282
1318
|
}
|
1283
1319
|
if (this.tempVector.length() > 0) {
|
1284
1320
|
this.tempVector.normalize();
|
1285
1321
|
this.addScaledVectorToCharacter(deltaTime);
|
1286
1322
|
}
|
1287
|
-
this.
|
1323
|
+
this.character.updateMatrixWorld();
|
1288
1324
|
this.tempSegment.copy(this.capsuleInfo.segment);
|
1289
|
-
this.tempSegment.start.applyMatrix4(this.
|
1290
|
-
this.tempSegment.end.applyMatrix4(this.
|
1325
|
+
this.tempSegment.start.applyMatrix4(this.character.matrixWorld).applyMatrix4(this.tempMatrix);
|
1326
|
+
this.tempSegment.end.applyMatrix4(this.character.matrixWorld).applyMatrix4(this.tempMatrix);
|
1291
1327
|
this.collisionsManager.applyColliders(this.tempSegment, this.capsuleInfo.radius);
|
1292
1328
|
const newPosition = this.tempVector;
|
1293
1329
|
newPosition.copy(this.tempSegment.start);
|
1294
1330
|
const deltaVector = this.tempVector2;
|
1295
|
-
deltaVector.subVectors(newPosition, this.
|
1331
|
+
deltaVector.subVectors(newPosition, this.character.position);
|
1296
1332
|
const offset = Math.max(0, deltaVector.length() - 1e-5);
|
1297
1333
|
deltaVector.normalize().multiplyScalar(offset);
|
1298
|
-
this.
|
1334
|
+
this.character.position.add(deltaVector);
|
1299
1335
|
this.characterOnGround = deltaVector.y > Math.abs(deltaTime * this.characterVelocity.y * 0.25);
|
1300
1336
|
if (this.characterWasOnGround && !this.characterOnGround) {
|
1301
1337
|
this.characterAirborneSince = Date.now();
|
1302
1338
|
}
|
1303
|
-
this.coyoteTime = this.characterVelocity.y < 0 && this.characterOnGround
|
1339
|
+
this.coyoteTime = this.characterVelocity.y < 0 && !this.characterOnGround && Date.now() - this.characterAirborneSince < this.coyoteTimeThreshold;
|
1304
1340
|
this.characterWasOnGround = this.characterOnGround;
|
1305
1341
|
if (this.characterOnGround) {
|
1306
1342
|
this.characterVelocity.set(0, 0, 0);
|
@@ -1310,130 +1346,33 @@ var LocalController = class {
|
|
1310
1346
|
}
|
1311
1347
|
}
|
1312
1348
|
updateNetworkState() {
|
1313
|
-
|
1314
|
-
|
1315
|
-
this.
|
1316
|
-
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1320
|
-
|
1321
|
-
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
1325
|
-
this.model.mesh.position.y,
|
1326
|
-
this.model.mesh.position.z
|
1327
|
-
);
|
1328
|
-
this.networkState = {
|
1329
|
-
id: this.id,
|
1330
|
-
position: positionUpdate,
|
1331
|
-
rotation: { quaternionY: characterQuaternion.y, quaternionW: characterQuaternion.w },
|
1332
|
-
state: this.model.currentAnimation
|
1333
|
-
};
|
1334
|
-
}
|
1349
|
+
const characterQuaternion = this.character.getWorldQuaternion(new Quaternion2());
|
1350
|
+
const positionUpdate = new Vector35(
|
1351
|
+
this.character.position.x,
|
1352
|
+
this.character.position.y,
|
1353
|
+
this.character.position.z
|
1354
|
+
);
|
1355
|
+
this.networkState = {
|
1356
|
+
id: this.id,
|
1357
|
+
position: positionUpdate,
|
1358
|
+
rotation: { quaternionY: characterQuaternion.y, quaternionW: characterQuaternion.w },
|
1359
|
+
state: this.character.getCurrentAnimation()
|
1360
|
+
};
|
1335
1361
|
}
|
1336
1362
|
resetPosition() {
|
1337
|
-
var _a;
|
1338
|
-
if (!((_a = this.model) == null ? void 0 : _a.mesh))
|
1339
|
-
return;
|
1340
1363
|
this.characterVelocity.y = 0;
|
1341
|
-
this.
|
1364
|
+
this.character.position.y = 3;
|
1342
1365
|
this.characterOnGround = false;
|
1343
1366
|
}
|
1344
1367
|
};
|
1345
1368
|
|
1346
|
-
// src/character/Character.ts
|
1347
|
-
var Character = class {
|
1348
|
-
constructor(characterDescription, characterModelLoader, id, isLocal, modelLoadedCallback, collisionsManager, keyInputManager, cameraManager, timeManager, composer) {
|
1349
|
-
this.characterDescription = characterDescription;
|
1350
|
-
this.characterModelLoader = characterModelLoader;
|
1351
|
-
this.id = id;
|
1352
|
-
this.isLocal = isLocal;
|
1353
|
-
this.modelLoadedCallback = modelLoadedCallback;
|
1354
|
-
this.collisionsManager = collisionsManager;
|
1355
|
-
this.keyInputManager = keyInputManager;
|
1356
|
-
this.cameraManager = cameraManager;
|
1357
|
-
this.timeManager = timeManager;
|
1358
|
-
this.composer = composer;
|
1359
|
-
this.controller = null;
|
1360
|
-
this.name = null;
|
1361
|
-
this.model = null;
|
1362
|
-
this.color = new Color3();
|
1363
|
-
this.position = new Vector35();
|
1364
|
-
this.tooltip = null;
|
1365
|
-
this.speakingIndicator = null;
|
1366
|
-
this.load();
|
1367
|
-
}
|
1368
|
-
async load() {
|
1369
|
-
this.model = new CharacterModel(this.characterDescription, this.characterModelLoader);
|
1370
|
-
await this.model.init();
|
1371
|
-
if (this.tooltip === null) {
|
1372
|
-
this.tooltip = new CharacterTooltip(this.model.mesh);
|
1373
|
-
}
|
1374
|
-
if (this.speakingIndicator === null) {
|
1375
|
-
this.speakingIndicator = new CharacterSpeakingIndicator(this.composer.postPostScene);
|
1376
|
-
}
|
1377
|
-
this.color = this.model.material.colorsCube216[this.id];
|
1378
|
-
if (this.isLocal) {
|
1379
|
-
this.controller = new LocalController(
|
1380
|
-
this.model,
|
1381
|
-
this.id,
|
1382
|
-
this.collisionsManager,
|
1383
|
-
this.keyInputManager,
|
1384
|
-
this.cameraManager,
|
1385
|
-
this.timeManager
|
1386
|
-
);
|
1387
|
-
}
|
1388
|
-
this.modelLoadedCallback();
|
1389
|
-
}
|
1390
|
-
update(time) {
|
1391
|
-
var _a;
|
1392
|
-
if (!this.model)
|
1393
|
-
return;
|
1394
|
-
if (this.tooltip) {
|
1395
|
-
this.tooltip.update(this.cameraManager.camera);
|
1396
|
-
}
|
1397
|
-
if (this.speakingIndicator) {
|
1398
|
-
this.speakingIndicator.setTime(time);
|
1399
|
-
if (this.model.mesh && this.model.headBone) {
|
1400
|
-
this.speakingIndicator.setBillboarding(
|
1401
|
-
(_a = this.model.headBone) == null ? void 0 : _a.getWorldPosition(new Vector35()),
|
1402
|
-
this.cameraManager.camera
|
1403
|
-
);
|
1404
|
-
}
|
1405
|
-
}
|
1406
|
-
this.model.mesh.getWorldPosition(this.position);
|
1407
|
-
if (typeof this.model.material.uniforms.time !== "undefined") {
|
1408
|
-
this.model.material.uniforms.time.value = time;
|
1409
|
-
this.model.material.uniforms.diffuseRandomColor.value = this.color;
|
1410
|
-
this.model.material.update();
|
1411
|
-
}
|
1412
|
-
}
|
1413
|
-
};
|
1414
|
-
|
1415
|
-
// src/character/CharacterManager.ts
|
1416
|
-
import { Euler, Group, Quaternion as Quaternion4, Vector3 as Vector37 } from "three";
|
1417
|
-
|
1418
1369
|
// src/character/RemoteController.ts
|
1419
|
-
import {
|
1420
|
-
AnimationMixer as AnimationMixer2,
|
1421
|
-
Object3D as Object3D4,
|
1422
|
-
Quaternion as Quaternion3,
|
1423
|
-
Vector3 as Vector36
|
1424
|
-
} from "three";
|
1370
|
+
import { Quaternion as Quaternion3, Vector3 as Vector36 } from "three";
|
1425
1371
|
var RemoteController = class {
|
1426
|
-
constructor(character,
|
1372
|
+
constructor(character, id) {
|
1427
1373
|
this.character = character;
|
1428
|
-
this.characterModelLoader = characterModelLoader;
|
1429
1374
|
this.id = id;
|
1430
|
-
this.characterModel = null;
|
1431
|
-
this.animationMixer = new AnimationMixer2(new Object3D4());
|
1432
|
-
this.animations = /* @__PURE__ */ new Map();
|
1433
1375
|
this.currentAnimation = 0 /* idle */;
|
1434
|
-
this.characterModel = this.character.model.mesh;
|
1435
|
-
this.characterModel.updateMatrixWorld();
|
1436
|
-
this.animationMixer = new AnimationMixer2(this.characterModel);
|
1437
1376
|
this.networkState = {
|
1438
1377
|
id: this.id,
|
1439
1378
|
position: { x: 0, y: 0, z: 0 },
|
@@ -1444,48 +1383,23 @@ var RemoteController = class {
|
|
1444
1383
|
update(clientUpdate, time, deltaTime) {
|
1445
1384
|
if (!this.character)
|
1446
1385
|
return;
|
1447
|
-
this.character.update(time);
|
1448
1386
|
this.updateFromNetwork(clientUpdate);
|
1449
|
-
this.
|
1450
|
-
}
|
1451
|
-
async setAnimationFromFile(animationType, fileName) {
|
1452
|
-
const animation = await this.characterModelLoader.load(fileName, "animation");
|
1453
|
-
const animationAction = this.animationMixer.clipAction(animation);
|
1454
|
-
this.animations.set(animationType, animationAction);
|
1455
|
-
if (animationType === 0 /* idle */) {
|
1456
|
-
animationAction.play();
|
1457
|
-
}
|
1458
|
-
}
|
1459
|
-
transitionToAnimation(targetAnimation, transitionDuration = 0.15) {
|
1460
|
-
if (this.currentAnimation === targetAnimation)
|
1461
|
-
return;
|
1462
|
-
const currentAction = this.animations.get(this.currentAnimation);
|
1463
|
-
const targetAction = this.animations.get(targetAnimation);
|
1464
|
-
if (!targetAction)
|
1465
|
-
return;
|
1466
|
-
if (currentAction) {
|
1467
|
-
currentAction.enabled = true;
|
1468
|
-
targetAction.reset().setEffectiveTimeScale(1).setEffectiveWeight(1).fadeIn(transitionDuration).play();
|
1469
|
-
currentAction.crossFadeTo(targetAction, transitionDuration, true);
|
1470
|
-
} else {
|
1471
|
-
targetAction.play();
|
1472
|
-
}
|
1473
|
-
this.currentAnimation = targetAnimation;
|
1387
|
+
this.character.update(time, deltaTime);
|
1474
1388
|
}
|
1475
1389
|
updateFromNetwork(clientUpdate) {
|
1476
|
-
if (!this.characterModel)
|
1477
|
-
return;
|
1478
1390
|
const { position, rotation, state } = clientUpdate;
|
1479
|
-
this.
|
1391
|
+
this.character.position.lerp(new Vector36(position.x, position.y, position.z), 0.15);
|
1480
1392
|
const rotationQuaternion = new Quaternion3(0, rotation.quaternionY, 0, rotation.quaternionW);
|
1481
|
-
this.
|
1393
|
+
this.character.quaternion.slerp(rotationQuaternion, 0.6);
|
1482
1394
|
if (state !== this.currentAnimation) {
|
1483
|
-
this.
|
1395
|
+
this.currentAnimation = state;
|
1396
|
+
this.character.updateAnimation(state);
|
1484
1397
|
}
|
1485
1398
|
}
|
1486
1399
|
};
|
1487
1400
|
|
1488
|
-
// src/character/
|
1401
|
+
// src/character/url-position.ts
|
1402
|
+
import { Quaternion as Quaternion4, Vector3 as Vector37 } from "three";
|
1489
1403
|
function encodeCharacterAndCamera(character, camera) {
|
1490
1404
|
return [
|
1491
1405
|
...toArray(character.position),
|
@@ -1494,135 +1408,96 @@ function encodeCharacterAndCamera(character, camera) {
|
|
1494
1408
|
...toArray(camera.quaternion)
|
1495
1409
|
].join(",");
|
1496
1410
|
}
|
1497
|
-
function decodeCharacterAndCamera(hash
|
1411
|
+
function decodeCharacterAndCamera(hash) {
|
1498
1412
|
const values = hash.split(",").map(Number);
|
1499
|
-
|
1500
|
-
|
1501
|
-
|
1502
|
-
|
1413
|
+
return {
|
1414
|
+
character: {
|
1415
|
+
position: new Vector37(values[0], values[1], values[2]),
|
1416
|
+
quaternion: new Quaternion4(values[3], values[4], values[5], values[6])
|
1417
|
+
},
|
1418
|
+
camera: {
|
1419
|
+
position: new Vector37(values[7], values[8], values[9]),
|
1420
|
+
quaternion: new Quaternion4(values[10], values[11], values[12], values[13])
|
1421
|
+
}
|
1422
|
+
};
|
1503
1423
|
}
|
1424
|
+
|
1425
|
+
// src/character/CharacterManager.ts
|
1504
1426
|
var CharacterManager = class {
|
1505
|
-
constructor(composer, characterModelLoader, collisionsManager, cameraManager, timeManager,
|
1427
|
+
constructor(composer, characterModelLoader, collisionsManager, cameraManager, timeManager, keyInputManager, clientStates, sendUpdate) {
|
1506
1428
|
this.composer = composer;
|
1507
1429
|
this.characterModelLoader = characterModelLoader;
|
1508
1430
|
this.collisionsManager = collisionsManager;
|
1509
1431
|
this.cameraManager = cameraManager;
|
1510
1432
|
this.timeManager = timeManager;
|
1511
|
-
this.
|
1433
|
+
this.keyInputManager = keyInputManager;
|
1512
1434
|
this.clientStates = clientStates;
|
1513
1435
|
this.sendUpdate = sendUpdate;
|
1514
|
-
|
1515
|
-
|
1516
|
-
character was standing on a model and the page is reloaded the character falls into the model before it loads and
|
1517
|
-
can be trapped).
|
1518
|
-
*/
|
1519
|
-
this.updateLocationHash = false;
|
1436
|
+
this.updateLocationHash = true;
|
1437
|
+
this.headTargetOffset = new Vector38(0, 1.3, 0);
|
1520
1438
|
this.id = 0;
|
1521
|
-
this.loadingCharacters = /* @__PURE__ */ new Map();
|
1522
1439
|
this.remoteCharacters = /* @__PURE__ */ new Map();
|
1523
1440
|
this.remoteCharacterControllers = /* @__PURE__ */ new Map();
|
1524
1441
|
this.characterDescription = null;
|
1525
|
-
this.
|
1442
|
+
this.localCharacter = null;
|
1526
1443
|
this.cameraOffsetTarget = 0;
|
1527
1444
|
this.cameraOffset = 0;
|
1528
1445
|
this.speakingCharacters = /* @__PURE__ */ new Map();
|
1529
|
-
this.group = new
|
1530
|
-
}
|
1531
|
-
|
1532
|
-
|
1533
|
-
2) Make this synchronous to avoid having loadingCharacters and instead manage
|
1534
|
-
the mesh loading async (would allow us to show a nameplate where a remote
|
1535
|
-
user is before the asset loads).
|
1536
|
-
*/
|
1537
|
-
spawnCharacter(characterDescription, id, isLocal = false, spawnPosition = new Vector37(), spawnRotation = new Euler()) {
|
1446
|
+
this.group = new Group2();
|
1447
|
+
}
|
1448
|
+
spawnCharacter(characterDescription, id, isLocal = false, spawnPosition = new Vector38(), spawnRotation = new Euler()) {
|
1449
|
+
var _a;
|
1538
1450
|
this.characterDescription = characterDescription;
|
1539
|
-
const
|
1540
|
-
|
1541
|
-
|
1542
|
-
|
1451
|
+
const character = new Character(
|
1452
|
+
characterDescription,
|
1453
|
+
this.characterModelLoader,
|
1454
|
+
id,
|
1455
|
+
() => {
|
1456
|
+
},
|
1457
|
+
this.cameraManager,
|
1458
|
+
this.composer
|
1459
|
+
);
|
1460
|
+
if (isLocal) {
|
1461
|
+
const quaternion = new Quaternion5().setFromEuler(character.rotation);
|
1462
|
+
this.sendUpdate({
|
1543
1463
|
id,
|
1544
|
-
|
1545
|
-
|
1546
|
-
|
1547
|
-
|
1548
|
-
decodeCharacterAndCamera(
|
1549
|
-
window.location.hash.substring(1),
|
1550
|
-
character.model.mesh,
|
1551
|
-
this.cameraManager.camera
|
1552
|
-
);
|
1553
|
-
} else {
|
1554
|
-
spawnPosition = spawnPosition || getSpawnPositionInsideCircle(3, 30, id, 0.4);
|
1555
|
-
character.model.mesh.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z);
|
1556
|
-
character.model.mesh.rotation.set(spawnRotation.x, spawnRotation.y, spawnRotation.z);
|
1557
|
-
character.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z);
|
1558
|
-
character.model.mesh.updateMatrixWorld();
|
1559
|
-
const quaternion = new Quaternion4().setFromEuler(character.model.mesh.rotation);
|
1560
|
-
this.sendUpdate({
|
1561
|
-
id,
|
1562
|
-
position: {
|
1563
|
-
x: spawnPosition.x,
|
1564
|
-
y: spawnPosition.y,
|
1565
|
-
z: spawnPosition.z
|
1566
|
-
},
|
1567
|
-
rotation: { quaternionY: quaternion.y, quaternionW: quaternion.w },
|
1568
|
-
state: 0 /* idle */
|
1569
|
-
});
|
1570
|
-
}
|
1571
|
-
character.model.hideMaterialByMeshName("SK_Mannequin_2");
|
1572
|
-
if (!isLocal) {
|
1573
|
-
(_b = (_a = character.model) == null ? void 0 : _a.mesh) == null ? void 0 : _b.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z);
|
1574
|
-
(_d = (_c = character.model) == null ? void 0 : _c.mesh) == null ? void 0 : _d.updateMatrixWorld();
|
1575
|
-
character.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z);
|
1576
|
-
}
|
1577
|
-
this.group.add(character.model.mesh);
|
1578
|
-
if (isLocal) {
|
1579
|
-
this.id = id;
|
1580
|
-
this.character = character;
|
1581
|
-
(_e = this.character.tooltip) == null ? void 0 : _e.setText(`${id}`);
|
1582
|
-
} else {
|
1583
|
-
this.remoteCharacters.set(id, character);
|
1584
|
-
const remoteController = new RemoteController(character, this.characterModelLoader, id);
|
1585
|
-
remoteController.setAnimationFromFile(
|
1586
|
-
0 /* idle */,
|
1587
|
-
characterDescription.idleAnimationFileUrl
|
1588
|
-
);
|
1589
|
-
remoteController.setAnimationFromFile(
|
1590
|
-
1 /* walking */,
|
1591
|
-
characterDescription.jogAnimationFileUrl
|
1592
|
-
);
|
1593
|
-
remoteController.setAnimationFromFile(
|
1594
|
-
2 /* running */,
|
1595
|
-
characterDescription.sprintAnimationFileUrl
|
1596
|
-
);
|
1597
|
-
remoteController.setAnimationFromFile(
|
1598
|
-
4 /* air */,
|
1599
|
-
characterDescription.airAnimationFileUrl
|
1600
|
-
);
|
1601
|
-
(_f = remoteController.characterModel) == null ? void 0 : _f.position.set(
|
1602
|
-
spawnPosition.x,
|
1603
|
-
spawnPosition.y,
|
1604
|
-
spawnPosition.z
|
1605
|
-
);
|
1606
|
-
this.remoteCharacterControllers.set(id, remoteController);
|
1607
|
-
(_g = character.tooltip) == null ? void 0 : _g.setText(`${id}`);
|
1608
|
-
}
|
1609
|
-
resolve(character);
|
1464
|
+
position: {
|
1465
|
+
x: spawnPosition.x,
|
1466
|
+
y: spawnPosition.y,
|
1467
|
+
z: spawnPosition.z
|
1610
1468
|
},
|
1469
|
+
rotation: { quaternionY: quaternion.y, quaternionW: quaternion.w },
|
1470
|
+
state: 0 /* idle */
|
1471
|
+
});
|
1472
|
+
}
|
1473
|
+
if (isLocal) {
|
1474
|
+
this.id = id;
|
1475
|
+
this.localCharacter = character;
|
1476
|
+
this.localController = new LocalController(
|
1477
|
+
this.localCharacter,
|
1478
|
+
this.id,
|
1611
1479
|
this.collisionsManager,
|
1612
|
-
this.
|
1480
|
+
this.keyInputManager,
|
1613
1481
|
this.cameraManager,
|
1614
|
-
this.timeManager
|
1615
|
-
this.composer
|
1482
|
+
this.timeManager
|
1616
1483
|
);
|
1617
|
-
|
1618
|
-
|
1619
|
-
|
1484
|
+
this.localCharacter.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z);
|
1485
|
+
this.localCharacter.rotation.set(spawnRotation.x, spawnRotation.y, spawnRotation.z);
|
1486
|
+
} else {
|
1487
|
+
this.remoteCharacters.set(id, character);
|
1488
|
+
const remoteController = new RemoteController(character, id);
|
1489
|
+
remoteController.character.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z);
|
1490
|
+
remoteController.character.rotation.set(spawnRotation.x, spawnRotation.y, spawnRotation.z);
|
1491
|
+
this.remoteCharacterControllers.set(id, remoteController);
|
1492
|
+
}
|
1493
|
+
(_a = character.tooltip) == null ? void 0 : _a.setText(`${id}`);
|
1494
|
+
this.group.add(character);
|
1620
1495
|
}
|
1621
1496
|
getLocalCharacterPositionAndRotation() {
|
1622
|
-
if (this.
|
1497
|
+
if (this.localCharacter && this.localCharacter && this.localCharacter) {
|
1623
1498
|
return {
|
1624
|
-
position: this.
|
1625
|
-
rotation: this.
|
1499
|
+
position: this.localCharacter.position,
|
1500
|
+
rotation: this.localCharacter.rotation
|
1626
1501
|
};
|
1627
1502
|
}
|
1628
1503
|
return {
|
@@ -1632,54 +1507,48 @@ var CharacterManager = class {
|
|
1632
1507
|
}
|
1633
1508
|
clear() {
|
1634
1509
|
for (const [id, character] of this.remoteCharacters) {
|
1635
|
-
this.group.remove(character
|
1510
|
+
this.group.remove(character);
|
1636
1511
|
this.remoteCharacters.delete(id);
|
1637
1512
|
this.remoteCharacterControllers.delete(id);
|
1638
1513
|
}
|
1639
|
-
if (this.
|
1640
|
-
this.group.remove(this.
|
1641
|
-
this.
|
1514
|
+
if (this.localCharacter) {
|
1515
|
+
this.group.remove(this.localCharacter);
|
1516
|
+
this.localCharacter = null;
|
1642
1517
|
}
|
1643
|
-
this.loadingCharacters.clear();
|
1644
1518
|
}
|
1645
1519
|
setSpeakingCharacter(id, value) {
|
1646
1520
|
this.speakingCharacters.set(id, value);
|
1647
1521
|
}
|
1648
1522
|
update() {
|
1649
|
-
var _a, _b, _c
|
1650
|
-
if (this.
|
1651
|
-
this.
|
1523
|
+
var _a, _b, _c;
|
1524
|
+
if (this.localCharacter) {
|
1525
|
+
this.localCharacter.update(this.timeManager.time, this.timeManager.deltaTime);
|
1652
1526
|
if (this.speakingCharacters.has(this.id)) {
|
1653
|
-
(_a = this.
|
1527
|
+
(_a = this.localCharacter.speakingIndicator) == null ? void 0 : _a.setSpeaking(this.speakingCharacters.get(this.id));
|
1654
1528
|
}
|
1655
|
-
|
1656
|
-
|
1657
|
-
|
1658
|
-
|
1659
|
-
|
1660
|
-
|
1661
|
-
|
1662
|
-
if (this.
|
1663
|
-
this.
|
1664
|
-
if (this.timeManager.frame % 2 === 0) {
|
1665
|
-
this.sendUpdate(this.character.controller.networkState);
|
1666
|
-
}
|
1529
|
+
this.cameraOffsetTarget = this.cameraManager.targetDistance <= 0.4 ? 0.13 : 0;
|
1530
|
+
this.cameraOffset += ease(this.cameraOffsetTarget, this.cameraOffset, 0.1);
|
1531
|
+
const targetOffset = new Vector38(0, 0, this.cameraOffset);
|
1532
|
+
targetOffset.add(this.headTargetOffset);
|
1533
|
+
targetOffset.applyQuaternion(this.localCharacter.quaternion);
|
1534
|
+
this.cameraManager.setTarget(targetOffset.add(this.localCharacter.position));
|
1535
|
+
this.localController.update();
|
1536
|
+
if (this.timeManager.frame % 2 === 0) {
|
1537
|
+
this.sendUpdate(this.localController.networkState);
|
1667
1538
|
}
|
1668
1539
|
for (const [id, update] of this.clientStates) {
|
1669
1540
|
if (this.remoteCharacters.has(id) && this.speakingCharacters.has(id)) {
|
1670
1541
|
const character = this.remoteCharacters.get(id);
|
1671
|
-
(
|
1542
|
+
(_b = character == null ? void 0 : character.speakingIndicator) == null ? void 0 : _b.setSpeaking(this.speakingCharacters.get(id));
|
1672
1543
|
}
|
1673
1544
|
const { position } = update;
|
1674
|
-
if (!this.remoteCharacters.has(id)
|
1545
|
+
if (!this.remoteCharacters.has(id)) {
|
1675
1546
|
this.spawnCharacter(
|
1676
1547
|
this.characterDescription,
|
1677
1548
|
id,
|
1678
1549
|
false,
|
1679
|
-
new
|
1680
|
-
)
|
1681
|
-
this.loadingCharacters.delete(id);
|
1682
|
-
});
|
1550
|
+
new Vector38(position.x, position.y, position.z)
|
1551
|
+
);
|
1683
1552
|
}
|
1684
1553
|
const characterController = this.remoteCharacterControllers.get(id);
|
1685
1554
|
if (characterController) {
|
@@ -1688,15 +1557,15 @@ var CharacterManager = class {
|
|
1688
1557
|
}
|
1689
1558
|
for (const [id, character] of this.remoteCharacters) {
|
1690
1559
|
if (!this.clientStates.has(id)) {
|
1691
|
-
(
|
1692
|
-
this.group.remove(character
|
1560
|
+
(_c = character.speakingIndicator) == null ? void 0 : _c.dispose();
|
1561
|
+
this.group.remove(character);
|
1693
1562
|
this.remoteCharacters.delete(id);
|
1694
1563
|
this.remoteCharacterControllers.delete(id);
|
1695
1564
|
}
|
1696
1565
|
}
|
1697
1566
|
if (this.updateLocationHash && this.timeManager.frame % 60 === 0) {
|
1698
1567
|
window.location.hash = encodeCharacterAndCamera(
|
1699
|
-
this.
|
1568
|
+
this.localCharacter,
|
1700
1569
|
this.cameraManager.camera
|
1701
1570
|
);
|
1702
1571
|
}
|
@@ -1708,8 +1577,9 @@ var CharacterManager = class {
|
|
1708
1577
|
import { LoadingManager } from "three";
|
1709
1578
|
import { GLTFLoader as ThreeGLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
1710
1579
|
var CachedGLTFLoader = class extends ThreeGLTFLoader {
|
1711
|
-
constructor(manager) {
|
1580
|
+
constructor(manager, debug = false) {
|
1712
1581
|
super(manager);
|
1582
|
+
this.debug = debug;
|
1713
1583
|
this.blobCache = /* @__PURE__ */ new Map();
|
1714
1584
|
}
|
1715
1585
|
setBlobUrl(originalUrl, blobUrl) {
|
@@ -1721,7 +1591,9 @@ var CachedGLTFLoader = class extends ThreeGLTFLoader {
|
|
1721
1591
|
load(url, onLoad, onProgress, onError) {
|
1722
1592
|
const blobUrl = this.getBlobUrl(url);
|
1723
1593
|
if (blobUrl) {
|
1724
|
-
|
1594
|
+
if (this.debug === true) {
|
1595
|
+
console.log(`Loading cached ${url.split("/").pop()}`);
|
1596
|
+
}
|
1725
1597
|
super.load(blobUrl, onLoad, onProgress, onError);
|
1726
1598
|
} else {
|
1727
1599
|
super.load(url, onLoad, onProgress, onError);
|
@@ -1749,20 +1621,14 @@ var LRUCache = class {
|
|
1749
1621
|
this.cache.set(key, value);
|
1750
1622
|
}
|
1751
1623
|
};
|
1752
|
-
var
|
1753
|
-
constructor(maxCacheSize = 100) {
|
1624
|
+
var CharacterModelLoader = class {
|
1625
|
+
constructor(maxCacheSize = 100, debug = false) {
|
1626
|
+
this.debug = debug;
|
1754
1627
|
this.ongoingLoads = /* @__PURE__ */ new Map();
|
1755
1628
|
this.loadingManager = new LoadingManager();
|
1756
|
-
this.gltfLoader = new CachedGLTFLoader(this.loadingManager);
|
1629
|
+
this.gltfLoader = new CachedGLTFLoader(this.loadingManager, this.debug);
|
1757
1630
|
this.modelCache = new LRUCache(maxCacheSize);
|
1758
1631
|
}
|
1759
|
-
/* TODO: decide between below lazy initialization or eager on this file's bottom export */
|
1760
|
-
static getInstance() {
|
1761
|
-
if (!_CharacterModelLoader.instance) {
|
1762
|
-
_CharacterModelLoader.instance = new _CharacterModelLoader();
|
1763
|
-
}
|
1764
|
-
return _CharacterModelLoader.instance;
|
1765
|
-
}
|
1766
1632
|
async load(fileUrl, fileType) {
|
1767
1633
|
const cachedModel = this.modelCache.get(fileUrl);
|
1768
1634
|
if (cachedModel) {
|
@@ -1770,19 +1636,27 @@ var _CharacterModelLoader = class _CharacterModelLoader {
|
|
1770
1636
|
this.gltfLoader.setBlobUrl(fileUrl, blobURL);
|
1771
1637
|
return this.loadFromUrl(fileUrl, fileType, cachedModel.originalExtension);
|
1772
1638
|
} else {
|
1773
|
-
|
1639
|
+
if (this.debug === true) {
|
1640
|
+
console.log(`Loading ${fileUrl} from server`);
|
1641
|
+
}
|
1774
1642
|
const ongoingLoad = this.ongoingLoads.get(fileUrl);
|
1775
1643
|
if (ongoingLoad)
|
1776
|
-
return ongoingLoad
|
1644
|
+
return ongoingLoad.then((loadedModel) => {
|
1645
|
+
const blobURL = URL.createObjectURL(loadedModel.blob);
|
1646
|
+
return this.loadFromUrl(blobURL, fileType, loadedModel.originalExtension);
|
1647
|
+
});
|
1777
1648
|
const loadPromise = fetch(fileUrl).then((response) => response.blob()).then((blob) => {
|
1778
1649
|
const originalExtension = fileUrl.split(".").pop() || "";
|
1779
|
-
|
1780
|
-
|
1650
|
+
const cached = { blob, originalExtension };
|
1651
|
+
this.modelCache.set(fileUrl, cached);
|
1781
1652
|
this.ongoingLoads.delete(fileUrl);
|
1782
|
-
return
|
1653
|
+
return cached;
|
1783
1654
|
});
|
1784
1655
|
this.ongoingLoads.set(fileUrl, loadPromise);
|
1785
|
-
return loadPromise
|
1656
|
+
return loadPromise.then((loadedModel) => {
|
1657
|
+
const blobURL = URL.createObjectURL(loadedModel.blob);
|
1658
|
+
return this.loadFromUrl(blobURL, fileType, loadedModel.originalExtension);
|
1659
|
+
});
|
1786
1660
|
}
|
1787
1661
|
}
|
1788
1662
|
async loadFromUrl(url, fileType, extension) {
|
@@ -1813,9 +1687,6 @@ var _CharacterModelLoader = class _CharacterModelLoader {
|
|
1813
1687
|
}
|
1814
1688
|
}
|
1815
1689
|
};
|
1816
|
-
_CharacterModelLoader.instance = null;
|
1817
|
-
var CharacterModelLoader = _CharacterModelLoader;
|
1818
|
-
var MODEL_LOADER = CharacterModelLoader.getInstance();
|
1819
1690
|
|
1820
1691
|
// src/input/KeyInputManager.ts
|
1821
1692
|
var KeyInputManager = class {
|
@@ -1884,9 +1755,10 @@ var KeyInputManager = class {
|
|
1884
1755
|
import {
|
1885
1756
|
InteractionManager,
|
1886
1757
|
MMLClickTrigger,
|
1887
|
-
PromptManager
|
1758
|
+
PromptManager,
|
1759
|
+
LoadingProgressManager
|
1888
1760
|
} from "mml-web";
|
1889
|
-
import { Group as
|
1761
|
+
import { Group as Group3 } from "three";
|
1890
1762
|
var MMLCompositionScene = class {
|
1891
1763
|
constructor(targetElement, renderer, scene, camera, audioListener, collisionsManager, getUserPositionAndRotation) {
|
1892
1764
|
this.renderer = renderer;
|
@@ -1896,7 +1768,7 @@ var MMLCompositionScene = class {
|
|
1896
1768
|
this.collisionsManager = collisionsManager;
|
1897
1769
|
this.getUserPositionAndRotation = getUserPositionAndRotation;
|
1898
1770
|
this.chatProbes = /* @__PURE__ */ new Set();
|
1899
|
-
this.group = new
|
1771
|
+
this.group = new Group3();
|
1900
1772
|
this.promptManager = PromptManager.init(targetElement);
|
1901
1773
|
const { interactionListener, interactionManager } = InteractionManager.init(
|
1902
1774
|
targetElement,
|
@@ -1905,6 +1777,7 @@ var MMLCompositionScene = class {
|
|
1905
1777
|
);
|
1906
1778
|
this.interactionManager = interactionManager;
|
1907
1779
|
this.interactionListener = interactionListener;
|
1780
|
+
this.loadingProgressManager = new LoadingProgressManager();
|
1908
1781
|
this.mmlScene = {
|
1909
1782
|
getAudioListener: () => this.audioListener,
|
1910
1783
|
getRenderer: () => this.renderer,
|
@@ -1940,6 +1813,9 @@ var MMLCompositionScene = class {
|
|
1940
1813
|
},
|
1941
1814
|
prompt: (promptProps, callback) => {
|
1942
1815
|
this.promptManager.prompt(promptProps, callback);
|
1816
|
+
},
|
1817
|
+
getLoadingProgressManager: () => {
|
1818
|
+
return this.loadingProgressManager;
|
1943
1819
|
}
|
1944
1820
|
};
|
1945
1821
|
this.clickTrigger = MMLClickTrigger.init(targetElement, this.mmlScene);
|
@@ -2384,7 +2260,7 @@ var n8ssaoOptions = {
|
|
2384
2260
|
aoSamples: [2, 4, 8, 16, 32, 64],
|
2385
2261
|
denoiseSamples: [2, 4, 8, 16, 32, 64],
|
2386
2262
|
denoiseRadius: [3, 6, 12],
|
2387
|
-
viewMode: ["Combined", "AO", "Split", "No AO"]
|
2263
|
+
viewMode: ["Combined", "AO", "No AO", "Split", "Split AO", "No AO"]
|
2388
2264
|
};
|
2389
2265
|
var ssaoMaterialParams = [
|
2390
2266
|
"fade",
|
@@ -2480,10 +2356,10 @@ var SSAOFolder = class {
|
|
2480
2356
|
this.aoDisplay = this.n8ssao.addBinding(n8ssaoValues, "viewMode", {
|
2481
2357
|
view: "radiogrid",
|
2482
2358
|
groupName: "viewMode",
|
2483
|
-
size: [
|
2359
|
+
size: [3, 2],
|
2484
2360
|
cells: (x, y) => ({
|
2485
|
-
title: `${n8ssaoOptions.viewMode[y *
|
2486
|
-
value: `${n8ssaoOptions.viewMode[y *
|
2361
|
+
title: `${n8ssaoOptions.viewMode[y * 3 + x]}`,
|
2362
|
+
value: `${n8ssaoOptions.viewMode[y * 3 + x]}`
|
2487
2363
|
}),
|
2488
2364
|
label: "viewMode"
|
2489
2365
|
});
|
@@ -2855,7 +2731,6 @@ var TweakPane = class {
|
|
2855
2731
|
};
|
2856
2732
|
|
2857
2733
|
// src/rendering/composer.ts
|
2858
|
-
import { N8AOPostPass } from "n8ao";
|
2859
2734
|
import {
|
2860
2735
|
EffectComposer as EffectComposer2,
|
2861
2736
|
RenderPass,
|
@@ -2875,25 +2750,25 @@ import {
|
|
2875
2750
|
} from "postprocessing";
|
2876
2751
|
import {
|
2877
2752
|
AmbientLight,
|
2878
|
-
Color as
|
2879
|
-
Fog,
|
2880
|
-
HalfFloatType,
|
2753
|
+
Color as Color7,
|
2754
|
+
Fog as Fog2,
|
2755
|
+
HalfFloatType as HalfFloatType2,
|
2881
2756
|
LinearSRGBColorSpace,
|
2882
2757
|
LoadingManager as LoadingManager2,
|
2883
2758
|
PMREMGenerator,
|
2884
|
-
Scene as
|
2885
|
-
Vector2 as
|
2886
|
-
WebGLRenderer as
|
2759
|
+
Scene as Scene4,
|
2760
|
+
Vector2 as Vector27,
|
2761
|
+
WebGLRenderer as WebGLRenderer4
|
2887
2762
|
} from "three";
|
2888
2763
|
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
|
2889
2764
|
|
2890
2765
|
// src/sun/Sun.ts
|
2891
|
-
import { CameraHelper, Color as Color5, DirectionalLight, Group as
|
2892
|
-
var Sun = class extends
|
2766
|
+
import { CameraHelper, Color as Color5, DirectionalLight, Group as Group4, OrthographicCamera, Vector3 as Vector39 } from "three";
|
2767
|
+
var Sun = class extends Group4 {
|
2893
2768
|
constructor() {
|
2894
2769
|
super();
|
2895
2770
|
this.debug = false;
|
2896
|
-
this.sunOffset = new
|
2771
|
+
this.sunOffset = new Vector39(
|
2897
2772
|
39 * (Math.PI / 180),
|
2898
2773
|
50 * (Math.PI / 180),
|
2899
2774
|
100
|
@@ -2920,7 +2795,7 @@ var Sun = class extends Group3 {
|
|
2920
2795
|
this.directionalLight.shadow.mapSize.set(this.shadowResolution, this.shadowResolution);
|
2921
2796
|
this.directionalLight.castShadow = true;
|
2922
2797
|
this.setColor();
|
2923
|
-
this.updateCharacterPosition(new
|
2798
|
+
this.updateCharacterPosition(new Vector39(0, 0, 0));
|
2924
2799
|
this.add(this.directionalLight);
|
2925
2800
|
if (this.debug === true && this.camHelper instanceof CameraHelper) {
|
2926
2801
|
this.add(this.camHelper);
|
@@ -2958,7 +2833,7 @@ var Sun = class extends Group3 {
|
|
2958
2833
|
if (!this.target)
|
2959
2834
|
return;
|
2960
2835
|
const distance = this.sunOffset.z;
|
2961
|
-
const sphericalPosition = new
|
2836
|
+
const sphericalPosition = new Vector39(
|
2962
2837
|
distance * Math.sin(polarAngle) * Math.cos(azimuthalAngle),
|
2963
2838
|
distance * Math.cos(polarAngle),
|
2964
2839
|
distance * Math.sin(polarAngle) * Math.sin(azimuthalAngle)
|
@@ -3114,44 +2989,1353 @@ var GaussGrainEffect = new ShaderMaterial2({
|
|
3114
2989
|
dithering: true
|
3115
2990
|
});
|
3116
2991
|
|
3117
|
-
// src/rendering/
|
3118
|
-
|
3119
|
-
|
3120
|
-
|
3121
|
-
|
3122
|
-
|
3123
|
-
|
3124
|
-
|
3125
|
-
|
3126
|
-
|
3127
|
-
|
3128
|
-
|
3129
|
-
|
3130
|
-
|
3131
|
-
|
3132
|
-
|
3133
|
-
|
3134
|
-
|
3135
|
-
|
3136
|
-
|
3137
|
-
|
3138
|
-
|
3139
|
-
|
3140
|
-
|
3141
|
-
|
3142
|
-
this.renderer.toneMapping = rendererValues.toneMapping;
|
3143
|
-
|
3144
|
-
|
3145
|
-
|
3146
|
-
|
3147
|
-
|
3148
|
-
|
3149
|
-
|
3150
|
-
|
3151
|
-
|
3152
|
-
|
3153
|
-
|
3154
|
-
|
2992
|
+
// src/rendering/post-effects/n8-ssao/N8SSAOPass.ts
|
2993
|
+
import { Pass } from "postprocessing";
|
2994
|
+
import {
|
2995
|
+
Color as Color6,
|
2996
|
+
DataTexture,
|
2997
|
+
FloatType,
|
2998
|
+
Fog,
|
2999
|
+
FogExp2,
|
3000
|
+
HalfFloatType,
|
3001
|
+
LinearFilter as LinearFilter3,
|
3002
|
+
NearestFilter,
|
3003
|
+
NoColorSpace,
|
3004
|
+
OrthographicCamera as OrthographicCamera3,
|
3005
|
+
RGBAFormat as RGBAFormat2,
|
3006
|
+
RedFormat,
|
3007
|
+
RepeatWrapping,
|
3008
|
+
ShaderMaterial as ShaderMaterial4,
|
3009
|
+
Uniform as Uniform7,
|
3010
|
+
Vector2 as Vector26,
|
3011
|
+
Vector3 as Vector313,
|
3012
|
+
WebGLMultipleRenderTargets,
|
3013
|
+
WebGLRenderTarget
|
3014
|
+
} from "three";
|
3015
|
+
|
3016
|
+
// src/rendering/post-effects/n8-ssao/BlueNoise.ts
|
3017
|
+
var BlueNoise = "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";
|
3018
|
+
|
3019
|
+
// src/rendering/post-effects/n8-ssao/DepthDownSample.ts
|
3020
|
+
import { Matrix4 as Matrix42, Uniform as Uniform3, Vector2 as Vector22 } from "three";
|
3021
|
+
var DepthDownSample = {
|
3022
|
+
uniforms: {
|
3023
|
+
sceneDepth: new Uniform3(null),
|
3024
|
+
resolution: new Uniform3(new Vector22()),
|
3025
|
+
near: new Uniform3(0.1),
|
3026
|
+
far: new Uniform3(1e3),
|
3027
|
+
viewMatrixInv: new Uniform3(new Matrix42()),
|
3028
|
+
projectionMatrixInv: new Uniform3(new Matrix42()),
|
3029
|
+
logDepth: new Uniform3(false)
|
3030
|
+
},
|
3031
|
+
depthWrite: false,
|
3032
|
+
depthTest: false,
|
3033
|
+
vertexShader: (
|
3034
|
+
/* glsl */
|
3035
|
+
`
|
3036
|
+
varying vec2 vUv;
|
3037
|
+
void main(void) {
|
3038
|
+
vUv = uv;
|
3039
|
+
gl_Position = vec4(position, 1);
|
3040
|
+
}`
|
3041
|
+
),
|
3042
|
+
fragmentShader: (
|
3043
|
+
/* glsl */
|
3044
|
+
`
|
3045
|
+
uniform highp sampler2D sceneDepth;
|
3046
|
+
uniform vec2 resolution;
|
3047
|
+
uniform float near;
|
3048
|
+
uniform float far;
|
3049
|
+
uniform bool logDepth;
|
3050
|
+
uniform mat4 viewMatrixInv;
|
3051
|
+
uniform mat4 projectionMatrixInv;
|
3052
|
+
varying vec2 vUv;
|
3053
|
+
|
3054
|
+
layout(location = 1) out vec4 gNormal;
|
3055
|
+
|
3056
|
+
vec3 getWorldPosLog(vec3 posS) {
|
3057
|
+
vec2 uv = posS.xy;
|
3058
|
+
float z = posS.z;
|
3059
|
+
float nearZ = near;
|
3060
|
+
float farZ = far;
|
3061
|
+
float depth = pow(2.0, z * log2(farZ + 1.0)) - 1.0;
|
3062
|
+
float a = farZ / (farZ - nearZ);
|
3063
|
+
float b = farZ * nearZ / (nearZ - farZ);
|
3064
|
+
float linDepth = a + b / depth;
|
3065
|
+
vec4 clipVec = vec4(uv, linDepth, 1.0) * 2.0 - 1.0;
|
3066
|
+
vec4 wpos = projectionMatrixInv * clipVec;
|
3067
|
+
return wpos.xyz / wpos.w;
|
3068
|
+
}
|
3069
|
+
|
3070
|
+
vec3 getWorldPos(float depth, vec2 coord) {
|
3071
|
+
if (logDepth) {
|
3072
|
+
return getWorldPosLog(vec3(coord, depth));
|
3073
|
+
}
|
3074
|
+
float z = depth * 2.0 - 1.0;
|
3075
|
+
vec4 clipSpacePosition = vec4(coord * 2.0 - 1.0, z, 1.0);
|
3076
|
+
vec4 viewSpacePosition = projectionMatrixInv * clipSpacePosition;
|
3077
|
+
|
3078
|
+
vec4 worldSpacePosition = viewSpacePosition;
|
3079
|
+
worldSpacePosition.xyz /= worldSpacePosition.w;
|
3080
|
+
|
3081
|
+
return worldSpacePosition.xyz;
|
3082
|
+
}
|
3083
|
+
|
3084
|
+
vec3 computeNormal(vec3 worldPos, vec2 vUv) {
|
3085
|
+
ivec2 p = ivec2(vUv * resolution);
|
3086
|
+
float c0 = texelFetch(sceneDepth, p, 0).x;
|
3087
|
+
float l2 = texelFetch(sceneDepth, p - ivec2(2, 0), 0).x;
|
3088
|
+
float l1 = texelFetch(sceneDepth, p - ivec2(1, 0), 0).x;
|
3089
|
+
float r1 = texelFetch(sceneDepth, p + ivec2(1, 0), 0).x;
|
3090
|
+
float r2 = texelFetch(sceneDepth, p + ivec2(2, 0), 0).x;
|
3091
|
+
float b2 = texelFetch(sceneDepth, p - ivec2(0, 2), 0).x;
|
3092
|
+
float b1 = texelFetch(sceneDepth, p - ivec2(0, 1), 0).x;
|
3093
|
+
float t1 = texelFetch(sceneDepth, p + ivec2(0, 1), 0).x;
|
3094
|
+
float t2 = texelFetch(sceneDepth, p + ivec2(0, 2), 0).x;
|
3095
|
+
float dl = abs((2.0 * l1 - l2) - c0);
|
3096
|
+
float dr = abs((2.0 * r1 - r2) - c0);
|
3097
|
+
float db = abs((2.0 * b1 - b2) - c0);
|
3098
|
+
float dt = abs((2.0 * t1 - t2) - c0);
|
3099
|
+
vec3 ce = getWorldPos(c0, vUv).xyz;
|
3100
|
+
vec3 dpdx = (
|
3101
|
+
(dl < dr)
|
3102
|
+
? ce - getWorldPos(l1, (vUv - vec2(1.0 / resolution.x, 0.0))).xyz
|
3103
|
+
: -ce + getWorldPos(r1, (vUv + vec2(1.0 / resolution.x, 0.0))).xyz
|
3104
|
+
);
|
3105
|
+
vec3 dpdy = (
|
3106
|
+
(db < dt)
|
3107
|
+
? ce - getWorldPos(b1, (vUv - vec2(0.0, 1.0 / resolution.y))).xyz
|
3108
|
+
: -ce + getWorldPos(t1, (vUv + vec2(0.0, 1.0 / resolution.y))).xyz
|
3109
|
+
);
|
3110
|
+
return normalize(cross(dpdx, dpdy));
|
3111
|
+
}
|
3112
|
+
|
3113
|
+
void main(void) {
|
3114
|
+
vec2 uv = vUv - vec2(0.5) / resolution;
|
3115
|
+
vec2 pixelSize = vec2(1.0) / resolution;
|
3116
|
+
vec2[] uvSamples = vec2[4](
|
3117
|
+
uv,
|
3118
|
+
uv + vec2(pixelSize.x, 0.0),
|
3119
|
+
uv + vec2(0.0, pixelSize.y),
|
3120
|
+
uv + pixelSize
|
3121
|
+
);
|
3122
|
+
float depth00 = texture2D(sceneDepth, uvSamples[0]).r;
|
3123
|
+
float depth10 = texture2D(sceneDepth, uvSamples[1]).r;
|
3124
|
+
float depth01 = texture2D(sceneDepth, uvSamples[2]).r;
|
3125
|
+
float depth11 = texture2D(sceneDepth, uvSamples[3]).r;
|
3126
|
+
float minDepth = min(min(depth00, depth10), min(depth01, depth11));
|
3127
|
+
float maxDepth = max(max(depth00, depth10), max(depth01, depth11));
|
3128
|
+
float targetDepth = minDepth;
|
3129
|
+
|
3130
|
+
if (mod(gl_FragCoord.x + gl_FragCoord.y, 2.0) > 0.5) {
|
3131
|
+
targetDepth = maxDepth;
|
3132
|
+
}
|
3133
|
+
|
3134
|
+
int chosenIndex = 0;
|
3135
|
+
float[] samples = float[4](depth00, depth10, depth01, depth11);
|
3136
|
+
|
3137
|
+
for(int i = 0; i < 4; ++i) {
|
3138
|
+
if (samples[i] == targetDepth) {
|
3139
|
+
chosenIndex = i;
|
3140
|
+
break;
|
3141
|
+
}
|
3142
|
+
}
|
3143
|
+
|
3144
|
+
gl_FragColor = vec4(samples[chosenIndex], 0.0, 0.0, 1.0);
|
3145
|
+
gNormal = vec4(
|
3146
|
+
computeNormal(
|
3147
|
+
getWorldPos(samples[chosenIndex], uvSamples[chosenIndex]), uvSamples[chosenIndex]
|
3148
|
+
),
|
3149
|
+
0.0
|
3150
|
+
);
|
3151
|
+
}`
|
3152
|
+
)
|
3153
|
+
};
|
3154
|
+
|
3155
|
+
// src/rendering/post-effects/n8-ssao/EffectCompositer.ts
|
3156
|
+
import { Matrix4 as Matrix43, Uniform as Uniform4, Vector2 as Vector23, Vector3 as Vector310 } from "three";
|
3157
|
+
var EffectCompositer = {
|
3158
|
+
uniforms: {
|
3159
|
+
sceneDiffuse: new Uniform4(null),
|
3160
|
+
sceneDepth: new Uniform4(null),
|
3161
|
+
tDiffuse: new Uniform4(null),
|
3162
|
+
projMat: new Uniform4(new Matrix43()),
|
3163
|
+
viewMat: new Uniform4(new Matrix43()),
|
3164
|
+
projectionMatrixInv: new Uniform4(new Matrix43()),
|
3165
|
+
viewMatrixInv: new Uniform4(new Matrix43()),
|
3166
|
+
cameraPos: new Uniform4(new Vector310()),
|
3167
|
+
resolution: new Uniform4(new Vector23()),
|
3168
|
+
color: new Uniform4(new Vector310()),
|
3169
|
+
blueNoise: new Uniform4(null),
|
3170
|
+
downsampledDepth: new Uniform4(null),
|
3171
|
+
time: new Uniform4(0),
|
3172
|
+
intensity: new Uniform4(10),
|
3173
|
+
renderMode: new Uniform4(0),
|
3174
|
+
gammaCorrection: new Uniform4(false),
|
3175
|
+
logDepth: new Uniform4(false),
|
3176
|
+
ortho: new Uniform4(false),
|
3177
|
+
near: new Uniform4(0.1),
|
3178
|
+
far: new Uniform4(1e3),
|
3179
|
+
screenSpaceRadius: new Uniform4(false),
|
3180
|
+
radius: new Uniform4(0),
|
3181
|
+
distanceFalloff: new Uniform4(1),
|
3182
|
+
fog: new Uniform4(false),
|
3183
|
+
fogExp: new Uniform4(false),
|
3184
|
+
fogDensity: new Uniform4(0),
|
3185
|
+
fogNear: new Uniform4(Infinity),
|
3186
|
+
fogFar: new Uniform4(Infinity),
|
3187
|
+
colorMultiply: new Uniform4(true)
|
3188
|
+
},
|
3189
|
+
depthWrite: false,
|
3190
|
+
depthTest: false,
|
3191
|
+
vertexShader: (
|
3192
|
+
/* glsl */
|
3193
|
+
`
|
3194
|
+
varying vec2 vUv;
|
3195
|
+
void main(void) {
|
3196
|
+
vUv = uv;
|
3197
|
+
gl_Position = vec4(position, 1);
|
3198
|
+
}`
|
3199
|
+
),
|
3200
|
+
fragmentShader: (
|
3201
|
+
/* glsl */
|
3202
|
+
`
|
3203
|
+
uniform sampler2D sceneDiffuse;
|
3204
|
+
uniform highp sampler2D sceneDepth;
|
3205
|
+
uniform highp sampler2D downsampledDepth;
|
3206
|
+
uniform sampler2D tDiffuse;
|
3207
|
+
uniform sampler2D blueNoise;
|
3208
|
+
uniform vec2 resolution;
|
3209
|
+
uniform vec3 color;
|
3210
|
+
uniform mat4 projectionMatrixInv;
|
3211
|
+
uniform mat4 viewMatrixInv;
|
3212
|
+
uniform float intensity;
|
3213
|
+
uniform float renderMode;
|
3214
|
+
uniform float near;
|
3215
|
+
uniform float far;
|
3216
|
+
uniform bool gammaCorrection;
|
3217
|
+
uniform bool logDepth;
|
3218
|
+
uniform bool ortho;
|
3219
|
+
uniform bool screenSpaceRadius;
|
3220
|
+
uniform bool fog;
|
3221
|
+
uniform bool fogExp;
|
3222
|
+
uniform bool colorMultiply;
|
3223
|
+
uniform float fogDensity;
|
3224
|
+
uniform float fogNear;
|
3225
|
+
uniform float fogFar;
|
3226
|
+
uniform float radius;
|
3227
|
+
uniform float distanceFalloff;
|
3228
|
+
uniform vec3 cameraPos;
|
3229
|
+
varying vec2 vUv;
|
3230
|
+
|
3231
|
+
highp float linearize_depth(highp float d, highp float zNear,highp float zFar) {
|
3232
|
+
return (zFar * zNear) / (zFar - d * (zFar - zNear));
|
3233
|
+
}
|
3234
|
+
|
3235
|
+
highp float linearize_depth_ortho(highp float d, highp float nearZ, highp float farZ) {
|
3236
|
+
return nearZ + (farZ - nearZ) * d;
|
3237
|
+
}
|
3238
|
+
|
3239
|
+
highp float linearize_depth_log(highp float d, highp float nearZ,highp float farZ) {
|
3240
|
+
float depth = pow(2.0, d * log2(farZ + 1.0)) - 1.0;
|
3241
|
+
float a = farZ / (farZ - nearZ);
|
3242
|
+
float b = farZ * nearZ / (nearZ - farZ);
|
3243
|
+
float linDepth = a + b / depth;
|
3244
|
+
return (
|
3245
|
+
ortho
|
3246
|
+
? linearize_depth_ortho(linDepth, nearZ, farZ)
|
3247
|
+
: linearize_depth(linDepth, nearZ, farZ)
|
3248
|
+
);
|
3249
|
+
}
|
3250
|
+
|
3251
|
+
vec3 getWorldPosLog(vec3 posS) {
|
3252
|
+
vec2 uv = posS.xy;
|
3253
|
+
float z = posS.z;
|
3254
|
+
float nearZ =near;
|
3255
|
+
float farZ = far;
|
3256
|
+
float depth = pow(2.0, z * log2(farZ + 1.0)) - 1.0;
|
3257
|
+
float a = farZ / (farZ - nearZ);
|
3258
|
+
float b = farZ * nearZ / (nearZ - farZ);
|
3259
|
+
float linDepth = a + b / depth;
|
3260
|
+
vec4 clipVec = vec4(uv, linDepth, 1.0) * 2.0 - 1.0;
|
3261
|
+
vec4 wpos = projectionMatrixInv * clipVec;
|
3262
|
+
return wpos.xyz / wpos.w;
|
3263
|
+
}
|
3264
|
+
|
3265
|
+
vec3 getWorldPos(float depth, vec2 coord) {
|
3266
|
+
#ifdef LOGDEPTH
|
3267
|
+
return getWorldPosLog(vec3(coord, depth));
|
3268
|
+
#endif
|
3269
|
+
|
3270
|
+
float z = depth * 2.0 - 1.0;
|
3271
|
+
vec4 clipSpacePosition = vec4(coord * 2.0 - 1.0, z, 1.0);
|
3272
|
+
vec4 viewSpacePosition = projectionMatrixInv * clipSpacePosition;
|
3273
|
+
|
3274
|
+
vec4 worldSpacePosition = viewSpacePosition;
|
3275
|
+
worldSpacePosition.xyz /= worldSpacePosition.w;
|
3276
|
+
return worldSpacePosition.xyz;
|
3277
|
+
}
|
3278
|
+
|
3279
|
+
vec3 computeNormal(vec3 worldPos, vec2 vUv) {
|
3280
|
+
ivec2 p = ivec2(vUv * resolution);
|
3281
|
+
float c0 = texelFetch(sceneDepth, p, 0).x;
|
3282
|
+
float l2 = texelFetch(sceneDepth, p - ivec2(2, 0), 0).x;
|
3283
|
+
float l1 = texelFetch(sceneDepth, p - ivec2(1, 0), 0).x;
|
3284
|
+
float r1 = texelFetch(sceneDepth, p + ivec2(1, 0), 0).x;
|
3285
|
+
float r2 = texelFetch(sceneDepth, p + ivec2(2, 0), 0).x;
|
3286
|
+
float b2 = texelFetch(sceneDepth, p - ivec2(0, 2), 0).x;
|
3287
|
+
float b1 = texelFetch(sceneDepth, p - ivec2(0, 1), 0).x;
|
3288
|
+
float t1 = texelFetch(sceneDepth, p + ivec2(0, 1), 0).x;
|
3289
|
+
float t2 = texelFetch(sceneDepth, p + ivec2(0, 2), 0).x;
|
3290
|
+
float dl = abs((2.0 * l1 - l2) - c0);
|
3291
|
+
float dr = abs((2.0 * r1 - r2) - c0);
|
3292
|
+
float db = abs((2.0 * b1 - b2) - c0);
|
3293
|
+
float dt = abs((2.0 * t1 - t2) - c0);
|
3294
|
+
vec3 ce = getWorldPos(c0, vUv).xyz;
|
3295
|
+
vec3 dpdx = (
|
3296
|
+
(dl < dr)
|
3297
|
+
? ce - getWorldPos(l1, (vUv - vec2(1.0 / resolution.x, 0.0))).xyz
|
3298
|
+
: -ce + getWorldPos(r1, (vUv + vec2(1.0 / resolution.x, 0.0))).xyz
|
3299
|
+
);
|
3300
|
+
vec3 dpdy = (
|
3301
|
+
(db < dt)
|
3302
|
+
? ce - getWorldPos(b1, (vUv - vec2(0.0, 1.0 / resolution.y))).xyz
|
3303
|
+
: -ce + getWorldPos(t1, (vUv + vec2(0.0, 1.0 / resolution.y))).xyz
|
3304
|
+
);
|
3305
|
+
return normalize(cross(dpdx, dpdy));
|
3306
|
+
}
|
3307
|
+
|
3308
|
+
#include <common>
|
3309
|
+
#include <dithering_pars_fragment>
|
3310
|
+
|
3311
|
+
void main(void) {
|
3312
|
+
vec4 sceneTexel = texture2D(sceneDiffuse, vUv);
|
3313
|
+
float depth = texture2D(sceneDepth, vUv).x;
|
3314
|
+
|
3315
|
+
#ifdef HALFRES
|
3316
|
+
vec4 texel;
|
3317
|
+
if (depth == 1.0) {
|
3318
|
+
texel = vec4(0.0, 0.0, 0.0, 1.0);
|
3319
|
+
} else {
|
3320
|
+
vec3 worldPos = getWorldPos(depth, vUv);
|
3321
|
+
vec3 normal = computeNormal(getWorldPos(depth, vUv), vUv);
|
3322
|
+
|
3323
|
+
float totalWeight = 0.0;
|
3324
|
+
float radiusToUse = (
|
3325
|
+
screenSpaceRadius
|
3326
|
+
? distance(worldPos, getWorldPos(depth, vUv + vec2(radius, 0.0) / resolution))
|
3327
|
+
: radius
|
3328
|
+
);
|
3329
|
+
float distanceFalloffToUse = (
|
3330
|
+
screenSpaceRadius
|
3331
|
+
? radiusToUse * distanceFalloff
|
3332
|
+
: distanceFalloff
|
3333
|
+
);
|
3334
|
+
for(float x = -1.0; x <= 1.0; x++) {
|
3335
|
+
for(float y = -1.0; y <= 1.0; y++) {
|
3336
|
+
vec2 offset = vec2(x, y);
|
3337
|
+
ivec2 p = ivec2((vUv * resolution * 0.5) + offset);
|
3338
|
+
vec2 pUv = vec2(p) / (resolution * 0.5);
|
3339
|
+
float sampleDepth = texelFetch(downsampledDepth,p, 0).x;
|
3340
|
+
vec4 sampleInfo = texelFetch(tDiffuse, p, 0);
|
3341
|
+
vec3 normalSample = sampleInfo.xyz * 2.0 - 1.0;
|
3342
|
+
vec3 worldPosSample = getWorldPos(sampleDepth, pUv);
|
3343
|
+
float tangentPlaneDist = abs(dot(worldPos - worldPosSample, normal));
|
3344
|
+
float rangeCheck = exp(
|
3345
|
+
-1.0 * tangentPlaneDist * (1.0 / distanceFalloffToUse)) * max(dot(normal, normalSample),
|
3346
|
+
0.0
|
3347
|
+
);
|
3348
|
+
float weight = rangeCheck;
|
3349
|
+
totalWeight += weight;
|
3350
|
+
texel += sampleInfo * weight;
|
3351
|
+
}
|
3352
|
+
}
|
3353
|
+
if (totalWeight == 0.0) {
|
3354
|
+
texel = texture2D(tDiffuse, vUv);
|
3355
|
+
} else {
|
3356
|
+
texel /= totalWeight;
|
3357
|
+
}
|
3358
|
+
}
|
3359
|
+
#else
|
3360
|
+
vec4 texel = texture2D(tDiffuse, vUv);
|
3361
|
+
#endif
|
3362
|
+
|
3363
|
+
#ifdef LOGDEPTH
|
3364
|
+
texel.a = clamp(texel.a, 0.0, 1.0);
|
3365
|
+
if (texel.a == 0.0) {
|
3366
|
+
texel.a = 1.0;
|
3367
|
+
}
|
3368
|
+
#endif
|
3369
|
+
|
3370
|
+
float finalAo = pow(texel.a, intensity);
|
3371
|
+
float fogFactor;
|
3372
|
+
float fogDepth = distance(cameraPos, getWorldPos(depth, vUv));
|
3373
|
+
|
3374
|
+
if (fog) {
|
3375
|
+
if (fogExp) {
|
3376
|
+
fogFactor = 1.0 - exp(-fogDensity * fogDensity * fogDepth * fogDepth);
|
3377
|
+
} else {
|
3378
|
+
fogFactor = smoothstep(fogNear, fogFar, fogDepth);
|
3379
|
+
}
|
3380
|
+
}
|
3381
|
+
|
3382
|
+
finalAo = mix(finalAo, 1.0, fogFactor);
|
3383
|
+
vec3 aoApplied = color * mix(vec3(1.0), sceneTexel.rgb, float(colorMultiply));
|
3384
|
+
if (renderMode == 0.0) {
|
3385
|
+
gl_FragColor = vec4( mix(sceneTexel.rgb, aoApplied, 1.0 - finalAo), sceneTexel.a);
|
3386
|
+
} else if (renderMode == 1.0) {
|
3387
|
+
gl_FragColor = vec4( mix(vec3(1.0), aoApplied, 1.0 - finalAo), sceneTexel.a);
|
3388
|
+
} else if (renderMode == 2.0) {
|
3389
|
+
gl_FragColor = vec4( sceneTexel.rgb, sceneTexel.a);
|
3390
|
+
} else if (renderMode == 3.0) {
|
3391
|
+
if (vUv.x < 0.5) {
|
3392
|
+
gl_FragColor = vec4( sceneTexel.rgb, sceneTexel.a);
|
3393
|
+
} else if (abs(vUv.x - 0.5) < 1.0 / resolution.x) {
|
3394
|
+
gl_FragColor = vec4(1.0);
|
3395
|
+
} else {
|
3396
|
+
gl_FragColor = vec4(mix(sceneTexel.rgb, aoApplied, 1.0 - finalAo), sceneTexel.a);
|
3397
|
+
}
|
3398
|
+
} else if (renderMode == 4.0) {
|
3399
|
+
if (vUv.x < 0.5) {
|
3400
|
+
gl_FragColor = vec4( sceneTexel.rgb, sceneTexel.a);
|
3401
|
+
} else if (abs(vUv.x - 0.5) < 1.0 / resolution.x) {
|
3402
|
+
gl_FragColor = vec4(1.0);
|
3403
|
+
} else {
|
3404
|
+
gl_FragColor = vec4(mix(vec3(1.0), aoApplied, 1.0 - finalAo), sceneTexel.a);
|
3405
|
+
}
|
3406
|
+
}
|
3407
|
+
|
3408
|
+
#include <dithering_fragment>
|
3409
|
+
|
3410
|
+
if (gammaCorrection) {
|
3411
|
+
gl_FragColor = LinearTosRGB(gl_FragColor);
|
3412
|
+
}
|
3413
|
+
}
|
3414
|
+
`
|
3415
|
+
)
|
3416
|
+
};
|
3417
|
+
|
3418
|
+
// src/rendering/post-effects/n8-ssao/EffectShader.ts
|
3419
|
+
import { Matrix4 as Matrix44, Uniform as Uniform5, Vector2 as Vector24, Vector3 as Vector311 } from "three";
|
3420
|
+
var EffectShader = {
|
3421
|
+
uniforms: {
|
3422
|
+
sceneDiffuse: new Uniform5(null),
|
3423
|
+
sceneDepth: new Uniform5(null),
|
3424
|
+
sceneNormal: new Uniform5(null),
|
3425
|
+
projMat: new Uniform5(new Matrix44()),
|
3426
|
+
viewMat: new Uniform5(new Matrix44()),
|
3427
|
+
projViewMat: new Uniform5(new Matrix44()),
|
3428
|
+
projectionMatrixInv: new Uniform5(new Matrix44()),
|
3429
|
+
viewMatrixInv: new Uniform5(new Matrix44()),
|
3430
|
+
cameraPos: new Uniform5(new Vector311()),
|
3431
|
+
resolution: new Uniform5(new Vector24()),
|
3432
|
+
time: new Uniform5(0),
|
3433
|
+
samples: new Uniform5([]),
|
3434
|
+
samplesR: new Uniform5([]),
|
3435
|
+
bluenoise: new Uniform5(null),
|
3436
|
+
distanceFalloff: new Uniform5(1),
|
3437
|
+
radius: new Uniform5(5),
|
3438
|
+
near: new Uniform5(0.1),
|
3439
|
+
far: new Uniform5(1e3),
|
3440
|
+
logDepth: new Uniform5(false),
|
3441
|
+
ortho: new Uniform5(false),
|
3442
|
+
screenSpaceRadius: new Uniform5(false)
|
3443
|
+
},
|
3444
|
+
depthWrite: false,
|
3445
|
+
depthTest: false,
|
3446
|
+
vertexShader: (
|
3447
|
+
/* glsl */
|
3448
|
+
`
|
3449
|
+
varying vec2 vUv;
|
3450
|
+
void main(void) {
|
3451
|
+
vUv = uv;
|
3452
|
+
gl_Position = vec4(position, 1);
|
3453
|
+
}
|
3454
|
+
`
|
3455
|
+
),
|
3456
|
+
fragmentShader: (
|
3457
|
+
/* glsl */
|
3458
|
+
`
|
3459
|
+
#define SAMPLES 16
|
3460
|
+
#define FSAMPLES 16.0
|
3461
|
+
uniform sampler2D sceneDiffuse;
|
3462
|
+
uniform highp sampler2D sceneNormal;
|
3463
|
+
uniform highp sampler2D sceneDepth;
|
3464
|
+
uniform mat4 projectionMatrixInv;
|
3465
|
+
uniform mat4 viewMatrixInv;
|
3466
|
+
uniform mat4 projMat;
|
3467
|
+
uniform mat4 viewMat;
|
3468
|
+
uniform mat4 projViewMat;
|
3469
|
+
uniform vec3 cameraPos;
|
3470
|
+
uniform vec2 resolution;
|
3471
|
+
uniform float time;
|
3472
|
+
uniform vec3[SAMPLES] samples;
|
3473
|
+
uniform float[SAMPLES] samplesR;
|
3474
|
+
uniform float radius;
|
3475
|
+
uniform float distanceFalloff;
|
3476
|
+
uniform float near;
|
3477
|
+
uniform float far;
|
3478
|
+
uniform bool logDepth;
|
3479
|
+
uniform bool ortho;
|
3480
|
+
uniform bool screenSpaceRadius;
|
3481
|
+
uniform sampler2D bluenoise;
|
3482
|
+
varying vec2 vUv;
|
3483
|
+
|
3484
|
+
highp float linearize_depth(highp float d, highp float zNear,highp float zFar) {
|
3485
|
+
return (zFar * zNear) / (zFar - d * (zFar - zNear));
|
3486
|
+
}
|
3487
|
+
|
3488
|
+
highp float linearize_depth_ortho(highp float d, highp float nearZ, highp float farZ) {
|
3489
|
+
return nearZ + (farZ - nearZ) * d;
|
3490
|
+
}
|
3491
|
+
|
3492
|
+
highp float linearize_depth_log(highp float d, highp float nearZ,highp float farZ) {
|
3493
|
+
float depth = pow(2.0, d * log2(farZ + 1.0)) - 1.0;
|
3494
|
+
float a = farZ / (farZ - nearZ);
|
3495
|
+
float b = farZ * nearZ / (nearZ - farZ);
|
3496
|
+
float linDepth = a + b / depth;
|
3497
|
+
return (
|
3498
|
+
ortho
|
3499
|
+
? linearize_depth_ortho(linDepth, nearZ, farZ)
|
3500
|
+
: linearize_depth(linDepth, nearZ, farZ)
|
3501
|
+
);
|
3502
|
+
}
|
3503
|
+
|
3504
|
+
vec3 getWorldPosLog(vec3 posS) {
|
3505
|
+
vec2 uv = posS.xy;
|
3506
|
+
float z = posS.z;
|
3507
|
+
float nearZ =near;
|
3508
|
+
float farZ = far;
|
3509
|
+
float depth = pow(2.0, z * log2(farZ + 1.0)) - 1.0;
|
3510
|
+
float a = farZ / (farZ - nearZ);
|
3511
|
+
float b = farZ * nearZ / (nearZ - farZ);
|
3512
|
+
float linDepth = a + b / depth;
|
3513
|
+
vec4 clipVec = vec4(uv, linDepth, 1.0) * 2.0 - 1.0;
|
3514
|
+
vec4 wpos = projectionMatrixInv * clipVec;
|
3515
|
+
return wpos.xyz / wpos.w;
|
3516
|
+
}
|
3517
|
+
|
3518
|
+
vec3 getWorldPos(float depth, vec2 coord) {
|
3519
|
+
#ifdef LOGDEPTH
|
3520
|
+
return getWorldPosLog(vec3(coord, depth));
|
3521
|
+
#endif
|
3522
|
+
float z = depth * 2.0 - 1.0;
|
3523
|
+
vec4 clipSpacePosition = vec4(coord * 2.0 - 1.0, z, 1.0);
|
3524
|
+
vec4 viewSpacePosition = projectionMatrixInv * clipSpacePosition;
|
3525
|
+
|
3526
|
+
vec4 worldSpacePosition = viewSpacePosition;
|
3527
|
+
worldSpacePosition.xyz /= worldSpacePosition.w;
|
3528
|
+
return worldSpacePosition.xyz;
|
3529
|
+
}
|
3530
|
+
|
3531
|
+
vec3 computeNormal(vec3 worldPos, vec2 vUv) {
|
3532
|
+
ivec2 p = ivec2(vUv * resolution);
|
3533
|
+
float c0 = texelFetch(sceneDepth, p, 0).x;
|
3534
|
+
float l2 = texelFetch(sceneDepth, p - ivec2(2, 0), 0).x;
|
3535
|
+
float l1 = texelFetch(sceneDepth, p - ivec2(1, 0), 0).x;
|
3536
|
+
float r1 = texelFetch(sceneDepth, p + ivec2(1, 0), 0).x;
|
3537
|
+
float r2 = texelFetch(sceneDepth, p + ivec2(2, 0), 0).x;
|
3538
|
+
float b2 = texelFetch(sceneDepth, p - ivec2(0, 2), 0).x;
|
3539
|
+
float b1 = texelFetch(sceneDepth, p - ivec2(0, 1), 0).x;
|
3540
|
+
float t1 = texelFetch(sceneDepth, p + ivec2(0, 1), 0).x;
|
3541
|
+
float t2 = texelFetch(sceneDepth, p + ivec2(0, 2), 0).x;
|
3542
|
+
float dl = abs((2.0 * l1 - l2) - c0);
|
3543
|
+
float dr = abs((2.0 * r1 - r2) - c0);
|
3544
|
+
float db = abs((2.0 * b1 - b2) - c0);
|
3545
|
+
float dt = abs((2.0 * t1 - t2) - c0);
|
3546
|
+
vec3 ce = getWorldPos(c0, vUv).xyz;
|
3547
|
+
vec3 dpdx = (
|
3548
|
+
(dl < dr)
|
3549
|
+
? ce - getWorldPos(l1, (vUv - vec2(1.0 / resolution.x, 0.0))).xyz
|
3550
|
+
: -ce + getWorldPos(r1, (vUv + vec2(1.0 / resolution.x, 0.0))).xyz
|
3551
|
+
);
|
3552
|
+
vec3 dpdy = (
|
3553
|
+
(db < dt)
|
3554
|
+
? ce - getWorldPos(b1, (vUv - vec2(0.0, 1.0 / resolution.y))).xyz
|
3555
|
+
: -ce + getWorldPos(t1, (vUv + vec2(0.0, 1.0 / resolution.y))).xyz
|
3556
|
+
);
|
3557
|
+
return normalize(cross(dpdx, dpdy));
|
3558
|
+
}
|
3559
|
+
|
3560
|
+
void main(void) {
|
3561
|
+
vec4 diffuse = texture2D(sceneDiffuse, vUv);
|
3562
|
+
float depth = texture2D(sceneDepth, vUv).x;
|
3563
|
+
|
3564
|
+
if (depth == 1.0) {
|
3565
|
+
gl_FragColor = vec4(vec3(1.0), 1.0);
|
3566
|
+
return;
|
3567
|
+
}
|
3568
|
+
|
3569
|
+
vec3 worldPos = getWorldPos(depth, vUv);
|
3570
|
+
|
3571
|
+
#ifdef HALFRES
|
3572
|
+
vec3 normal = texture2D(sceneNormal, vUv).rgb;
|
3573
|
+
#else
|
3574
|
+
vec3 normal = computeNormal(worldPos, vUv);
|
3575
|
+
#endif
|
3576
|
+
|
3577
|
+
vec4 noise = texture2D(bluenoise, gl_FragCoord.xy / 128.0);
|
3578
|
+
vec3 randomVec = normalize(noise.rgb * 2.0 - 1.0);
|
3579
|
+
vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal));
|
3580
|
+
vec3 bitangent = cross(normal, tangent);
|
3581
|
+
mat3 tbn = mat3(tangent, bitangent, normal);
|
3582
|
+
float occluded = 0.0;
|
3583
|
+
float totalWeight = 0.0;
|
3584
|
+
|
3585
|
+
float radiusToUse = (
|
3586
|
+
screenSpaceRadius
|
3587
|
+
? distance(worldPos, getWorldPos(depth, vUv + vec2(radius, 0.0) / resolution))
|
3588
|
+
: radius
|
3589
|
+
);
|
3590
|
+
float distanceFalloffToUse = (
|
3591
|
+
screenSpaceRadius
|
3592
|
+
? radiusToUse * distanceFalloff
|
3593
|
+
: distanceFalloff
|
3594
|
+
);
|
3595
|
+
float bias = (0.1 / near) * fwidth(distance(worldPos, cameraPos)) / radiusToUse;
|
3596
|
+
for(float i = 0.0; i < FSAMPLES; i++) {
|
3597
|
+
vec3 sampleDirection = tbn * samples[int(i)];
|
3598
|
+
float moveAmt = samplesR[int(mod(i + noise.a * FSAMPLES, FSAMPLES))];
|
3599
|
+
vec3 samplePos = worldPos + radiusToUse * moveAmt * sampleDirection;
|
3600
|
+
vec4 offset = projMat * vec4(samplePos, 1.0);
|
3601
|
+
offset.xyz /= offset.w;
|
3602
|
+
offset.xyz = offset.xyz * 0.5 + 0.5;
|
3603
|
+
float sampleDepth = textureLod(sceneDepth, offset.xy, 0.0).x;
|
3604
|
+
#ifdef LOGDEPTH
|
3605
|
+
float distSample = linearize_depth_log(sampleDepth, near, far);
|
3606
|
+
#else
|
3607
|
+
float distSample = (
|
3608
|
+
ortho
|
3609
|
+
? linearize_depth_ortho(sampleDepth, near, far)
|
3610
|
+
: linearize_depth(sampleDepth, near, far)
|
3611
|
+
);
|
3612
|
+
#endif
|
3613
|
+
float distWorld = (
|
3614
|
+
ortho
|
3615
|
+
? linearize_depth_ortho(offset.z, near, far)
|
3616
|
+
: linearize_depth(offset.z, near, far)
|
3617
|
+
);
|
3618
|
+
float rangeCheck = smoothstep(0.0, 1.0, distanceFalloffToUse / (abs(distSample - distWorld)));
|
3619
|
+
vec2 diff = gl_FragCoord.xy - ( offset.xy * resolution);
|
3620
|
+
float weight = dot(sampleDirection, normal);
|
3621
|
+
occluded += rangeCheck * weight *
|
3622
|
+
(distSample + bias < distWorld ? 1.0 : 0.0) *
|
3623
|
+
(
|
3624
|
+
(
|
3625
|
+
dot(diff, diff) < 1.0 ||
|
3626
|
+
(sampleDepth == depth) ||
|
3627
|
+
(offset.x < 0.0 || offset.x > 1.0 || offset.y < 0.0 || offset.y > 1.0) ? 0.0 : 1.0
|
3628
|
+
)
|
3629
|
+
);
|
3630
|
+
totalWeight += weight;
|
3631
|
+
}
|
3632
|
+
float occ = clamp(1.0 - occluded / totalWeight, 0.0, 1.0);
|
3633
|
+
gl_FragColor = vec4(0.5 + 0.5 * normal, occ);
|
3634
|
+
}`
|
3635
|
+
)
|
3636
|
+
};
|
3637
|
+
|
3638
|
+
// src/rendering/post-effects/n8-ssao/FullScreenTriangle.ts
|
3639
|
+
import {
|
3640
|
+
BufferAttribute,
|
3641
|
+
BufferGeometry,
|
3642
|
+
Mesh as Mesh4,
|
3643
|
+
OrthographicCamera as OrthographicCamera2,
|
3644
|
+
Sphere
|
3645
|
+
} from "three";
|
3646
|
+
var FullScreenTriangle = class {
|
3647
|
+
constructor(material) {
|
3648
|
+
this.camera = new OrthographicCamera2();
|
3649
|
+
this.geometry = new BufferGeometry();
|
3650
|
+
this.geometry.setAttribute(
|
3651
|
+
"position",
|
3652
|
+
new BufferAttribute(new Float32Array([-1, -1, 3, -1, -1, 3]), 2)
|
3653
|
+
);
|
3654
|
+
this.geometry.setAttribute("uv", new BufferAttribute(new Float32Array([0, 0, 2, 0, 0, 2]), 2));
|
3655
|
+
this.geometry.boundingSphere = new Sphere();
|
3656
|
+
this.geometry.computeBoundingSphere = function() {
|
3657
|
+
};
|
3658
|
+
this.mesh = new Mesh4(this.geometry, material);
|
3659
|
+
this.mesh.frustumCulled = false;
|
3660
|
+
}
|
3661
|
+
get material() {
|
3662
|
+
return this.mesh.material;
|
3663
|
+
}
|
3664
|
+
set material(value) {
|
3665
|
+
this.mesh.material = value;
|
3666
|
+
}
|
3667
|
+
render(renderer) {
|
3668
|
+
renderer.render(this.mesh, this.camera);
|
3669
|
+
}
|
3670
|
+
dispose() {
|
3671
|
+
this.mesh.material.dispose();
|
3672
|
+
this.mesh.geometry.dispose();
|
3673
|
+
}
|
3674
|
+
};
|
3675
|
+
|
3676
|
+
// src/rendering/post-effects/n8-ssao/PoissionBlur.ts
|
3677
|
+
import { Matrix4 as Matrix45, Uniform as Uniform6, Vector2 as Vector25, Vector3 as Vector312 } from "three";
|
3678
|
+
var PoissionBlur = {
|
3679
|
+
uniforms: {
|
3680
|
+
sceneDiffuse: new Uniform6(null),
|
3681
|
+
sceneDepth: new Uniform6(null),
|
3682
|
+
tDiffuse: new Uniform6(null),
|
3683
|
+
projMat: new Uniform6(new Matrix45()),
|
3684
|
+
viewMat: new Uniform6(new Matrix45()),
|
3685
|
+
projectionMatrixInv: new Uniform6(new Matrix45()),
|
3686
|
+
viewMatrixInv: new Uniform6(new Matrix45()),
|
3687
|
+
cameraPos: new Uniform6(new Vector312()),
|
3688
|
+
resolution: new Uniform6(new Vector25()),
|
3689
|
+
time: new Uniform6(0),
|
3690
|
+
r: new Uniform6(5),
|
3691
|
+
blueNoise: new Uniform6(null),
|
3692
|
+
radius: new Uniform6(12),
|
3693
|
+
worldRadius: new Uniform6(5),
|
3694
|
+
index: new Uniform6(0),
|
3695
|
+
poissonDisk: new Uniform6([]),
|
3696
|
+
distanceFalloff: new Uniform6(1),
|
3697
|
+
near: new Uniform6(0.1),
|
3698
|
+
far: new Uniform6(1e3),
|
3699
|
+
logDepth: new Uniform6(false),
|
3700
|
+
screenSpaceRadius: new Uniform6(false)
|
3701
|
+
},
|
3702
|
+
depthWrite: false,
|
3703
|
+
depthTest: false,
|
3704
|
+
vertexShader: (
|
3705
|
+
/* glsl */
|
3706
|
+
`
|
3707
|
+
varying vec2 vUv;
|
3708
|
+
void main(void) {
|
3709
|
+
vUv = uv;
|
3710
|
+
gl_Position = vec4(position, 1.0);
|
3711
|
+
}`
|
3712
|
+
),
|
3713
|
+
fragmentShader: (
|
3714
|
+
/* glsl */
|
3715
|
+
`
|
3716
|
+
uniform sampler2D sceneDiffuse;
|
3717
|
+
uniform highp sampler2D sceneDepth;
|
3718
|
+
uniform sampler2D tDiffuse;
|
3719
|
+
uniform sampler2D blueNoise;
|
3720
|
+
uniform mat4 projectionMatrixInv;
|
3721
|
+
uniform mat4 viewMatrixInv;
|
3722
|
+
uniform vec2 resolution;
|
3723
|
+
uniform float r;
|
3724
|
+
uniform float radius;
|
3725
|
+
uniform float worldRadius;
|
3726
|
+
uniform float index;
|
3727
|
+
uniform float near;
|
3728
|
+
uniform float far;
|
3729
|
+
uniform float distanceFalloff;
|
3730
|
+
uniform bool logDepth;
|
3731
|
+
uniform bool screenSpaceRadius;
|
3732
|
+
varying vec2 vUv;
|
3733
|
+
|
3734
|
+
highp float linearize_depth(highp float d, highp float zNear,highp float zFar) {
|
3735
|
+
highp float z_n = 2.0 * d - 1.0;
|
3736
|
+
return 2.0 * zNear * zFar / (zFar + zNear - z_n * (zFar - zNear));
|
3737
|
+
}
|
3738
|
+
|
3739
|
+
highp float linearize_depth_log(highp float d, highp float nearZ,highp float farZ) {
|
3740
|
+
float depth = pow(2.0, d * log2(farZ + 1.0)) - 1.0;
|
3741
|
+
float a = farZ / (farZ - nearZ);
|
3742
|
+
float b = farZ * nearZ / (nearZ - farZ);
|
3743
|
+
float linDepth = a + b / depth;
|
3744
|
+
return linearize_depth(linDepth, nearZ, farZ);
|
3745
|
+
}
|
3746
|
+
|
3747
|
+
highp float linearize_depth_ortho(highp float d, highp float nearZ, highp float farZ) {
|
3748
|
+
return nearZ + (farZ - nearZ) * d;
|
3749
|
+
}
|
3750
|
+
|
3751
|
+
vec3 getWorldPosLog(vec3 posS) {
|
3752
|
+
vec2 uv = posS.xy;
|
3753
|
+
float z = posS.z;
|
3754
|
+
float nearZ =near;
|
3755
|
+
float farZ = far;
|
3756
|
+
float depth = pow(2.0, z * log2(farZ + 1.0)) - 1.0;
|
3757
|
+
float a = farZ / (farZ - nearZ);
|
3758
|
+
float b = farZ * nearZ / (nearZ - farZ);
|
3759
|
+
float linDepth = a + b / depth;
|
3760
|
+
vec4 clipVec = vec4(uv, linDepth, 1.0) * 2.0 - 1.0;
|
3761
|
+
vec4 wpos = projectionMatrixInv * clipVec;
|
3762
|
+
return wpos.xyz / wpos.w;
|
3763
|
+
}
|
3764
|
+
|
3765
|
+
vec3 getWorldPos(float depth, vec2 coord) {
|
3766
|
+
#ifdef LOGDEPTH
|
3767
|
+
return getWorldPosLog(vec3(coord, depth));
|
3768
|
+
#endif
|
3769
|
+
|
3770
|
+
float z = depth * 2.0 - 1.0;
|
3771
|
+
vec4 clipSpacePosition = vec4(coord * 2.0 - 1.0, z, 1.0);
|
3772
|
+
vec4 viewSpacePosition = projectionMatrixInv * clipSpacePosition;
|
3773
|
+
|
3774
|
+
vec4 worldSpacePosition = viewSpacePosition;
|
3775
|
+
worldSpacePosition.xyz /= worldSpacePosition.w;
|
3776
|
+
return worldSpacePosition.xyz;
|
3777
|
+
}
|
3778
|
+
|
3779
|
+
#include <common>
|
3780
|
+
|
3781
|
+
#define NUM_SAMPLES 16
|
3782
|
+
|
3783
|
+
uniform vec2 poissonDisk[NUM_SAMPLES];
|
3784
|
+
|
3785
|
+
void main(void) {
|
3786
|
+
const float pi = acos(-1.0);
|
3787
|
+
vec2 texelSize = vec2(1.0 / resolution.x, 1.0 / resolution.y);
|
3788
|
+
vec2 uv = vUv;
|
3789
|
+
vec4 data = texture2D(tDiffuse, vUv);
|
3790
|
+
float occlusion = data.a;
|
3791
|
+
float baseOcc = data.a;
|
3792
|
+
vec3 normal = data.rgb * 2.0 - 1.0;
|
3793
|
+
float count = 1.0;
|
3794
|
+
float d = texture2D(sceneDepth, vUv).x;
|
3795
|
+
if (d == 1.0) {
|
3796
|
+
gl_FragColor = data;
|
3797
|
+
return;
|
3798
|
+
}
|
3799
|
+
vec3 worldPos = getWorldPos(d, vUv);
|
3800
|
+
float size = radius;
|
3801
|
+
float angle;
|
3802
|
+
|
3803
|
+
if (index == 0.0) {
|
3804
|
+
angle = texture2D(blueNoise, gl_FragCoord.xy / 128.0).x * PI2;
|
3805
|
+
} else if (index == 1.0) {
|
3806
|
+
angle = texture2D(blueNoise, gl_FragCoord.xy / 128.0).y * PI2;
|
3807
|
+
} else if (index == 2.0) {
|
3808
|
+
angle = texture2D(blueNoise, gl_FragCoord.xy / 128.0).z * PI2;
|
3809
|
+
} else {
|
3810
|
+
angle = texture2D(blueNoise, gl_FragCoord.xy / 128.0).w * PI2;
|
3811
|
+
}
|
3812
|
+
|
3813
|
+
mat2 rotationMatrix = mat2(cos(angle), -sin(angle), sin(angle), cos(angle));
|
3814
|
+
float radiusToUse = (
|
3815
|
+
screenSpaceRadius
|
3816
|
+
? distance(worldPos, getWorldPos(d, vUv + vec2(worldRadius, 0.0) / resolution))
|
3817
|
+
: worldRadius
|
3818
|
+
);
|
3819
|
+
float distanceFalloffToUse = (
|
3820
|
+
screenSpaceRadius
|
3821
|
+
? radiusToUse * distanceFalloff
|
3822
|
+
: distanceFalloff
|
3823
|
+
);
|
3824
|
+
|
3825
|
+
for(int i = 0; i < NUM_SAMPLES; i++) {
|
3826
|
+
vec2 offset = (rotationMatrix * poissonDisk[i]) * texelSize * size;
|
3827
|
+
vec4 dataSample = texture2D(tDiffuse, uv + offset);
|
3828
|
+
float occSample = dataSample.a;
|
3829
|
+
vec3 normalSample = dataSample.rgb * 2.0 - 1.0;
|
3830
|
+
float dSample = texture2D(sceneDepth, uv + offset).x;
|
3831
|
+
vec3 worldPosSample = getWorldPos(dSample, uv + offset);
|
3832
|
+
float tangentPlaneDist = abs(dot(worldPos - worldPosSample, normal));
|
3833
|
+
float rangeCheck = (
|
3834
|
+
(dSample == 1.0)
|
3835
|
+
? 0.0
|
3836
|
+
: exp(
|
3837
|
+
-1.0 * tangentPlaneDist * (1.0 / distanceFalloffToUse)
|
3838
|
+
) * max(dot(normal, normalSample), 0.0) * (1.0 - abs(occSample - baseOcc))
|
3839
|
+
);
|
3840
|
+
occlusion += occSample * rangeCheck;
|
3841
|
+
count += rangeCheck;
|
3842
|
+
}
|
3843
|
+
|
3844
|
+
if (count > 0.0) {
|
3845
|
+
occlusion /= count;
|
3846
|
+
}
|
3847
|
+
|
3848
|
+
#ifdef LOGDEPTH
|
3849
|
+
occlusion = clamp(occlusion, 0.0, 1.0);
|
3850
|
+
if (occlusion == 0.0) {
|
3851
|
+
occlusion = 1.0;
|
3852
|
+
}
|
3853
|
+
#endif
|
3854
|
+
gl_FragColor = vec4(0.5 + 0.5 * normal, occlusion);
|
3855
|
+
}
|
3856
|
+
`
|
3857
|
+
)
|
3858
|
+
};
|
3859
|
+
|
3860
|
+
// src/rendering/post-effects/n8-ssao/N8SSAOPass.ts
|
3861
|
+
var bluenoiseBits = Uint8Array.from(atob(BlueNoise), (c) => c.charCodeAt(0));
|
3862
|
+
function checkTimerQuery(timerQuery, gl, pass) {
|
3863
|
+
const available = gl.getQueryParameter(timerQuery, gl.QUERY_RESULT_AVAILABLE);
|
3864
|
+
if (available) {
|
3865
|
+
const elapsedTimeInNs = gl.getQueryParameter(timerQuery, gl.QUERY_RESULT);
|
3866
|
+
const elapsedTimeInMs = elapsedTimeInNs / 1e6;
|
3867
|
+
pass.lastTime = elapsedTimeInMs;
|
3868
|
+
} else {
|
3869
|
+
setTimeout(() => checkTimerQuery(timerQuery, gl, pass), 1);
|
3870
|
+
}
|
3871
|
+
}
|
3872
|
+
var N8SSAOPass = class extends Pass {
|
3873
|
+
constructor(scene, camera, width = 512, height = 512) {
|
3874
|
+
super();
|
3875
|
+
this.lastTime = 0;
|
3876
|
+
this.autosetGamma = true;
|
3877
|
+
this.samples = [];
|
3878
|
+
this.samplesR = [];
|
3879
|
+
this.samplesDenoise = [];
|
3880
|
+
this.copyQuadMaterial = new ShaderMaterial4({
|
3881
|
+
uniforms: { tDiffuse: new Uniform7(null) },
|
3882
|
+
depthWrite: false,
|
3883
|
+
vertexShader: (
|
3884
|
+
/* glsl */
|
3885
|
+
`
|
3886
|
+
varying vec2 vUv;
|
3887
|
+
void main(void) {
|
3888
|
+
vUv = uv;
|
3889
|
+
gl_Position = vec4(position, 1);
|
3890
|
+
}
|
3891
|
+
`
|
3892
|
+
),
|
3893
|
+
fragmentShader: (
|
3894
|
+
/* glsl */
|
3895
|
+
`
|
3896
|
+
uniform sampler2D tDiffuse;
|
3897
|
+
varying vec2 vUv;
|
3898
|
+
void main(void) {
|
3899
|
+
gl_FragColor = texture2D(tDiffuse, vUv);
|
3900
|
+
}
|
3901
|
+
`
|
3902
|
+
)
|
3903
|
+
});
|
3904
|
+
this.copyQuad = new FullScreenTriangle(this.copyQuadMaterial);
|
3905
|
+
this.width = width;
|
3906
|
+
this.height = height;
|
3907
|
+
this.camera = camera;
|
3908
|
+
this.scene = scene;
|
3909
|
+
this.configuration = new Proxy(
|
3910
|
+
{
|
3911
|
+
aoSamples: 16,
|
3912
|
+
aoRadius: 5,
|
3913
|
+
denoiseSamples: 8,
|
3914
|
+
denoiseRadius: 12,
|
3915
|
+
distanceFalloff: 1,
|
3916
|
+
intensity: 5,
|
3917
|
+
denoiseIterations: 2,
|
3918
|
+
renderMode: 0,
|
3919
|
+
color: new Color6(0, 0, 0),
|
3920
|
+
gammaCorrection: true,
|
3921
|
+
logarithmicDepthBuffer: false,
|
3922
|
+
screenSpaceRadius: false,
|
3923
|
+
halfRes: false,
|
3924
|
+
depthAwareUpsampling: true,
|
3925
|
+
colorMultiply: true
|
3926
|
+
},
|
3927
|
+
{
|
3928
|
+
set: (target, propName, value) => {
|
3929
|
+
const oldProp = target[propName];
|
3930
|
+
target[propName] = value;
|
3931
|
+
if (propName === "aoSamples" && oldProp !== value) {
|
3932
|
+
this.configureAOPass(this.configuration.logarithmicDepthBuffer);
|
3933
|
+
}
|
3934
|
+
if (propName === "denoiseSamples" && oldProp !== value) {
|
3935
|
+
this.configureDenoisePass(this.configuration.logarithmicDepthBuffer);
|
3936
|
+
}
|
3937
|
+
if (propName === "halfRes" && oldProp !== value) {
|
3938
|
+
this.configureAOPass(this.configuration.logarithmicDepthBuffer);
|
3939
|
+
this.configureHalfResTargets();
|
3940
|
+
this.configureEffectCompositer(this.configuration.logarithmicDepthBuffer);
|
3941
|
+
this.setSize(this.width, this.height);
|
3942
|
+
}
|
3943
|
+
if (propName === "depthAwareUpsampling" && oldProp !== value) {
|
3944
|
+
this.configureEffectCompositer(this.configuration.logarithmicDepthBuffer);
|
3945
|
+
}
|
3946
|
+
if (propName === "gammaCorrection") {
|
3947
|
+
this.autosetGamma = false;
|
3948
|
+
}
|
3949
|
+
return true;
|
3950
|
+
}
|
3951
|
+
}
|
3952
|
+
);
|
3953
|
+
this.configureEffectCompositer(this.configuration.logarithmicDepthBuffer);
|
3954
|
+
this.configureSampleDependentPasses();
|
3955
|
+
this.configureHalfResTargets();
|
3956
|
+
this.writeTargetInternal = new WebGLRenderTarget(this.width, this.height, {
|
3957
|
+
minFilter: LinearFilter3,
|
3958
|
+
magFilter: LinearFilter3,
|
3959
|
+
depthBuffer: false
|
3960
|
+
});
|
3961
|
+
this.readTargetInternal = new WebGLRenderTarget(this.width, this.height, {
|
3962
|
+
minFilter: LinearFilter3,
|
3963
|
+
magFilter: LinearFilter3,
|
3964
|
+
depthBuffer: false
|
3965
|
+
});
|
3966
|
+
this.outputTargetInternal = new WebGLRenderTarget(this.width, this.height, {
|
3967
|
+
minFilter: LinearFilter3,
|
3968
|
+
magFilter: LinearFilter3,
|
3969
|
+
depthBuffer: false
|
3970
|
+
});
|
3971
|
+
this.bluenoise = new DataTexture(bluenoiseBits, 128, 128);
|
3972
|
+
this.bluenoise.colorSpace = NoColorSpace;
|
3973
|
+
this.bluenoise.wrapS = RepeatWrapping;
|
3974
|
+
this.bluenoise.wrapT = RepeatWrapping;
|
3975
|
+
this.bluenoise.minFilter = NearestFilter;
|
3976
|
+
this.bluenoise.magFilter = NearestFilter;
|
3977
|
+
this.bluenoise.needsUpdate = true;
|
3978
|
+
this.lastTime = 0;
|
3979
|
+
this.needsDepthTexture = true;
|
3980
|
+
this.needsSwap = true;
|
3981
|
+
this.r = new Vector26();
|
3982
|
+
this.c = new Color6();
|
3983
|
+
}
|
3984
|
+
configureHalfResTargets() {
|
3985
|
+
if (this.configuration.halfRes) {
|
3986
|
+
this.depthDownsampleTarget = new WebGLMultipleRenderTargets(
|
3987
|
+
this.width / 2,
|
3988
|
+
this.height / 2,
|
3989
|
+
2,
|
3990
|
+
{
|
3991
|
+
depthBuffer: false
|
3992
|
+
}
|
3993
|
+
);
|
3994
|
+
this.depthDownsampleTarget.texture[0].format = RedFormat;
|
3995
|
+
this.depthDownsampleTarget.texture[0].type = FloatType;
|
3996
|
+
this.depthDownsampleTarget.texture[0].minFilter = NearestFilter;
|
3997
|
+
this.depthDownsampleTarget.texture[0].magFilter = NearestFilter;
|
3998
|
+
this.depthDownsampleTarget.texture[1].format = RGBAFormat2;
|
3999
|
+
this.depthDownsampleTarget.texture[1].type = HalfFloatType;
|
4000
|
+
this.depthDownsampleTarget.texture[1].minFilter = NearestFilter;
|
4001
|
+
this.depthDownsampleTarget.texture[1].magFilter = NearestFilter;
|
4002
|
+
this.depthDownsampleQuad = new FullScreenTriangle(new ShaderMaterial4(DepthDownSample));
|
4003
|
+
} else {
|
4004
|
+
if (this.depthDownsampleTarget) {
|
4005
|
+
this.depthDownsampleTarget.dispose();
|
4006
|
+
this.depthDownsampleTarget = null;
|
4007
|
+
}
|
4008
|
+
if (this.depthDownsampleQuad) {
|
4009
|
+
this.depthDownsampleQuad.dispose();
|
4010
|
+
this.depthDownsampleQuad = null;
|
4011
|
+
}
|
4012
|
+
}
|
4013
|
+
}
|
4014
|
+
configureSampleDependentPasses() {
|
4015
|
+
this.configureAOPass(this.configuration.logarithmicDepthBuffer);
|
4016
|
+
this.configureDenoisePass(this.configuration.logarithmicDepthBuffer);
|
4017
|
+
}
|
4018
|
+
configureAOPass(logarithmicDepthBuffer = false) {
|
4019
|
+
this.samples = this.generateHemisphereSamples(this.configuration.aoSamples);
|
4020
|
+
this.samplesR = this.generateHemisphereSamplesR(this.configuration.aoSamples);
|
4021
|
+
const e = { ...EffectShader };
|
4022
|
+
e.fragmentShader = e.fragmentShader.replace("16", this.configuration.aoSamples.toString()).replace("16.0", this.configuration.aoSamples.toString() + ".0");
|
4023
|
+
if (logarithmicDepthBuffer) {
|
4024
|
+
e.fragmentShader = "#define LOGDEPTH\n" + e.fragmentShader;
|
4025
|
+
}
|
4026
|
+
if (this.configuration.halfRes) {
|
4027
|
+
e.fragmentShader = "#define HALFRES\n" + e.fragmentShader;
|
4028
|
+
}
|
4029
|
+
if (this.effectShaderQuad) {
|
4030
|
+
this.effectShaderQuad.material.dispose();
|
4031
|
+
this.effectShaderQuad.material = new ShaderMaterial4(e);
|
4032
|
+
} else {
|
4033
|
+
this.effectShaderQuad = new FullScreenTriangle(new ShaderMaterial4(e));
|
4034
|
+
}
|
4035
|
+
}
|
4036
|
+
configureDenoisePass(logarithmicDepthBuffer = false) {
|
4037
|
+
this.samplesDenoise = this.generateDenoiseSamples(this.configuration.denoiseSamples, 11);
|
4038
|
+
const p = { ...PoissionBlur };
|
4039
|
+
p.fragmentShader = p.fragmentShader.replace("16", this.configuration.denoiseSamples.toString());
|
4040
|
+
if (logarithmicDepthBuffer) {
|
4041
|
+
p.fragmentShader = "#define LOGDEPTH\n" + p.fragmentShader;
|
4042
|
+
}
|
4043
|
+
if (this.poissonBlurQuad) {
|
4044
|
+
this.poissonBlurQuad.material.dispose();
|
4045
|
+
this.poissonBlurQuad.material = new ShaderMaterial4(p);
|
4046
|
+
} else {
|
4047
|
+
this.poissonBlurQuad = new FullScreenTriangle(new ShaderMaterial4(p));
|
4048
|
+
}
|
4049
|
+
}
|
4050
|
+
configureEffectCompositer(logarithmicDepthBuffer = false) {
|
4051
|
+
const e = { ...EffectCompositer };
|
4052
|
+
if (logarithmicDepthBuffer) {
|
4053
|
+
e.fragmentShader = "#define LOGDEPTH\n" + e.fragmentShader;
|
4054
|
+
}
|
4055
|
+
if (this.configuration.halfRes && this.configuration.depthAwareUpsampling) {
|
4056
|
+
e.fragmentShader = "#define HALFRES\n" + e.fragmentShader;
|
4057
|
+
}
|
4058
|
+
if (this.effectCompositerQuad) {
|
4059
|
+
this.effectCompositerQuad.material.dispose();
|
4060
|
+
this.effectCompositerQuad.material = new ShaderMaterial4(e);
|
4061
|
+
} else {
|
4062
|
+
this.effectCompositerQuad = new FullScreenTriangle(new ShaderMaterial4(e));
|
4063
|
+
}
|
4064
|
+
}
|
4065
|
+
generateHemisphereSamples(n) {
|
4066
|
+
const points = [];
|
4067
|
+
for (let k = 0; k < n; k++) {
|
4068
|
+
const theta = 2.399963 * k;
|
4069
|
+
const r = Math.sqrt(k + 0.5) / Math.sqrt(n);
|
4070
|
+
const x = r * Math.cos(theta);
|
4071
|
+
const y = r * Math.sin(theta);
|
4072
|
+
const z = Math.sqrt(1 - (x * x + y * y));
|
4073
|
+
points.push(new Vector313(x, y, z));
|
4074
|
+
}
|
4075
|
+
return points;
|
4076
|
+
}
|
4077
|
+
generateHemisphereSamplesR(n) {
|
4078
|
+
const samplesR = [];
|
4079
|
+
for (let i = 0; i < n; i++) {
|
4080
|
+
samplesR.push((i + 1) / n);
|
4081
|
+
}
|
4082
|
+
return samplesR;
|
4083
|
+
}
|
4084
|
+
generateDenoiseSamples(numSamples, numRings) {
|
4085
|
+
const angleStep = 2 * Math.PI * numRings / numSamples;
|
4086
|
+
const invNumSamples = 1 / numSamples;
|
4087
|
+
const radiusStep = invNumSamples;
|
4088
|
+
const samples = [];
|
4089
|
+
let radius = invNumSamples;
|
4090
|
+
let angle = 0;
|
4091
|
+
for (let i = 0; i < numSamples; i++) {
|
4092
|
+
samples.push(
|
4093
|
+
new Vector26(Math.cos(angle), Math.sin(angle)).multiplyScalar(Math.pow(radius, 0.75))
|
4094
|
+
);
|
4095
|
+
radius += radiusStep;
|
4096
|
+
angle += angleStep;
|
4097
|
+
}
|
4098
|
+
return samples;
|
4099
|
+
}
|
4100
|
+
setSize(width, height) {
|
4101
|
+
this.width = width;
|
4102
|
+
this.height = height;
|
4103
|
+
const c = this.configuration.halfRes ? 0.5 : 1;
|
4104
|
+
this.writeTargetInternal.setSize(width * c, height * c);
|
4105
|
+
this.readTargetInternal.setSize(width * c, height * c);
|
4106
|
+
if (this.configuration.halfRes && this.depthDownsampleTarget) {
|
4107
|
+
this.depthDownsampleTarget.setSize(width * c, height * c);
|
4108
|
+
}
|
4109
|
+
this.outputTargetInternal.setSize(width, height);
|
4110
|
+
}
|
4111
|
+
setDepthTexture(depthTexture) {
|
4112
|
+
this.depthTexture = depthTexture;
|
4113
|
+
}
|
4114
|
+
render(renderer, inputBuffer, outputBuffer) {
|
4115
|
+
const xrEnabled = renderer.xr.enabled;
|
4116
|
+
renderer.xr.enabled = false;
|
4117
|
+
let ext;
|
4118
|
+
let timerQuery = null;
|
4119
|
+
let gl = null;
|
4120
|
+
gl = renderer.getContext();
|
4121
|
+
if (this.debugMode) {
|
4122
|
+
ext = gl.getExtension("EXT_disjoint_timer_query_webgl2");
|
4123
|
+
if (ext === null) {
|
4124
|
+
console.error("EXT_disjoint_timer_query_webgl2 not available, disabling debug mode.");
|
4125
|
+
this.debugMode = false;
|
4126
|
+
gl = null;
|
4127
|
+
}
|
4128
|
+
}
|
4129
|
+
if (this.debugMode && gl) {
|
4130
|
+
timerQuery = gl.createQuery();
|
4131
|
+
gl.beginQuery(ext.TIME_ELAPSED_EXT, timerQuery);
|
4132
|
+
}
|
4133
|
+
if (renderer.capabilities.logarithmicDepthBuffer !== this.configuration.logarithmicDepthBuffer) {
|
4134
|
+
this.configuration.logarithmicDepthBuffer = renderer.capabilities.logarithmicDepthBuffer;
|
4135
|
+
this.configureAOPass(this.configuration.logarithmicDepthBuffer);
|
4136
|
+
this.configureDenoisePass(this.configuration.logarithmicDepthBuffer);
|
4137
|
+
this.configureEffectCompositer(this.configuration.logarithmicDepthBuffer);
|
4138
|
+
}
|
4139
|
+
if (inputBuffer.texture.type !== this.outputTargetInternal.texture.type) {
|
4140
|
+
this.outputTargetInternal.texture.type = inputBuffer.texture.type;
|
4141
|
+
this.outputTargetInternal.texture.needsUpdate = true;
|
4142
|
+
}
|
4143
|
+
this.camera.updateMatrixWorld();
|
4144
|
+
this.r.set(this.width, this.height);
|
4145
|
+
let trueRadius = this.configuration.aoRadius;
|
4146
|
+
if (this.configuration.halfRes && this.configuration.screenSpaceRadius) {
|
4147
|
+
trueRadius *= 0.5;
|
4148
|
+
}
|
4149
|
+
if (this.configuration.halfRes && this.depthDownsampleQuad) {
|
4150
|
+
const depthDownsampleUniforms = this.depthDownsampleQuad.material.uniforms;
|
4151
|
+
renderer.setRenderTarget(this.depthDownsampleTarget);
|
4152
|
+
depthDownsampleUniforms.sceneDepth.value = this.depthTexture;
|
4153
|
+
depthDownsampleUniforms.resolution.value = this.r;
|
4154
|
+
depthDownsampleUniforms.near.value = this.camera.near;
|
4155
|
+
depthDownsampleUniforms.far.value = this.camera.far;
|
4156
|
+
depthDownsampleUniforms.projectionMatrixInv.value = this.camera.projectionMatrixInverse;
|
4157
|
+
depthDownsampleUniforms.viewMatrixInv.value = this.camera.matrixWorld;
|
4158
|
+
depthDownsampleUniforms.logDepth.value = this.configuration.logarithmicDepthBuffer;
|
4159
|
+
this.depthDownsampleQuad.render(renderer);
|
4160
|
+
}
|
4161
|
+
if (!this.effectShaderQuad)
|
4162
|
+
return;
|
4163
|
+
const effectShaderUniforms = this.effectShaderQuad.material.uniforms;
|
4164
|
+
effectShaderUniforms.sceneDiffuse.value = inputBuffer.texture;
|
4165
|
+
effectShaderUniforms.sceneDepth.value = this.configuration.halfRes ? this.depthDownsampleTarget.texture[0] : this.depthTexture;
|
4166
|
+
effectShaderUniforms.sceneNormal.value = this.configuration.halfRes ? this.depthDownsampleTarget.texture[1] : null;
|
4167
|
+
effectShaderUniforms.projMat.value = this.camera.projectionMatrix;
|
4168
|
+
effectShaderUniforms.viewMat.value = this.camera.matrixWorldInverse;
|
4169
|
+
effectShaderUniforms.projViewMat.value = this.camera.projectionMatrix.clone().multiply(this.camera.matrixWorldInverse.clone());
|
4170
|
+
effectShaderUniforms.projectionMatrixInv.value = this.camera.projectionMatrixInverse;
|
4171
|
+
effectShaderUniforms.viewMatrixInv.value = this.camera.matrixWorld;
|
4172
|
+
effectShaderUniforms.cameraPos.value = this.camera.getWorldPosition(new Vector313());
|
4173
|
+
effectShaderUniforms.resolution.value = this.configuration.halfRes ? this.r.clone().multiplyScalar(1 / 2).floor() : this.r;
|
4174
|
+
effectShaderUniforms.time.value = performance.now() / 1e3;
|
4175
|
+
effectShaderUniforms.samples.value = this.samples;
|
4176
|
+
effectShaderUniforms.samplesR.value = this.samplesR;
|
4177
|
+
effectShaderUniforms.bluenoise.value = this.bluenoise;
|
4178
|
+
effectShaderUniforms.radius.value = trueRadius;
|
4179
|
+
effectShaderUniforms.distanceFalloff.value = this.configuration.distanceFalloff;
|
4180
|
+
effectShaderUniforms.near.value = this.camera.near;
|
4181
|
+
effectShaderUniforms.far.value = this.camera.far;
|
4182
|
+
effectShaderUniforms.logDepth.value = renderer.capabilities.logarithmicDepthBuffer;
|
4183
|
+
effectShaderUniforms.ortho.value = this.camera instanceof OrthographicCamera3;
|
4184
|
+
effectShaderUniforms.screenSpaceRadius.value = this.configuration.screenSpaceRadius;
|
4185
|
+
renderer.setRenderTarget(this.writeTargetInternal);
|
4186
|
+
this.effectShaderQuad.render(renderer);
|
4187
|
+
const poissonBlurUniforms = this.poissonBlurQuad.material.uniforms;
|
4188
|
+
for (let i = 0; i < this.configuration.denoiseIterations; i++) {
|
4189
|
+
if (!poissonBlurUniforms || !this.poissonBlurQuad)
|
4190
|
+
return;
|
4191
|
+
[this.writeTargetInternal, this.readTargetInternal] = [
|
4192
|
+
this.readTargetInternal,
|
4193
|
+
this.writeTargetInternal
|
4194
|
+
];
|
4195
|
+
poissonBlurUniforms.tDiffuse.value = this.readTargetInternal.texture;
|
4196
|
+
poissonBlurUniforms.sceneDepth.value = this.configuration.halfRes ? this.depthDownsampleTarget.texture[0] : this.depthTexture;
|
4197
|
+
poissonBlurUniforms.projMat.value = this.camera.projectionMatrix;
|
4198
|
+
poissonBlurUniforms.viewMat.value = this.camera.matrixWorldInverse;
|
4199
|
+
poissonBlurUniforms.projectionMatrixInv.value = this.camera.projectionMatrixInverse;
|
4200
|
+
poissonBlurUniforms.viewMatrixInv.value = this.camera.matrixWorld;
|
4201
|
+
poissonBlurUniforms.cameraPos.value = this.camera.getWorldPosition(new Vector313());
|
4202
|
+
poissonBlurUniforms.resolution.value = this.configuration.halfRes ? this.r.clone().multiplyScalar(1 / 2).floor() : this.r;
|
4203
|
+
poissonBlurUniforms.time.value = performance.now() / 1e3;
|
4204
|
+
poissonBlurUniforms.blueNoise.value = this.bluenoise;
|
4205
|
+
poissonBlurUniforms.radius.value = this.configuration.denoiseRadius * (this.configuration.halfRes ? 1 / 2 : 1);
|
4206
|
+
poissonBlurUniforms.worldRadius.value = trueRadius;
|
4207
|
+
poissonBlurUniforms.distanceFalloff.value = this.configuration.distanceFalloff;
|
4208
|
+
poissonBlurUniforms.index.value = i;
|
4209
|
+
poissonBlurUniforms.poissonDisk.value = this.samplesDenoise;
|
4210
|
+
poissonBlurUniforms.near.value = this.camera.near;
|
4211
|
+
poissonBlurUniforms.far.value = this.camera.far;
|
4212
|
+
poissonBlurUniforms.logDepth.value = renderer.capabilities.logarithmicDepthBuffer;
|
4213
|
+
poissonBlurUniforms.screenSpaceRadius.value = this.configuration.screenSpaceRadius;
|
4214
|
+
renderer.setRenderTarget(this.writeTargetInternal);
|
4215
|
+
this.poissonBlurQuad.render(renderer);
|
4216
|
+
}
|
4217
|
+
const effectCompositerUniforms = this.effectCompositerQuad.material.uniforms;
|
4218
|
+
if (!effectCompositerUniforms || !this.effectCompositerQuad)
|
4219
|
+
return;
|
4220
|
+
effectCompositerUniforms.sceneDiffuse.value = inputBuffer.texture;
|
4221
|
+
effectCompositerUniforms.sceneDepth.value = this.depthTexture;
|
4222
|
+
effectCompositerUniforms.near.value = this.camera.near;
|
4223
|
+
effectCompositerUniforms.far.value = this.camera.far;
|
4224
|
+
effectCompositerUniforms.projectionMatrixInv.value = this.camera.projectionMatrixInverse;
|
4225
|
+
effectCompositerUniforms.viewMatrixInv.value = this.camera.matrixWorld;
|
4226
|
+
effectCompositerUniforms.logDepth.value = renderer.capabilities.logarithmicDepthBuffer;
|
4227
|
+
effectCompositerUniforms.ortho.value = this.camera instanceof OrthographicCamera3;
|
4228
|
+
effectCompositerUniforms.downsampledDepth.value = this.configuration.halfRes ? this.depthDownsampleTarget.texture[0] : this.depthTexture;
|
4229
|
+
effectCompositerUniforms.resolution.value = this.r;
|
4230
|
+
effectCompositerUniforms.blueNoise.value = this.bluenoise;
|
4231
|
+
effectCompositerUniforms.intensity.value = this.configuration.intensity;
|
4232
|
+
effectCompositerUniforms.renderMode.value = this.configuration.renderMode;
|
4233
|
+
effectCompositerUniforms.screenSpaceRadius.value = this.configuration.screenSpaceRadius;
|
4234
|
+
effectCompositerUniforms.radius.value = trueRadius;
|
4235
|
+
effectCompositerUniforms.distanceFalloff.value = this.configuration.distanceFalloff;
|
4236
|
+
effectCompositerUniforms.gammaCorrection.value = this.autosetGamma ? this.renderToScreen : this.configuration.gammaCorrection;
|
4237
|
+
effectCompositerUniforms.tDiffuse.value = this.writeTargetInternal.texture;
|
4238
|
+
effectCompositerUniforms.color.value = this.c.copy(this.configuration.color).convertSRGBToLinear();
|
4239
|
+
effectCompositerUniforms.colorMultiply.value = this.configuration.colorMultiply;
|
4240
|
+
effectCompositerUniforms.cameraPos.value = this.camera.getWorldPosition(new Vector313());
|
4241
|
+
effectCompositerUniforms.fog.value = !!this.scene.fog;
|
4242
|
+
if (this.scene.fog) {
|
4243
|
+
if (this.scene.fog instanceof Fog && this.scene.fog.isFog === true) {
|
4244
|
+
effectCompositerUniforms.fogExp.value = false;
|
4245
|
+
effectCompositerUniforms.fogNear.value = this.scene.fog.near;
|
4246
|
+
effectCompositerUniforms.fogFar.value = this.scene.fog.far;
|
4247
|
+
} else if (this.scene.fog instanceof FogExp2) {
|
4248
|
+
effectCompositerUniforms.fogExp.value = true;
|
4249
|
+
effectCompositerUniforms.fogDensity.value = this.scene.fog.density;
|
4250
|
+
} else {
|
4251
|
+
console.error(`Unsupported fog type ${this.scene.fog.constructor.name} in SSAOPass.`);
|
4252
|
+
}
|
4253
|
+
}
|
4254
|
+
renderer.setRenderTarget(this.outputTargetInternal);
|
4255
|
+
this.effectCompositerQuad.render(renderer);
|
4256
|
+
renderer.setRenderTarget(this.renderToScreen ? null : outputBuffer);
|
4257
|
+
this.copyQuad.material.uniforms.tDiffuse.value = this.outputTargetInternal.texture;
|
4258
|
+
this.copyQuad.render(renderer);
|
4259
|
+
if (this.debugMode && gl && timerQuery) {
|
4260
|
+
gl.endQuery(ext.TIME_ELAPSED_EXT);
|
4261
|
+
checkTimerQuery(timerQuery, gl, this);
|
4262
|
+
}
|
4263
|
+
renderer.xr.enabled = xrEnabled;
|
4264
|
+
}
|
4265
|
+
enableDebugMode() {
|
4266
|
+
this.debugMode = true;
|
4267
|
+
}
|
4268
|
+
disableDebugMode() {
|
4269
|
+
this.debugMode = false;
|
4270
|
+
}
|
4271
|
+
setDisplayMode(mode) {
|
4272
|
+
this.configuration.renderMode = ["Combined", "AO", "No AO", "Split", "Split AO"].indexOf(
|
4273
|
+
mode
|
4274
|
+
);
|
4275
|
+
}
|
4276
|
+
setQualityMode(mode) {
|
4277
|
+
if (mode === "Performance") {
|
4278
|
+
this.configuration.aoSamples = 8;
|
4279
|
+
this.configuration.denoiseSamples = 4;
|
4280
|
+
this.configuration.denoiseRadius = 12;
|
4281
|
+
} else if (mode === "Low") {
|
4282
|
+
this.configuration.aoSamples = 16;
|
4283
|
+
this.configuration.denoiseSamples = 4;
|
4284
|
+
this.configuration.denoiseRadius = 12;
|
4285
|
+
} else if (mode === "Medium") {
|
4286
|
+
this.configuration.aoSamples = 16;
|
4287
|
+
this.configuration.denoiseSamples = 8;
|
4288
|
+
this.configuration.denoiseRadius = 12;
|
4289
|
+
} else if (mode === "High") {
|
4290
|
+
this.configuration.aoSamples = 64;
|
4291
|
+
this.configuration.denoiseSamples = 8;
|
4292
|
+
this.configuration.denoiseRadius = 6;
|
4293
|
+
} else if (mode === "Ultra") {
|
4294
|
+
this.configuration.aoSamples = 64;
|
4295
|
+
this.configuration.denoiseSamples = 16;
|
4296
|
+
this.configuration.denoiseRadius = 6;
|
4297
|
+
}
|
4298
|
+
}
|
4299
|
+
};
|
4300
|
+
|
4301
|
+
// src/rendering/composer.ts
|
4302
|
+
var Composer = class {
|
4303
|
+
constructor(scene, camera, spawnSun = false) {
|
4304
|
+
this.width = 1;
|
4305
|
+
this.height = 1;
|
4306
|
+
this.resolution = new Vector27(this.width, this.height);
|
4307
|
+
this.isEnvHDRI = false;
|
4308
|
+
this.bcs = BrightnessContrastSaturation;
|
4309
|
+
this.gaussGrainEffect = GaussGrainEffect;
|
4310
|
+
this.ambientLight = null;
|
4311
|
+
this.sun = null;
|
4312
|
+
this.scene = scene;
|
4313
|
+
this.postPostScene = new Scene4();
|
4314
|
+
this.camera = camera;
|
4315
|
+
this.spawnSun = spawnSun;
|
4316
|
+
this.renderer = new WebGLRenderer4({
|
4317
|
+
powerPreference: "high-performance",
|
4318
|
+
antialias: false,
|
4319
|
+
stencil: false,
|
4320
|
+
depth: false
|
4321
|
+
});
|
4322
|
+
this.renderer.info.autoReset = false;
|
4323
|
+
this.renderer.setSize(this.width, this.height);
|
4324
|
+
this.renderer.shadowMap.enabled = true;
|
4325
|
+
this.renderer.shadowMap.type = rendererValues.shadowMap;
|
4326
|
+
this.renderer.toneMapping = rendererValues.toneMapping;
|
4327
|
+
this.renderer.toneMappingExposure = rendererValues.exposure;
|
4328
|
+
this.setAmbientLight();
|
4329
|
+
this.setFog();
|
4330
|
+
this.effectComposer = new EffectComposer2(this.renderer, {
|
4331
|
+
frameBufferType: HalfFloatType2
|
4332
|
+
});
|
4333
|
+
this.renderPass = new RenderPass(this.scene, this.camera);
|
4334
|
+
this.normalPass = new NormalPass2(this.scene, this.camera);
|
4335
|
+
this.normalPass.enabled = ppssaoValues.enabled;
|
4336
|
+
this.normalTextureEffect = new TextureEffect({
|
4337
|
+
blendFunction: BlendFunction2.SKIP,
|
4338
|
+
texture: this.normalPass.texture
|
3155
4339
|
});
|
3156
4340
|
this.ppssaoEffect = new SSAOEffect2(this.camera, this.normalPass.texture, {
|
3157
4341
|
blendFunction: ppssaoValues.blendFunction,
|
@@ -3165,7 +4349,7 @@ var Composer = class {
|
|
3165
4349
|
bias: ppssaoValues.bias,
|
3166
4350
|
fade: ppssaoValues.fade,
|
3167
4351
|
resolutionScale: ppssaoValues.resolutionScale,
|
3168
|
-
color: new
|
4352
|
+
color: new Color7().setRGB(ppssaoValues.color.r, ppssaoValues.color.g, ppssaoValues.color.b),
|
3169
4353
|
worldDistanceThreshold: ppssaoValues.worldDistanceThreshold,
|
3170
4354
|
worldDistanceFalloff: ppssaoValues.worldDistanceFalloff,
|
3171
4355
|
worldProximityThreshold: ppssaoValues.worldProximityThreshold,
|
@@ -3177,11 +4361,11 @@ var Composer = class {
|
|
3177
4361
|
this.bloomEffect = new BloomEffect({
|
3178
4362
|
intensity: extrasValues.bloom
|
3179
4363
|
});
|
3180
|
-
this.n8aopass = new
|
4364
|
+
this.n8aopass = new N8SSAOPass(this.scene, this.camera, this.width, this.height);
|
3181
4365
|
this.n8aopass.configuration.aoRadius = n8ssaoValues.aoRadius;
|
3182
4366
|
this.n8aopass.configuration.distanceFalloff = n8ssaoValues.distanceFalloff;
|
3183
4367
|
this.n8aopass.configuration.intensity = n8ssaoValues.intensity;
|
3184
|
-
this.n8aopass.configuration.color = new
|
4368
|
+
this.n8aopass.configuration.color = new Color7().setRGB(
|
3185
4369
|
n8ssaoValues.color.r,
|
3186
4370
|
n8ssaoValues.color.g,
|
3187
4371
|
n8ssaoValues.color.b
|
@@ -3357,19 +4541,19 @@ var Composer = class {
|
|
3357
4541
|
fileInput.click();
|
3358
4542
|
}
|
3359
4543
|
setFog() {
|
3360
|
-
const fogColor = new
|
4544
|
+
const fogColor = new Color7().setRGB(
|
3361
4545
|
envValues.fog.fogColor.r,
|
3362
4546
|
envValues.fog.fogColor.g,
|
3363
4547
|
envValues.fog.fogColor.b
|
3364
4548
|
);
|
3365
|
-
this.scene.fog = new
|
4549
|
+
this.scene.fog = new Fog2(fogColor, envValues.fog.fogNear, envValues.fog.fogFar);
|
3366
4550
|
}
|
3367
4551
|
setAmbientLight() {
|
3368
4552
|
if (this.ambientLight) {
|
3369
4553
|
this.scene.remove(this.ambientLight);
|
3370
4554
|
this.ambientLight.dispose();
|
3371
4555
|
}
|
3372
|
-
const ambientLightColor = new
|
4556
|
+
const ambientLightColor = new Color7().setRGB(
|
3373
4557
|
envValues.ambientLight.ambientLightColor.r,
|
3374
4558
|
envValues.ambientLight.ambientLightColor.g,
|
3375
4559
|
envValues.ambientLight.ambientLightColor.b
|
@@ -3435,16 +4619,16 @@ import {
|
|
3435
4619
|
} from "mml-web";
|
3436
4620
|
import {
|
3437
4621
|
Box3,
|
3438
|
-
Color as
|
4622
|
+
Color as Color8,
|
3439
4623
|
DoubleSide,
|
3440
4624
|
Euler as Euler2,
|
3441
|
-
Group as
|
4625
|
+
Group as Group5,
|
3442
4626
|
Line3 as Line32,
|
3443
|
-
Matrix4 as
|
3444
|
-
Mesh as
|
4627
|
+
Matrix4 as Matrix46,
|
4628
|
+
Mesh as Mesh5,
|
3445
4629
|
MeshBasicMaterial as MeshBasicMaterial3,
|
3446
4630
|
Ray,
|
3447
|
-
Vector3 as
|
4631
|
+
Vector3 as Vector314
|
3448
4632
|
} from "three";
|
3449
4633
|
import { VertexNormalsHelper } from "three/examples/jsm/helpers/VertexNormalsHelper.js";
|
3450
4634
|
import * as BufferGeometryUtils from "three/examples/jsm/utils/BufferGeometryUtils.js";
|
@@ -3452,12 +4636,12 @@ import { MeshBVH, MeshBVHVisualizer } from "three-mesh-bvh";
|
|
3452
4636
|
var CollisionsManager = class {
|
3453
4637
|
constructor(scene) {
|
3454
4638
|
this.debug = false;
|
3455
|
-
this.tempVector = new
|
3456
|
-
this.tempVector2 = new
|
3457
|
-
this.tempVector3 = new
|
4639
|
+
this.tempVector = new Vector314();
|
4640
|
+
this.tempVector2 = new Vector314();
|
4641
|
+
this.tempVector3 = new Vector314();
|
3458
4642
|
this.tempRay = new Ray();
|
3459
|
-
this.tempMatrix = new
|
3460
|
-
this.tempMatrix2 = new
|
4643
|
+
this.tempMatrix = new Matrix46();
|
4644
|
+
this.tempMatrix2 = new Matrix46();
|
3461
4645
|
this.tempBox = new Box3();
|
3462
4646
|
this.tempEuler = new Euler2();
|
3463
4647
|
this.tempSegment = new Line32();
|
@@ -3488,13 +4672,13 @@ var CollisionsManager = class {
|
|
3488
4672
|
group.updateWorldMatrix(true, false);
|
3489
4673
|
const invertedRootMatrix = this.tempMatrix.copy(group.matrixWorld).invert();
|
3490
4674
|
group.traverse((child) => {
|
3491
|
-
|
3492
|
-
|
3493
|
-
const clonedGeometry =
|
4675
|
+
const asMesh = child;
|
4676
|
+
if (asMesh.isMesh) {
|
4677
|
+
const clonedGeometry = asMesh.geometry.clone();
|
3494
4678
|
if (child !== group) {
|
3495
|
-
|
4679
|
+
asMesh.updateWorldMatrix(true, false);
|
3496
4680
|
clonedGeometry.applyMatrix4(
|
3497
|
-
this.tempMatrix2.multiplyMatrices(invertedRootMatrix,
|
4681
|
+
this.tempMatrix2.multiplyMatrices(invertedRootMatrix, asMesh.matrixWorld)
|
3498
4682
|
);
|
3499
4683
|
}
|
3500
4684
|
for (const key in clonedGeometry.attributes) {
|
@@ -3520,11 +4704,11 @@ var CollisionsManager = class {
|
|
3520
4704
|
};
|
3521
4705
|
if (this.debug) {
|
3522
4706
|
newBufferGeometry.boundsTree = meshBVH;
|
3523
|
-
const wireframeMesh = new
|
4707
|
+
const wireframeMesh = new Mesh5(newBufferGeometry, new MeshBasicMaterial3({ wireframe: true }));
|
3524
4708
|
const normalsHelper = new VertexNormalsHelper(wireframeMesh, 0.25, 65280);
|
3525
4709
|
const visualizer = new MeshBVHVisualizer(wireframeMesh, 4);
|
3526
|
-
visualizer.edgeMaterial.color = new
|
3527
|
-
const debugGroup = new
|
4710
|
+
visualizer.edgeMaterial.color = new Color8("blue");
|
4711
|
+
const debugGroup = new Group5();
|
3528
4712
|
debugGroup.add(wireframeMesh, normalsHelper, visualizer);
|
3529
4713
|
group.matrixWorld.decompose(debugGroup.position, debugGroup.quaternion, debugGroup.scale);
|
3530
4714
|
visualizer.update();
|
@@ -3603,7 +4787,7 @@ var CollisionsManager = class {
|
|
3603
4787
|
const realDistance = intersectionSegment.distance();
|
3604
4788
|
if (realDistance < capsuleRadius) {
|
3605
4789
|
if (!collisionPosition) {
|
3606
|
-
collisionPosition = new
|
4790
|
+
collisionPosition = new Vector314().copy(closestPointOnSegment).applyMatrix4(meshState.matrix);
|
3607
4791
|
}
|
3608
4792
|
const ratio = realDistance / modelReferenceDistance;
|
3609
4793
|
const realDepth = capsuleRadius - realDistance;
|
@@ -3659,6 +4843,15 @@ export {
|
|
3659
4843
|
MMLCompositionScene,
|
3660
4844
|
Sun,
|
3661
4845
|
TimeManager,
|
3662
|
-
TweakPane
|
4846
|
+
TweakPane,
|
4847
|
+
clamp,
|
4848
|
+
decodeCharacterAndCamera,
|
4849
|
+
ease,
|
4850
|
+
encodeCharacterAndCamera,
|
4851
|
+
getSpawnPositionInsideCircle,
|
4852
|
+
remap,
|
4853
|
+
round,
|
4854
|
+
roundToDecimalPlaces,
|
4855
|
+
toArray
|
3663
4856
|
};
|
3664
4857
|
//# sourceMappingURL=index.js.map
|