DigDig.IO/DigWorm.IO Effects

3D, particles and glow effect for DigDig.IO and DigWorm.IO. Use num keys from 1 to 3 to toggle effects

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください。
// ==UserScript==
// @name         DigDig.IO/DigWorm.IO Effects
// @namespace    http://tampermonkey.net/
// @version      0.2.5
// @description  3D, particles and glow effect for DigDig.IO and DigWorm.IO. Use num keys from 1 to 3 to toggle effects
// @author       Zertalious (Zert)
// @match        *://digdig.io/*
// @match        *://digworm.io/*
// @icon         https://www.google.com/s2/favicons?domain=digdig.io
// @grant        none
// @require      https://unpkg.com/three@0.120.0/build/three.min.js
// @require      https://unpkg.com/three@0.120.0/examples/js/postprocessing/EffectComposer.js
// @require      https://unpkg.com/three@0.120.0/examples/js/postprocessing/RenderPass.js
// @require      https://unpkg.com/three@0.120.0/examples/js/postprocessing/UnrealBloomPass.js
// @require      https://unpkg.com/three@0.120.0/examples/js/postprocessing/ShaderPass.js
// @require      https://unpkg.com/three@0.120.0/examples/js/shaders/LuminosityHighPassShader.js
// @require      https://unpkg.com/three@0.120.0/examples/js/shaders/CopyShader.js
// ==/UserScript==

window.enable3d = true;

window.enableParticles = function ( bool ) {

	if ( bool === undefined ) {

		bool = ! particlesEnabled();

	}

	maskMaterial.uniforms.enableParticles.value = bool;

}

window.enableGlow = function ( bool ) {

	if ( bool === undefined ) {

		bool = ! glowEnabled();

	}

	maskMaterial.uniforms.enableGlow.value = bool;

}

window.addEventListener( 'keyup', function ( event ) {

	const key = String.fromCharCode( event.keyCode );

	switch ( key ) {

		case '1' : enable3d = ! enable3d; break;
		case '2' : enableGlow(); break;
		case '3' : enableParticles(); break;

	}

} );

const canvas = document.getElementById( 'canvas' );
canvas.style.opacity = '0';

const particleColor = '#0000ff';

CanvasRenderingContext2D.prototype.fillRect = new Proxy( CanvasRenderingContext2D.prototype.fillRect, {
	apply( target, ctx, args ) {

		if ( ctx.globalAlpha <= 1 ) {

			if ( ctx.fillStyle === '#000000' ) {

				return;

			} if ( particlesEnabled() ) {

				if ( ctx.getTransform().d < 20 ) {

					ctx.fillStyle = '#00' + Math.floor( ctx.globalAlpha * 256 ).toString( 16 ).padStart( 2, '0' ) + 'ff';
					ctx.globalAlpha = 1;

				}

			}

		}

		return Reflect.apply( ...arguments );

	}
} );

const Canvas = window.OffscreenCanvas ? OffscreenCanvas.prototype : HTMLCanvasElement.prototype;

Canvas.getContext = new Proxy( Canvas.getContext, {
	apply( target, canvas, args ) {

		const ctx = Reflect.apply( ...arguments );

		ctx.fillRect = new Proxy( ctx.fillRect, {
			apply( target, thisArgs, args ) {

				if ( ctx.globalAlpha < 1 ) {

					if ( ctx.fillStyle === '#000000' ) {

						return;

					}

				}

				return Reflect.apply( ...arguments );

			}
		} );

		return ctx;

	}
} );

window.Image = new Proxy( window.Image, {
	construct( target, thisArgs, args ) {

		const image = Reflect.construct( ...arguments );

		image.crossOrigin = 'anonymous';

		return image;

	}
} );

const renderer = new THREE.WebGLRenderer( { antialias: true, preserveDrawingBuffer: true } );

renderer.domElement.style.position = 'absolute';
renderer.domElement.style.left = '0';
renderer.domElement.style.top = '0';
renderer.domElement.style.pointerEvents = 'none';

renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );

canvas.parentNode.insertBefore( renderer.domElement, canvas );

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 60, 1, 0.1, 1000 );

camera.position.z = Math.sin( camera.fov * Math.PI / 180 ) * 2;

const texture = new THREE.CanvasTexture( canvas );
texture.minFilter = texture.magFilter = THREE.NearestFilter;

scene.background = new THREE.Color( '#522e00' );

const ground = toVec3( scene.background );
const diamond = toVec3( '#31a59e' );
const gold = toVec3( '#a59e15' );
const lava = toVec3( '#a61906' );
const uranium = toVec3( '#32a430' );
const particle = toVec3( particleColor );
const grid = toVec3( '#4e2c00' );
const amethyst = toVec3( '#b332b5' );

const material = new THREE.RawShaderMaterial( {
    vertexShader: `

		attribute vec3 position;

		varying vec3 vPosition;

		void main() {

			vPosition = position;

			gl_Position = vec4( position, 1.0 );

		}

		`,
    fragmentShader: `

		precision mediump float;

		uniform sampler2D map;
		uniform float depth;

		uniform mat4 modelViewMatrix;
		uniform mat4 projectionMatrix;

		varying vec3 vPosition;

		void main() {

			vec4 a;

			const int count = 20;

			for ( int i = 0; i <= count; i ++ ) {

				vec4 p = projectionMatrix * modelViewMatrix * vec4( vec3( vPosition.xy, float( i ) / float( count ) * depth ), 1.0 );

				vec4 b = texture2D( map, p.xy / p.w * 0.5 + 0.5 );

				if ( length( b.rgb - ${ground} ) < 0.1 || length( b.rgb - ${grid} ) < 0.1 ) {

					if ( i != count ) {

						b.a = 0.0;

					}

				} else if ( i != 0 ) {

					b.rgb = ${ground} * 0.8;

				}

				a.rgb = a.rgb * a.a + b.rgb * b.a * ( 1.0 - a.a );
				a.a = a.a + b.a * ( 1.0 - a.a );

			}

			gl_FragColor = a;

		}

		`,
    uniforms: {
        map: {
            value: texture
        },
        depth: {
            value: 0.20
        }
    }
} );

const tessellation = new THREE.Mesh( new THREE.PlaneGeometry( 2, 2 ), material );
scene.add( tessellation );

const rtt = new THREE.WebGLRenderTarget( window.innerWidth * window.devicePixelRatio, window.innerHeight * window.devicePixelRatio );

const array = [ diamond, gold, lava, uranium, amethyst ];

let text = '';

for ( let i = 0; i < array.length; i ++ ) {

	text += 'length( ' + array[ i ] + ' - gl_FragColor.rgb ) > 0.1';

	if ( i < array.length - 1 ) {

		text += ' && ';

	}

}

const maskMaterial = new THREE.RawShaderMaterial( {
	vertexShader: `

	precision mediump float;

	attribute vec3 position;
	attribute vec2 uv;

	uniform mat4 projectionMatrix;
	uniform mat4 modelViewMatrix;

	varying vec2 vUv;

	void main() {

		gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
		vUv = uv;

	}

	`,
	fragmentShader: `

	precision mediump float;

	uniform sampler2D texture;
	uniform bool enableParticles;
	uniform bool enableGlow;

	varying vec2 vUv;

	void main() {

		gl_FragColor = texture2D( texture, vUv );

		float value = length( ${particle} - gl_FragColor.rgb ) / 0.2;

		if ( enableParticles && gl_FragColor.r == 0.0 && gl_FragColor.b == 1.0 ) {

			gl_FragColor = vec4( 1.0, 1.0 - gl_FragColor.g, gl_FragColor.g * 0.5 + 0.5, 1.0 );

		} else if ( ! enableGlow || ${text} ) {

			gl_FragColor = vec4( 0.0 );

		}

	}

	`,
	uniforms: {
		texture: { value: undefined },
		enableParticles: { value: true },
		enableGlow: { value: true }
	}
} );

function toVec3( color ) {

	if ( color.isColor ) {

		return 'vec3(' + color.r + ', ' + color.g + ', ' + color.b + ')';

	} else {

		const [ r, g, b ] = toRGB( color );

		return 'vec3(' + r + ', ' + g + ', ' + b + ')';

	}

}

function toRGB( hex ) {

	return [
		parseInt( hex.slice( 1, 3 ), 16 ) / 255,
		parseInt( hex.slice( 3, 5 ), 16 ) / 255,
		parseInt( hex.slice( 5, 7 ), 16 ) / 255
	]

}

const bloomScene = new THREE.Scene();
bloomScene.background = null;

const bloomCamera = new THREE.OrthographicCamera();

bloomCamera.position.z = 5;

const mask = new THREE.Mesh( new THREE.PlaneGeometry( 2, 2 ), maskMaterial );
bloomScene.add( mask );

const finalPass = new THREE.ShaderPass(
	new THREE.ShaderMaterial( {
		uniforms: {
			baseTexture: { value: null },
			originalTexture: { value: undefined }
		},
		vertexShader: `

		varying vec2 vUv;

		void main() {

			vUv = uv;

			gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );

		}

		`,
		fragmentShader: `

		uniform sampler2D baseTexture;
		uniform sampler2D originalTexture;

		varying vec2 vUv;

		void main() {

			gl_FragColor = texture2D( originalTexture, vUv ) + texture2D( baseTexture, vUv );

		}

		`,
		defines: {}
	} ), 'baseTexture'
);

const params = {
	exposure: 1,
	bloomStrength: 0.5,
	bloomThreshold: 0,
	bloomRadius: 0
};

const bloomPass = new THREE.UnrealBloomPass( new THREE.Vector2( window.innerWidth, window.innerHeight ), 1.5, 0.4, 0.85 );
bloomPass.threshold = params.bloomThreshold;
bloomPass.strength = params.bloomStrength;
bloomPass.radius = params.bloomRadius;

const renderPass = new THREE.RenderPass( bloomScene, bloomCamera );

const composer = new THREE.EffectComposer( renderer );
composer.addPass( renderPass );
composer.addPass( bloomPass );
composer.addPass( finalPass );

window.addEventListener( 'resize', function () {

	composer.setSize( window.innerWidth, window.innerHeight );

	renderer.setSize( window.innerWidth, window.innerHeight );

	rtt.setSize( window.innerWidth, window.innerHeight );

	render();

} );

window.requestAnimationFrame = new Proxy( window.requestAnimationFrame, {
	apply( target, thisArgs, args ) {

		args[ 0 ] = new Proxy( args[ 0 ], {
			apply() {

				Reflect.apply( ...arguments );

				render();

			}
		} )

		Reflect.apply( ...arguments );

	}
} );

function particlesEnabled() {

	return maskMaterial.uniforms.enableParticles.value === true;

}

function glowEnabled() {

	return maskMaterial.uniforms.enableGlow.value === true;

}

function render() {

	if ( ! ( enable3d || glowEnabled() || particlesEnabled() ) ) {

		if ( canvas.style.opacity === '0' ) {

			canvas.style.opacity = '1';
			renderer.domElement.style.display = 'none';

		}

		return;

	} else {

		if ( canvas.style.opacity === '1' ) {

			canvas.style.opacity = '0';
			renderer.domElement.style.display = '';

		}

	}

	texture.needsUpdate = true;

	bloomPass.strength = ( Math.sin( Date.now() / 150 ) * 0.5 + 0.5 ) * 0.75 + 0.5;

	if ( enable3d ) {

		finalPass.material.uniforms.originalTexture.value = maskMaterial.uniforms.texture.value = rtt.texture;

		renderer.setRenderTarget( rtt );
		renderer.render( scene, camera );

		renderer.setRenderTarget( null );

	} else {

		finalPass.material.uniforms.originalTexture.value = maskMaterial.uniforms.texture.value = texture;

	}

	composer.render();

}