Отобразить изображение как текстуру на плоскости в пользовательском шейдере в THREE.js - PullRequest
0 голосов
/ 23 декабря 2019

Я пытаюсь загрузить 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;
        }
    `;
}

Чтобы исправить это, я попытался:

  • гарантировал, что плоскость видна, заштриховав ее простым цветом
  • гарантировал, что ультрафиолетовые координаты переданы в шейдер, визуализировав их как цвет
  • , гарантировал, что texture1 и texture2перед передачей их в шейдер
  • с использованием THREE.Texture вместо THREE.MeshBasicMaterial
  • изменения типа униформы в js texture1: { type: "t", value: texture1 },

Я думаю, что проблема можетбыть в части передачи текстуры как шейдера. Я мог бы использовать неправильный тип где-то .. Я был бы признателен за любую помощь!

1 Ответ

0 голосов
/ 23 декабря 2019

Предполагая, что loader - это TextureLoader, тогда он вызывает вас с текстурой, поэтому

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 обновит их после загрузки изображений.

Возможно, вас заинтересуют некоторые другие актуальные уроки

...