136 lines
3.3 KiB
TypeScript
136 lines
3.3 KiB
TypeScript
import { Renderer, Camera, Transform, Texture, Sphere, Program, Mesh } from "ogl"
|
|
import { Orbit } from "./CustomOrbit"
|
|
import { bufToImageUrl } from "../../helpers";
|
|
|
|
|
|
import VertexShader from "./Orb.vert";
|
|
import FragmentShader from "./Orb.frag";
|
|
import Toast from "../Toast";
|
|
|
|
let hasConfirmed = false;
|
|
|
|
export default (image: Image, canvas2D: CanvasRenderingContext2D, canvas3D: HTMLCanvasElement) => {
|
|
|
|
const renderer = new Renderer({ dpr: 2, canvas: canvas3D });
|
|
const gl = renderer.gl;
|
|
gl.clearColor(1, 1, 1, 1);
|
|
|
|
const camera = new Camera(gl, { fov: 45 });
|
|
camera.position.set(0, 0, 8);
|
|
|
|
const controls = new Orbit(camera, {
|
|
enablePan: false,
|
|
enableZoom: false,
|
|
rotateSpeed: -0.1
|
|
});
|
|
|
|
function resize() {
|
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
camera.perspective({ aspect: gl.canvas.width / gl.canvas.height });
|
|
}
|
|
window.addEventListener('resize', resize, false);
|
|
resize();
|
|
|
|
const scene = new Transform();
|
|
|
|
// Texture is equirectangular
|
|
const texture = new Texture(gl);
|
|
const img = new Image();
|
|
img.onload = () => (texture.image = img);
|
|
img.src = bufToImageUrl(image.data, image.type);
|
|
|
|
// Use Sphere geometry to render equirectangular textures
|
|
const geometry = new Sphere(gl, { radius: 1, widthSegments: 64 });
|
|
|
|
const program = new Program(gl, {
|
|
vertex: VertexShader,
|
|
fragment: FragmentShader,
|
|
uniforms: {
|
|
tMap: { value: texture },
|
|
opacity: { value: 1 }
|
|
},
|
|
|
|
// Need inside of sphere to be visible
|
|
cullFace: null,
|
|
});
|
|
|
|
// Camera will dwell inside skybox
|
|
const skybox = new Mesh(gl, { geometry, program });
|
|
skybox.scale.set(10);
|
|
skybox.scale.x = -10;
|
|
skybox.setParent(scene);
|
|
|
|
|
|
const overlayTexture = new Texture(gl, {
|
|
image: new Uint8Array(image.data),
|
|
width: image.width,
|
|
height: image.height,
|
|
});
|
|
|
|
// Use Sphere geometry to render equirectangular textures
|
|
const overlayGeometry = new Sphere(gl, { radius: 1, widthSegments: 64 });
|
|
|
|
const overlayProgram = new Program(gl, {
|
|
vertex: VertexShader,
|
|
fragment: FragmentShader,
|
|
uniforms: {
|
|
tMap: { value: overlayTexture },
|
|
opacity: { value: 0.5 }
|
|
},
|
|
transparent: true,
|
|
// Need inside of sphere to be visible
|
|
cullFace: null,
|
|
});
|
|
// Camera will dwell inside skybox
|
|
const overlay = new Mesh(gl, { geometry: overlayGeometry, program: overlayProgram });
|
|
overlay.scale.set(9.995);
|
|
overlay.scale.x = -9.995;
|
|
overlay.setParent(scene);
|
|
|
|
|
|
let activeTool = "pan";
|
|
let shouldBeRendering = false;
|
|
function update() {
|
|
if (!shouldBeRendering) return;
|
|
|
|
requestAnimationFrame(update);
|
|
|
|
controls.update();
|
|
renderer.render({ scene, camera });
|
|
}
|
|
|
|
|
|
function start() {
|
|
!hasConfirmed && Toast.confirm("Drawing does not work correctly in 3D at the moment").then(c => {
|
|
hasConfirmed = c;
|
|
})
|
|
if (shouldBeRendering) return;
|
|
|
|
updateOverlay();
|
|
|
|
shouldBeRendering = true;
|
|
update();
|
|
}
|
|
|
|
function updateOverlay() {
|
|
overlayProgram.uniforms.tMap.value.image = canvas2D.getImageData(0, 0, image.width, image.height).data;
|
|
}
|
|
|
|
function stop() {
|
|
shouldBeRendering = false;
|
|
}
|
|
|
|
function setTool(t) {
|
|
activeTool = t;
|
|
controls.enabled = t === "pan";
|
|
}
|
|
|
|
function setOpacity(o) {
|
|
overlayProgram.uniforms.opacity.value = o / 100;
|
|
}
|
|
|
|
return {
|
|
start, stop, setTool, updateOverlay, setOpacity
|
|
}
|
|
|
|
} |