-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathaoshader.js
182 lines (153 loc) · 6.33 KB
/
aoshader.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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
var glslify = require("glslify")
var fs = require("fs")
var glShader = require('gl-shader')
var mat4 = require('gl-mat4')
var inherits = require('inherits');
var EventEmitter = require('events').EventEmitter;
module.exports = function(game, opts) {
return new ShaderPlugin(game, opts);
};
module.exports.pluginInfo = {
clientOnly: true,
loadAfter: ['voxel-stitch', 'game-shell-fps-camera'],
};
function ShaderPlugin(game, opts) {
this.shell = game.shell;
this.stitcher = game.plugins.get('voxel-stitch');
if (!this.stitcher) throw new Error('voxel-shader requires voxel-stitch plugin'); // for tileCount uniform and updateTexture event
this.meshes = opts.meshes || game.voxels.meshes
if (!this.meshes) throw new Error('voxel-shader requires "meshes" option or game.voxels.meshes set to array of voxel-mesher meshes')
if (game.getCamera) {
this.camera = game.getCamera()
if (!(this.camera && this.camera.view)) throw new Error('voxel-shader requires a camera with a view matrix'); // for camera view matrix
} else {
this.camera = game.plugins.get('game-shell-fps-camera');
if (!this.camera) throw new Error('voxel-shader requires game-shell-fps-camera plugin'); // for camera view matrix
}
this.perspectiveResize = opts.perspectiveResize !== undefined ? opts.perspectiveResize : true;
this.cameraNear = opts.cameraNear !== undefined ? opts.cameraNear : 0.1;
this.cameraFar = opts.cameraFar !== undefined ? opts.cameraFar : 200.0;
this.cameraFOV = opts.cameraFOV !== undefined ? opts.cameraFOV : 45.0;
this.projectionMatrix = mat4.create();
this.enable();
}
inherits(ShaderPlugin, EventEmitter);
ShaderPlugin.prototype.enable = function() {
this.on('updateProjectionMatrix', this.perspective.bind(this));
this.shell.on('gl-init', this.onInit = this.ginit.bind(this));
this.shell.on('gl-render', this.onRender = this.render.bind(this));
if (this.perspectiveResize) this.shell.on('gl-resize', this.onResize = this.updateProjectionMatrix.bind(this));
this.stitcher.on('updateTexture', this.onUpdateTexture = this.texturesReady.bind(this));
};
ShaderPlugin.prototype.disable = function() {
this.shell.removeListener('gl-init', this.onInit);
this.shell.removeListener('gl-render', this.onRender);
if (this.onResize) this.shell.removeListener('gl-resize', this.onResize);
this.stitcher.removeListener('updateTexture', this.onUpdateTexture);
};
ShaderPlugin.prototype.texturesReady = function(texture) {
this.texture = texture; // used in tileMap uniform
}
ShaderPlugin.prototype.ginit = function() {
this.shader = this.createAOShader();
this.shader2 = this.createCustomModelShader();
this.updateProjectionMatrix();
this.viewMatrix = mat4.create();
};
ShaderPlugin.prototype.perspective = function(out) {
mat4.perspective(out, this.cameraFOV*Math.PI/180, this.shell.width/this.shell.height, this.cameraNear, this.cameraFar)
};
ShaderPlugin.prototype.updateProjectionMatrix = function() {
this.emit('updateProjectionMatrix', this.projectionMatrix);
};
ShaderPlugin.prototype.render = function() {
var gl = this.shell.gl
this.camera.view(this.viewMatrix)
gl.enable(gl.CULL_FACE)
gl.enable(gl.DEPTH_TEST)
//Bind the shader
// phase 1 - solid blocks
gl.disable(gl.BLEND)
var shader = this.shader
if (!shader) throw new Error('voxel-shader render() called before gl-init, shader=', this.shader)
shader.bind()
shader.attributes.attrib0.location = 0
shader.attributes.attrib1.location = 1
shader.uniforms.projection = this.projectionMatrix
shader.uniforms.view = this.viewMatrix
shader.uniforms.tileCount = this.stitcher.tileCount
if (this.texture) shader.uniforms.tileMap = this.texture.bind() // if a texture is loaded
var keys = Object.keys(this.meshes)
var length = keys.length
for (var k = 0; k < length; ++k) {
var chunkIndex = keys[k]
var mesh = this.meshes[chunkIndex]
var triangleVAO = mesh.vertexArrayObjects.surface
if (triangleVAO && triangleVAO.length !== 0) { // if there are triangles to render
shader.uniforms.model = mesh.modelMatrix
triangleVAO.bind()
gl.drawArrays(gl.TRIANGLES, 0, triangleVAO.length)
triangleVAO.unbind()
}
}
// phase 2 - "porous" blocks
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA) // TODO: premult alpha? https://github.com/deathcap/voxel-stitch/issues/6
gl.enable(gl.BLEND)
var shader2 = this.shader2
shader2.bind()
shader2.attributes.position.location = 0
shader2.uniforms.view = this.viewMatrix
shader2.uniforms.projection = this.projectionMatrix
if (this.texture) shader2.uniforms.texture = this.texture.bind()
for (k = 0; k < length; ++k) {
var chunkIndex = keys[k]
var mesh = this.meshes[chunkIndex]
var blockMesh = mesh.vertexArrayObjects.porous
if (blockMesh && blockMesh.length !== 0) {
shader2.uniforms.model = this.meshes[chunkIndex].modelMatrix
blockMesh.bind()
blockMesh.draw(gl.TRIANGLES, blockMesh.length)
blockMesh.unbind()
}
}
};
ShaderPlugin.prototype.createAOShader = function() {
return glShader(this.shell.gl ,
glslify('./lib/ao.vsh'),
glslify('./lib/ao.fsh')
)
// return glslify({
// vertex: './lib/ao.vsh',
// fragment: './lib/ao.fsh'
// })(this.shell.gl)
};
ShaderPlugin.prototype.createCustomModelShader = function() {
// TODO: refactor with voxel-decals, voxel-chunkborder?
return glShader(this.shell.gl,
glslify(
"\
attribute vec3 position;\
attribute vec2 uv;\
\
uniform mat4 projection;\
uniform mat4 view;\
uniform mat4 model;\
varying vec2 vUv;\
\
void main() {\
gl_Position = projection * view * model * vec4(position, 1.0);\
vUv = uv;\
}",
{inline: true}),
glslify(
"\
precision highp float;\
\
uniform sampler2D texture;\
varying vec2 vUv;\
\
void main() {\
gl_FragColor = texture2D(texture, vUv);\
}",
{inline: true}));
};