簡單例子
這個例子,是在一個視圖中,看到照相機的輔助線,也就是,一個照相機的觀察訪問
這樣,就需要兩個照相機,一個是主照相機,一個是加有輔助線的照相機(有兩種,正交和透視,這里輔助的使用的是正交的)
設置兩個照相機位置:注意,輔助的子照相機要在主照相機里面,這樣才能在主照相機的鏡頭下看到輔助照相機的觀察范圍

//場景、攝像機、渲染器、實體 var scene, camera, renderer, cameraHelper; var cube, controls; //在頁面加載完,進行繪制渲染頁面 window.onload = function() { init(); //數據初始化 setSize(); //設置大小畫布 cube(); //繪制實體 animate(); //動畫渲染 }; //初始化攝像機,場景,渲染器,以及一些工具,比如攝像機輔助線,控制器 function init() { scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 500 ); camera.position.set(10, 5, 20); camera.lookAt(new THREE.Vector3(0, 0, 0)); //正交投影照相機 camera2 = new THREE.OrthographicCamera(-1, 1, 1, -1, 5, 10); renderer = new THREE.WebGLRenderer({ alpha: true }); camera2.position.set(0, 0, 5); camera2.lookAt(new THREE.Vector3(0, 0, 0)); //renderer = new THREE.WebGLRenderer(); //camera.position.z = 10; controls = new THREE.OrbitControls(camera); controls.autoRotate = true; //照相機幫助線 cameraHelper = new THREE.CameraHelper(camera2); scene.add(cameraHelper); } //設置畫布大小,這個設置為整個視圖,就不需要剪切了 function setSize() { renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); } //普通的四方體 function cube() { var geometry = new THREE.BoxGeometry(1, 1, 1); var material = new THREE.MeshNormalMaterial({ color: 0x00ff00 }); cube = new THREE.Mesh(geometry, material); //設置位置 cube.position.set(0, 0, -1.5); scene.add(cube); } function animate() { requestAnimationFrame(animate); //一幀幀動畫 cube.rotation.x += 0.005; cube.rotation.y += 0.005; cube.rotation.z += 0.005; camera.updateProjectionMatrix(); controls.update(); cameraHelper.update(); renderer.render(scene, camera); //渲染 }
看完簡單的例子,看看復雜的,
左邊是一個視圖,用一個小的照相機渲染出來的就是右邊輔助線的照相機,
右邊是兩個照相機渲染出來的,右邊,外面有個大的照相機,看到里面有個小的照相機,並且通過輔助線看到里面照相機的觀察區域。

html部分:是,一個Canvas ,然后拆分為左右兩個視圖
<canvas id="c"></canvas>
<div class="split">
<div id="view1" tabindex="1"></div>
<div id="view2" tabindex="2"></div>
</div>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r105/three.min.js"></script>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r105/js/controls/OrbitControls.js"></script>
css
html, body {
margin: 0; height: 100%; } #c { width: 100%; height: 100%; display: block; } .split { position: absolute; left: 0; top: 0; width: 100%; height: 100%; display: flex; } .split>div { width: 100%; height: 100%; }
js,他是有兩個照相機,
1.一個透視作為主照相機,
2.一個正交作為輔助照相機,
在正交照相機加上輔助線,然后把輔助線弄到場景里面,
這樣我們就可以在一個照相機(主照相機下)下看到另一個照相機(另一個有輔助線的照相機)的作用范圍(輔助線范圍)
var renderer,
scene,
camera,
camera2,
cameraHelper,
canvas,
view1Elem,
view2Elem;
function init() {
renderer = new THREE.WebGLRenderer({ canvas }); const size = 1; const near = 5; const far = 50; //正交投影照相機 camera = new THREE.OrthographicCamera(-size, size, size, -size, near, far); //透視投影照相機 camera2 = new THREE.PerspectiveCamera( 60, // fov 2, // aspect 0.1, // near 500 // far ); //照相機幫助線 cameraHelper = new THREE.CameraHelper(camera); scene = new THREE.Scene(); scene.background = new THREE.Color("black"); scene.add(cameraHelper); } function setCarema() { camera.zoom = 0.2; camera.position.set(0, 10, 20); //旋轉控制器 const controls = new THREE.OrbitControls(camera, view1Elem); controls.target.set(0, 5, 0); controls.update(); camera2.position.set(16, 28, 40); camera2.lookAt(0, 5, 0); //旋轉控制器 const controls2 = new THREE.OrbitControls(camera2, view2Elem); controls2.target.set(0, 5, 0); controls2.update(); } function drawObj() { //面的繪制 { const planeSize = 40; const loader = new THREE.TextureLoader(); const texture = loader.load( "https://threejsfundamentals.org/threejs/resources/images/checker.png" ); texture.wrapS = THREE.RepeatWrapping; texture.wrapT = THREE.RepeatWrapping; texture.magFilter = THREE.NearestFilter; const repeats = planeSize / 2; texture.repeat.set(repeats, repeats); const planeGeo = new THREE.PlaneBufferGeometry(planeSize, planeSize); const planeMat = new THREE.MeshPhongMaterial({ map: texture, side: THREE.DoubleSide }); const mesh = new THREE.Mesh(planeGeo, planeMat); mesh.rotation.x = Math.PI * -0.5; scene.add(mesh); } //正方體的繪制 { const cubeSize = 4; const cubeGeo = new THREE.BoxBufferGeometry(cubeSize, cubeSize, cubeSize); const cubeMat = new THREE.MeshPhongMaterial({ color: "#8AC" }); const mesh = new THREE.Mesh(cubeGeo, cubeMat); mesh.position.set(cubeSize + 1, cubeSize / 2, 0); scene.add(mesh); } //球體的繪制 { const sphereRadius = 3; const sphereWidthDivisions = 32; const sphereHeightDivisions = 16; const sphereGeo = new THREE.SphereBufferGeometry( sphereRadius, sphereWidthDivisions, sphereHeightDivisions ); const sphereMat = new THREE.MeshPhongMaterial({ color: "#CA8" }); const mesh = new THREE.Mesh(sphereGeo, sphereMat); mesh.position.set(-sphereRadius - 1, sphereRadius + 2, 0); scene.add(mesh); } //光線的設置 { const color = 0xffffff; const intensity = 1; const light = new THREE.DirectionalLight(color, intensity); light.position.set(0, 10, 0); light.target.position.set(-5, 0, 0); scene.add(light); scene.add(light.target); } } //重新渲染 渲染器的大小,如果canvas的大小不是renderer的大小,就重新設置大小 canvas的大小,這個是因為 function resizeRendererToDisplaySize(renderer) { const canvas = renderer.domElement; const width = canvas.clientWidth; const height = canvas.clientHeight; const needResize = canvas.width !== width || canvas.height !== height; if (needResize) { renderer.setSize(width, height, false); } return needResize; }
//剪刀,用來切割canvas 到兩個view中,通過view切割計算,找到view的位置,然后進行渲染 function setScissorForElement(elem) { const canvasRect = canvas.getBoundingClientRect(); //包圍盒的正方體 const elemRect = elem.getBoundingClientRect(); // compute a canvas relative rectangle const right = Math.min(elemRect.right, canvasRect.right) - canvasRect.left; const left = Math.max(0, elemRect.left - canvasRect.left); const bottom = Math.min(elemRect.bottom, canvasRect.bottom) - canvasRect.top; const top = Math.max(0, elemRect.top - canvasRect.top); const width = Math.min(canvasRect.width, right - left); const height = Math.min(canvasRect.height, bottom - top); // setup the scissor to only render to that part of the canvas const positiveYUpBottom = canvasRect.height - bottom; renderer.setScissor(left, positiveYUpBottom, width, height); renderer.setViewport(left, positiveYUpBottom, width, height); // return the aspect return width / height; } function render() { resizeRendererToDisplaySize(renderer); // turn on the scissor 開啟剪刀,可以進行切割 renderer.setScissorTest(true); // render the original view { const aspect = setScissorForElement(view1Elem); // update the camera for this aspect camera.left = -aspect; camera.right = aspect; camera.updateProjectionMatrix(); cameraHelper.update(); // don't draw the camera helper in the original view cameraHelper.visible = false; scene.background.set(0x000000); renderer.render(scene, camera); } // render from the 2nd camera { const aspect = setScissorForElement(view2Elem); // update the camera for this aspect camera2.aspect = aspect; camera2.updateProjectionMatrix(); // draw the camera helper in the 2nd view cameraHelper.visible = true; scene.background.set(0x000040); renderer.render(scene, camera2); } requestAnimationFrame(render); } window.onload = function() { canvas = document.querySelector("#c"); view1Elem = document.querySelector("#view1"); view2Elem = document.querySelector("#view2"); init(); setCarema(); drawObj(); requestAnimationFrame(render); };
上面這個例子有點小復雜,因為涉及到,剪刀進行切割視圖的計算
