Last active
March 18, 2023 22:24
-
-
Save rleaf/e98a11f15d334304960f8e322a704e81 to your computer and use it in GitHub Desktop.
Three.js "mixed mode": DOM element with shadow and shine.
This file contains hidden or 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
<script src="https://threejs.org/build/three.min.js"></script> | |
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script> | |
<script src="https://threejs.org/examples/js/renderers/CSS3DRenderer.js"></script> | |
<div id="css"></div> | |
<div id="webgl"></div> |
This file contains hidden or 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
var camera, root, scene, renderer, renderer2, windowHalfX, windowHalfY, background; | |
var mouseX = 0, mouseY = 0; | |
var sphere; | |
var light | |
var lightMovementAmplitude = 200 | |
init(); | |
animate(performance.now()); | |
function init() { | |
windowHalfX = window.innerWidth / 2; | |
windowHalfY = window.innerHeight / 2; | |
camera = new THREE.PerspectiveCamera( | |
45, window.innerWidth / window.innerHeight, 1, 2000 | |
); | |
camera.position.set( 0, 0, 500 ); | |
scene = new THREE.Scene() | |
root = new THREE.Object3D() | |
root.position.y = 20 | |
root.rotation.y = Math.PI / 3 | |
scene.add(root) | |
background = makeElementObject('div', 200, 200) | |
background.css3dObject.element.textContent = "How can we make the Sphere show behind this surface?" | |
background.css3dObject.element.setAttribute('contenteditable', '') | |
background.position.z = 20 | |
background.css3dObject.element.style.opacity = "0.65" | |
root.add( background ); | |
const button = makeElementObject('button', 75, 20) | |
button.css3dObject.element.style.border = '1px solid orange' | |
button.css3dObject.element.textContent = "Click me!" | |
button.css3dObject.element.addEventListener('click', () => alert('Button clicked!')) | |
button.position.y = 10 | |
button.position.z = 10 | |
background.add(button) | |
// make a geometry to see if we can clip it with the DOM elememt. | |
~function() { | |
var material = new THREE.MeshPhongMaterial({ | |
color: 0x156289, | |
emissive: 0x000000, | |
specular: 0x111111, | |
side: THREE.DoubleSide, | |
flatShading: false, | |
shininess: 30, | |
}) | |
var geometry = new THREE.SphereGeometry( 70, 32, 32 ); | |
sphere = new THREE.Mesh( geometry, material ); | |
sphere.position.z = 20; | |
sphere.position.y = -100; | |
sphere.castShadow = true; | |
sphere.receiveShadow = false; | |
root.add( sphere ); | |
}() | |
// light | |
~function() { | |
var ambientLight = new THREE.AmbientLight( 0x999999 ); | |
root.add( ambientLight ); | |
light = new THREE.PointLight( 0xffffff, 1, 0 ); | |
light.castShadow = true; | |
light.position.z = 150; | |
light.shadow.mapSize.width = 512; // default | |
light.shadow.mapSize.height = 512; // default | |
light.shadow.camera.near = 1; // default | |
light.shadow.camera.far = 2000; // default | |
scene.add( new THREE.PointLightHelper( light, 10 ) ) | |
root.add( light ); | |
}() | |
renderer2 = new THREE.CSS3DRenderer(); | |
renderer2.setSize( window.innerWidth, window.innerHeight ); | |
renderer2.domElement.style.position = 'absolute'; | |
renderer2.domElement.style.top = 0; | |
document.querySelector('#css').appendChild( renderer2.domElement ); | |
renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true }); | |
renderer.setClearColor( 0x000000, 0 ); | |
renderer.setPixelRatio( window.devicePixelRatio ); | |
renderer.setSize( window.innerWidth, window.innerHeight ); | |
renderer.shadowMap.enabled = true; | |
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap | |
document.querySelector('#webgl').appendChild( renderer.domElement ); | |
document.addEventListener( 'mousemove', onDocumentMouseMove, false ); | |
} | |
function onDocumentMouseMove( event ) { | |
mouseX = event.clientX - windowHalfX; | |
mouseY = event.clientY - windowHalfY; | |
} | |
function animate(time) { | |
light.position.x = 20 * Math.sin(time * 0.003); | |
light.position.y = 40 * Math.cos(time * 0.002) - 80; | |
background.rotation.y = Math.PI/8 * Math.cos(time * 0.001) - Math.PI/6; | |
background.rotation.x = Math.PI/10 * Math.sin(time * 0.001) - Math.PI/10; | |
scene.updateMatrixWorld() | |
renderer.render( scene, camera ); | |
renderer2.render( scene, camera ); | |
requestAnimationFrame( animate ); | |
} | |
function makeElementObject(type, width, height) { | |
const obj = new THREE.Object3D | |
const element = document.createElement( type ); | |
element.style.width = width+'px'; | |
element.style.height = height+'px'; | |
element.style.opacity = 0.999; | |
element.style.background = new THREE.Color( | |
Math.random() * 0.21568627451 + 0.462745098039, | |
Math.random() * 0.21568627451 + 0.462745098039, | |
Math.random() * 0.21568627451 + 0.462745098039, | |
).getStyle(); | |
var css3dObject = new THREE.CSS3DObject( element ); | |
obj.css3dObject = css3dObject | |
obj.add(css3dObject) | |
// make an invisible plane for the DOM element to chop | |
// clip a WebGL geometry with it. | |
var material = new THREE.MeshPhongMaterial({ | |
opacity : 0.15, | |
color : new THREE.Color( 0x111111 ), | |
blending: THREE.NoBlending, | |
side : THREE.DoubleSide, | |
}); | |
var geometry = new THREE.BoxGeometry( width, height, 1 ); | |
var mesh = new THREE.Mesh( geometry, material ); | |
mesh.castShadow = true; | |
mesh.receiveShadow = true; | |
obj.lightShadowMesh = mesh | |
obj.add( mesh ); | |
return obj | |
} |
This file contains hidden or 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
body { | |
background-color: #ffffff; | |
margin: 0; | |
overflow: hidden; | |
} | |
* { | |
outline: none; | |
} | |
#css, #webgl { | |
width: 100%; | |
height: 100%; | |
position: absolute; | |
top: 0; left: 0; | |
} | |
#css { | |
background: repeating-linear-gradient( | |
45deg, | |
#606dbc, | |
#606dbc 10px, | |
#465298 10px, | |
#465298 20px | |
); | |
} | |
#webgl { | |
pointer-events: none; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
That demo probably broke due to un-versioned script URLs. Use these instead: