【问题标题】:How to mix / blend between 2 vertex positions based on distance from camera?如何根据与相机的距离在 2 个顶点位置之间混合/混合?
【发布时间】:2019-03-22 11:48:19
【问题描述】:

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

我想从中融合(一架平放在地面上的飞机):

对此(同一平面,只是旋转了 90 度):

到目前为止,我的实现感觉很接近,但我无法确定完成它需要哪些部分。我从a similar Tangram demo (shader code) 采取了一种方法,但是我无法在这附近得到任何结果。 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根据距离在水平位置和垂直位置之间混合

我尝试了多种方法,但似乎无法使其正常工作。

有什么想法吗?由于我的着色器/矩阵知识有限,即使为我指明正确的道路也会非常有帮助。

【问题讨论】:

    标签: three.js glsl shader webgl


    【解决方案1】:

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

    【讨论】:

    • 谢谢!我觉得我很接近所以很高兴知道这只是平面几何定义的一个愚蠢的错误。我应该已经发现了。
    猜你喜欢
    • 1970-01-01
    • 2016-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多