Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import { addMedia } from "../utils/media-utils";
import { ObjectTypes } from "../object-types";
const snapCanvas = document.createElement("canvas");
async function pixelsToPNG(pixels, width, height) {
snapCanvas.width = width;
snapCanvas.height = height;
const context = snapCanvas.getContext("2d");
const imageData = context.createImageData(width, height);
imageData.data.set(pixels);
const bitmap = await createImageBitmap(imageData);
context.scale(1, -1);
context.drawImage(bitmap, 0, -height);
const blob = await new Promise(resolve => snapCanvas.toBlob(resolve));
return new File([blob], "snap.png", { type: "image/png" });
}
AFRAME.registerComponent("camera-tool", {
schema: {
previewFPS: { default: 6 },
imageWidth: { default: 512 },
imageHeight: { default: 512 }
},
init() {
this.stateAdded = this.stateAdded.bind(this);
this.lastUpdate = performance.now();
this.renderTarget = new THREE.WebGLRenderTarget(this.data.imageWidth, this.data.imageHeight, {
format: THREE.RGBAFormat,
minFilter: THREE.LinearFilter,
magFilter: THREE.NearestFilter,
encoding: THREE.sRGBEncoding,
depth: false,
stencil: false
});
this.camera = new THREE.PerspectiveCamera();
this.camera.rotation.set(0, Math.PI, 0);
this.el.setObject3D("camera", this.camera);
const material = new THREE.MeshBasicMaterial({
map: this.renderTarget.texture
});
// Bit of a hack here to only update the renderTarget when the screens are in view and at a reduced FPS
material.map.isVideoTexture = true;
material.map.update = () => {
if (performance.now() - this.lastUpdate >= 1000 / this.data.previewFPS) {
this.updateRenderTargetNextTick = true;
}
};
this.el.addEventListener(
"model-loaded",
() => {
const geometry = new THREE.PlaneGeometry(0.25, 0.25);
const screen = new THREE.Mesh(geometry, material);
screen.rotation.set(0, Math.PI, 0);
screen.position.set(0, -0.015, -0.08);
this.el.setObject3D("screen", screen);
const selfieScreen = new THREE.Mesh(geometry, material);
selfieScreen.position.set(0, 0.3, 0);
selfieScreen.scale.set(-1, 1, 1);
this.el.setObject3D("selfieScreen", selfieScreen);
this.updateRenderTargetNextTick = true;
},
{ once: true }
);
},
play() {
this.el.addEventListener("stateadded", this.stateAdded);
},
pause() {
this.el.removeEventListener("stateadded", this.stateAdded);
},
stateAdded(evt) {
if (evt.detail === "activated") {
this.takeSnapshotNextTick = true;
}
},
const sceneEl = this.el.sceneEl;
const renderer = this.renderer || sceneEl.renderer;
const now = performance.now();
if (!this.playerHead) {
const headEl = document.getElementById("player-head");
this.playerHead = headEl && headEl.object3D;
}
if (this.takeSnapshotNextTick || this.updateRenderTargetNextTick) {
const tempScale = new THREE.Vector3();
if (this.playerHead) {
tempScale.copy(this.playerHead.scale);
this.playerHead.scale.set(1, 1, 1);
}
const tmpVRFlag = renderer.vr.enabled;
const tmpOnAfterRender = sceneEl.object3D.onAfterRender;
delete sceneEl.object3D.onAfterRender;
renderer.vr.enabled = false;
renderer.render(sceneEl.object3D, this.camera, this.renderTarget, true);
renderer.vr.enabled = tmpVRFlag;
sceneEl.object3D.onAfterRender = tmpOnAfterRender;
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
if (this.playerHead) {
this.playerHead.scale.copy(tempScale);
}
this.lastUpdate = now;
this.updateRenderTargetNextTick = false;
}
if (this.takeSnapshotNextTick) {
const width = this.renderTarget.width;
const height = this.renderTarget.height;
if (!this.snapPixels) {
this.snapPixels = new Uint8Array(width * height * 4);
}
renderer.readRenderTargetPixels(this.renderTarget, 0, 0, width, height, this.snapPixels);
pixelsToPNG(this.snapPixels, width, height).then(file => {
const { entity, orientation } = addMedia(file, "#interactable-media", undefined, true);
orientation.then(() => {
entity.object3D.position.copy(this.el.object3D.position);
entity.object3D.rotation.copy(this.el.object3D.rotation);
entity.components["sticky-object"].setLocked(false);
sceneEl.emit("object_spawned", { objectType: ObjectTypes.CAMERA });
});
});
this.takeSnapshotNextTick = false;
}
}
});