pex-renderer
Version:
Physically Based Renderer for Pex
171 lines (151 loc) • 5.32 kB
JavaScript
const Signal = require('signals')
const vec3 = require('pex-math').vec3
function CameraHelper(opts) {
this.type = 'CameraHelper'
this.entity = null
this.color = [1, 0, 0, 1]
this.changed = new Signal()
this.dirty = false
this.enabled = true
if (opts) this.set(opts)
}
// this function gets called when the component is added
// to an enity
CameraHelper.prototype.init = function(entity) {
this.entity = entity
}
CameraHelper.prototype.set = function(opts) {
Object.assign(this, opts)
this.dirty = true
Object.keys(opts).forEach((prop) => this.changed.dispatch(prop))
}
CameraHelper.prototype.update = function() {
if (!this.dirty) return
this.dirty = false
}
CameraHelper.prototype.getBBoxPositionsList = function(bbox) {
return [
[ ][0], bbox[0][1], bbox[0][2]],
[ ][0], bbox[0][1], bbox[0][2]],
[ ][0], bbox[0][1], bbox[0][2]],
[ ][0], bbox[1][1], bbox[0][2]],
[ ][0], bbox[0][1], bbox[0][2]],
[ ][0], bbox[0][1], bbox[1][2]],
[ ][0], bbox[1][1], bbox[1][2]],
[ ][0], bbox[1][1], bbox[1][2]],
[ ][0], bbox[1][1], bbox[1][2]],
[ ][0], bbox[0][1], bbox[1][2]],
[ ][0], bbox[1][1], bbox[1][2]],
[ ][0], bbox[1][1], bbox[0][2]],
[ ][0], bbox[0][1], bbox[0][2]],
[ ][0], bbox[0][1], bbox[1][2]],
[ ][0], bbox[0][1], bbox[0][2]],
[ ][0], bbox[1][1], bbox[0][2]],
[ ][0], bbox[1][1], bbox[0][2]],
[ ][0], bbox[1][1], bbox[0][2]],
[ ][0], bbox[1][1], bbox[0][2]],
[ ][0], bbox[1][1], bbox[1][2]],
[ ][0], bbox[0][1], bbox[1][2]],
[ ][0], bbox[1][1], bbox[1][2]],
[ ][0], bbox[0][1], bbox[1][2]],
[ ][0], bbox[0][1], bbox[1][2]]
]
}
CameraHelper.prototype.draw = function(geomBuilder, camera) {
cType = this.entity.getComponent('Camera')
if (cType.projection == 'orthographic') {
let orthoTransform = this.entity.getComponent('Transform')
let left =
(cType.right + cType.left) / 2 -
(cType.right - cType.left) / (2 / cType.zoom)
let right =
(cType.right + cType.left) / 2 +
(cType.right - cType.left) / (2 / cType.zoom)
let top =
(cType.top + cType.bottom) / 2 +
(cType.top - cType.bottom) / (2 / cType.zoom)
let bottom =
(cType.top + cType.bottom) / 2 -
(cType.top - cType.bottom) / (2 / cType.zoom)
if (cType.view) {
const zoomW =
1 / cType.zoom / (cType.view.size[0] / cType.view.totalSize[0])
const zoomH =
1 / cType.zoom / (cType.view.size[1] / cType.view.totalSize[1])
const scaleW = (cType.right - cType.left) / cType.view.size[0]
const scaleH = (cType.top - cType.bottom) / cType.view.size[1]
left += scaleW * (cType.view.offset[0] / zoomW)
right = left + scaleW * (cType.view.size[0] / zoomW)
top -= scaleH * (cType.view.offset[1] / zoomH)
bottom = top - scaleH * (cType.view.size[1] / zoomH)
}
let orthoHelperPositions = this.getBBoxPositionsList([
[ ],
[ ]
])
orthoHelperPositions.forEach((pos) => {
geomBuilder.addPosition(
vec3.multMat4(vec3.copy(pos), orthoTransform.modelMatrix)
)
geomBuilder.addColor(this.color)
})
}
if (cType.projection == 'perspective') {
const perspectiveCameraTransform = this.entity.getComponent('Transform')
const farCenter = [0, 0, cType.far]
const nearCenter = [0, 0, cType.near]
const nearHeight = 2 * Math.tan(cType.fov / 2) * cType.near
const farHeight = 2 * Math.tan(cType.fov / 2) * cType.far
const nearWidth = nearHeight * cType.aspect
const farWidth = farHeight * cType.aspect
const farTopLeft = [-(farWidth * 0.5), farHeight * 0.5, -cType.far]
const farTopRight = [farWidth * 0.5, farHeight * 0.5, -cType.far]
const farBottomLeft = [-(farWidth * 0.5), -(farHeight * 0.5), -cType.far]
const farBottomRight = [farWidth * 0.5, -(farHeight * 0.5), -cType.far]
const nearTopLeft = [-(nearWidth * 0.5), nearHeight * 0.5, -cType.near]
const nearTopRight = [nearWidth * 0.5, nearHeight * 0.5, -cType.near]
const nearBottomLeft = [
-(nearWidth * 0.5),
-(nearHeight * 0.5),
-cType.near
]
const nearBottomRight = [nearWidth * 0.5, -(nearHeight * 0.5), -cType.near]
const perspectiveCameraHelperPositions = [
[ ],
farTopLeft,
[ ],
farTopRight,
[ ],
farBottomLeft,
[ ],
farBottomRight,
farTopLeft,
farTopRight,
farTopRight,
farBottomRight,
farBottomRight,
farBottomLeft,
farBottomLeft,
farTopLeft,
nearTopLeft,
nearTopRight,
nearTopRight,
nearBottomRight,
nearBottomRight,
nearBottomLeft,
nearBottomLeft,
nearTopLeft
]
perspectiveCameraHelperPositions.forEach((pos) => {
geomBuilder.addPosition(
vec3.multMat4(vec3.copy(pos), perspectiveCameraTransform.modelMatrix)
)
geomBuilder.addColor(this.color)
})
}
}
// by pex-renderer convention we export factory function
// instead of the class type
module.exports = function createCameraHelper(opts) {
return new CameraHelper(opts)
}