Обзор:
- У меня есть сцена с позиционированной перспективной камерой и несколькими активами, которые производят желаемый результат
- Я не хочу перемещать / изменять поле обзора камеры, так как это потребует от меня динамической настройки всех элементов сцены (см. изображение вида отладки камеры)
- Я хочу «обрезать вид» сцены от любого полного размера до меньшего ( не всегда в одинаковых пропорциях. См. результирующее изображение холста
I have tried combinations of:
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'
- Applying the scissor gives me example what I want to see, because only those items are rendered, but the whole view is still the same size
- Applying the viewport scales the WHOLE image down,
- Adjusting the canvas crops relative to the whole image rather than the points I want to crop from.
I CAN do blitting (copy the exact pixels I want onto a separate canvas, but I was hoping there was another simpler way.
Any ideas?
I've added a codepen example here:
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>