SOURCE

console 命令行工具 X clear

                    
>
console
import * as $ from '//unpkg.com/three@0.117.1/build/three.module.js'
import { OrbitControls } from '//unpkg.com/three@0.117.1/examples/jsm/controls/OrbitControls.js'
import { EffectComposer } from '//unpkg.com/three@0.117.1/examples/jsm/postprocessing/EffectComposer'
import { RenderPass } from '//unpkg.com/three@0.117.1/examples/jsm/postprocessing/RenderPass'
import { UnrealBloomPass } from '//unpkg.com/three@0.117.1/examples/jsm/postprocessing/UnrealBloomPass'
import { BokehPass } from '//unpkg.com/three@0.117.1/examples/jsm/postprocessing/BokehPass'

// ----
// Boot
// ----

const renderer = new $.WebGLRenderer({ antialias: true });
const scene = new $.Scene();
const camera = new $.PerspectiveCamera(75, 2, .01, 1e8);
const controls = new OrbitControls(camera, renderer.domElement);
const composer = new EffectComposer(renderer);
const res = new $.Vector2();
window.addEventListener('resize', () => {
    const { clientWidth, clientHeight } = renderer.domElement;
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(clientWidth, clientHeight, false);
    camera.aspect = clientWidth / clientHeight;
    camera.updateProjectionMatrix();
    composer.setPixelRatio(window.devicePixelRatio);
    composer.setSize(clientWidth, clientHeight);
    res.set(clientWidth, clientHeight);
});
document.body.prepend(renderer.domElement);
window.dispatchEvent(new Event('resize'));
renderer.setAnimationLoop(function (t) {
    composer.render();
    controls.update();
    animate(t);
});

// ----
// Main
// ---- 

scene.background = new $.Color('lightgray');
camera.position.set(0, .15, 1);
controls.autoRotate = true;
controls.autoRotateSpeed = -.2;

//// Make ShaderMaterial 

function makeMat() {
    return new $.ShaderMaterial({
        defines: { 'USE_MAP': '', 'USE_UV': '' },
        uniforms: {
            ...$.ShaderLib.lambert.uniforms,
            influence: { value: 1.0 },
        },
        vertexShader: $.ShaderLib.lambert.vertexShader,
        fragmentShader: document.querySelector('#fs').textContent,
        lights: true,
    });
}

//// Make Mesh

const geom = (new $.BoxBufferGeometry(1, 1, .1)).toNonIndexed();
const uvs = new Float32Array([
    1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1,
    0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1,
    0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1,
    0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0,
    0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1,
    1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1,
]);
geom.setAttribute('uv', new $.BufferAttribute(uvs, 2));
const mat0 = makeMat();
const mesh = new $.Mesh(geom, mat0);
scene.add(mesh);

//// Make Room

const roomGeom = geom.clone();
const roomMat = new $.MeshLambertMaterial({
    side: $.BackSide,
    color: new $.Color().setHSL(0, 0, 1) // diffuse
});
const roomMesh = new $.Mesh(roomGeom, roomMat);
roomMesh.scale.set(1e3, 1e3, 1e7);
scene.add(roomMesh);

//// Load Texture

function* TexUrlGen() {
    let i = 0;
    while (true) {
        yield `https://source.unsplash.com/collection/11016078/?${++i}`;
    }
}

function loadImage(texUrl, onLoad, onError, idx = 0) {
    new $.TextureLoader().load(texUrl, (tex) => {
        gsap.timeline({ onComplete: onLoad })
            .timeScale(0.75)
            .to(mat0.uniforms.influence, { value: 1 })
            .set(mat0.uniforms.map, { value: tex })
            .addLabel('STAGE-1')
            .set(roomMat, { map: tex, onComplete: () => roomMat.needsUpdate = true })
            .to(mesh.scale, { x: tex.image.width / tex.image.height, ease: 'bounce' })
            .to(roomMesh.scale, { x: 1000 * tex.image.width / tex.image.height }, '<')
            .to(mat0.uniforms.influence, { value: 0, ease: 'elastic' })
            .to(mesh.rotation, { y: Math.PI / 10 * (idx % 2 ? 1 : -1) }, 'STAGE-1')
            .to(controls, {autoRotateSpeed: controls.autoRotateSpeed * -1 }, 'STAGE-1');
    }, null, onError);
}

function start() {
    const texUrlGen = TexUrlGen();
    let i = 0;
    const next = () => loadImage(texUrlGen.next().value, onLoad, onError, i++);
    const onLoad = () => setTimeout(next, 5e3);
    const onError = () => setTimeout(next, 3e3);
    next();
}

start();

//// Lighting

const light0 = new $.AmbientLight('white', 1);
scene.add(light0);

//// PostProcessing

composer.addPass(new RenderPass(scene, camera));
composer.addPass(new UnrealBloomPass(res, .2, 1, .5));
const bokehPass = new BokehPass(scene, camera, {
    focus: camera.position.length(),
    aperture: 0.01 / (10),
    maxblur: 0.02
});
composer.addPass(bokehPass);

//// Animate

function animate() {
    bokehPass.uniforms.focus.value = camera.position.length();
}
<base target='_blank'>
<div class='info'>
    <a href='//codepen.io/ycw'>gradport</a>
    <a href='//unsplash.com/collections/11016078/gradport'>coll</a>
</div>
<script type='x-shader/x-fragment' id='fs'>
uniform float influence;
uniform vec3 diffuse;
uniform vec3 emissive;
uniform float opacity;
varying vec3 vLightFront;
varying vec3 vIndirectFront;
#ifdef DOUBLE_SIDED
	varying vec3 vLightBack;
	varying vec3 vIndirectBack;
#endif
#include <common>
#include <packing>
#include <dithering_pars_fragment>
#include <color_pars_fragment>
#include <uv_pars_fragment>
#include <uv2_pars_fragment>
#include <map_pars_fragment>
#include <alphamap_pars_fragment>
#include <aomap_pars_fragment>
#include <lightmap_pars_fragment>
#include <emissivemap_pars_fragment>
#include <envmap_common_pars_fragment>
#include <envmap_pars_fragment>
#include <cube_uv_reflection_fragment>
#include <bsdfs>
#include <lights_pars_begin>
#include <fog_pars_fragment>
#include <shadowmap_pars_fragment>
#include <shadowmask_pars_fragment>
#include <specularmap_pars_fragment>
#include <logdepthbuf_pars_fragment>
#include <clipping_planes_pars_fragment>

vec4 RGBA2HSLA(vec4 C) {
    float Cmax = max(max(C.r, C.g), C.b);
    float Cmin = min(min(C.r, C.g), C.b);
    float Cdiff = Cmax - Cmin;
    float H = 0.0;
    float L = (Cmax + Cmin) / 2.0;
    float S = Cdiff == 0.0 ? 0.0 : Cdiff / (1.0 - abs(2.0 * L - 1.0));
    if (Cdiff != 0.) {
        if (Cmax == C.r) {
            H = 60. * mod((C.g - C.b) / Cdiff, 6.);
        } else if (Cmax == C.g) {
            H = 60. * ((C.b - C.r) / Cdiff + 2.);
        } else if (Cmax == C.b) {
            H = 60. * ((C.r - C.g)/ Cdiff + 4.);    
        }
    }
    return vec4(H, S, L, C.a);
}

vec4 HSLA2RGBA(vec4 hsla) {
    float H = hsla[0];
    float S = hsla[1];
    float L = hsla[2];
    float C = (1.0 - abs(2.0 * L - 1.0)) * S;
    float X = C * (1.0 - abs(mod(H / 60.0, 2.0) - 1.0));
    float m = L - C / 2.0;
    float R = 0.0;
    float G = 0.0;
    float B = 0.0;
    if (H >= 0.000 && H < 60.00) { R = C; G = X; }
    if (H >= 60.00 && H < 120.0) { R = X; G = C; }
    if (H >= 120.0 && H < 180.0) { G = C; B = X; }
    if (H >= 180.0 && H < 240.0) { G = X; B = C; }
    if (H >= 240.0 && H < 300.0) { R = X; B = C; }
    if (H >= 300.0 && H < 360.0) { R = C; B = X; }
    return vec4(R + m, G + m, B + m, hsla[3]);
}

vec4 hueRotate(vec4 rgba, float deg) {
    vec4 hsla = RGBA2HSLA(rgba);
    hsla[0] = mod(hsla[0] + deg, 360.0);
    return HSLA2RGBA(hsla);
}

float random(vec2 uv) {
    return fract(sin(dot(uv, vec2(200., 100.))));
}

void main() {

	#include <clipping_planes_fragment>
	vec4 diffuseColor = vec4( diffuse, opacity );
	ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );
	vec3 totalEmissiveRadiance = emissive;
	#include <logdepthbuf_fragment>
	//---- #include <map_fragment>
    //++++
        #ifdef USE_MAP
            vec4 texelColor = texture2D( map, influence * random(vUv) + vUv );
            texelColor = mapTexelToLinear( texelColor );
            diffuseColor *= texelColor;
        #endif
    #include <color_fragment>
    //++++
        diffuseColor = hueRotate(diffuseColor, influence * 180.0);
    #include <alphamap_fragment>
	#include <alphatest_fragment>
	#include <specularmap_fragment>
	#include <emissivemap_fragment>
	// accumulation
	#ifdef DOUBLE_SIDED
		reflectedLight.indirectDiffuse += ( gl_FrontFacing ) ? vIndirectFront : vIndirectBack;
	#else
		reflectedLight.indirectDiffuse += vIndirectFront;
	#endif
	#include <lightmap_fragment>
	reflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb );
	#ifdef DOUBLE_SIDED
		reflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;
	#else
		reflectedLight.directDiffuse = vLightFront;
	#endif
	reflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();
	// modulation
	#include <aomap_fragment>
	vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;
	#include <envmap_fragment>
	gl_FragColor = vec4( outgoingLight, diffuseColor.a );
	#include <tonemapping_fragment>
	#include <encodings_fragment>
	#include <fog_fragment>
	#include <premultiplied_alpha_fragment>
	#include <dithering_fragment>
}
</script>
@import url('https://fonts.googleapis.com/css2?family=MuseoModerno:wght@200&display=swap');

canvas {
    width: 100%;
    height: 100vh;
    display: block;
    position: fixed;
    cursor: grab;
}

.info {
    position: relative;
    display: flex;
    width: min-content;
}

a {
    font: bold 1em/1 'MuseoModerno', cursive;
    padding: 5vmin;
    text-shadow: .1em .1ch 0 magenta, -.1em -.1ch 0 cyan;
    color: #222;
    text-decoration: none;
}

a:hover {
    transition: all .3s;
    background: yellow;
}

本项目引用的自定义外部资源