Нанесите текстуру на половину квадрата

#javascript #three.js #webgl #textures

Вопрос:

Я работаю над сценой в трех кадрах, которая отображает изображение кошки.

В частности, я хотел бы отобразить прямоугольник, и я бы хотел, чтобы правая половина этого прямоугольника была красной, а левая половина этого прямоугольника содержала полное изображение кошки (изображение будет растянуто, и это нормально).

Вот моя сцена:

 var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 2;
var renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

var geometry = new THREE.BufferGeometry();
var imageSize = {width: 3, height: 2};

// add verts
var coords = {x: -1.5, y: -1, z: 0};
var vertices = new Float32Array([
  coords.x, coords.y, coords.z,
  coords.x imageSize.width, coords.y, coords.z,
  coords.x imageSize.width, coords.y imageSize.height, coords.z,
  coords.x, coords.y imageSize.height, coords.z,
])

var uvs = new Float32Array([
  0.0, 0.0,
  1.0, 0.0,
  1.0, 1.0,
  0.0, 1.0,
])

geometry.setIndex([0,1,2, 2,3,0])
geometry.setAttribute('position', new THREE.BufferAttribute( vertices, 3 ));
geometry.setAttribute('uv', new THREE.BufferAttribute( uvs, 2) )

var loader = new THREE.TextureLoader();
var url = 'https://s3.amazonaws.com/duhaime/blog/tsne-webgl/assets/cat.jpg';
var material = new THREE.RawShaderMaterial({  
  uniforms: {
    texture: {
      type: 't',
      value: loader.load(url)
    },
  },
  vertexShader: document.getElementById('vertex-shader').textContent,
  fragmentShader: document.getElementById('fragment-shader').textContent
});

var mesh = new THREE.Mesh(geometry, material);
mesh.position.set(0,0,0)
scene.add(mesh);
    
function render() {
  requestAnimationFrame(render);
  renderer.render(scene, camera);
  console.clear();
};

render(); 
 <script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.min.js'></script>

<script type='x-shader/x-vertex' id='vertex-shader'>
  precision mediump float;

  uniform mat4 modelViewMatrix;
  uniform mat4 projectionMatrix;
  uniform vec3 cameraPosition;

  attribute vec3 position;
  attribute vec3 translation;
  attribute vec2 uv;

  varying vec2 vUv;
  varying vec3 vPosition;

  void main() {
    vUv = uv;
    vPosition = position;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  }
</script>

<script type='x-shader/x-fragment' id='fragment-shader'>
  precision highp float;

  uniform sampler2D texture;

  varying vec2 vUv;
  varying vec3 vPosition;

  void main() {
    vec2 uv = vUv;
    if (vPosition.x > 0.0) {
      gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
    } else {
      gl_FragColor = texture2D(texture, uv);
    }
  }
</script> 

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

Комментарии:

1. Возможно, можно нарисовать на холсте то, что вы хотите, и использовать этот холст в качестве текстуры..

2. Должен же быть способ сделать это, взаимодействуя с параметром uv, верно?

3. Вы могли бы написать свой собственный простой шейдер, но я просто предлагал альтернативное, возможно, более простое решение.

Ответ №1:

[…] Я бы хотел, чтобы правая половина этого прямоугольника была красной, а левая половина этого прямоугольника содержала полное изображение […]

Координаты текстуры находятся в диапазоне [0.0, 1.0]. Центр текстуры находится в точке (0,5, 0,5). Поэтому в правой половине текстуры компонент x координаты текстуры равен > 0,5. Слева вам нужно масштабировать компонент x координат текстуры на 2,0:

 gl_FragColor = vUv.x > 0.5 
    ? vec4(1.0, 0.0, 0.0, 1.0) 
    : texture2D(texture, vec2(vUv.x*2.0, vUv.y));