TREE.JS / GLSL Как сопоставить размер шейдера с мировыми координатами? - PullRequest
0 голосов
/ 01 декабря 2019

Странно, что я не смог найти ответ на этот простой вопрос. Я пытаюсь сопоставить размер частиц шейдера с мировыми координатами.

verts.push(new THREE.Vector3(-2.0, 0.0, 0.0));
colors.push(0.0, 1.0, 0.0);
size.push(1.0);

var geometry = new THREE.BufferGeometry().setFromPoints(verts);
geometry.addAttribute("color", new THREE.BufferAttribute(new Float32Array(colors), 3));
geometry.addAttribute("size", new THREE.BufferAttribute(new Float32Array(size), 1));

var material = new THREE.ShaderMaterial({

   uniforms: {

        resolution: new THREE.Uniform(new THREE.Vector2(renderer.domElement.width, renderer.domElement.height)),
        texture: {
        value: new THREE.TextureLoader().load(circularPoint) },
        scale: {
        value: window.innerHeight / 2 }
    },
    vertexShader: document.getElementById("vertexShader").textContent,
    fragmentShader: document.getElementById("fragmentShader").textContent,
    depthTest : true,
    alphaTest: 0.9

})

material.extensions.fragDepth = true;
material.extensions.drawBuffers = true;

var points = new THREE.Points(geometry, material);
scene.add(points);

var sphere = new THREE.Mesh(new THREE.SphereGeometry(0.5, 8, 8), new THREE.MeshNormalMaterial({wireframe: true}));
sphere.position.set(-2.0, 0., 0.0);
scene.add(sphere);

Я установил размер частиц на 1,0 и радиус сферы на 0,5, надеясь, что они будут одинаковыми, но это не так.

enter image description here

Экспериментально я выяснил, что размер частиц как-то связан с параметрами камеры и размерами холста.

Может ли кто-нибудь помочь мне настроить шейдер, чтобы он соответствовал всем, так что размер практики n будеттого же размера, что и сферическая геометрия с радиусом 0,5 или кубическая с 1,0 гранями?

THREE.OrbitControls = function(e, t) {
  var n, o, a, i, r;
  this.object = e, this.domElement = void 0 !== t ? t : document, this.enabled = !0, this.target = new THREE.Vector3, this.minDistance = 0, this.maxDistance = 1 / 0, this.minZoom = 0, this.maxZoom = 1 / 0, this.minPolarAngle = 0, this.maxPolarAngle = Math.PI, this.minAzimuthAngle = -1 / 0, this.maxAzimuthAngle = 1 / 0, this.enableDamping = !1, this.dampingFactor = .25, this.enableZoom = !0, this.zoomSpeed = 1, this.enableRotate = !0, this.rotateSpeed = 1, this.enablePan = !0, this.keyPanSpeed = 7, this.autoRotate = !1, this.autoRotateSpeed = 2, this.enableKeys = !0, this.keys = {
    LEFT: 37,
    UP: 38,
    RIGHT: 39,
    BOTTOM: 40
  }, this.mouseButtons = {
    ORBIT: THREE.MOUSE.LEFT,
    ZOOM: THREE.MOUSE.MIDDLE,
    PAN: THREE.MOUSE.RIGHT
  }, this.target0 = this.target.clone(), this.position0 = this.object.position.clone(), this.zoom0 = this.object.zoom, this.getPolarAngle = function() {
    return E.phi
  }, this.getAzimuthalAngle = function() {
    return E.theta
  }, this.saveState = function() {
    s.target0.copy(s.target), s.position0.copy(s.object.position), s.zoom0 = s.object.zoom
  }, this.reset = function() {
    s.target.copy(s.target0), s.object.position.copy(s.position0), s.object.zoom = s.zoom0, s.object.updateProjectionMatrix(), s.dispatchEvent(c), s.update(), u = l.NONE
  }, this.update = (n = new THREE.Vector3, o = (new THREE.Quaternion).setFromUnitVectors(e.up, new THREE.Vector3(0, 1, 0)), a = o.clone().inverse(), i = new THREE.Vector3, r = new THREE.Quaternion, function() {
    var e = s.object.position;
    return n.copy(e).sub(s.target), n.applyQuaternion(o), E.setFromVector3(n), s.autoRotate && u === l.NONE && M(2 * Math.PI / 60 / 60 * s.autoRotateSpeed), E.theta += p.theta, E.phi += p.phi, E.theta = Math.max(s.minAzimuthAngle, Math.min(s.maxAzimuthAngle, E.theta)), E.phi = Math.max(s.minPolarAngle, Math.min(s.maxPolarAngle, E.phi)), E.makeSafe(), E.radius *= b, E.radius = Math.max(s.minDistance, Math.min(s.maxDistance, E.radius)), s.target.add(g), n.setFromSpherical(E), n.applyQuaternion(a), e.copy(s.target).add(n), s.object.lookAt(s.target), !0 === s.enableDamping ? (p.theta *= 1 - s.dampingFactor, p.phi *= 1 - s.dampingFactor) : p.set(0, 0, 0), b = 1, g.set(0, 0, 0), !(!(T || i.distanceToSquared(s.object.position) > h || 8 * (1 - r.dot(s.object.quaternion)) > h) || (s.dispatchEvent(c), i.copy(s.object.position), r.copy(s.object.quaternion), T = !1))
  }), this.dispose = function() {
    s.domElement.removeEventListener("contextmenu", B, !1), s.domElement.removeEventListener("mousedown", Z, !1), s.domElement.removeEventListener("wheel", F, !1), s.domElement.removeEventListener("touchstart", X, !1), s.domElement.removeEventListener("touchend", _, !1), s.domElement.removeEventListener("touchmove", K, !1), document.removeEventListener("mousemove", Y, !1), document.removeEventListener("mouseup", z, !1), window.removeEventListener("keydown", I, !1)
  };
  var s = this,
    c = {
      type: "change"
    },
    m = {
      type: "start"
    },
    d = {
      type: "end"
    },
    l = {
      NONE: -1,
      ROTATE: 0,
      DOLLY: 1,
      PAN: 2,
      TOUCH_ROTATE: 3,
      TOUCH_DOLLY: 4,
      TOUCH_PAN: 5
    },
    u = l.NONE,
    h = 1e-6,
    E = new THREE.Spherical,
    p = new THREE.Spherical,
    b = 1,
    g = new THREE.Vector3,
    T = !1,
    v = new THREE.Vector2,
    R = new THREE.Vector2,
    O = new THREE.Vector2,
    f = new THREE.Vector2,
    y = new THREE.Vector2,
    H = new THREE.Vector2,
    w = new THREE.Vector2,
    P = new THREE.Vector2,
    j = new THREE.Vector2;

  function C() {
    return Math.pow(.95, s.zoomSpeed)
  }

  function M(e) {
    p.theta -= e
  }

  function L(e) {
    p.phi -= e
  }
  var N, A, k, x = (N = new THREE.Vector3, function(e, t) {
      N.setFromMatrixColumn(t, 0), N.multiplyScalar(-e), g.add(N)
    }),
    D = (A = new THREE.Vector3, function(e, t) {
      A.setFromMatrixColumn(t, 1), A.multiplyScalar(e), g.add(A)
    }),
    U = (k = new THREE.Vector3, function(e, t) {
      var n = s.domElement === document ? s.domElement.body : s.domElement;
      if (s.object.isPerspectiveCamera) {
        var o = s.object.position;
        k.copy(o).sub(s.target);
        var a = k.length();
        a *= Math.tan(s.object.fov / 2 * Math.PI / 180), x(2 * e * a / n.clientHeight, s.object.matrix), D(2 * t * a / n.clientHeight, s.object.matrix)
      } else s.object.isOrthographicCamera ? (x(e * (s.object.right - s.object.left) / s.object.zoom / n.clientWidth, s.object.matrix), D(t * (s.object.top - s.object.bottom) / s.object.zoom / n.clientHeight, s.object.matrix)) : (console.warn("WARNING"), s.enablePan = !1)
    });

  function S(e) {
    s.object.isPerspectiveCamera ? b /= e : s.object.isOrthographicCamera ? (s.object.zoom = Math.max(s.minZoom, Math.min(s.maxZoom, s.object.zoom * e)), s.object.updateProjectionMatrix(), T = !0) : (console.warn("WARNING"), s.enableZoom = !1)
  }

  function V(e) {
    s.object.isPerspectiveCamera ? b *= e : s.object.isOrthographicCamera ? (s.object.zoom = Math.max(s.minZoom, Math.min(s.maxZoom, s.object.zoom / e)), s.object.updateProjectionMatrix(), T = !0) : (console.warn("WARNING"), s.enableZoom = !1)
  }

  function Z(e) {
    if (!1 !== s.enabled) {
      switch (e.preventDefault(), e.button) {
        case s.mouseButtons.ORBIT:
          if (!1 === s.enableRotate) return;
          o = e, v.set(o.clientX, o.clientY), u = l.ROTATE;
          break;
        case s.mouseButtons.ZOOM:
          if (!1 === s.enableZoom) return;
          n = e, w.set(n.clientX, n.clientY), u = l.DOLLY;
          break;
        case s.mouseButtons.PAN:
          if (!1 === s.enablePan) return;
          t = e, f.set(t.clientX, t.clientY), u = l.PAN
      }
      var t, n, o;
      u !== l.NONE && (document.addEventListener("mousemove", Y, !1), document.addEventListener("mouseup", z, !1), s.dispatchEvent(m))
    }
  }

  function Y(e) {
    var t, n;
    if (!1 !== s.enabled) switch (e.preventDefault(), u) {
      case l.ROTATE:
        if (!1 === s.enableRotate) return;
        ! function(e) {
          R.set(e.clientX, e.clientY), O.subVectors(R, v);
          var t = s.domElement === document ? s.domElement.body : s.domElement;
          M(2 * Math.PI * O.x / t.clientWidth * s.rotateSpeed), L(2 * Math.PI * O.y / t.clientHeight * s.rotateSpeed), v.copy(R), s.update()
        }(e);
        break;
      case l.DOLLY:
        if (!1 === s.enableZoom) return;
        n = e, P.set(n.clientX, n.clientY), j.subVectors(P, w), 0 < j.y ? S(C()) : j.y < 0 && V(C()), w.copy(P), s.update();
        break;
      case l.PAN:
        if (!1 === s.enablePan) return;
        t = e, y.set(t.clientX, t.clientY), H.subVectors(y, f), U(H.x, H.y), f.copy(y), s.update()
    }
  }

  function z(e) {
    !1 !== s.enabled && (document.removeEventListener("mousemove", Y, !1), document.removeEventListener("mouseup", z, !1), s.dispatchEvent(d), u = l.NONE)
  }

  function F(e) {
    var t;
    !1 === s.enabled || !1 === s.enableZoom || u !== l.NONE && u !== l.ROTATE || (e.preventDefault(), e.stopPropagation(), (t = e).deltaY < 0 ? V(C()) : 0 < t.deltaY && S(C()), s.update(), s.dispatchEvent(m), s.dispatchEvent(d))
  }

  function I(e) {
    !1 !== s.enabled && !1 !== s.enableKeys && !1 !== s.enablePan && function(e) {
      switch (e.keyCode) {
        case s.keys.UP:
          U(0, s.keyPanSpeed), s.update();
          break;
        case s.keys.BOTTOM:
          U(0, -s.keyPanSpeed), s.update();
          break;
        case s.keys.LEFT:
          U(s.keyPanSpeed, 0), s.update();
          break;
        case s.keys.RIGHT:
          U(-s.keyPanSpeed, 0), s.update()
      }
    }(e)
  }

  function X(e) {
    if (!1 !== s.enabled) {
      switch (e.touches.length) {
        case 1:
          if (!1 === s.enableRotate) return;
          r = e, v.set(r.touches[0].pageX, r.touches[0].pageY), u = l.TOUCH_ROTATE;
          break;
        case 2:
          if (!1 === s.enableZoom) return;
          o = (n = e).touches[0].pageX - n.touches[1].pageX, a = n.touches[0].pageY - n.touches[1].pageY, i = Math.sqrt(o * o + a * a), w.set(0, i), u = l.TOUCH_DOLLY;
          break;
        case 3:
          if (!1 === s.enablePan) return;
          t = e, f.set(t.touches[0].pageX, t.touches[0].pageY), u = l.TOUCH_PAN;
          break;
        default:
          u = l.NONE
      }
      var t, n, o, a, i, r;
      u !== l.NONE && s.dispatchEvent(m)
    }
  }

  function K(e) {
    var t, n, o, a, i;
    if (!1 !== s.enabled) switch (e.preventDefault(), e.stopPropagation(), e.touches.length) {
      case 1:
        if (!1 === s.enableRotate) return;
        if (u !== l.TOUCH_ROTATE) return;
        ! function(e) {
          R.set(e.touches[0].pageX, e.touches[0].pageY), O.subVectors(R, v);
          var t = s.domElement === document ? s.domElement.body : s.domElement;
          M(2 * Math.PI * O.x / t.clientWidth * s.rotateSpeed), L(2 * Math.PI * O.y / t.clientHeight * s.rotateSpeed), v.copy(R), s.update()
        }(e);
        break;
      case 2:
        if (!1 === s.enableZoom) return;
        if (u !== l.TOUCH_DOLLY) return;
        o = (n = e).touches[0].pageX - n.touches[1].pageX, a = n.touches[0].pageY - n.touches[1].pageY, i = Math.sqrt(o * o + a * a), P.set(0, i), j.subVectors(P, w), 0 < j.y ? V(C()) : j.y < 0 && S(C()), w.copy(P), s.update();
        break;
      case 3:
        if (!1 === s.enablePan) return;
        if (u !== l.TOUCH_PAN) return;
        t = e, y.set(t.touches[0].pageX, t.touches[0].pageY), H.subVectors(y, f), U(H.x, H.y), f.copy(y), s.update();
        break;
      default:
        u = l.NONE
    }
  }

  function _(e) {
    !1 !== s.enabled && (s.dispatchEvent(d), u = l.NONE)
  }

  function B(e) {
    !1 !== s.enabled && e.preventDefault()
  }
  s.domElement.addEventListener("contextmenu", B, !1), s.domElement.addEventListener("mousedown", Z, !1), s.domElement.addEventListener("wheel", F, !1), s.domElement.addEventListener("touchstart", X, !1), s.domElement.addEventListener("touchend", _, !1), s.domElement.addEventListener("touchmove", K, !1), window.addEventListener("keydown", I, !1), this.update()
}, THREE.OrbitControls.prototype = Object.create(THREE.EventDispatcher.prototype), THREE.OrbitControls.prototype.constructor = THREE.OrbitControls, Object.defineProperties(THREE.OrbitControls.prototype, {
  center: {
    get: function() {
      return console.warn("THREE.OrbitControls"), this.target
    }
  },
  noZoom: {
    get: function() {
      return console.warn("THREE.OrbitControls"), !this.enableZoom
    },
    set: function(e) {
      console.warn("THREE.OrbitControls"), this.enableZoom = !e
    }
  },
  noRotate: {
    get: function() {
      return console.warn("THREE.OrbitControls"), !this.enableRotate
    },
    set: function(e) {
      console.warn("THREE.OrbitControls"), this.enableRotate = !e
    }
  },
  noPan: {
    get: function() {
      return console.warn("THREE.OrbitControls"), !this.enablePan
    },
    set: function(e) {
      console.warn("THREE.OrbitControls"), this.enablePan = !e
    }
  },
  noKeys: {
    get: function() {
      return console.warn("THREE.OrbitControls"), !this.enableKeys
    },
    set: function(e) {
      console.warn("THREE.OrbitControls"), this.enableKeys = !e
    }
  },
  staticMoving: {
    get: function() {
      return console.warn("THREE.OrbitControls"), !this.enableDamping
    },
    set: function(e) {
      console.warn("THREE.OrbitControls"), this.enableDamping = !e
    }
  },
  dynamicDampingFactor: {
    get: function() {
      return console.warn("THREE.OrbitControls"), this.dampingFactor
    },
    set: function(e) {
      console.warn("THREE.OrbitControls"), this.dampingFactor = e
    }
  }
});

var circularPoint = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAAF8WlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDAgNzkuMTYwNDUxLCAyMDE3LzA1LzA2LTAxOjA4OjIxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIiB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgKE1hY2ludG9zaCkiIHhtcDpDcmVhdGVEYXRlPSIyMDE5LTExLTMwVDE4OjI4OjI1KzAzOjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDE5LTExLTMwVDE4OjI4OjI1KzAzOjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAxOS0xMS0zMFQxODoyODoyNSswMzowMCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo5ZTcwYzU1Ni02ODI3LTRhY2EtOTM2Mi0yNTY2MzRmODFiNWQiIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDowY2MzZGE4OC04NGIxLWRkNDAtYWRjZS03MjE3ZjFhZTMyN2IiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo3ZGFlOTc3ZC1mYTM2LTQ3ZGUtOTNmZC1kMDVkOTRjNDVlOWUiIGRjOmZvcm1hdD0iaW1hZ2UvcG5nIiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiBwaG90b3Nob3A6SUNDUHJvZmlsZT0ic1JHQiBJRUM2MTk2Ni0yLjEiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjdkYWU5NzdkLWZhMzYtNDdkZS05M2ZkLWQwNWQ5NGM0NWU5ZSIgc3RFdnQ6d2hlbj0iMjAxOS0xMS0zMFQxODoyODoyNSswMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo5ZTcwYzU1Ni02ODI3LTRhY2EtOTM2Mi0yNTY2MzRmODFiNWQiIHN0RXZ0OndoZW49IjIwMTktMTEtMzBUMTg6Mjg6MjUrMDM6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAoTWFjaW50b3NoKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7xYfCfAAABw0lEQVRYhcWXPWsVQRhGz44iJigmiAjxE1PYKWIjSSGm1cLKwsIfEEELaxsL/0EKWwsbsVdBMcSIVa6dgt+FlUHRxibusZiMHwvZO/Heu/PANLvwnmdmd2aet1LJVABOAXPAMeAwMAnUwBfgPbACPAJ6uUVR+41J9br60Xy9VK+q4/3qt70M6rz6dRPgpj6pF/7HwG71wQDgpm6rY7kG9huXcNhaUnf1M7BHfTUCeNKijZX4G16p90cIT7q1kYH5DuBJZxO3Mp4DE+v7eCJ7/w6md8BRYC2sP7jSIRzgCHARoFID8AE40KEBgGfAbKXOAk87hgMIHAzAmQJwgAo4HYgXSykdD8B0QQPTAdhR0MDOQPwZSqkOwPeCBr4F4E1BA28Dm4lPw1evUk8Qs1zXqoG9AXhBmc/wGFhNu2ChgIEF4Pd1PEZchamO4D3gJGC6jn8A1zqC18Bl0vnjv5nwTgdp6KYtoXRcfT5C+D11S5sBjNF5aQTwu+q2Jm+jxmS7Mb0OQz/VGzZm3s9AGufU1wPAV9SZNkZOc7pVvaQuq3UGdE19qJ439hqt9dM5kKt9/GnPDxHbc4FVYrDtAU+Az7kFfwFboSKDalnNAwAAAABJRU5ErkJggg==";

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 0, 10);

var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setClearColor(0xEEEEEE, 1.0);
document.body.appendChild(renderer.domElement);

var controls = new THREE.OrbitControls(camera, renderer.domElement);

var verts = [],
  colors = [],
  size = [];

verts.push(new THREE.Vector3(-2.0, 0.0, 0.0));

colors.push(0.0, 1.0, 0.0);

size.push(1.0);

var geometry = new THREE.BufferGeometry().setFromPoints(verts);
geometry.addAttribute("color", new THREE.BufferAttribute(new Float32Array(colors), 3));
geometry.addAttribute("size", new THREE.BufferAttribute(new Float32Array(size), 1));

var material = new THREE.ShaderMaterial({

  uniforms: {

    resolution: new THREE.Uniform(new THREE.Vector2(renderer.domElement.width, renderer.domElement.height)),
    texture: {
      value: new THREE.TextureLoader().load(circularPoint)
    },
    scale: {
      value: window.innerHeight / 2
    }
  },
  vertexShader: document.getElementById("vertexShader").textContent,
  fragmentShader: document.getElementById("fragmentShader").textContent,
  depthTest: true,
  alphaTest: 0.9


})

material.extensions.derivatives = true;
material.extensions.fragDepth = true;
material.extensions.drawBuffers = true;

var sphere = new THREE.Mesh(new THREE.SphereGeometry(0.5, 8, 8), new THREE.MeshNormalMaterial({
  wireframe: true
}));
sphere.position.set(-2.0, 0., 0.0);
scene.add(sphere);

var points = new THREE.Points(geometry, material);
scene.add(points);

var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
var inverseMatrix = new THREE.Matrix4();
var ray = new THREE.Ray();

renderer.domElement.addEventListener("mousemove", onMouseMove, false);

function onMouseMove(event) {

  camera.clearViewOffset();

  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

  raycaster.setFromCamera(mouse, camera);

}

renderer.setAnimationLoop(() => {
  renderer.render(scene, camera)
});
body {
  overflow: hidden;
  margin: 0;
}
<html>

<head>

  <meta charset="utf-8">
  <title>THREE.JS | D3.JS : 3D SCATTERPLOT [rc]</title>
  <meta name="description" content="Ehno based on D3.JS | THREE.JS stack.">
  <meta name="keywords" content="HTML,CSS,CSV,JavaScript,D3.JS,THREE.JS">
  <meta name="author" content="Vladimir V. KUCHINOV">

  <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/98/three.min.js"></script>


</head>

<script type="x-shader/x-vertex" id="vertexShader">

  attribute float size; attribute vec3 color; uniform float scale; uniform vec2 resolution; varying vec3 vColor; void main() { vColor = color; vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 ); gl_PointSize = size * ( scale / -mvPosition.z ); gl_Position
  = projectionMatrix * mvPosition; }


</script>

<script type="x-shader/x-fragment" id="fragmentShader">

  varying vec3 vColor; uniform sampler2D texture; void main() { gl_FragColor = vec4(vColor, 1.); gl_FragColor = gl_FragColor * texture2D(texture, gl_PointCoord); if (gl_FragColor.a
  < 0.1) discard; } </script>

    <body>

    </body>

</html>

1 Ответ

2 голосов
/ 05 декабря 2019

Следует помнить, что значение gl_PointSize в шейдере THREE.Points всегда преобразуется в пикселей , а не в мировые координаты. Таким образом, оператор gl_PointSize = 2.0; будет иметь ширину 2 пикселя и высоту, независимо от высоты окна браузера. Вы должны вручную преобразовать пиксели в мировые координаты, передав uniform float высоты области просмотра, поскольку высота перспективной камеры определяет масштабирование мира:

uniforms: {
    viewport: { value: window.innerHeight },
}

Затем вы можете использовать это значение для умноженияпо вашему диаметру в шейдере

gl_PointSize = viewport * radius / -mvPosition.z;

Еще одна вещь, которую нужно иметь в виду, это то, что, устанавливая соотношение пикселей на более высокое значение DPI с помощью renderer.setPixelRatio(window.devicePixelRatio);, вы также добавляете больше пикселей, поэтому вам нужно взятьчто необходимо учитывать при объявлении вашей униформы:

uniforms: {
    viewport: {value: window.innerHeight * window.devicePixelRatio },
}

Я заново создал упрощенную версию вашего примера с двумя точками, одной внутри плоскости с шириной и высотой 1 мировых единиц, и сферой с радиусом0,5. (Я удалил все вещи OrbitControls, чтобы сделать его простым). Обратите внимание, что я также добавил слушатель событий 'resize' внизу, чтобы пересчитать все соответствующие значения при изменении размера окна.

var circularPoint = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAAF8WlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDAgNzkuMTYwNDUxLCAyMDE3LzA1LzA2LTAxOjA4OjIxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIiB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgKE1hY2ludG9zaCkiIHhtcDpDcmVhdGVEYXRlPSIyMDE5LTExLTMwVDE4OjI4OjI1KzAzOjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDE5LTExLTMwVDE4OjI4OjI1KzAzOjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAxOS0xMS0zMFQxODoyODoyNSswMzowMCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo5ZTcwYzU1Ni02ODI3LTRhY2EtOTM2Mi0yNTY2MzRmODFiNWQiIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDowY2MzZGE4OC04NGIxLWRkNDAtYWRjZS03MjE3ZjFhZTMyN2IiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo3ZGFlOTc3ZC1mYTM2LTQ3ZGUtOTNmZC1kMDVkOTRjNDVlOWUiIGRjOmZvcm1hdD0iaW1hZ2UvcG5nIiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiBwaG90b3Nob3A6SUNDUHJvZmlsZT0ic1JHQiBJRUM2MTk2Ni0yLjEiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjdkYWU5NzdkLWZhMzYtNDdkZS05M2ZkLWQwNWQ5NGM0NWU5ZSIgc3RFdnQ6d2hlbj0iMjAxOS0xMS0zMFQxODoyODoyNSswMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo5ZTcwYzU1Ni02ODI3LTRhY2EtOTM2Mi0yNTY2MzRmODFiNWQiIHN0RXZ0OndoZW49IjIwMTktMTEtMzBUMTg6Mjg6MjUrMDM6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAoTWFjaW50b3NoKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7xYfCfAAABw0lEQVRYhcWXPWsVQRhGz44iJigmiAjxE1PYKWIjSSGm1cLKwsIfEEELaxsL/0EKWwsbsVdBMcSIVa6dgt+FlUHRxibusZiMHwvZO/Heu/PANLvwnmdmd2aet1LJVABOAXPAMeAwMAnUwBfgPbACPAJ6uUVR+41J9br60Xy9VK+q4/3qt70M6rz6dRPgpj6pF/7HwG71wQDgpm6rY7kG9huXcNhaUnf1M7BHfTUCeNKijZX4G16p90cIT7q1kYH5DuBJZxO3Mp4DE+v7eCJ7/w6md8BRYC2sP7jSIRzgCHARoFID8AE40KEBgGfAbKXOAk87hgMIHAzAmQJwgAo4HYgXSykdD8B0QQPTAdhR0MDOQPwZSqkOwPeCBr4F4E1BA28Dm4lPw1evUk8Qs1zXqoG9AXhBmc/wGFhNu2ChgIEF4Pd1PEZchamO4D3gJGC6jn8A1zqC18Bl0vnjv5nwTgdp6KYtoXRcfT5C+D11S5sBjNF5aQTwu+q2Jm+jxmS7Mb0OQz/VGzZm3s9AGufU1wPAV9SZNkZOc7pVvaQuq3UGdE19qJ439hqt9dM5kKt9/GnPDxHbc4FVYrDtAU+Az7kFfwFboSKDalnNAwAAAABJRU5ErkJggg==";
var circleTexture = new THREE.TextureLoader().load(circularPoint);

// Three.js boilerplate
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setClearColor(0xEEEEEE, 1.0);
document.body.appendChild(renderer.domElement);

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 0, 10);

// Build Plane
var planeGeom = new THREE.PlaneBufferGeometry(1, 1, 4, 4);
var normMat = new THREE.MeshNormalMaterial({
	wireframe: true
});
var plane = new THREE.Mesh(planeGeom, normMat);
plane.position.set(-2.0, 0., 0.0);
scene.add(plane);

// Build Sphere
var sphereGeom = new THREE.SphereBufferGeometry(0.5, 16, 16);
var sphere = new THREE.Mesh(sphereGeom, normMat);
sphere.position.set(2.0, 0., 0.0);
scene.add(sphere);

// Build points
var verts = [],
	colors = [0.0, 1.0, 0.0, 1.0, 0.0, 0.5],
	radius = [0.5, 0.5];

// Green point at x: -2
verts.push(new THREE.Vector3(-2.0, 0.0, 0.0));

// Pink point at x: +2
verts.push(new THREE.Vector3(2.0, 0.0, 0.0));

var geometry = new THREE.BufferGeometry().setFromPoints(verts);
geometry.addAttribute("color", new THREE.BufferAttribute(new Float32Array(colors), 3));
geometry.addAttribute("radius", new THREE.BufferAttribute(new Float32Array(radius), 1));

var material = new THREE.ShaderMaterial({
	uniforms: {
		viewport: {value: window.innerHeight * window.devicePixelRatio },
		texture: {value: circleTexture}
	},
	vertexShader: document.getElementById("vertexShader").textContent,
	fragmentShader: document.getElementById("fragmentShader").textContent,
  transparent: true
});

var points = new THREE.Points(geometry, material);
scene.add(points);

// We move the camera to generate animation & sense of depth
renderer.setAnimationLoop((t) => {
	camera.position.set(
      Math.sin(t * 0.0007) * 7,
      Math.sin(t * 0.0005) * 3,
      Math.cos(t * 0.0003) * 7
  );
	camera.lookAt(0, 0, 0);
	renderer.render(scene, camera)
});

// We must recalculate all values when window is resized
window.addEventListener('resize', function(event){
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
  material.uniforms.viewport.value = window.innerHeight * window.devicePixelRatio;
  console.log("viewport uniform: " + material.uniforms.viewport.value);
});
body {
  overflow: hidden;
  margin: 0;
}
<html>

<head>

  <meta charset="utf-8">
  <title>THREE.JS | D3.JS : 3D SCATTERPLOT [rc]</title>
  <meta name="description" content="Ehno based on D3.JS | THREE.JS stack.">
  <meta name="keywords" content="HTML,CSS,CSV,JavaScript,D3.JS,THREE.JS">
  <meta name="author" content="Vladimir V. KUCHINOV">

  <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/98/three.min.js"></script>


</head>

<script type="x-shader/x-vertex" id="vertexShader">
#define PI 3.141592
attribute float radius;
attribute vec3 color;

uniform float viewport;
varying vec3 vColor;
void main() {
  vColor = color;
  
  vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
  gl_PointSize = viewport * radius * PI / -mvPosition.z;
  gl_Position = projectionMatrix * mvPosition;
}


</script>

<script type="x-shader/x-fragment" id="fragmentShader">

  varying vec3 vColor;
  uniform sampler2D texture;
  void main() {
    gl_FragColor = vec4(vColor, 0.5) * texture2D(texture, gl_PointCoord);;
  }
  </script>

    <body>

    </body>

</html>
...