三个js混合两个背景图像

时间:2018-04-28 12:04:50

标签: three.js

我做了一个游戏,它有一个绿色图像素材的地面网格,我想要做的是当一个特定事件发生时,假设点击一个按钮,背景图像可以逐渐变成另一个图像,如混合,但是我不知道threejs中的哪个函数可以做到这一点。

1 个答案:

答案 0 :(得分:0)

第一种方法是简单地使用canvas作为纹理并重绘canvas元素本身。这里的缺点是每次更改它的值时都需要将更新的画布带入绘图缓冲区,因此它不理想,但它可以工作(单击渲染器以淡化纹理):

// I have compressed this function as its just an utility to just draw a circle in two colors to use as example images and prevent cross-origin issues.
function anImage( color1, color2 ){ var canvas = document.createElement( 'canvas' ), ctx = canvas.getContext( '2d' ); canvas.width = 256; canvas.height = 256; ctx.fillStyle = color1; ctx.fillRect( 0, 0, 400, 400 ); ctx.fillStyle = color2; ctx.arc( 200, 200, 200, 0, Math.PI * 2 ); ctx.fill(); return canvas; }

function drawTexture(){
	
	// Draw the first image full opaque
	
	ctx.globalAlpha = 1;

	ctx.drawImage( image1, 0, 0, 512, 512 );

	// Draw the second image as transparent as its transition requires
	
	ctx.globalAlpha = state;

	ctx.drawImage( image2, 0, 0, 512, 512 );

	texture.needsUpdate = true;

}
function render(){

	state = targetState >= state ? state + .01 : state - .01;
	state = state < 0 ? 0 : state > 1 ? 1 : state;

	drawTexture();
	
	cube.rotation.y += .01;

	renderer.render( scene, camera );

	window.requestAnimationFrame( render );

}

var image1 = anImage( 'red', 'yellow' );
var image2 = anImage( 'blue', 'green' );
var renderer = new THREE.WebGLRenderer;
var camera = new THREE.PerspectiveCamera;
var scene = new THREE.Scene;
var canvas = document.createElement( 'canvas' );
var ctx = canvas.getContext( '2d' );
var state = 0;
var targetState = 0;

// Lets set up our canvas for the texture

canvas.width = 512;
canvas.height = 512;

ctx.drawImage( image1, 0, 0, 512, 512 );

var texture = new THREE.Texture( canvas );
var cube = new THREE.Mesh(
  new THREE.BoxGeometry,
  new THREE.MeshBasicMaterial({ map: texture })
);

scene.add( cube );

camera.position.set( 0, 0, 5 );
camera.lookAt( scene.position );

renderer.domElement.addEventListener( 'click', event => {
	targetState = targetState === 1 ? 0 : 1
});
renderer.setSize( 512, 512 );

render();

document.body.appendChild( renderer.domElement );
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/92/three.min.js"></script>

第二种方法是使用您可以自己构建的特殊ShaderMaterial。它要求一些制服(包括我们的textures)和我们可以修改的值,我们将调用fade,这将是我们的。然后我们需要编写自己的vertex着色器 - 这很简单,我们只使用我们可以在THREE.js文档中找到的默认位置。然后我们需要添加我们的fragment着色器,它会为像素着色。在这里,我们在那时阅读我们的颜色并将它们混合在一起。我们还必须从uv着色器中调出vertex,因此我们知道在哪里查找像素。这种方法效率更高,因为纹理被缓冲一次而后从未触及,让我们的GPU处理繁重的工作。

function anImage( color1, color2 ){ var canvas = document.createElement( 'canvas' ), ctx = canvas.getContext( '2d' ); canvas.width = 256; canvas.height = 256; ctx.fillStyle = color1; ctx.fillRect( 0, 0, 400, 400 ); ctx.fillStyle = color2; ctx.arc( 200, 200, 200, 0, Math.PI * 2 ); ctx.fill(); return canvas; }
function render(){

  state = targetState >= state ? state + .01 : state - .01;
  state = state < 0 ? 0 : state > 1 ? 1 : state;
	
  // Set the fade value in the uniforms
  cube.material.uniforms.fade.value = state;
  cube.rotation.y += .01;

  renderer.render( scene, camera );

  window.requestAnimationFrame( render );

}

var texture1 = new THREE.Texture( anImage( 'red', 'yellow' ) );
var texture2 = new THREE.Texture( anImage( 'blue', 'green' ) );
var renderer = new THREE.WebGLRenderer;
var camera = new THREE.PerspectiveCamera;
var scene = new THREE.Scene;
var canvas = document.createElement( 'canvas' );
var ctx = canvas.getContext( '2d' );
var state = 0;
var targetState = 0;

texture1.needsUpdate = true;
texture2.needsUpdate = true;

var cube = new THREE.Mesh(
  new THREE.BoxGeometry,
  new THREE.ShaderMaterial({
    uniforms: {
  	
      fade: { type: 'f', value: 0 },
      texture1: { value: texture1 },
      texture2: { value: texture2 }
  		
    },
    vertexShader: `

      // Define the uv we want to pass to our fragment shader
      varying vec2 vUv;
  		
      void main(){
  		
        vUv = uv;
        gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
			
      }
		
    `,
    fragmentShader: `
  	
      // Read our uv and textures, as well as fade value
      uniform sampler2D texture1;
      uniform sampler2D texture2;
      uniform float fade;
      varying vec2 vUv;
  		
      void main(){
  		
        // Read our pixel colors as rgba
        vec4 t1 = texture2D( texture1, vUv );
        vec4 t2 = texture2D( texture2, vUv );
  			
        // Mix our pixels together based on fade value
        gl_FragColor = mix( t1, t2, fade );
  			
      }
  		
    `
  })
);

scene.add( cube );

camera.position.set( 0, 0, 5 );
camera.lookAt( scene.position );

renderer.domElement.addEventListener( 'click', event => {
  targetState = targetState === 1 ? 0 : 1
});
renderer.setSize( 512, 512 );

render();

document.body.appendChild( renderer.domElement );
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/92/three.min.js"></script>