【问题标题】:Map image as texture to plane in a custom shader in THREE.js在 THREE.js 的自定义着色器中将图像作为纹理映射到平面
【发布时间】:2020-04-14 08:26:28
【问题描述】:

我正在尝试将 2 个图像加载为纹理,在片段着色器中在它们之间进行插值并将颜色应用于平面。不幸的是,我什至无法显示单个纹理。

我正在创建平面并按如下方式加载图像:

const planeGeometry = new THREE.PlaneBufferGeometry(imageSize * screenRatio, imageSize);

loader.load(
    "textures/IMG_6831.jpeg",
    (image) => {
        texture1 = new THREE.MeshBasicMaterial({ map: image });
        //texture1 = new THREE.Texture({ image: image });
    }
)

当我像往常一样直接使用 MeshBasicMaterial 作为 Mesh 的材质时,它可以正确地在平面上显示图像。当尝试在自定义着色器中做同样的事情时,我只得到黑色:

const uniforms = {
    texture1: { type: "sampler2D", value: texture1 },
    texture2: { type: "sampler2D", value: texture2 }
};

const planeMaterial = new THREE.ShaderMaterial({
    uniforms: uniforms,
    fragmentShader: fragmentShader(),
    vertexShader: vertexShader()
});

const plane = new THREE.Mesh(planeGeometry, planeMaterial);
scene.add(plane);

着色器:

const vertexShader = () => {
    return `
        varying vec2 vUv; 

        void main() {
            vUv = uv; 

            vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0);
            gl_Position = projectionMatrix * modelViewPosition; 
        }
    `;
}

const fragmentShader = () => {
    return `
        uniform sampler2D texture1; 
        uniform sampler2D texture2; 
        varying vec2 vUv;

        void main() {
            vec4 color1 = texture2D(texture1, vUv);
            vec4 color2 = texture2D(texture2, vUv);
            //vec4 fColor = mix(color1, color2, vUv.y);
            //fColor.a = 1.0;
            gl_FragColor = color1;
        }
    `;
}

为了修复它,我尝试了:

  • 通过使用简单的颜色对其进行着色来确保平面可见
  • 通过将 uv 坐标可视化为颜色来确保将 uv 坐标传递给着色器
  • 确保在将 texture1texture2 传递给着色器之前定义它们
  • 使用THREE.Texture 而不是THREE.MeshBasicMaterial
  • 更改 js 中的统一类型 texture1: { type: "t", value: texture1 },

我认为问题可能在于将纹理作为统一传递给着色器。我可能在某处使用了错误的类型。如果有任何帮助,我将不胜感激!

【问题讨论】:

    标签: javascript three.js shader


    【解决方案1】:

    假设loaderTextureLoader,那么它会用纹理调用你

    loader.load(
        "textures/IMG_6831.jpeg",
        (texture) => {
            texture1 = texture;
        }
    )
    

    否则虽然它不是错误,但 type 不再用于 three.js 制服。

    const planeGeometry = new THREE.PlaneBufferGeometry(1, 1);
    const loader = new THREE.TextureLoader();
    let texture1;
    loader.load(
        "https://i.imgur.com/KjUybBD.png",
        (texture) => {
            texture1 = texture;
            start();
        }
    );
    
    const vertexShader = () => {
        return `
            varying vec2 vUv; 
    
            void main() {
                vUv = uv; 
    
                vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0);
                gl_Position = projectionMatrix * modelViewPosition; 
            }
        `;
    }
    
    const fragmentShader = () => {
        return `
            uniform sampler2D texture1; 
            uniform sampler2D texture2; 
            varying vec2 vUv;
    
            void main() {
                vec4 color1 = texture2D(texture1, vUv);
                vec4 color2 = texture2D(texture2, vUv);
                //vec4 fColor = mix(color1, color2, vUv.y);
                //fColor.a = 1.0;
                gl_FragColor = color1;
            }
        `;
    }
    
    function start() {
      const renderer = new THREE.WebGLRenderer();
      document.body.appendChild(renderer.domElement);
      const scene = new THREE.Scene();
      
      const camera = new THREE.Camera();
      
      const uniforms = {
          texture1: { value: texture1 },
          texture2: { value: texture1 },
      };
    
      const planeMaterial = new THREE.ShaderMaterial({
          uniforms: uniforms,
          fragmentShader: fragmentShader(),
          vertexShader: vertexShader()
      });
    
      const plane = new THREE.Mesh(planeGeometry, planeMaterial);
      scene.add(plane);
    
      renderer.render(scene, camera);
    }
    <script src="https://cdn.jsdelivr.net/npm/three@0.111.0/build/three.min.js"></script>

    TextureLoader 也返回一个纹理,所以如果你在 requestAnimationFrame 循环中连续渲染,你可以这样写

    const planeGeometry = new THREE.PlaneBufferGeometry(1, 1);
    const loader = new THREE.TextureLoader();
    const texture1 = loader.load("https://i.imgur.com/KjUybBD.png");
    const texture2 = loader.load("https://i.imgur.com/UKBsvV0.jpg");
    
    const vertexShader = () => {
        return `
            varying vec2 vUv; 
    
            void main() {
                vUv = uv; 
    
                vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0);
                gl_Position = projectionMatrix * modelViewPosition; 
            }
        `;
    }
    
    const fragmentShader = () => {
        return `
            uniform sampler2D texture1; 
            uniform sampler2D texture2; 
            varying vec2 vUv;
    
            void main() {
                vec4 color1 = texture2D(texture1, vUv);
                vec4 color2 = texture2D(texture2, vUv);
                gl_FragColor = mix(color1, color2, vUv.y);
            }
        `;
    }
    
    const renderer = new THREE.WebGLRenderer();
    document.body.appendChild(renderer.domElement);
    const scene = new THREE.Scene();
    
    const camera = new THREE.Camera();
    
    const uniforms = {
        texture1: { value: texture1 },
        texture2: { value: texture2 },
    };
    
    const planeMaterial = new THREE.ShaderMaterial({
        uniforms: uniforms,
        fragmentShader: fragmentShader(),
        vertexShader: vertexShader()
    });
    
    const plane = new THREE.Mesh(planeGeometry, planeMaterial);
    scene.add(plane);
    
    function render() {
      renderer.render(scene, camera);
      requestAnimationFrame(render);
    }
    requestAnimationFrame(render);
    <script src="https://cdn.jsdelivr.net/npm/three@0.111.0/build/three.min.js"></script>

    纹理将是空白的,但 three.js 会在图像加载后更新它们。

    您可能对更多up to date tutorials 感兴趣

    【讨论】:

    • 是的,问题在于从加载器分配纹理。我将:texture1 = new THREE.MeshBasicMaterial({ map: image }); 更改为:texture1 = image;,它起作用了。谢谢!
    猜你喜欢
    • 2012-09-19
    • 2017-01-17
    • 2019-05-28
    • 1970-01-01
    • 2013-11-03
    • 2016-03-06
    • 2019-02-27
    • 2017-01-20
    • 2012-09-28
    相关资源
    最近更新 更多