DigDig.IO Effects

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

目前為 2021-08-23 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         DigDig.IO Effects
// @namespace    http://tampermonkey.net/
// @version      0.1.6
// @description  3D, particles and glow effect for DigDig.IO. Use num keys from 1 to 3 to toggle effects
// @author       Zertalious (Zert)
// @match        *://digdig.io/*
// @icon         https://www.google.com/s2/favicons?domain=digdig.io
// @grant        none
// @require      https://unpkg.com/three@latest/build/three.min.js
// @require      https://unpkg.com/three@latest/examples/js/postprocessing/EffectComposer.js
// @require      https://unpkg.com/three@latest/examples/js/postprocessing/RenderPass.js
// @require      https://unpkg.com/three@latest/examples/js/postprocessing/UnrealBloomPass.js
// @require      https://unpkg.com/three@latest/examples/js/postprocessing/ShaderPass.js
// @require      https://unpkg.com/three@latest/examples/js/shaders/LuminosityHighPassShader.js
// @require      https://unpkg.com/three@latest/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 ) {

			const height = ctx.getTransform().d;

			if ( height > window.innerHeight * 0.9 ) {

				return;

			} if ( height < 10 && particlesEnabled() ) {

				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.getTransform().d > window.innerHeight * 0.9 ) {

						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( { alpha: 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 );

document.body.insertBefore( renderer.domElement, canvas );

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

camera.position.z = Math.sin( Math.PI / 3 );

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 material = new THREE.RawShaderMaterial( {
	vertexShader: `

	precision mediump float;

	attribute vec3 position;
	attribute vec2 uv;

	uniform mat4 projectionMatrix;
	uniform mat4 modelViewMatrix;

	uniform sampler2D texture;
	uniform float groundDepth;

	varying vec2 vUv;
	varying float vDepth;

	void main() {

		vec4 p = vec4( position, 1.0 );

		vec3 texColor = texture2D( texture, uv ).rgb;

		if ( length( ${ground} - texColor ) < 0.05 ) p.z -= groundDepth;

		vDepth = - p.z;

		gl_Position = projectionMatrix * modelViewMatrix * p;
		vUv = uv;

	}

	`,
	fragmentShader: `

	precision mediump float;

	uniform sampler2D texture;
	uniform float groundDepth;

	varying vec2 vUv;
	varying float vDepth;

	void main() {

		if ( vDepth > 0.0 && vDepth < groundDepth ) {

			gl_FragColor = vec4( ${ground} * 0.8, 1.0 );

		} else {

			gl_FragColor = texture2D( texture, vUv );

		}

	}

	`,
	uniforms: {
		texture: { value: texture },
		groundDepth: { value: 0.10 }
	}
} );

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

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

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

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 = parseInt( color.slice( 1, 3 ), 16 ) / 255;
		const g = parseInt( color.slice( 3, 5 ), 16 ) / 255;
		const b = parseInt( color.slice( 5, 7 ), 16 ) / 255;

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

	}

}

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();

}