Last active
May 1, 2024 12:52
-
-
Save duhaime/6fc409012087f13d790133fa4df2fa8a to your computer and use it in GitHub Desktop.
Three.js Image Overlay
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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