-
-
Notifications
You must be signed in to change notification settings - Fork 223
Expand file tree
/
Copy pathpostProcess.js
More file actions
166 lines (145 loc) · 6.96 KB
/
Copy pathpostProcess.js
File metadata and controls
166 lines (145 loc) · 6.96 KB
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
/**
* LittleJS Post Processing Plugin
* - Supports shadertoy style post processing shaders
* - call new PostProcessPlugin() to setup post processing
* - can be enabled to pass other canvases through a final shader
* @namespace PostProcess
*/
'use strict';
///////////////////////////////////////////////////////////////////////////////
/** Global Post Process plugin object
* @type {PostProcessPlugin}
* @memberof PostProcess */
let postProcess;
/////////////////////////////////////////////////////////////////////////
/**
* Post Process Plugin - Applies a full screen shader to the rendered output
* @memberof PostProcess
*/
class PostProcessPlugin
{
/** Create global post processing shader
* @param {string} shaderCode
* @param {boolean} [includeMainCanvas] - combine mainCanvas onto glCanvas
* @param {boolean} [feedbackTexture] - use glCanvas from previous frame as the texture
* @example
* // create the post process plugin object
* new PostProcessPlugin(shaderCode);
*/
constructor(shaderCode, includeMainCanvas=false, feedbackTexture=false)
{
ASSERT(!postProcess, 'Post process already initialized');
ASSERT(!(includeMainCanvas && feedbackTexture), 'Post process cannot both include main canvas and use feedback texture');
postProcess = this;
if (!shaderCode) // default shader pass through
shaderCode = 'void mainImage(out vec4 c,vec2 p){c=texture(iChannel0,p/iResolution.xy);}';
/** @property {WebGLProgram} - Shader for post processing */
this.shader = undefined;
/** @property {WebGLTexture} - Texture for post processing */
this.texture = undefined;
/** @property {WebGLVertexArrayObject} - Vertex array object */
this.vao = undefined;
// setup the post processing plugin
initPostProcess();
engineAddPlugin(undefined, postProcessRender, postProcessContextLost, postProcessContextRestored);
function initPostProcess()
{
if (headlessMode) return;
if (!glEnable)
{
console.warn('PostProcessPlugin: WebGL not enabled!');
return;
}
// create resources
postProcess.texture = glCreateTexture();
postProcess.shader = glCreateProgram(
'#version 300 es\n' + // specify GLSL ES version
'precision highp float;'+ // use highp for accuracy
'in vec2 p;'+ // position
'void main(){'+ // shader entry point
'gl_Position=vec4(p+p-1.,1,1);'+ // set position
'}' // end of shader
,
'#version 300 es\n' + // specify GLSL ES version
'precision highp float;'+ // use highp for accuracy
'uniform sampler2D iChannel0;'+ // input texture
'uniform vec3 iResolution;'+ // size of output texture
'uniform float iTime;'+ // time
'out vec4 c;'+ // out color
'\n' + shaderCode + '\n'+ // insert custom shader code
'void main(){'+ // shader entry point
'mainImage(c,gl_FragCoord.xy);'+ // call post process function
'c.a=1.;'+ // always use full alpha
'}' // end of shader
);
// setup VAO for post processing
postProcess.vao = glContext.createVertexArray();
glContext.bindVertexArray(postProcess.vao);
glContext.bindBuffer(glContext.ARRAY_BUFFER, glGeometryBuffer);
// configure vertex attributes
const vertexByteStride = 8;
const pLocation = glContext.getAttribLocation(postProcess.shader, 'p');
glContext.enableVertexAttribArray(pLocation);
glContext.vertexAttribPointer(pLocation, 2, glContext.FLOAT, false, vertexByteStride, 0);
}
function postProcessContextLost()
{
postProcess.shader = undefined;
postProcess.texture = undefined;
LOG('PostProcessPlugin: WebGL context lost');
}
function postProcessContextRestored()
{
initPostProcess();
LOG('PostProcessPlugin: WebGL context restored');
}
function postProcessRender()
{
if (headlessMode || !glEnable) return;
// clear out the buffer
glFlush();
// ensure we render to the default framebuffer (in case any earlier
// caller this frame left a render target bound)
glContext.bindFramebuffer(glContext.FRAMEBUFFER, null);
// setup shader program to draw a quad
glContext.useProgram(postProcess.shader);
glContext.bindVertexArray(postProcess.vao);
glContext.pixelStorei(glContext.UNPACK_FLIP_Y_WEBGL, true);
glContext.disable(glContext.BLEND);
// setup texture
glContext.activeTexture(glContext.TEXTURE0);
glContext.bindTexture(glContext.TEXTURE_2D, postProcess.texture);
if (includeMainCanvas)
{
// copy main canvas to work canvas
workCanvas.width = mainCanvasSize.x;
workCanvas.height = mainCanvasSize.y;
glCopyToContext(workContext);
workContext.drawImage(mainCanvas, 0, 0);
mainCanvas.width |= 0; // setting size clears the main canvas
// copy work canvas to texture
glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, glContext.RGBA, glContext.UNSIGNED_BYTE, workCanvas);
}
else if (!feedbackTexture)
{
// copy glCanvas to texture
glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, glContext.RGBA, glContext.UNSIGNED_BYTE, glCanvas);
}
// set uniforms and draw
const uniformLocation = (name)=>glContext.getUniformLocation(postProcess.shader, name);
glContext.uniform1i(uniformLocation('iChannel0'), 0);
glContext.uniform1f(uniformLocation('iTime'), time);
glContext.uniform3f(uniformLocation('iResolution'), mainCanvas.width, mainCanvas.height, 1);
glContext.drawArrays(glContext.TRIANGLE_STRIP, 0, 4);
if (feedbackTexture)
{
// pass glCanvas back to overlay texture
glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, glContext.RGBA, glContext.UNSIGNED_BYTE, glCanvas);
}
// restore default so subsequent dynamic texture uploads aren't flipped
glContext.pixelStorei(glContext.UNPACK_FLIP_Y_WEBGL, false);
// force it to set instanced mode
glSetInstancedMode(true);
}
}
}