<!DOCTYPE html> <html lang="en"> <head> <title>three.js webgl - materials - custom blending</title> <meta charset="utf-8"> <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_pre { background: transparent } #btn_rsub, #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> 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 src="../build/three.min.js"></script> <script src="js/Detector.js"></script> <script> if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); var camera, scene, renderer; var materialBg; var materials = []; var mapsPre = []; var mapsNoPre = []; var currentMaps = mapsNoPre; var currentIndex = 4; init(); animate(); function init() { // CAMERA camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 ); camera.position.z = 700; // SCENE scene = new THREE.Scene(); // BACKGROUND IMAGES var x = document.createElement( "canvas" ); var xc = x.getContext( "2d" ); x.width = x.height = 128; xc.fillStyle = "#eee"; xc.fillRect( 0, 0, 128, 128 ); xc.fillStyle = "#999"; xc.fillRect( 0, 0, 64, 64 ); xc.fillStyle = "#aaa"; xc.fillRect( 32, 32, 32, 32 ); xc.fillStyle = "#999"; xc.fillRect( 64, 64, 64, 64 ); xc.fillStyle = "#bbb"; xc.fillRect( 96, 96, 32, 32 ); document.getElementById("bg_1").appendChild( x ); var x2 = document.createElement( "canvas" ); var xc2 = x2.getContext( "2d" ); x2.width = x2.height = 128; xc2.fillStyle = "#444"; xc2.fillRect( 0, 0, 128, 128 ); xc2.fillStyle = "#000"; xc2.fillRect( 0, 0, 64, 64 ); xc2.fillStyle = "#111"; xc2.fillRect( 32, 32, 32, 32 ); xc2.fillStyle = "#000"; xc2.fillRect( 64, 64, 64, 64 ); xc2.fillStyle = "#222"; xc2.fillRect( 96, 96, 32, 32 ); document.getElementById("bg_1").appendChild( x ); document.getElementById("bg_2").appendChild( x2 ); var mapBg0 = new THREE.Texture( x ); mapBg0.wrapS = mapBg0.wrapT = THREE.RepeatWrapping; mapBg0.repeat.set( 128, 64 ); mapBg0.needsUpdate = true; var mapBg1 = new THREE.Texture( x2 ); mapBg1.wrapS = mapBg1.wrapT = THREE.RepeatWrapping; mapBg1.repeat.set( 128, 64 ); mapBg1.needsUpdate = true; var mapBg2 = THREE.ImageUtils.loadTexture( "textures/disturb.jpg" ); mapBg2.wrapS = mapBg2.wrapT = THREE.RepeatWrapping; mapBg2.repeat.set( 8, 4 ); var mapBg3 = THREE.ImageUtils.loadTexture( "textures/crate.gif" ); mapBg3.wrapS = mapBg3.wrapT = THREE.RepeatWrapping; mapBg3.repeat.set( 32, 16 ); var mapBg4 = THREE.ImageUtils.loadTexture( "textures/lava/lavatile.jpg" ); mapBg4.wrapS = mapBg4.wrapT = THREE.RepeatWrapping; mapBg4.repeat.set( 8, 4 ); var mapBg5 = THREE.ImageUtils.loadTexture( "textures/water.jpg" ); mapBg5.wrapS = mapBg5.wrapT = THREE.RepeatWrapping; mapBg5.repeat.set( 8, 4 ); var mapBg6 = THREE.ImageUtils.loadTexture( "textures/lava/cloud.png" ); mapBg6.wrapS = mapBg6.wrapT = THREE.RepeatWrapping; mapBg6.repeat.set( 2, 1 ); // BACKGROUND materialBg = new THREE.MeshBasicMaterial( { map: mapBg1 } ); var meshBg = new THREE.Mesh( new THREE.PlaneBufferGeometry( 4000, 2000 ), materialBg ); meshBg.position.set( 0, 0, -1 ); scene.add( meshBg ); // FOREGROUND IMAGES var 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 ( var i = 0; i < images.length; i ++ ) { var map = THREE.ImageUtils.loadTexture( images[ i ] ); var mapPre = map.clone(); mapPre.premultiplyAlpha = true; mapPre.needsUpdate = true; mapsNoPre.push( map ); mapsPre.push( mapPre ); } // FOREGROUND OBJECTS var blendings = [ "NoBlending", "NormalBlending", "AdditiveBlending", "SubtractiveBlending", "MultiplyBlending", "AdditiveAlphaBlending" ]; var src = [ "ZeroFactor", "OneFactor", "SrcAlphaFactor", "OneMinusSrcAlphaFactor", "DstAlphaFactor", "OneMinusDstAlphaFactor", "DstColorFactor", "OneMinusDstColorFactor", "SrcAlphaSaturateFactor" ]; var dst = [ "ZeroFactor", "OneFactor", "SrcColorFactor", "OneMinusSrcColorFactor", "SrcAlphaFactor", "OneMinusSrcAlphaFactor", "DstAlphaFactor", "OneMinusDstAlphaFactor" ]; var geo1 = new THREE.PlaneBufferGeometry( 100, 100 ); var geo2 = new THREE.PlaneBufferGeometry( 100, 25 ); var blending = "CustomBlending"; for ( var i = 0; i < dst.length; i ++ ) { var blendDst = dst[ i ]; for ( var j = 0; j < src.length; j ++ ) { var blendSrc = src[ j ]; var material = new THREE.MeshBasicMaterial( { map: currentMaps[ currentIndex ] } ); material.transparent = true; material.blending = THREE[ blending ]; material.blendSrc = THREE[ blendSrc ]; material.blendDst = THREE[ blendDst ]; material.blendEquation = THREE.AddEquation; var x = ( j - src.length / 2 ) * 110; var z = 0; var y = ( i - dst.length / 2 ) * 110 + 50; var mesh = new THREE.Mesh( geo1, material ); mesh.position.set( x, y, z ); mesh.matrixAutoUpdate = false; mesh.updateMatrix(); scene.add( mesh ); materials.push( material ); } } for ( var j = 0; j < src.length; j ++ ) { var blendSrc = src[ j ]; var x = ( j - src.length / 2 ) * 110; var z = 0; var y = ( 0 - dst.length / 2 ) * 110 + 50; var mesh = new THREE.Mesh( geo2, generateLabelMaterial( blendSrc.replace( "Factor", "" ), "rgba( 0, 150, 0, 1 )" ) ); mesh.position.set( x, - (y - 70), z ); mesh.matrixAutoUpdate = false; mesh.updateMatrix(); scene.add( mesh ); } for ( var i = 0; i < dst.length; i ++ ) { var blendDst = dst[ i ]; var x = ( 0 - src.length / 2 ) * 110 - 125; var z = 0; var y = ( i - dst.length / 2 ) * 110 + 165; var mesh = new THREE.Mesh( geo2, generateLabelMaterial( blendDst.replace( "Factor", "" ), "rgba( 150, 0, 0, 1 )" ) ); mesh.position.set( x, - (y - 70), 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, false ); 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 ); addPreHandler( "btn_pre", mapsPre ); addPreHandler( "btn_nopre", mapsNoPre ); } // function addImgHandler( id, index ) { var el = document.getElementById( id ); el.addEventListener( 'click', function () { for ( var i = 0; i < materials.length; i ++ ) { materials[ i ].map = currentMaps[ index ]; } currentIndex = index; } ); } function addEqHandler( id, eq ) { var el = document.getElementById( id ); el.addEventListener( 'click', function () { for ( var 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"; el.style.backgroundColor = "darkorange"; }); } function addBgHandler( id, map ) { var el = document.getElementById( id ); el.addEventListener( 'click', function () { materialBg.map = map; } ); } function addPreHandler( id, marray ) { var el = document.getElementById( id ); el.addEventListener( 'click', function () { currentMaps = marray; for ( var 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( event ) { renderer.setSize( window.innerWidth, window.innerHeight ); camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); } // function generateLabelMaterial( text, bg ) { var x = document.createElement( "canvas" ); var xc = x.getContext( "2d" ); x.width = 128; x.height = 32; xc.fillStyle = bg; xc.fillRect( 0, 0, 128, 32 ); //xc.shadowColor = "#000"; //xc.shadowBlur = 3; xc.fillStyle = "white"; xc.font = "12pt arial bold"; xc.fillText( text, 8, 22 ); var map = new THREE.Texture( x ); map.needsUpdate = true; var material = new THREE.MeshBasicMaterial( { map: map, transparent: true } ); return material; } function animate() { requestAnimationFrame( animate ); var time = Date.now() * 0.00025; var ox = ( time * -0.01 * materialBg.map.repeat.x ) % 1; var oy = ( time * -0.01 * materialBg.map.repeat.y ) % 1; materialBg.map.offset.set( ox, oy ); renderer.render( scene, camera ); } </script> </body> </html>