如何根据距相机的距离在2个顶点位置之间进行混合/融合?

时间:2018-10-17 17:58:20

标签: three.js glsl webgl

我正在尝试根据距相机的距离在2个不同的顶点位置之间进行混合/混合。具体来说,我正在尝试创建一种效果,使其在更靠近相机的水平面与远处的垂直平面之间融合。结果应该是一个弯曲的平面,该平面会从当前的相机位置离开并向上移动。

我要从中混合(地面上的平面): enter image description here

对此(同一平面,仅旋转90度): enter image description here

到目前为止,我的实现感觉还很接近,但我只是不能将我需要完成的部分放在我的手指上。我采用了a similar Tangram demoshader code)的方法,但是无法在此附近获得结果。七巧板示例还使用了与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 :(得分:2)

主要问题是,您将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>