Files
apt-nl-map/static/Magic4/js/three.js-dev/examples/webgl_materials_blending_custom.html
2024-12-04 10:21:04 +08:00

470 lines
13 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - materials - custom blending</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
margin: 0px;
background-color: #111;
overflow: hidden;
font-family: arial;
}
.menu { color: #fff; font-weight: bold; font-size: 12px; z-index: 100; width: 75px; position: absolute; top: 0px; padding: 16px; }
.menu img, .menu canvas { width: 75px; margin: 10px 0 }
#images { background: rgba(0,0,0,0); left: 0px; }
#backgrounds { background: rgba(0,0,0,0.0); left: 107px; }
#labels { background: rgba(0,0,0,0.75); left: 214px; width: 100px }
.lbl { color: #fff; z-index: 150; float:left; padding: 0.25em; width: 75px; display: block }
#lbl_dst { background:#800; }
#lbl_src { background:green; }
.btn { background: darkorange; width: 100px; cursor: pointer }
#btn_sub { background: transparent }
#btn_rsub { background: transparent }
#btn_min { background: transparent }
#btn_max { background: transparent }
#btn_pre { background: transparent }
#btn_max, #btn_nopre { margin-bottom: 2em }
</style>
</head>
<body>
<div id="images" class="menu">
Foreground
<a id="img_0" href="#"><img src="textures/disturb.jpg" /></a>
<a id="img_1" href="#"><img src="textures/sprite0.jpg" /></a>
<a id="img_2" href="#"><img src="textures/sprite0.png" /></a>
<a id="img_3" href="#"><img src="textures/lensflare/lensflare0.png" /></a>
<a id="img_4" href="#"><img src="textures/lensflare/lensflare0_alpha.png" /></a>
<a id="img_5" href="#"><img src="textures/sprites/ball.png" /></a>
<a id="img_6" href="#"><img src="textures/sprites/snowflake7_alpha.png" /></a>
</div>
<div id="backgrounds" class="menu">
Background
<a id="bg_0" href="#"><img src="textures/disturb.jpg" /></a>
<a id="bg_1" href="#"></a>
<a id="bg_2" href="#"></a>
<a id="bg_3" href="#"><img src="textures/crate.gif" /></a>
<a id="bg_4" href="#"><img src="textures/lava/lavatile.jpg" /></a>
<a id="bg_5" href="#"><img src="textures/water.jpg" /></a>
<a id="bg_6" href="#"><img src="textures/lava/cloud.png" /></a>
</div>
<div id="labels" class="menu">
Equation<br/><br/>
<div class="lbl btn" id="btn_add">Add</div>
<div class="lbl btn" id="btn_sub">Subtract</div>
<div class="lbl btn" id="btn_rsub">ReverseSubtract</div>
<div class="lbl btn" id="btn_min">Min</div>
<div class="lbl btn" id="btn_max">Max</div>
Premultiply alpha<br/><br/>
<div class="lbl btn" id="btn_pre">On</div>
<div class="lbl btn" id="btn_nopre">Off</div>
Labels<br/><br/>
<div class="lbl" id="lbl_src">Source</div>
<div class="lbl" id="lbl_dst">Destination</div>
</div>
<script type="module">
import * as THREE from '../build/three.module.js';
let camera, scene, renderer;
let materialBg;
const materials = [];
const mapsPre = [];
const mapsNoPre = [];
let currentMaps = mapsNoPre;
let currentIndex = 4;
init();
animate();
function init() {
// CAMERA
camera = new THREE.PerspectiveCamera( 80, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.z = 700;
// SCENE
scene = new THREE.Scene();
// TEXTURE LOADER
const textureLoader = new THREE.TextureLoader();
// BACKGROUND IMAGES
const canvas1 = document.createElement( 'canvas' );
const ctx1 = canvas1.getContext( '2d' );
canvas1.width = canvas1.height = 128;
ctx1.fillStyle = '#eee';
ctx1.fillRect( 0, 0, 128, 128 );
ctx1.fillStyle = '#999';
ctx1.fillRect( 0, 0, 64, 64 );
ctx1.fillStyle = '#aaa';
ctx1.fillRect( 32, 32, 32, 32 );
ctx1.fillStyle = '#999';
ctx1.fillRect( 64, 64, 64, 64 );
ctx1.fillStyle = '#bbb';
ctx1.fillRect( 96, 96, 32, 32 );
document.getElementById( 'bg_1' ).appendChild( canvas1 );
const canvas2 = document.createElement( 'canvas' );
const ctx2 = canvas2.getContext( '2d' );
canvas2.width = canvas2.height = 128;
ctx2.fillStyle = '#444';
ctx2.fillRect( 0, 0, 128, 128 );
ctx2.fillStyle = '#000';
ctx2.fillRect( 0, 0, 64, 64 );
ctx2.fillStyle = '#111';
ctx2.fillRect( 32, 32, 32, 32 );
ctx2.fillStyle = '#000';
ctx2.fillRect( 64, 64, 64, 64 );
ctx2.fillStyle = '#222';
ctx2.fillRect( 96, 96, 32, 32 );
document.getElementById( 'bg_2' ).appendChild( canvas2 );
const mapBg0 = new THREE.CanvasTexture( canvas1 );
mapBg0.wrapS = mapBg0.wrapT = THREE.RepeatWrapping;
mapBg0.repeat.set( 128, 64 );
const mapBg1 = new THREE.CanvasTexture( canvas2 );
mapBg1.wrapS = mapBg1.wrapT = THREE.RepeatWrapping;
mapBg1.repeat.set( 128, 64 );
const mapBg2 = textureLoader.load( 'textures/disturb.jpg' );
mapBg2.wrapS = mapBg2.wrapT = THREE.RepeatWrapping;
mapBg2.repeat.set( 8, 4 );
const mapBg3 = textureLoader.load( 'textures/crate.gif' );
mapBg3.wrapS = mapBg3.wrapT = THREE.RepeatWrapping;
mapBg3.repeat.set( 32, 16 );
const mapBg4 = textureLoader.load( 'textures/lava/lavatile.jpg' );
mapBg4.wrapS = mapBg4.wrapT = THREE.RepeatWrapping;
mapBg4.repeat.set( 8, 4 );
const mapBg5 = textureLoader.load( 'textures/water.jpg' );
mapBg5.wrapS = mapBg5.wrapT = THREE.RepeatWrapping;
mapBg5.repeat.set( 8, 4 );
const mapBg6 = textureLoader.load( 'textures/lava/cloud.png' );
mapBg6.wrapS = mapBg6.wrapT = THREE.RepeatWrapping;
mapBg6.repeat.set( 2, 1 );
// BACKGROUND
materialBg = new THREE.MeshBasicMaterial( { map: mapBg1 } );
const meshBg = new THREE.Mesh( new THREE.PlaneGeometry( 4000, 2000 ), materialBg );
meshBg.position.set( 0, 0, - 1 );
scene.add( meshBg );
// FOREGROUND IMAGES
const images = [ 'textures/disturb.jpg',
'textures/sprite0.jpg',
'textures/sprite0.png',
'textures/lensflare/lensflare0.png',
'textures/lensflare/lensflare0_alpha.png',
'textures/sprites/ball.png',
'textures/sprites/snowflake7_alpha.png' ];
for ( let i = 0; i < images.length; i ++ ) {
const map = textureLoader.load( images[ i ] );
mapsNoPre.push( map );
const mapPre = textureLoader.load( images[ i ] );
mapPre.premultiplyAlpha = true;
mapPre.needsUpdate = true;
mapsPre.push( mapPre );
}
// FOREGROUND OBJECTS
const src = [
{ name: 'Zero', constant: THREE.ZeroFactor },
{ name: 'One', constant: THREE.OneFactor },
{ name: 'SrcColor', constant: THREE.SrcColorFactor },
{ name: 'OneMinusSrcColor', constant: THREE.OneMinusSrcColorFactor },
{ name: 'SrcAlpha', constant: THREE.SrcAlphaFactor },
{ name: 'OneMinusSrcAlpha', constant: THREE.OneMinusSrcAlphaFactor },
{ name: 'DstAlpha', constant: THREE.DstAlphaFactor },
{ name: 'OneMinusDstAlpha', constant: THREE.OneMinusDstAlphaFactor },
{ name: 'DstColor', constant: THREE.DstColorFactor },
{ name: 'OneMinusDstColor', constant: THREE.OneMinusDstColorFactor },
{ name: 'SrcAlphaSaturate', constant: THREE.SrcAlphaSaturateFactor }
];
const dst = [
{ name: 'Zero', constant: THREE.ZeroFactor },
{ name: 'One', constant: THREE.OneFactor },
{ name: 'SrcColor', constant: THREE.SrcColorFactor },
{ name: 'OneMinusSrcColor', constant: THREE.OneMinusSrcColorFactor },
{ name: 'SrcAlpha', constant: THREE.SrcAlphaFactor },
{ name: 'OneMinusSrcAlpha', constant: THREE.OneMinusSrcAlphaFactor },
{ name: 'DstAlpha', constant: THREE.DstAlphaFactor },
{ name: 'OneMinusDstAlpha', constant: THREE.OneMinusDstAlphaFactor },
{ name: 'DstColor', constant: THREE.DstColorFactor },
{ name: 'OneMinusDstColor', constant: THREE.OneMinusDstColorFactor }
];
const geo1 = new THREE.PlaneGeometry( 100, 100 );
const geo2 = new THREE.PlaneGeometry( 100, 25 );
for ( let i = 0; i < dst.length; i ++ ) {
const blendDst = dst[ i ];
for ( let j = 0; j < src.length; j ++ ) {
const blendSrc = src[ j ];
const material = new THREE.MeshBasicMaterial( { map: currentMaps[ currentIndex ] } );
material.transparent = true;
material.blending = THREE.CustomBlending;
material.blendSrc = blendSrc.constant;
material.blendDst = blendDst.constant;
material.blendEquation = THREE.AddEquation;
const x = ( j - src.length / 2 ) * 110;
const z = 0;
const y = ( i - dst.length / 2 ) * 110 + 50;
const mesh = new THREE.Mesh( geo1, material );
mesh.position.set( x, - y, z );
mesh.matrixAutoUpdate = false;
mesh.updateMatrix();
scene.add( mesh );
materials.push( material );
}
}
for ( let j = 0; j < src.length; j ++ ) {
const blendSrc = src[ j ];
const x = ( j - src.length / 2 ) * 110;
const z = 0;
const y = ( 0 - dst.length / 2 ) * 110 + 50;
const mesh = new THREE.Mesh( geo2, generateLabelMaterial( blendSrc.name, 'rgba( 0, 150, 0, 1 )' ) );
mesh.position.set( x, - ( y - 70 ), z );
mesh.matrixAutoUpdate = false;
mesh.updateMatrix();
scene.add( mesh );
}
for ( let i = 0; i < dst.length; i ++ ) {
const blendDst = dst[ i ];
const x = ( 0 - src.length / 2 ) * 110 - 125;
const z = 0;
const y = ( i - dst.length / 2 ) * 110 + 165;
const mesh = new THREE.Mesh( geo2, generateLabelMaterial( blendDst.name, 'rgba( 150, 0, 0, 1 )' ) );
mesh.position.set( x, - ( y - 120 ), z );
mesh.matrixAutoUpdate = false;
mesh.updateMatrix();
scene.add( mesh );
}
// RENDERER
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.domElement.style.position = 'absolute';
renderer.domElement.style.left = '215px';
document.body.appendChild( renderer.domElement );
// EVENTS
window.addEventListener( 'resize', onWindowResize );
addImgHandler( 'img_0', 0 );
addImgHandler( 'img_1', 1 );
addImgHandler( 'img_2', 2 );
addImgHandler( 'img_3', 3 );
addImgHandler( 'img_4', 4 );
addImgHandler( 'img_5', 5 );
addImgHandler( 'img_6', 6 );
addBgHandler( 'bg_0', mapBg2 );
addBgHandler( 'bg_1', mapBg0 );
addBgHandler( 'bg_2', mapBg1 );
addBgHandler( 'bg_3', mapBg3 );
addBgHandler( 'bg_4', mapBg4 );
addBgHandler( 'bg_5', mapBg5 );
addBgHandler( 'bg_6', mapBg6 );
addEqHandler( 'btn_add', THREE.AddEquation );
addEqHandler( 'btn_sub', THREE.SubtractEquation );
addEqHandler( 'btn_rsub', THREE.ReverseSubtractEquation );
addEqHandler( 'btn_min', THREE.MinEquation );
addEqHandler( 'btn_max', THREE.MaxEquation );
addPreHandler( 'btn_pre', mapsPre );
addPreHandler( 'btn_nopre', mapsNoPre );
}
//
function addImgHandler( id, index ) {
const el = document.getElementById( id );
el.addEventListener( 'click', function () {
for ( let i = 0; i < materials.length; i ++ ) {
materials[ i ].map = currentMaps[ index ];
}
currentIndex = index;
} );
}
function addEqHandler( id, eq ) {
const el = document.getElementById( id );
el.addEventListener( 'click', function () {
for ( let i = 0; i < materials.length; i ++ ) {
materials[ i ].blendEquation = eq;
}
document.getElementById( 'btn_add' ).style.backgroundColor = 'transparent';
document.getElementById( 'btn_sub' ).style.backgroundColor = 'transparent';
document.getElementById( 'btn_rsub' ).style.backgroundColor = 'transparent';
document.getElementById( 'btn_min' ).style.backgroundColor = 'transparent';
document.getElementById( 'btn_max' ).style.backgroundColor = 'transparent';
el.style.backgroundColor = 'darkorange';
} );
}
function addBgHandler( id, map ) {
const el = document.getElementById( id );
el.addEventListener( 'click', function () {
materialBg.map = map;
} );
}
function addPreHandler( id, marray ) {
const el = document.getElementById( id );
el.addEventListener( 'click', function () {
currentMaps = marray;
for ( let i = 0; i < materials.length; i ++ ) {
materials[ i ].map = currentMaps[ currentIndex ];
}
document.getElementById( 'btn_pre' ).style.backgroundColor = 'transparent';
document.getElementById( 'btn_nopre' ).style.backgroundColor = 'transparent';
el.style.backgroundColor = 'darkorange';
} );
}
//
function onWindowResize() {
renderer.setSize( window.innerWidth, window.innerHeight );
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}
//
function generateLabelMaterial( text, bg ) {
const canvas = document.createElement( 'canvas' );
const ctx = canvas.getContext( '2d' );
canvas.width = 128;
canvas.height = 32;
ctx.fillStyle = bg;
ctx.fillRect( 0, 0, 128, 32 );
ctx.fillStyle = 'white';
ctx.font = '12pt arial bold';
ctx.fillText( text, 8, 22 );
const map = new THREE.CanvasTexture( canvas );
const material = new THREE.MeshBasicMaterial( { map: map, transparent: true } );
return material;
}
function animate() {
requestAnimationFrame( animate );
const time = Date.now() * 0.00025;
const ox = ( time * - 0.01 * materialBg.map.repeat.x ) % 1;
const oy = ( time * - 0.01 * materialBg.map.repeat.y ) % 1;
materialBg.map.offset.set( ox, oy );
renderer.render( scene, camera );
}
</script>
</body>
</html>