Как смешивать / смешивать 2 положения вершин в зависимости от расстояния до камеры? - PullRequest
0 голосов
/ 17 октября 2018

Я пытаюсь смешивать / смешивать 2 разных положения вершин в зависимости от расстояния до камеры.В частности, я пытаюсь создать эффект, который смешивается между горизонтальной плоскостью ближе к камере и вертикальной плоскостью на расстоянии.В результате должна получиться изогнутая плоскость, уходящая и уходящая из текущей позиции камеры.

Я хочу из этого слиться (плоскость на земле): enter image description here

К этому (та же самая плоскость, только что повернутая на 90 градусов): enter image description here

Реализация, которую я до сих пор чувствую, близка, но я просто не могу понять, чтоштук мне нужно закончить.Я использовал подход из аналогичного демо Tangram ( код шейдера ), однако я не могу получить результаты где-либо рядом с этим.Пример Tangram также использует полностью другую настройку по сравнению с тем, что я использую в Three.js, поэтому я не смог воспроизвести все.

Это то, что я до сих пор: https://jsfiddle.net/robhawkes/a97tu864/

varying float distance;

mat4 rotateX(float rotationX) {
  return mat4(
    vec4(1.0,0.0,0.0,0.0),
    vec4(0.0,cos(rotationX),-sin(rotationX),0.0),
    vec4(0.0,sin(rotationX),cos(rotationX),0.0),
    vec4(0.0,0.0,0.0,1.0)
  );
}

void main() 
{
  vec4 vPosition = vec4(position, 1.0);
  vec4 modelViewPosition = modelViewMatrix * vPosition;

  float bend = radians(-90.0);
  vec4 newPos = rotateX(bend) * vPosition;

  distance = -modelViewPosition.z;

  // Show bent position
  //gl_Position = projectionMatrix * modelViewMatrix * newPos;

  float factor = 0.0;

  //if (vPosition.x > 0.0) {
  //    factor = 1.0;
  //}

  //factor = clamp(0.0, 1.0, distance / 2000.0);

  vPosition = mix(vPosition, newPos, factor);

  gl_Position = projectionMatrix * modelViewMatrix * vPosition;
}

Я делаю следующее:

  • Рассчитать повернутое положение вершины (вертикальная версия)
  • Найти расстояние от вершины до камеры
  • Используйте mix, чтобы смешать горизонтальное и вертикальное положение в зависимости от расстояния

Я пробовал несколько подходов, и мне просто не удается заставить его работатьправильно.

Есть идеи?Даже направление меня по правильному пути будет очень полезно, так как мои знания шейдеров / матриц ограничены.

1 Ответ

0 голосов
/ 17 октября 2018

Основная проблема заключается в том, что вы тесселяции THREE.PlaneBufferGeometry в сегментах ширины, но не в сегментах высоты:

groundGeometry = new THREE.PlaneBufferGeometry( 
    1000, 10000, 
    100,    // <----- widthSegments 
    100 );  // <----- heightSegments is missing

Теперь вы можете использовать координату z представленияместо для интерполяции:

float factor = -modelViewPosition.z / 2000.0;

var camera, controls, scene, renderer;
var groundGeometry, groundMaterial, groundMesh;
var ambientLight;

init();
initLight();
initGround();
animate();

function init() {
 
  camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 10000 );
  camera.position.y = 500;
  camera.position.z = 1000;
  
  controls = new THREE.MapControls( camera );
  controls.maxPolarAngle = Math.PI / 2;

  scene = new THREE.Scene();
  
  scene.add(camera);
  
  var axesHelper = new THREE.AxesHelper( 500 );
	scene.add( axesHelper );

  renderer = new THREE.WebGLRenderer( { antialias: true } );
  renderer.setSize( window.innerWidth, window.innerHeight );
        
  document.body.appendChild( renderer.domElement );
 
}

function initLight() {
  ambientLight = new THREE.AmbientLight( 0x404040 );
	scene.add( ambientLight );
}

function initGround() {
	groundMaterial = new THREE.ShaderMaterial({
    vertexShader: document.getElementById( 'vertexShader' ).textContent,
    fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
    transparent: true
  });
  
  groundGeometry = new THREE.PlaneBufferGeometry( 1000, 10000, 100, 100 );
  groundMesh = new THREE.Mesh( groundGeometry, groundMaterial );
  groundMesh.position.z = -3000;
  groundMesh.position.y = -100;
  groundMesh.rotateX(-Math.PI / 2)
  scene.add( groundMesh );
}

function animate() {
 
  requestAnimationFrame( animate );
  
  controls.update();
  
  renderer.render( scene, camera );
 
}
<script type="x-shader/x-vertex" id="vertexShader">
varying float distance;

mat4 rotateX(float rotationX) {
  return mat4(
    vec4(1.0,0.0,0.0,0.0),
    vec4(0.0,cos(rotationX),-sin(rotationX),0.0),
    vec4(0.0,sin(rotationX),cos(rotationX),0.0),
    vec4(0.0,0.0,0.0,1.0)
  );
}

void main() 
{
  vec4 vPosition = vec4(position, 1.0);
  vec4 modelViewPosition = modelViewMatrix * vPosition;
    
  float bend = radians(-90.0);
  vec4 newPos = rotateX(bend) * vPosition;
  
  distance = -modelViewPosition.z;
  
  float factor = -modelViewPosition.z / 2000.0;
  
  vPosition = mix(vPosition, newPos, factor);
  
  gl_Position = projectionMatrix * modelViewMatrix * vPosition;
}
</script>
<script type="x-shader/x-fragment" id="fragmentShader">
varying float distance;

void main() {
  if (distance < 3000.0) {
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
  } else {
    gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
  }
}
</script>

<script src="https://threejs.org/build/three.min.js"></script>

<script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/controls/MapControls.js"></script>
...