Spaces:
Running
Running
Update viewer.js
Browse files
viewer.js
CHANGED
|
@@ -23,19 +23,12 @@ async function loadImageAsTexture(url, app) {
|
|
| 23 |
let pc;
|
| 24 |
export let app = null;
|
| 25 |
let cameraEntity = null;
|
| 26 |
-
let textureCamera = null;
|
| 27 |
let modelEntity = null;
|
| 28 |
let tubeEntity = null;
|
| 29 |
let filtreEntity = null;
|
| 30 |
-
let bgPlane = null;
|
| 31 |
-
let bgMat = null;
|
| 32 |
let viewerInitialized = false;
|
| 33 |
let resizeObserver = null;
|
| 34 |
|
| 35 |
-
// Render target globals (pour resize)
|
| 36 |
-
let rtTexture = null;
|
| 37 |
-
let renderTarget = null;
|
| 38 |
-
|
| 39 |
// Materials (for real-time switching)
|
| 40 |
let matTransparent = null;
|
| 41 |
let matOpaque = null;
|
|
@@ -56,73 +49,6 @@ function traverse(entity, callback) {
|
|
| 56 |
}
|
| 57 |
}
|
| 58 |
|
| 59 |
-
// ----- Helpers: viewport size / copy cam / RT / fullscreen plane -----
|
| 60 |
-
function camViewportSize(cam) {
|
| 61 |
-
const gd = app.graphicsDevice;
|
| 62 |
-
const r = cam.rect; // x, y, width, height in [0..1]
|
| 63 |
-
return {
|
| 64 |
-
w: Math.max(1, Math.round(gd.width * r.z)),
|
| 65 |
-
h: Math.max(1, Math.round(gd.height * r.w))
|
| 66 |
-
};
|
| 67 |
-
}
|
| 68 |
-
|
| 69 |
-
function copyCam(src, dst) {
|
| 70 |
-
dst.camera.projection = src.camera.projection;
|
| 71 |
-
dst.camera.horizontalFov = src.camera.horizontalFov;
|
| 72 |
-
dst.camera.fov = src.camera.fov;
|
| 73 |
-
dst.camera.nearClip = src.camera.nearClip;
|
| 74 |
-
dst.camera.farClip = src.camera.farClip;
|
| 75 |
-
dst.camera.rect.set(src.camera.rect.x, src.camera.rect.y, src.camera.rect.z, src.camera.rect.w);
|
| 76 |
-
}
|
| 77 |
-
|
| 78 |
-
function createRTFor(cam) {
|
| 79 |
-
const { w, h } = camViewportSize(cam);
|
| 80 |
-
if (rtTexture) {
|
| 81 |
-
rtTexture.destroy();
|
| 82 |
-
rtTexture = null;
|
| 83 |
-
}
|
| 84 |
-
const tex = new pc.Texture(app.graphicsDevice, {
|
| 85 |
-
width: w,
|
| 86 |
-
height: h,
|
| 87 |
-
format: pc.PIXELFORMAT_SRGBA8,
|
| 88 |
-
mipmaps: false
|
| 89 |
-
});
|
| 90 |
-
tex.minFilter = pc.FILTER_LINEAR;
|
| 91 |
-
tex.magFilter = pc.FILTER_LINEAR;
|
| 92 |
-
tex.addressU = pc.ADDRESS_CLAMP_TO_EDGE;
|
| 93 |
-
tex.addressV = pc.ADDRESS_CLAMP_TO_EDGE;
|
| 94 |
-
|
| 95 |
-
const rt = new pc.RenderTarget({
|
| 96 |
-
name: 'RT',
|
| 97 |
-
colorBuffer: tex,
|
| 98 |
-
depth: true,
|
| 99 |
-
samples: 1
|
| 100 |
-
});
|
| 101 |
-
return { tex, rt };
|
| 102 |
-
}
|
| 103 |
-
|
| 104 |
-
function fitFullscreenPlane(camEntity, planeEntity, d = 0.5) {
|
| 105 |
-
const cam = camEntity.camera;
|
| 106 |
-
const { w: vpW, h: vpH } = camViewportSize(cam);
|
| 107 |
-
const aspect = vpW / vpH;
|
| 108 |
-
|
| 109 |
-
// fov en radians (vertical si horizontalFov === false)
|
| 110 |
-
let vFovRad = cam.fov * pc.math.DEG_TO_RAD;
|
| 111 |
-
if (cam.horizontalFov) {
|
| 112 |
-
const hFovRad = vFovRad;
|
| 113 |
-
vFovRad = 2 * Math.atan(Math.tan(hFovRad / 2) / aspect);
|
| 114 |
-
}
|
| 115 |
-
|
| 116 |
-
const h = 2 * d * Math.tan(vFovRad / 2);
|
| 117 |
-
const w = h * aspect;
|
| 118 |
-
|
| 119 |
-
// plein écran en espace caméra
|
| 120 |
-
planeEntity.reparent(camEntity);
|
| 121 |
-
planeEntity.setLocalPosition(0, 0, -d);
|
| 122 |
-
planeEntity.setLocalEulerAngles(-90, 0, 0); // plane (normale +Y) -> face -Z
|
| 123 |
-
planeEntity.setLocalScale(w, h, 1);
|
| 124 |
-
}
|
| 125 |
-
|
| 126 |
// ----- Main Viewer Initialization -----
|
| 127 |
export async function initializeViewer(config, instanceId) {
|
| 128 |
if (viewerInitialized) return; // Prevent double-init
|
|
@@ -208,7 +134,7 @@ export async function initializeViewer(config, instanceId) {
|
|
| 208 |
app.setCanvasFillMode(pc.FILLMODE_NONE);
|
| 209 |
app.setCanvasResolution(pc.RESOLUTION_AUTO);
|
| 210 |
|
| 211 |
-
// Canvas responsive resize
|
| 212 |
resizeObserver = new ResizeObserver(entries => {
|
| 213 |
entries.forEach(entry => {
|
| 214 |
app.resizeCanvas(entry.contentRect.width, entry.contentRect.height);
|
|
@@ -219,11 +145,12 @@ export async function initializeViewer(config, instanceId) {
|
|
| 219 |
app.on('destroy', () => resizeObserver.disconnect());
|
| 220 |
|
| 221 |
// ----- Load all images as Textures (async, safe for CORS) -----
|
| 222 |
-
//
|
| 223 |
-
const hdrTex
|
| 224 |
-
const emitTex
|
| 225 |
-
const opTex
|
| 226 |
-
const thicknessTex
|
|
|
|
| 227 |
|
| 228 |
// ----- GLB asset definition -----
|
| 229 |
const assets = {
|
|
@@ -246,97 +173,76 @@ export async function initializeViewer(config, instanceId) {
|
|
| 246 |
app.start();
|
| 247 |
if (progressDialog) progressDialog.style.display = 'none';
|
| 248 |
|
| 249 |
-
//
|
| 250 |
-
const backgroundLayer = new pc.Layer({ name: 'Background' });
|
| 251 |
-
app.scene.layers.insert(backgroundLayer, 0); // tout au début
|
| 252 |
-
|
| 253 |
-
const excludedLayer = new pc.Layer({ name: 'Excluded' });
|
| 254 |
-
app.scene.layers.insert(excludedLayer, 1);
|
| 255 |
-
|
| 256 |
-
// get existing layers
|
| 257 |
-
const worldLayer = app.scene.layers.getLayerByName('World');
|
| 258 |
-
const skyboxLayer = app.scene.layers.getLayerByName('Skybox');
|
| 259 |
-
const uiLayer = app.scene.layers.getLayerByName('UI');
|
| 260 |
-
|
| 261 |
-
// Reorder depth layer for transmission (si utile)
|
| 262 |
const depthLayer = app.scene.layers.getLayerById(pc.LAYERID_DEPTH);
|
| 263 |
app.scene.layers.remove(depthLayer);
|
| 264 |
app.scene.layers.insertOpaque(depthLayer, 2);
|
| 265 |
|
| 266 |
-
//
|
| 267 |
-
modelEntity
|
| 268 |
-
tubeEntity
|
| 269 |
filtreEntity = assets.filtre.resource.instantiateRenderEntity();
|
| 270 |
|
| 271 |
-
// mettre tube/filtre dans la couche Excluded
|
| 272 |
-
traverse(tubeEntity, (node) => { if (node.render) node.render.layers = [excludedLayer.id]; });
|
| 273 |
-
traverse(filtreEntity, (node) => { if (node.render) node.render.layers = [excludedLayer.id]; });
|
| 274 |
-
|
| 275 |
app.root.addChild(modelEntity);
|
| 276 |
app.root.addChild(tubeEntity);
|
| 277 |
app.root.addChild(filtreEntity);
|
| 278 |
|
| 279 |
// ----- Materials Setup -----
|
| 280 |
// Transparent material (main model)
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
|
| 288 |
-
|
| 289 |
-
|
| 290 |
-
|
| 291 |
-
|
| 292 |
-
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
|
| 296 |
-
|
| 297 |
-
|
| 298 |
-
|
| 299 |
-
|
| 300 |
-
|
| 301 |
-
|
| 302 |
-
}
|
| 303 |
// Opaque material (main model)
|
| 304 |
-
|
| 305 |
-
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
|
| 309 |
-
|
| 310 |
-
|
| 311 |
-
|
| 312 |
-
|
| 313 |
-
|
| 314 |
-
|
| 315 |
-
|
| 316 |
-
|
| 317 |
-
|
| 318 |
-
|
| 319 |
-
}
|
| 320 |
// Transparent material (tube)
|
| 321 |
-
|
| 322 |
-
|
| 323 |
-
|
| 324 |
-
|
| 325 |
-
|
| 326 |
-
|
| 327 |
-
|
| 328 |
-
|
| 329 |
-
|
| 330 |
-
|
| 331 |
-
|
| 332 |
-
}
|
| 333 |
// Opaque material (tube)
|
| 334 |
-
|
| 335 |
-
|
| 336 |
-
|
| 337 |
-
|
| 338 |
-
tubeOpaque.update();
|
| 339 |
-
}
|
| 340 |
|
| 341 |
// ----- Assign materials to meshes -----
|
| 342 |
traverse(modelEntity, node => {
|
|
@@ -367,17 +273,12 @@ export async function initializeViewer(config, instanceId) {
|
|
| 367 |
filtreEntity.setLocalScale(modelScale, modelScale, modelScale);
|
| 368 |
filtreEntity.setLocalEulerAngles(modelRotationX, modelRotationY, modelRotationZ);
|
| 369 |
|
| 370 |
-
// -----
|
| 371 |
cameraEntity = new pc.Entity('camera');
|
| 372 |
cameraEntity.addComponent('camera', {
|
| 373 |
clearColor: new pc.Color(0.8, 0.8, 0.8, 1),
|
| 374 |
-
// Important : Background d'abord, puis World, puis UI et Depth
|
| 375 |
-
layers: [backgroundLayer.id, worldLayer.id, /*skyboxLayer.id,*/ uiLayer.id, depthLayer.id],
|
| 376 |
toneMapping: pc.TONEMAP_NEUTRAL
|
| 377 |
});
|
| 378 |
-
// Option : forcer FOV vertical partout
|
| 379 |
-
cameraEntity.camera.horizontalFov = false;
|
| 380 |
-
|
| 381 |
cameraEntity.setPosition(chosenCameraX, chosenCameraY, chosenCameraZ);
|
| 382 |
cameraEntity.lookAt(modelEntity.getPosition());
|
| 383 |
cameraEntity.addComponent('script');
|
|
@@ -401,45 +302,35 @@ export async function initializeViewer(config, instanceId) {
|
|
| 401 |
cameraEntity.script.create('orbitCameraInputTouch');
|
| 402 |
app.root.addChild(cameraEntity);
|
| 403 |
|
| 404 |
-
//
|
| 405 |
-
|
| 406 |
-
|
| 407 |
-
|
| 408 |
-
|
| 409 |
-
|
| 410 |
-
|
| 411 |
-
|
| 412 |
-
|
| 413 |
-
|
| 414 |
-
|
| 415 |
-
|
| 416 |
-
|
| 417 |
-
copyCam(cameraEntity, textureCamera);
|
| 418 |
-
|
| 419 |
-
// ----- Background plane plein écran (espace caméra) -----
|
| 420 |
-
bgPlane = new pc.Entity("Plane");
|
| 421 |
bgPlane.addComponent("model", { type: "plane" });
|
| 422 |
-
|
| 423 |
-
|
| 424 |
-
|
| 425 |
-
|
| 426 |
-
|
| 427 |
-
|
| 428 |
-
|
| 429 |
-
|
| 430 |
-
|
| 431 |
-
|
| 432 |
-
|
| 433 |
-
|
| 434 |
-
|
| 435 |
-
|
| 436 |
-
|
| 437 |
-
bgPlane.model.material = bgMat;
|
| 438 |
-
// plane rendu dans la layer Background (rendu AVANT World)
|
| 439 |
-
bgPlane.model.layers = [backgroundLayer.id];
|
| 440 |
-
// placement plein écran devant la caméra (mais dans Background)
|
| 441 |
-
fitFullscreenPlane(cameraEntity, bgPlane, 0.5);
|
| 442 |
-
|
| 443 |
// ----- Lighting -----
|
| 444 |
const light = new pc.Entity("mainLight");
|
| 445 |
light.addComponent('light', {
|
|
@@ -451,22 +342,6 @@ export async function initializeViewer(config, instanceId) {
|
|
| 451 |
light.lookAt(0, 0, 0);
|
| 452 |
app.root.addChild(light);
|
| 453 |
|
| 454 |
-
// ----- Resize / viewport / FOV change handling -----
|
| 455 |
-
const onAppResize = () => {
|
| 456 |
-
({ tex: rtTexture, rt: renderTarget } = createRTFor(cameraEntity.camera));
|
| 457 |
-
textureCamera.camera.renderTarget = renderTarget;
|
| 458 |
-
|
| 459 |
-
// rebrancher la nouvelle texture sur le matériau
|
| 460 |
-
bgMat.emissiveMap = rtTexture;
|
| 461 |
-
bgMat.update();
|
| 462 |
-
|
| 463 |
-
// même projection / viewport
|
| 464 |
-
copyCam(cameraEntity, textureCamera);
|
| 465 |
-
// refaire le fit plein écran (FOV/aspect)
|
| 466 |
-
fitFullscreenPlane(cameraEntity, bgPlane, 0.5);
|
| 467 |
-
};
|
| 468 |
-
app.on('resize', onAppResize);
|
| 469 |
-
|
| 470 |
app.resizeCanvas(viewerContainer.clientWidth, viewerContainer.clientHeight);
|
| 471 |
app.once('update', () => resetViewerCamera());
|
| 472 |
|
|
@@ -562,7 +437,7 @@ export function changeColor(dr, dg, db, er, eg, eb, ei, op, boolTrans) {
|
|
| 562 |
traverse(tubeEntity, node => {
|
| 563 |
if (node.render && node.render.meshInstances) {
|
| 564 |
for (let mi of node.render.meshInstances) {
|
| 565 |
-
mi.material =
|
| 566 |
}
|
| 567 |
}
|
| 568 |
});
|
|
|
|
| 23 |
let pc;
|
| 24 |
export let app = null;
|
| 25 |
let cameraEntity = null;
|
|
|
|
| 26 |
let modelEntity = null;
|
| 27 |
let tubeEntity = null;
|
| 28 |
let filtreEntity = null;
|
|
|
|
|
|
|
| 29 |
let viewerInitialized = false;
|
| 30 |
let resizeObserver = null;
|
| 31 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
// Materials (for real-time switching)
|
| 33 |
let matTransparent = null;
|
| 34 |
let matOpaque = null;
|
|
|
|
| 49 |
}
|
| 50 |
}
|
| 51 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
// ----- Main Viewer Initialization -----
|
| 53 |
export async function initializeViewer(config, instanceId) {
|
| 54 |
if (viewerInitialized) return; // Prevent double-init
|
|
|
|
| 134 |
app.setCanvasFillMode(pc.FILLMODE_NONE);
|
| 135 |
app.setCanvasResolution(pc.RESOLUTION_AUTO);
|
| 136 |
|
| 137 |
+
// Canvas responsive resize
|
| 138 |
resizeObserver = new ResizeObserver(entries => {
|
| 139 |
entries.forEach(entry => {
|
| 140 |
app.resizeCanvas(entry.contentRect.width, entry.contentRect.height);
|
|
|
|
| 145 |
app.on('destroy', () => resizeObserver.disconnect());
|
| 146 |
|
| 147 |
// ----- Load all images as Textures (async, safe for CORS) -----
|
| 148 |
+
// All of these can fail (network, CORS), so wrap with try/catch if needed.
|
| 149 |
+
const hdrTex = await loadImageAsTexture('https://huggingface.co/datasets/MikaFil/3D_models/resolve/main/EARCARE/hdr/ciel_nuageux_1k.png', app);
|
| 150 |
+
const emitTex = await loadImageAsTexture('https://huggingface.co/datasets/MikaFil/3D_models/resolve/main/EARCARE/textures/emit_map_1k.png', app);
|
| 151 |
+
const opTex = await loadImageAsTexture('https://huggingface.co/datasets/MikaFil/3D_models/resolve/main/EARCARE/textures/op_map_1k.png', app);
|
| 152 |
+
const thicknessTex= await loadImageAsTexture('https://huggingface.co/datasets/MikaFil/3D_models/resolve/main/EARCARE/textures/thickness_map_1k.png', app);
|
| 153 |
+
const bgTex = await loadImageAsTexture('https://huggingface.co/datasets/MikaFil/3D_models/resolve/main/EARCARE/images/banniere_earcare.png', app);
|
| 154 |
|
| 155 |
// ----- GLB asset definition -----
|
| 156 |
const assets = {
|
|
|
|
| 173 |
app.start();
|
| 174 |
if (progressDialog) progressDialog.style.display = 'none';
|
| 175 |
|
| 176 |
+
// Reorder depth layer for transmission
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 177 |
const depthLayer = app.scene.layers.getLayerById(pc.LAYERID_DEPTH);
|
| 178 |
app.scene.layers.remove(depthLayer);
|
| 179 |
app.scene.layers.insertOpaque(depthLayer, 2);
|
| 180 |
|
| 181 |
+
// Instantiate GLB entities
|
| 182 |
+
modelEntity = assets.model.resource.instantiateRenderEntity();
|
| 183 |
+
tubeEntity = assets.tube.resource.instantiateRenderEntity();
|
| 184 |
filtreEntity = assets.filtre.resource.instantiateRenderEntity();
|
| 185 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 186 |
app.root.addChild(modelEntity);
|
| 187 |
app.root.addChild(tubeEntity);
|
| 188 |
app.root.addChild(filtreEntity);
|
| 189 |
|
| 190 |
// ----- Materials Setup -----
|
| 191 |
// Transparent material (main model)
|
| 192 |
+
matTransparent = new pc.StandardMaterial();
|
| 193 |
+
matTransparent.blendType = pc.BLEND_NORMAL;
|
| 194 |
+
matTransparent.diffuse = new pc.Color(1, 1, 1);
|
| 195 |
+
matTransparent.specular = new pc.Color(0.01, 0.01, 0.01);
|
| 196 |
+
matTransparent.gloss = 1;
|
| 197 |
+
matTransparent.metalness = 0;
|
| 198 |
+
matTransparent.useMetalness = true;
|
| 199 |
+
matTransparent.useDynamicRefraction = true;
|
| 200 |
+
matTransparent.depthWrite = true;
|
| 201 |
+
matTransparent.refraction = 0.8;
|
| 202 |
+
matTransparent.refractionIndex = 1;
|
| 203 |
+
matTransparent.thickness = 0.02;
|
| 204 |
+
matTransparent.thicknessMap = thicknessTex;
|
| 205 |
+
matTransparent.opacityMap = opTex;
|
| 206 |
+
matTransparent.opacityMapChannel = "r";
|
| 207 |
+
matTransparent.opacity = 0.97;
|
| 208 |
+
matTransparent.emissive = new pc.Color(1, 1, 1);
|
| 209 |
+
matTransparent.emissiveMap = emitTex;
|
| 210 |
+
matTransparent.emissiveIntensity = 0.1;
|
| 211 |
+
matTransparent.update();
|
| 212 |
+
|
|
|
|
| 213 |
// Opaque material (main model)
|
| 214 |
+
matOpaque = new pc.StandardMaterial();
|
| 215 |
+
matOpaque.blendType = pc.BLEND_NORMAL;
|
| 216 |
+
matOpaque.diffuse = new pc.Color(0.7, 0.05, 0.05);
|
| 217 |
+
matOpaque.specular = new pc.Color(0.01, 0.01, 0.01);
|
| 218 |
+
matOpaque.specularityFactor = 1;
|
| 219 |
+
matOpaque.gloss = 1;
|
| 220 |
+
matOpaque.metalness = 0;
|
| 221 |
+
matOpaque.opacityMap = opTex;
|
| 222 |
+
matOpaque.opacityMapChannel = "r";
|
| 223 |
+
matOpaque.opacity = 1;
|
| 224 |
+
matOpaque.emissive = new pc.Color(0.372, 0.03, 0.003);
|
| 225 |
+
matOpaque.emissiveMap = emitTex;
|
| 226 |
+
matOpaque.emissiveIntensity = 2;
|
| 227 |
+
matOpaque.update();
|
| 228 |
+
|
|
|
|
| 229 |
// Transparent material (tube)
|
| 230 |
+
tubeTransparent = new pc.StandardMaterial();
|
| 231 |
+
tubeTransparent.diffuse = new pc.Color(1, 1, 1);
|
| 232 |
+
tubeTransparent.blendType = pc.BLEND_NORMAL;
|
| 233 |
+
tubeTransparent.opacity = 0.05;
|
| 234 |
+
tubeTransparent.depthTest = false;
|
| 235 |
+
tubeTransparent.depthWrite = false;
|
| 236 |
+
tubeTransparent.useMetalness = true;
|
| 237 |
+
tubeTransparent.useDynamicRefraction = true;
|
| 238 |
+
tubeTransparent.thickness = 4;
|
| 239 |
+
tubeTransparent.update();
|
| 240 |
+
|
|
|
|
| 241 |
// Opaque material (tube)
|
| 242 |
+
tubeOpaque = new pc.StandardMaterial();
|
| 243 |
+
tubeOpaque.diffuse = new pc.Color(1, 1, 1);
|
| 244 |
+
tubeOpaque.opacity = 0.9;
|
| 245 |
+
tubeOpaque.update();
|
|
|
|
|
|
|
| 246 |
|
| 247 |
// ----- Assign materials to meshes -----
|
| 248 |
traverse(modelEntity, node => {
|
|
|
|
| 273 |
filtreEntity.setLocalScale(modelScale, modelScale, modelScale);
|
| 274 |
filtreEntity.setLocalEulerAngles(modelRotationX, modelRotationY, modelRotationZ);
|
| 275 |
|
| 276 |
+
// ----- Camera + Orbit Controls -----
|
| 277 |
cameraEntity = new pc.Entity('camera');
|
| 278 |
cameraEntity.addComponent('camera', {
|
| 279 |
clearColor: new pc.Color(0.8, 0.8, 0.8, 1),
|
|
|
|
|
|
|
| 280 |
toneMapping: pc.TONEMAP_NEUTRAL
|
| 281 |
});
|
|
|
|
|
|
|
|
|
|
| 282 |
cameraEntity.setPosition(chosenCameraX, chosenCameraY, chosenCameraZ);
|
| 283 |
cameraEntity.lookAt(modelEntity.getPosition());
|
| 284 |
cameraEntity.addComponent('script');
|
|
|
|
| 302 |
cameraEntity.script.create('orbitCameraInputTouch');
|
| 303 |
app.root.addChild(cameraEntity);
|
| 304 |
|
| 305 |
+
// Remove Skybox layer from camera
|
| 306 |
+
const skyboxLayer = app.scene.layers.getLayerByName("Skybox");
|
| 307 |
+
if (skyboxLayer) {
|
| 308 |
+
const camLayers = cameraEntity.camera.layers.slice();
|
| 309 |
+
const idx = camLayers.indexOf(skyboxLayer.id);
|
| 310 |
+
if (idx !== -1) {
|
| 311 |
+
camLayers.splice(idx, 1);
|
| 312 |
+
cameraEntity.camera.layers = camLayers;
|
| 313 |
+
}
|
| 314 |
+
}
|
| 315 |
+
/*
|
| 316 |
+
// ----- Camera-attached background plane -----
|
| 317 |
+
const bgPlane = new pc.Entity("Plane");
|
|
|
|
|
|
|
|
|
|
|
|
|
| 318 |
bgPlane.addComponent("model", { type: "plane" });
|
| 319 |
+
bgPlane.setLocalPosition(0, 0, -10);
|
| 320 |
+
bgPlane.setLocalScale(11, 1, 5.5);
|
| 321 |
+
bgPlane.setLocalEulerAngles(90, 0, 0);
|
| 322 |
+
// Simple material for the banner
|
| 323 |
+
const mat = new pc.StandardMaterial();
|
| 324 |
+
mat.diffuse = new pc.Color(1, 1, 1);
|
| 325 |
+
mat.diffuseMap = bgTex;
|
| 326 |
+
mat.emissive = new pc.Color(1, 1, 1);
|
| 327 |
+
mat.emissiveMap = bgTex;
|
| 328 |
+
mat.emissiveIntensity = 1;
|
| 329 |
+
mat.useLighting = false;
|
| 330 |
+
mat.update();
|
| 331 |
+
bgPlane.model.material = mat;
|
| 332 |
+
cameraEntity.addChild(bgPlane);
|
| 333 |
+
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 334 |
// ----- Lighting -----
|
| 335 |
const light = new pc.Entity("mainLight");
|
| 336 |
light.addComponent('light', {
|
|
|
|
| 342 |
light.lookAt(0, 0, 0);
|
| 343 |
app.root.addChild(light);
|
| 344 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 345 |
app.resizeCanvas(viewerContainer.clientWidth, viewerContainer.clientHeight);
|
| 346 |
app.once('update', () => resetViewerCamera());
|
| 347 |
|
|
|
|
| 437 |
traverse(tubeEntity, node => {
|
| 438 |
if (node.render && node.render.meshInstances) {
|
| 439 |
for (let mi of node.render.meshInstances) {
|
| 440 |
+
mi.material = tubeTransparent;
|
| 441 |
}
|
| 442 |
}
|
| 443 |
});
|