jjzjj

javascript - 如何使对象在 three.js 场景中仅对一个摄像机可见

coder 2025-01-25 原文

我使用 three.js 创建了一个用于 3D 场景的嵌入式轨迹球相机 Controller 。目前,这使用一个小立方体、一个圆和一个放置在世界原点的正交相机。然而,这三个对象在场景本身中仍然可见,如通过主摄像机所见。 (在我下面的演示代码中,我特意将立方体设为 10x10x10,以便清晰可见,但它可以做得更小。)

此外,作为主场景一部分的穿过原点的元素在插图中可见。例如:插图中可以看到属于主场景的AxisHelper。

是否可以在 three.js/webgl 中使某些对象仅对某些相机可见?

如果没有,那么一个解决方法是将轨迹球功能所需的对象放置在远离深空的地方,主摄像头看不到它们,但如果可能的话我更喜欢更纯粹的解决方案。

演示:http://codepen.io/anon/pen/MKWrOr

<!DOCTYPE html>
<html>

<head>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r73/three.js"></script>
  <style>
    body {
      margin: 0;
      overflow: hidden;
    }
  </style>
</head>
<body>

<div id="WebGL-output"></div>

<script>
function init() {
  var scene = new THREE.Scene()
  var renderer = new THREE.WebGLRenderer()
  var camera
  var cameras = []

  var WIDTH = window.innerWidth
  var HEIGHT = window.innerHeight

  ;(function createPerspectiveCamera(){
    var FOV = 45
    var ASPECT = WIDTH / HEIGHT
    var NEAR = 1
    var FAR = 360
    camera = new THREE.PerspectiveCamera(FOV, ASPECT, NEAR, FAR)

    camera.position.x = 100
    camera.position.y = 100
    camera.position.z = 100
    camera.viewport = { x: 0, y: 0, width: WIDTH, height: HEIGHT }
    camera.lookAt(scene.position)
    cameras.push(camera)
  })()

  ;(function initializeRenderer(){
    renderer.setClearColor(new THREE.Color(0xEEEEFF))
    renderer.setSize(WIDTH, HEIGHT)
    renderer.autoClear = false;

    document.getElementById("WebGL-output").appendChild(renderer.domElement)

    ;(function render() {
      var viewport
      renderer.setViewport( 0, 0, WIDTH, HEIGHT );
      renderer.clear();

      cameras.forEach(function (camera) {
        viewport = camera.viewport // custom property
        renderer.setViewport(
          viewport.x
        , viewport.y
        , viewport.width
        , viewport.height
        )
        renderer.render(scene, camera)
      })

      requestAnimationFrame(render)
    })()
  })()

  ;(function createCameraController(){
    var viewport = {
      x: WIDTH - 100
    , y: HEIGHT - 100
    , width: 100
    , height: 100
    }
    var circle = {
      x: WIDTH - 50
    , y: 50
    , radius: 50
    }
    var settings = {
      viewport: viewport
    , circle: circle
    }
    addCameraController(scene, camera, cameras, settings)
  })()

  // Something to look at
  scene.add(new THREE.AxisHelper(70))
}

function addCameraController(scene, camera, cameras, settings) {
  var controlCamera
  var viewport = settings.viewport

  // For mouse interactions
  var centreX = settings.circle.x
  var centreY = settings.circle.y
  var radius = settings.circle.radius
  var radius2 = radius * radius
  var rotationMatrix = new THREE.Matrix4()
  var pivotMatrix = new THREE.Matrix4()
  var startMatrix = new THREE.Matrix4()
  var start = new THREE.Vector3()
  var end = new THREE.Vector3() 
  var angle

  camera.matrixAutoUpdate = false /** takes control of main camera **/

  ;(function createControlCameraCubeAndCircle(){
    var side = 10
    var radius = Math.sqrt(side/2 * side/2 * 3)

    ;(function createCamera(){
      controlCamera = new THREE.OrthographicCamera(
       -radius, radius
      , radius, -radius
      , -radius, radius
      );
      controlCamera.viewport = viewport
      controlCamera.rotation.copy(camera.rotation)

      // If matrixAutoUpdate is set immediately, the camera rotation is
      // not applied
      setTimeout(function () {
        controlCamera.matrixAutoUpdate = false
      }, 1)

      scene.add(controlCamera)
      cameras.push( controlCamera )
    })()

    ;(function createCompanionCube(){
      var cube = new THREE.Object3D()
      var cubeGeometry = new THREE.BoxGeometry( side, side, side )

      var lineMaterial = new THREE.LineBasicMaterial({
        color: 0xffffff
      , transparent: true
      , opacity: 0.5
      })

      var faceMaterial = new THREE.MeshPhongMaterial({
        color: 0x006699
      , emissive: 0x006699
      , shading: THREE.FlatShading
      , transparent: true
      , opacity: 0.2
      })

      cube.add(
        new THREE.LineSegments(
          new THREE.WireframeGeometry( cubeGeometry )
        , lineMaterial
        )
      )
      cube.add(
        new THREE.Mesh(
          cubeGeometry
        , faceMaterial
        )
      )

      // cube.add(new THREE.AxisHelper(radius))
      scene.add(cube);
    })()

    ;(function createCircle(){
      var circleGeometry = new THREE.CircleGeometry( radius, 36 );
      var material = new THREE.MeshBasicMaterial( {
        color: 0xccccff
      } );
      var circle = new THREE.Mesh( circleGeometry, material );
      controlCamera.add( circle );
      circle.translateZ(-radius)
    })()
  })()

  window.addEventListener("mousedown", startDrag, false)

  function startDrag(event) {
    var x = event.clientX - centreX
    var y = centreY - event.clientY
    var delta2 = x * x + y * y
    if (delta2 > radius2) {
      return
    }

    var z = Math.sqrt(radius2 - delta2)
    start.set(x, y, z)

    window.addEventListener("mousemove", drag, false)
    window.addEventListener("mouseup", stopDrag, false)

    function drag(event) {     
      var delta
      x = event.clientX - centreX
      y = centreY - event.clientY
      delta2 = x * x + y * y

      if (delta2 > radius2) {
        // constrain to adge of sphere
        delta = Math.sqrt(delta2)
        x = x / delta * radius
        y = y / delta * radius
        z = 0
      } else {
        z = Math.sqrt(radius2 - delta2)
      }

      end.set(x, y, z)
      angle = start.angleTo(end)
      start.cross(end).normalize()

      rotationMatrix.makeRotationAxis(start, -angle)
      controlCamera.matrix.multiply(rotationMatrix)
      controlCamera.matrixWorldNeedsUpdate = true

      rotationMatrix.extractRotation(camera.matrixWorld)
      start.applyMatrix4(rotationMatrix).normalize()
      rotationMatrix.makeRotationAxis(start, -angle)
      camera.applyMatrix(rotationMatrix)
      camera.matrixWorldNeedsUpdate = true

      start.copy(end)
    }

    function stopDrag(event) {
      window.removeEventListener("mousemove", drag, false)
      window.removeEventListener("mouseup", stopDrag, false)      
    }
  }
}

window.onload = init
</script>
</body>
</html>

最佳答案

three.js 支持图层。

如果对象和相机共享一个公共(public)层,则该对象对相机可见。默认情况下,相机和所有对象都在第 0 层。

例如,

camera.layers.enable( 1 ); // camera now sees default layer 0 and layer 1
camera.layers.set( 1 ); // camera now sees only layer 1

mesh.layers.set( 1 ); // mesh is in layer 1

three.js r.75

关于javascript - 如何使对象在 three.js 场景中仅对一个摄像机可见,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34099808/

有关javascript - 如何使对象在 three.js 场景中仅对一个摄像机可见的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  4. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  5. ruby-on-rails - 按天对 Mongoid 对象进行分组 - 2

    在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev

  6. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  7. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  8. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  9. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  10. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

随机推荐