-
Notifications
You must be signed in to change notification settings - Fork 16
/
point-light.js
115 lines (99 loc) · 2.89 KB
/
point-light.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
const Signal = require('signals')
const mat4 = require('pex-math').mat4
function PointLight(opts) {
this.type = 'PointLight'
this.enabled = true
this.changed = new Signal()
this.color = [1, 1, 1, 1]
this.intensity = 1
this.range = 10
this.castShadows = false
const ctx = opts.ctx
this._ctx = ctx
this.set(opts)
}
PointLight.prototype.init = function(entity) {
this.entity = entity
}
PointLight.prototype.set = function(opts) {
Object.assign(this, opts)
if (opts.color !== undefined || opts.intensity !== undefined) {
this.color[3] = this.intensity
}
if (opts.castShadows && !this._ctx.capabilities.depthTexture) {
console.warn(
'PointLight.castShadows is not supported. WEBGL_depth_texture missing.'
)
this.castShadows = false
}
Object.keys(opts).forEach((prop) => this.changed.dispatch(prop))
if (this.castShadows) {
if (!this._shadowCubemap) this.allocateResources()
} else {
if (this._shadowCubemap) this.disposeResources()
}
}
PointLight.prototype.allocateResources = function() {
const ctx = this._ctx
const CUBEMAP_SIZE = 512
this._shadowCubemap = ctx.textureCube({
width: CUBEMAP_SIZE,
height: CUBEMAP_SIZE,
pixelFormat: this.rgbm ? ctx.PixelFormat.RGBA8 : ctx.PixelFormat.RGBA16F,
encoding: this.rgbm ? ctx.Encoding.RGBM : ctx.Encoding.Linear
})
this._shadowMap = ctx.texture2D({
name: 'pointLightShadowMap',
width: CUBEMAP_SIZE,
height: CUBEMAP_SIZE,
pixelFormat: ctx.PixelFormat.Depth,
encoding: ctx.Encoding.Linear
})
this._sides = [
{ eye: [0, 0, 0], target: [1, 0, 0], up: [0, -1, 0] },
{ eye: [0, 0, 0], target: [-1, 0, 0], up: [0, -1, 0] },
{ eye: [0, 0, 0], target: [0, 1, 0], up: [0, 0, 1] },
{ eye: [0, 0, 0], target: [0, -1, 0], up: [0, 0, -1] },
{ eye: [0, 0, 0], target: [0, 0, 1], up: [0, -1, 0] },
{ eye: [0, 0, 0], target: [0, 0, -1], up: [0, -1, 0] }
].map((side, i) => {
side.projectionMatrix = mat4.perspective(
mat4.create(),
Math.PI / 2,
1,
0.1,
100
) // TODO: change this to radians
side.viewMatrix = mat4.lookAt(mat4.create(), side.eye, side.target, side.up)
side.drawPassCmd = {
name: 'PointLight.sidePass',
pass: ctx.pass({
name: 'PointLight.sidePass',
depth: this._shadowMap,
color: [
{
texture: this._shadowCubemap,
target: ctx.gl.TEXTURE_CUBE_MAP_POSITIVE_X + i
}
],
clearColor: [0, 0, 0, 1],
clearDepth: 1
})
}
return side
})
}
PointLight.prototype.disposeResources = function() {
const ctx = this._ctx
ctx.dispose(this._shadowCubemap)
this._shadowCubemap = null
ctx.dispose(this._shadowMap)
this._shadowMap = null
this._sides.forEach((side) => {
ctx.dispose(side.drawPassCmd.pass)
})
this._sides = null
}
module.exports = function(opts) {
return new PointLight(opts)
}