【问题标题】:Threejs 'view crop' using viewport and scissorsThreejs 使用视口和剪刀“查看裁剪”
【发布时间】:2020-08-06 11:26:41
【问题描述】:

概述:

  • 我有一个带有定位透视相机和多个资产的场景,可以产生我想要的输出
  • 我不想移动/更改相机的 fov,因为这需要我动态调整场景中的所有元素(请参阅调试相机视图图像)
  • 我想要一个场景的“视图裁剪”,从全尺寸到更小的尺寸(并不总是相同的比例。查看生成的画布图像

我尝试过以下组合:

renderer.setScissor(0, 0, 320, 240)
renderer.setScissorTest(true)
renderer.setViewport(0, 0, 320, 240)
renderer.setSize(320, 240)
renderer.getContext().canvas.width = 320
renderer.getContext().canvas.height = 240
renderer.getContext().canvas.style.width = '320px'
renderer.getContext().canvas.style.height = '240px'
  • 应用剪刀给了我想要看到的示例,因为只有那些项目被渲染,但整个视图仍然是相同的大小
  • 应用视口会缩小整个图像,
  • 相对于整个图像而不是我要裁剪的点调整画布裁剪。

我可以进行 blitting(将我想要的确切像素复制到单独的画布上,但我希望有另一种更简单的方法。

有什么想法吗?

我在这里添加了一个 codepen 示例: https://codepen.io/faysvas/pen/KKzPQpa

const makeCube = (scene, color, x) => {
    const material = new THREE.MeshPhongMaterial({ color })
    const cube = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), material)
    scene.add(cube)
    cube.position.x = x
    return cube;
}
const addSceneContents = (scene) => {
    const light = new THREE.DirectionalLight(0xffffff, 1)
    light.position.set(-1, 2, 4)
    scene.add(light)
    return [
        makeCube(scene, 0x44aa88, 0),
        makeCube(scene, 0x8844aa, -2),
        makeCube(scene, 0xaa8844, 2)
    ]
}
const main = () => {
    const canvas = document.querySelector("#c")
    const renderer = new THREE.WebGLRenderer({ canvas })
    renderer.setSize(512, 512, false)
    const fov = 75
    const aspect = 1
    const near = 0.1
    const far = 5
    const camera = new THREE.PerspectiveCamera(fov, aspect, near, far)
    camera.position.z = 2

    const scene = new THREE.Scene()
    scene.background = new THREE.Color( 0xff0000 )
    let cubes = addSceneContents(scene)

    resizeTo320x240(renderer, canvas) 


    const render = (time) => {
        time *= 0.001
        cubes.forEach((cube, ndx) => {
            const speed = 1 + ndx * 0.1
            const rot = time * speed
            cube.rotation.x = rot
            cube.rotation.y = rot
        })
        renderer.render(scene, camera)
        requestAnimationFrame(render)
    }
    requestAnimationFrame(render)
}
/*
This function should 'crop' from the whole scene without 
distorting the perspective of the camera and ensuring the 
canvas is 320x240
e.g. I want the canvas to be the same size and output of 
red cropped view below. Eg, no black and the canvas (and 
it's red contents) should be in the top left of the corner 
of the screen
*/
const resizeTo320x240 = (renderer, canvas) => {
    console.log('code goes here')
    const desiredWidth = 320
    const desiredHeight = 240
    const currentSize = renderer.getSize(new THREE.Vector2())
    const x = (currentSize.x / 2) - (desiredWidth/2)
    const y = (currentSize.y / 2) - (desiredHeight/2)

    renderer.setScissor(x, y, desiredWidth, desiredHeight)
    renderer.setScissorTest(true)
    //renderer.setViewport(x, y, desiredWidth, desiredHeight)
}
main()
html, body {
   margin: 0;
   height: 100%;
   background-color: grey;
}
#c {
   display: block;
   background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r119/three.min.js"></script>
<canvas id="c"></canvas>

【问题讨论】:

    标签: three.js rendering viewport


    【解决方案1】:

    我想通了。渲染器或视口不是解决它的地方,相反,相机本身具有偏移或剪辑它自己的输出的能力。

    const makeCube = (scene, color, x) => {
        const material = new THREE.MeshPhongMaterial({ color })
        const cube = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), material)
        scene.add(cube)
        cube.position.x = x
        return cube;
    }
    const addSceneContents = (scene) => {
        const light = new THREE.DirectionalLight(0xffffff, 1)
        light.position.set(-1, 2, 4)
        scene.add(light)
        return [
            makeCube(scene, 0x44aa88, 0),
            makeCube(scene, 0x8844aa, -2),
            makeCube(scene, 0xaa8844, 2)
        ]
    }
    const main = () => {
        const canvas = document.querySelector("#c")
        const renderer = new THREE.WebGLRenderer({ canvas })
        renderer.setSize(512, 512, false)
        const fov = 75
        const aspect = 1
        const near = 0.1
        const far = 5
        const camera = new THREE.PerspectiveCamera(fov, aspect, near, far)
        camera.position.z = 2
    
        const scene = new THREE.Scene()
        scene.background = new THREE.Color( 0xff0000 )
        let cubes = addSceneContents(scene)
    
        resizeTo320x240(renderer, canvas, camera) 
    
    
        const render = (time) => {
            time *= 0.001
            cubes.forEach((cube, ndx) => {
                const speed = 1 + ndx * 0.1
                const rot = time * speed
                cube.rotation.x = rot
                cube.rotation.y = rot
            })
            renderer.render(scene, camera)
            requestAnimationFrame(render)
        }
        requestAnimationFrame(render)
    }
    /*
    This function should 'crop' from the whole scene without 
    distorting the perspective of the camera and ensuring the 
    canvas is 320x240
    e.g. I want the canvas to be the same size and output of 
    red cropped view below. Eg, no black and the canvas (and 
    it's red contents) should be in the top left of the corner 
    of the screen
    */
    const resizeTo320x240 = (renderer, canvas, camera) => {
        console.log('code goes here')
        const desiredWidth = 320
        const desiredHeight = 240
        
        const currentSize = renderer.getSize(new THREE.Vector2())
        const x = (currentSize.x / 2) - (desiredWidth/2)
        const y = (currentSize.y / 2) - (desiredHeight/2)
        
        // Set the size of the renderer to the correct desired output size
        renderer.setSize(desiredWidth, desiredHeight, false)
      
        // The camera its is one that should be cropped
        // This is referred to as the view offset in three.js
        camera.setViewOffset(currentSize.x,currentSize.y,x,y, desiredWidth, desiredHeight)
    }
    main()
    html, body {
       margin: 0;
       height: 100%;
       background-color: grey;
    }
    #c {
       display: block;
       background-color: red;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r119/three.min.js"></script>
    <canvas id="c"></canvas>

    【讨论】:

      猜你喜欢
      • 2021-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多