<canvas class="webgl"></canvas>
<script type="x-shader/x-vertex" id="vertexshaderCandle">
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
</script>
<script type="x-shader/x-fragment" id="fragmentshaderCandle">
uniform float time;
uniform float colorSpeed;
uniform float delay;
uniform vec3 baseColor;
varying vec2 vUv;
void main() {
float animatedTime = time - delay;
animatedTime = mod(animatedTime, colorSpeed);
float mixFactor = animatedTime / colorSpeed;
vec3 finalColor = mix(baseColor, vec3(0.702,0.71,0.459), mixFactor);
gl_FragColor = vec4(finalColor, 1.0);
}
</script>
<!-- ========================== -->
<script type="x-shader/x-vertex" id="vertexshaderBubble">
varying vec2 vUv;
uniform float time;
void main() {
vUv = uv;
vec3 newPosition = position;
newPosition.x += sin(time * 2.0) * 0.0075;
newPosition.y += cos(time * 2.0) * 0.0075;
gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0);
}
</script>
<script type="x-shader/x-fragment" id="fragmentshaderBubble">
varying vec2 vUv;
void main() {
gl_FragColor = vec4(0.765,0.965,0.733, 1.0);
}
</script>
<!-- ========================== -->
<script type="x-shader/x-vertex" id="vertexshaderDoor">
uniform float time;
varying vec2 vUv;
void main() {
vUv = uv;
vec2 center = vec2(0.0, 0.0);
float distance = length(uv - center);
vec3 newPosition = position + vec3(0.0, 0.0, 0.0);
gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0);
}
</script>
<script type="x-shader/x-fragment" id="fragmentshaderDoor">
uniform float time;
varying vec2 vUv;
void main() {
vec3 waveColor = vec3(0.702,0.71,0.459);
vec2 center = vec2(0.5, 0.5);
float distance = length(vUv - center);
float waveIntensity = abs(sin(distance * 100.0 + time));
vec3 finalColor = mix(vec3(0.545,0.553,0.306), waveColor, waveIntensity);
gl_FragColor = vec4(finalColor, 1.0);
}
</script>
// Original code: https://codepen.io/aderaaij/details/BapYONL
<script type="x-shader/x-vertex" id="vertexshader">
uniform float uPixelRatio;
uniform float uSize;
uniform float uTime;
attribute float aScale;
void main() {
vec4 modelPosition = modelMatrix * vec4(position, 1.0);
modelPosition.y += sin(uTime + modelPosition.x * 100.0) * aScale * 0.2;
modelPosition.z += sin(uTime + modelPosition.x * 100.0) * aScale * 0.2;
modelPosition.x += cos(uTime + modelPosition.x * 100.0) * aScale * 0.2;
vec4 viewPosition = viewMatrix * modelPosition;
vec4 projectionPostion = projectionMatrix * viewPosition;
gl_Position = projectionPostion;
gl_PointSize = uSize * aScale * uPixelRatio;
gl_PointSize += (1.0 / - viewPosition.z);
}
</script>
<script type="x-shader/x-fragment" id="fragmentshader">
void main() {
float distanceToCenter = distance(gl_PointCoord, vec2(0.5));
float strength = 0.05 / distanceToCenter - 0.1;
gl_FragColor = vec4(1.0, 1.0, 1.0, strength);
}
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r124/three.min.js"></script>
<script src='https://unpkg.com/three@0.126.0/examples/js/postprocessing/EffectComposer.js'></script>
<script src='https://unpkg.com/three@0.126.0/examples/js/postprocessing/RenderPass.js'></script>
<script src='https://unpkg.com/three@0.126.0/examples/js/postprocessing/ShaderPass.js'></script>
<script src='https://unpkg.com/three@0.126.0/examples/js/shaders/CopyShader.js'></script>
<script src='https://unpkg.com/three@0.126.0/examples/js/shaders/LuminosityHighPassShader.js'></script>
<script src='https://unpkg.com/three@0.126.0/examples/js/postprocessing/UnrealBloomPass.js'></script>
<script src="https://unpkg.com/three@0.126.0/examples/js/loaders/GLTFLoader.js"></script>
<script src="https://unpkg.com/three@0.126.0/examples/js/controls/OrbitControls.js"></script>
*,
*::after,
*::before {
margin: 0;
padding: 0;
box-sizing: border-box;
outline: none;
}
body{
overflow: hidden;
background-color: #0d0d0d;
}
.webgl{
position: fixed;
top: 0;
left: 0;
}
View Compiled
const canvas = document.querySelector('.webgl')
const scene = new THREE.Scene()
const textureLoader = new THREE.TextureLoader()
let composer
const sizes = {
width: window.innerWidth,
height: window.innerHeight
}
const params = {
exposure: 1,
bloomStrength: .4,
bloomThreshold: .1,
bloomRadius: 1
}
// Base camera
const camera = new THREE.PerspectiveCamera(10, sizes.width / sizes.height, 0.1, 100)
camera.position.x = 18
camera.position.y = 8
camera.position.z = 20
scene.add(camera)
// Controls
const controls = new THREE.OrbitControls(camera, canvas)
controls.enableDamping = true
controls.enableZoom = true
controls.enablePan = true
controls.minDistance = 15
controls.maxDistance = 30
controls.minPolarAngle = Math.PI / 5
controls.maxPolarAngle = Math.PI / 2
// Renderer
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true,
alpha: true,
})
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
renderer.outputEncoding = THREE.sRGBEncoding
// Materials
const candleMaterial = new THREE.ShaderMaterial({
uniforms: {
time: { value: 1.0 },
delay: { value: 1.0 },
colorSpeed: { value: 5.0 },
baseColor: { value: new THREE.Color(0xFFD7BC) }
},
vertexShader: document.getElementById( 'vertexshaderCandle' ).textContent,
fragmentShader: document.getElementById( 'fragmentshaderCandle' ).textContent,
})
const bubbleMaterial = new THREE.ShaderMaterial({
uniforms: {
time: { value: 0.0 },
},
vertexShader: document.getElementById( 'vertexshaderBubble' ).textContent,
fragmentShader: document.getElementById( 'fragmentshaderBubble' ).textContent,
})
const doorMaterial = new THREE.ShaderMaterial({
uniforms: {
time: { value: 10.0 },
resolution: { value: new THREE.Vector2() },
},
vertexShader: document.getElementById( 'vertexshaderDoor' ).textContent,
fragmentShader: document.getElementById( 'fragmentshaderDoor' ).textContent,
})
// Original code: https://codepen.io/aderaaij/details/BapYONL
const firefliesGeometry = new THREE.BufferGeometry()
const firefliesCount = 30
const positionArray = new Float32Array(firefliesCount * 3)
const scaleArray = new Float32Array(firefliesCount)
for (let i = 0; i < firefliesCount; i++) {
new THREE.Vector3(
(Math.random() - 0.5) * 2,
(Math.random() * 2) * 1,
(Math.random() - 0.5) * 4
).toArray(positionArray, i * 3)
scaleArray[i] = Math.random()
scaleArray[i] = Math.random()
}
firefliesGeometry.setAttribute("position", new THREE.BufferAttribute(positionArray, 3))
firefliesGeometry.setAttribute("aScale", new THREE.BufferAttribute(scaleArray, 1))
const firefliesMaterial = new THREE.ShaderMaterial({
uniforms: {
uTime: { value: 0 },
uPixelRatio: { value: Math.min(window.devicePixelRatio, 2) },
uSize: { value: 15 }
},
vertexShader: document.getElementById( 'vertexshader' ).textContent,
fragmentShader: document.getElementById( 'fragmentshader' ).textContent,
transparent: true,
blending: THREE.AdditiveBlending,
depthWrite: false
})
const fireflies = new THREE.Points(firefliesGeometry, firefliesMaterial)
scene.add(fireflies)
const bakedTexture = textureLoader.load('https://rawcdn.githack.com/ricardoolivaalonso/ThreeJS-Room08/7937528ab05555575b588691c884195b73459f89/dist/baked.jpg')
bakedTexture.flipY = false
bakedTexture.encoding = THREE.sRGBEncoding
const bakedMaterial = new THREE.MeshBasicMaterial({
map: bakedTexture,
side: THREE.DoubleSide,
})
const candle = [ 'Sphere001', 'Sphere002', 'Sphere003']
const bubbles = ['Vela_Flama', 'Vela_Flama002', 'Vela_Flama003', 'Vela_Flama004', 'Vela_Flama005', 'Vela_Flama006', 'Vela_Flama007', 'Vela_Flama008', 'Vela_Flama009', 'Vela_Flama010', 'Vela_Flama018', 'Vela_Flama019', 'Vela_Flama020', 'Vela_Flama021', 'Vela_Flama022', 'Vela_Flama023', 'Vela_Flama024']
//Loader
const loader = new THREE.GLTFLoader()
loader.load( 'https://rawcdn.githack.com/ricardoolivaalonso/ThreeJS-Room08/d54201d862fc2225142bdfec341a93a726a11a74/dist/model.glb',
(gltf) => {
const model = gltf.scene
model.traverse( child => {
child.material = bakedMaterial
if (candle.includes(child.name)) child.material = candleMaterial
if (bubbles.includes(child.name)) child.material = bubbleMaterial
if (child.name === 'Foto') child.material = doorMaterial
})
scene.add(model)
},
( xhr ) => console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' )
)
const renderScene = new THREE.RenderPass( scene, camera )
const bloomPass = new THREE.UnrealBloomPass( new THREE.Vector2( sizes.width, sizes.height ), 1, 1, 1 )
bloomPass.threshold = params.bloomThreshold
bloomPass.strength = params.bloomStrength
bloomPass.radius = params.bloomRadius
composer = new THREE.EffectComposer( renderer )
composer.addPass( renderScene )
composer.addPass( bloomPass )
window.addEventListener('resize', () =>
{
sizes.width = window.innerWidth
sizes.height = window.innerHeight
camera.aspect = sizes.width / sizes.height
camera.updateProjectionMatrix()
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
composer.setSize(sizes.width, sizes.height)
composer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})
const clock = new THREE.Clock()
// Animation
const tick = () => {
const elapsedTime = clock.getElapsedTime()
candleMaterial.uniforms.time.value += 0.075
doorMaterial.uniforms.time.value += 0.1
bubbleMaterial.uniforms.time.value += 0.035
firefliesMaterial.uniforms.uTime.value = elapsedTime
controls.update()
renderer.render(scene, camera)
//composer.render()
window.requestAnimationFrame(tick)
}
tick()
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.