首页 > 解决方案 > 三.JS | GLSL 使用画布作为着色器统一纹理

问题描述

我正在尝试使用画布作为统一纹理:

uniforms = {
    
    canvasTexture: { type: "t", value: new THREE.Texture(canvas) }
        
};

也试过:

uniforms = {
    
    canvasTexture: { type: "t", value: new THREE.CanvasTexture(canvas) }
        
};

但是除了黑屏我什么都看不到。

我还尝试在 animate() 处更新制服:

mesh.material.uniforms.canvasTexture.needsUpdate = true;

没有任何成功。有什么建议吗?

 
var renderer, scene, camera, canvas, ctx, mesh, canvasTexture;
    
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
document.body.appendChild( renderer.domElement );
renderer.setSize( window.innerWidth, window.innerHeight );
    
camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );

scene = new THREE.Scene();

var canvas = document.createElement("canvas");
canvas.height = window.innerHeight;
canvas.width = window.innerWidth;
ctx = canvas.getContext("2d");

var geometry = new THREE.PlaneBufferGeometry( 2, 2 );
    
uniforms = {
    
    canvasTexture: { type: "t", value: new THREE.Texture(canvas) }
        
};

var material = new THREE.ShaderMaterial( {

    uniforms: uniforms,
    vertexShader: document.getElementById( "vs-canvasTest" ).textContent,
    fragmentShader: document.getElementById( "fs-canvasTest" ).textContent,

} );

mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
    
window.addEventListener("resize", onWindowResize, false);

animate();
    
function onWindowResize() { 
    
    renderer.setSize( window.innerWidth, window.innerHeight );
    
    canvas.height = window.innerHeight;
    canvas.width = window.innerWidth;
        
}
    
function animate() {
    
    requestAnimationFrame( animate );
    renderer.render( scene, camera );
    
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = "#FF0000";
    ctx.fill();
    
    mesh.material.uniforms.canvasTexture.needsUpdate = true;

}
body { margin: 0; }
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Test</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">

    <script src="https://unpkg.com/three@0.106.0/build/three.min.js"></script>

</head>
<body>
    
<script id="vs-canvasTest" type="x-shader/x-vertex">

    varying vec2 vUv;

    void main() {

        vUv = uv;
        gl_Position = vec4( position, 1.0 );

    }

</script>

<script id="fs-canvasTest" type="x-shader/x-fragment">

    varying vec2 vUv;
    uniform sampler2D canvasTexture;

    void main() {

        gl_FragColor = texture2D(canvasTexture, vUv);

    }


</script>

</body>  
</html>

标签: canvasthree.jsglsltextures

解决方案


这是一个小错误,我也经常犯。这是你现在拥有的:

mesh.material.uniforms.canvasTexture.needsUpdate = true;

这是您需要的:

mesh.material.uniforms.canvasTexture.value.needsUpdate = true;

你只需要.valuebefore.needsUpdate所以你的目标是纹理而不是包含纹理的制服。

var renderer, scene, camera, canvas, ctx, mesh, tex;
    
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
document.body.appendChild( renderer.domElement );
renderer.setSize( window.innerWidth, window.innerHeight );
    
camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );

scene = new THREE.Scene();

var canvas = document.createElement("canvas");
canvas.height = window.innerHeight;
canvas.width = window.innerWidth;
ctx = canvas.getContext("2d");

var geometry = new THREE.PlaneBufferGeometry( 2, 2 );

uniforms = {
    
    canvasTexture: { value: new THREE.Texture(canvas) }
        
};

var material = new THREE.ShaderMaterial( {

    uniforms: uniforms,
    vertexShader: document.getElementById( "vs-canvasTest" ).textContent,
    fragmentShader: document.getElementById( "fs-canvasTest" ).textContent,

} );

mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
    
window.addEventListener("resize", onWindowResize, false);

animate();
    
function onWindowResize() { 
    
    renderer.setSize( window.innerWidth, window.innerHeight );
    
    canvas.height = window.innerHeight;
    canvas.width = window.innerWidth;
        
}
    
function animate() {
    
    requestAnimationFrame( animate );
    renderer.render( scene, camera );
    
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = "#FF0000";
    ctx.fill();
    
    mesh.material.uniforms.canvasTexture.value.needsUpdate = true;

}
body { margin: 0; }
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Test</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">

    <script src="https://unpkg.com/three@0.106.0/build/three.min.js"></script>

</head>
<body>
    
<script id="vs-canvasTest" type="x-shader/x-vertex">

    varying vec2 vUv;

    void main() {

        vUv = uv;
        gl_Position = vec4( position, 1.0 );

    }

</script>

<script id="fs-canvasTest" type="x-shader/x-fragment">

    varying vec2 vUv;
    uniform sampler2D canvasTexture;

    void main() {

        gl_FragColor = texture2D(canvasTexture, vUv);

    }


</script>

</body>  
</html>


推荐阅读