Skip to content

Instantly share code, notes, and snippets.

@duhaime
Last active January 28, 2023 21:33
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save duhaime/6fc409012087f13d790133fa4df2fa8a to your computer and use it in GitHub Desktop.
Save duhaime/6fc409012087f13d790133fa4df2fa8a to your computer and use it in GitHub Desktop.
Three.js Image Overlay
<html>
<head>
<style>
html, body {
width: 100%;
height: 100%;
}
body {
margin: 0;
overflow: hidden;
}
canvas {
width: 100%;
height: 100%;
}
body {
background: url(sterling.jpg) no-repeat center center fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
#opacity {
position: absolute;
z-index: 10;
top: 20px;
right: 20px;
}
</style>
</head>
<body>
<script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/88/three.min.js'></script>
<script src='https://cdn.rawgit.com/YaleDHLab/pix-plot/14445202/assets/js/trackball-controls.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/cannon.js/0.6.2/cannon.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.5/dat.gui.min.js'></script>
<script>
/**
* Generate a scene object with a background color
**/
function getScene() {
var scene = new THREE.Scene();
return scene;
}
/**
* Generate the camera to be used in the scene. Camera args:
* [0] field of view: identifies the portion of the scene
* visible at any time (in degrees)
* [1] aspect ratio: identifies the aspect ratio of the
* scene in width/height
* [2] near clipping plane: objects closer than the near
* clipping plane are culled from the scene
* [3] far clipping plane: objects farther than the far
* clipping plane are culled from the scene
**/
function getCamera() {
var aspectRatio = window.innerWidth / window.innerHeight;
var camera = new THREE.PerspectiveCamera(75, aspectRatio, 0.1, 1000);
camera.position.set(0, 0, 10);
return camera;
}
/**
* Generate the light to be used in the scene. Light args:
* [0]: Hexadecimal color of the light
* [1]: Numeric value of the light's strength/intensity
* [2]: The distance from the light where the intensity is 0
* @param {obj} scene: the current scene object
**/
function getLight(scene) {
var light = new THREE.PointLight(0xffffff, 1, 0);
light.position.set(1, 1, -10);
scene.add(light);
var ambientLight = new THREE.AmbientLight(0x111111);
scene.add(ambientLight);
return light;
}
/**
* Generate the renderer to be used in the scene
**/
function getRenderer() {
// Create the canvas with a renderer
var renderer = new THREE.WebGLRenderer({
antialias: true, alpha: true});
// Add support for retina displays
renderer.setPixelRatio(window.devicePixelRatio);
// Specify the size of the canvas
renderer.setSize(window.innerWidth, window.innerHeight);
// Add the canvas to the DOM
document.body.appendChild(renderer.domElement);
// Allow the renderer to have a clear background
renderer.setClearColor( 0x000000, 0 );
return renderer;
}
/**
* Generate some physics!
**/
function getPhysics() {
world = new CANNON.World();
world.gravity.set(0, -10, 0); // earth = -9.82 m/s
world.broadphase = new CANNON.NaiveBroadphase();
world.broadphase.useBoundingBoxes = true;
var solver = new CANNON.GSSolver();
solver.iterations = 7;
solver.tolerance = 0.1;
world.solver = solver;
world.quatNormalizeSkip = 0;
world.quatNormalizeFast = false;
world.defaultContactMaterial.contactEquationStiffness = 1e9;
world.defaultContactMaterial.contactEquationRelaxation = 4;
return world;
}
/**
* Define contact material for interactions
**/
function getPhysicsMaterial() {
var physicsMaterial = new CANNON.Material('slipperyMaterial');
var physicsContactMaterial = new CANNON.ContactMaterial(
physicsMaterial, physicsMaterial, 0.0, 0.3)
world.addContactMaterial(physicsContactMaterial);
return physicsMaterial;
}
/**
* Generate the controls to be used in the scene
* @param {obj} camera: the three.js camera for the scene
* @param {obj} renderer: the three.js renderer for the scene
**/
function getControls(camera, renderer) {
var controls = new THREE.TrackballControls(camera, renderer.domElement);
controls.zoomSpeed = 0.4;
controls.panSpeed = 0.4;
return controls;
}
/**
* Add plane
**/
function getPlaneGroup() {
var planeGroup = new THREE.Group();
planeGroup.add( getPlane() );
scene.add(planeGroup);
return planeGroup;
}
function getPlane() {
var geometry = new THREE.PlaneGeometry(4, 6, 32);
var material = getImage();
var plane = new THREE.Mesh(geometry, material);
return plane;
}
function getImage() {
var loader = new THREE.TextureLoader();
var texture = loader.load('doors-ice.jpg');
var material = new THREE.MeshBasicMaterial({
map: texture,
side: THREE.DoubleSide,
opacity: 1
});
return material;
}
function getSphere() {
var geometry = new THREE.SphereGeometry(.3, 12, 9);
var material = new THREE.MeshPhongMaterial({
color: 0x00ffff,
emissive: 0x00ffff,
side: THREE.DoubleSide,
flatShading: true
});
var sphere = new THREE.Mesh(geometry, material);
sphere.position.set(2.5, -2.5, 0)
return sphere;
}
/**
* Add event listeners
**/
function addEventListeners() {
window.onload = buildGui;
window.addEventListener('resize', handleResize)
}
function handleResize(e) {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
if (typeof(controls) != 'undefined') controls.handleResize();
}
// Initial GUI state
function sceneManager() {
this.message = 'Controls';
this.opacity = 100;
this.save = setUrlHash;
}
// Simple GUI for user-facing params
function buildGui() {
var hud = new sceneManager;
var gui = new dat.GUI();
var opacity = gui.add(hud, 'opacity', 1, 100);
var save = gui.add(hud, 'save');
opacity.onChange(function(val) {
scene.children[2].children[0].material.opacity = val/100;
});
};
function setUrlHash() {
window.location.hash = JSON.stringify({
position: camera.position,
quaternion: camera.quaternion,
up: camera.up,
target: controls.target,
})
}
function setImagePositionFromHash() {
try {
var pos = JSON.parse(window.location.hash.substring(1));
var p = pos.position;
var q = pos.quaternion;
var u = pos.up;
var t = pos.target;
camera.position.set(p.x, p.y, p.z);
// set quaternion
rotObjectMatrix = new THREE.Matrix4();
rotObjectMatrix.makeRotationFromQuaternion(q);
camera.quaternion.setFromRotationMatrix(rotObjectMatrix);
// set the up direction
camera.up.set(u.x, u.y, u.z);
// set the controls target
controls.target.set(t.x, t.y, t.z);
// dirty
camera.matrixNeedsUpdate = true;
camera.matrixWorldNeedsUpdate = true;
positionSet = true;
} catch (err) {}
}
/**
* Render!
**/
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
if (typeof controls != 'undefined') controls.update();
};
// state
var positionSet = false;
var clock = new THREE.Clock();
var scene = getScene();
var camera = getCamera();
var light = getLight(scene);
var renderer = getRenderer();
var world = getPhysics();
var physicsMaterial = getPhysicsMaterial();
var controls = getControls(camera, renderer);
// add objects
var plane = getPlaneGroup();
setImagePositionFromHash();
addEventListeners();
render();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment