在THREE.js中的自定义着色器中将图像作为纹理映射到平面

时间:2019-12-22 23:05:51

标签: javascript three.js shader

我试图将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坐标传递给着色器
  • 确保texture1texture2在传递给着色器之前已定义
  • 使用THREE.Texture代替THREE.MeshBasicMaterial
  • 在js texture1: { type: "t", value: texture1 },中更改统一类型

我认为问题可能出在将纹理均匀地传递给着色器方面。我可能在某个地方使用了错误的类型。.我将不胜感激!

1 个答案:

答案 0 :(得分:0)

假设loaderTextureLoader,那么它会给您一个纹理,从而使您

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

否则,虽然不是bug,但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

感兴趣