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