uti.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802
  1. // Utilities
  2. var Vector3 = {};
  3. var Matrix44 = {};
  4. Vector3.create = function(x, y, z) {
  5. return {'x':x, 'y':y, 'z':z};
  6. };
  7. Vector3.dot = function (v0, v1) {
  8. return v0.x * v1.x + v0.y * v1.y + v0.z * v1.z;
  9. };
  10. Vector3.cross = function (v, v0, v1) {
  11. v.x = v0.y * v1.z - v0.z * v1.y;
  12. v.y = v0.z * v1.x - v0.x * v1.z;
  13. v.z = v0.x * v1.y - v0.y * v1.x;
  14. };
  15. Vector3.normalize = function (v) {
  16. var l = v.x * v.x + v.y * v.y + v.z * v.z;
  17. if(l > 0.00001) {
  18. l = 1.0 / Math.sqrt(l);
  19. v.x *= l;
  20. v.y *= l;
  21. v.z *= l;
  22. }
  23. };
  24. Vector3.arrayForm = function(v) {
  25. if(v.array) {
  26. v.array[0] = v.x;
  27. v.array[1] = v.y;
  28. v.array[2] = v.z;
  29. }
  30. else {
  31. v.array = new Float32Array([v.x, v.y, v.z]);
  32. }
  33. return v.array;
  34. };
  35. Matrix44.createIdentity = function () {
  36. return new Float32Array([1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0]);
  37. };
  38. Matrix44.loadProjection = function (m, aspect, vdeg, near, far) {
  39. var h = near * Math.tan(vdeg * Math.PI / 180.0 * 0.5) * 2.0;
  40. var w = h * aspect;
  41. m[0] = 2.0 * near / w;
  42. m[1] = 0.0;
  43. m[2] = 0.0;
  44. m[3] = 0.0;
  45. m[4] = 0.0;
  46. m[5] = 2.0 * near / h;
  47. m[6] = 0.0;
  48. m[7] = 0.0;
  49. m[8] = 0.0;
  50. m[9] = 0.0;
  51. m[10] = -(far + near) / (far - near);
  52. m[11] = -1.0;
  53. m[12] = 0.0;
  54. m[13] = 0.0;
  55. m[14] = -2.0 * far * near / (far - near);
  56. m[15] = 0.0;
  57. };
  58. Matrix44.loadLookAt = function (m, vpos, vlook, vup) {
  59. var frontv = Vector3.create(vpos.x - vlook.x, vpos.y - vlook.y, vpos.z - vlook.z);
  60. Vector3.normalize(frontv);
  61. var sidev = Vector3.create(1.0, 0.0, 0.0);
  62. Vector3.cross(sidev, vup, frontv);
  63. Vector3.normalize(sidev);
  64. var topv = Vector3.create(1.0, 0.0, 0.0);
  65. Vector3.cross(topv, frontv, sidev);
  66. Vector3.normalize(topv);
  67. m[0] = sidev.x;
  68. m[1] = topv.x;
  69. m[2] = frontv.x;
  70. m[3] = 0.0;
  71. m[4] = sidev.y;
  72. m[5] = topv.y;
  73. m[6] = frontv.y;
  74. m[7] = 0.0;
  75. m[8] = sidev.z;
  76. m[9] = topv.z;
  77. m[10] = frontv.z;
  78. m[11] = 0.0;
  79. m[12] = -(vpos.x * m[0] + vpos.y * m[4] + vpos.z * m[8]);
  80. m[13] = -(vpos.x * m[1] + vpos.y * m[5] + vpos.z * m[9]);
  81. m[14] = -(vpos.x * m[2] + vpos.y * m[6] + vpos.z * m[10]);
  82. m[15] = 1.0;
  83. };
  84. //
  85. var timeInfo = {
  86. 'start':0, 'prev':0, // Date
  87. 'delta':0, 'elapsed':0 // Number(sec)
  88. };
  89. //
  90. var gl;
  91. var renderSpec = {
  92. 'width':0,
  93. 'height':0,
  94. 'aspect':1,
  95. 'array':new Float32Array(3),
  96. 'halfWidth':0,
  97. 'halfHeight':0,
  98. 'halfArray':new Float32Array(3)
  99. // and some render targets. see setViewport()
  100. };
  101. renderSpec.setSize = function(w, h) {
  102. renderSpec.width = w;
  103. renderSpec.height = h;
  104. renderSpec.aspect = renderSpec.width / renderSpec.height;
  105. renderSpec.array[0] = renderSpec.width;
  106. renderSpec.array[1] = renderSpec.height;
  107. renderSpec.array[2] = renderSpec.aspect;
  108. renderSpec.halfWidth = Math.floor(w / 2);
  109. renderSpec.halfHeight = Math.floor(h / 2);
  110. renderSpec.halfArray[0] = renderSpec.halfWidth;
  111. renderSpec.halfArray[1] = renderSpec.halfHeight;
  112. renderSpec.halfArray[2] = renderSpec.halfWidth / renderSpec.halfHeight;
  113. };
  114. function deleteRenderTarget(rt) {
  115. gl.deleteFramebuffer(rt.frameBuffer);
  116. gl.deleteRenderbuffer(rt.renderBuffer);
  117. gl.deleteTexture(rt.texture);
  118. }
  119. function createRenderTarget(w, h) {
  120. var ret = {
  121. 'width':w,
  122. 'height':h,
  123. 'sizeArray':new Float32Array([w, h, w / h]),
  124. 'dtxArray':new Float32Array([1.0 / w, 1.0 / h])
  125. };
  126. ret.frameBuffer = gl.createFramebuffer();
  127. ret.renderBuffer = gl.createRenderbuffer();
  128. ret.texture = gl.createTexture();
  129. gl.bindTexture(gl.TEXTURE_2D, ret.texture);
  130. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, w, h, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
  131. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  132. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  133. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  134. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  135. gl.bindFramebuffer(gl.FRAMEBUFFER, ret.frameBuffer);
  136. gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, ret.texture, 0);
  137. gl.bindRenderbuffer(gl.RENDERBUFFER, ret.renderBuffer);
  138. gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, w, h);
  139. gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, ret.renderBuffer);
  140. gl.bindTexture(gl.TEXTURE_2D, null);
  141. gl.bindRenderbuffer(gl.RENDERBUFFER, null);
  142. gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  143. return ret;
  144. }
  145. function compileShader(shtype, shsrc) {
  146. var retsh = gl.createShader(shtype);
  147. gl.shaderSource(retsh, shsrc);
  148. gl.compileShader(retsh);
  149. if(!gl.getShaderParameter(retsh, gl.COMPILE_STATUS)) {
  150. var errlog = gl.getShaderInfoLog(retsh);
  151. gl.deleteShader(retsh);
  152. console.error(errlog);
  153. return null;
  154. }
  155. return retsh;
  156. }
  157. function createShader(vtxsrc, frgsrc, uniformlist, attrlist) {
  158. var vsh = compileShader(gl.VERTEX_SHADER, vtxsrc);
  159. var fsh = compileShader(gl.FRAGMENT_SHADER, frgsrc);
  160. if(vsh == null || fsh == null) {
  161. return null;
  162. }
  163. var prog = gl.createProgram();
  164. gl.attachShader(prog, vsh);
  165. gl.attachShader(prog, fsh);
  166. gl.deleteShader(vsh);
  167. gl.deleteShader(fsh);
  168. gl.linkProgram(prog);
  169. if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) {
  170. var errlog = gl.getProgramInfoLog(prog);
  171. console.error(errlog);
  172. return null;
  173. }
  174. if(uniformlist) {
  175. prog.uniforms = {};
  176. for(var i = 0; i < uniformlist.length; i++) {
  177. prog.uniforms[uniformlist[i]] = gl.getUniformLocation(prog, uniformlist[i]);
  178. }
  179. }
  180. if(attrlist) {
  181. prog.attributes = {};
  182. for(var i = 0; i < attrlist.length; i++) {
  183. var attr = attrlist[i];
  184. prog.attributes[attr] = gl.getAttribLocation(prog, attr);
  185. }
  186. }
  187. return prog;
  188. }
  189. function useShader(prog) {
  190. gl.useProgram(prog);
  191. for(var attr in prog.attributes) {
  192. gl.enableVertexAttribArray(prog.attributes[attr]);;
  193. }
  194. }
  195. function unuseShader(prog) {
  196. for(var attr in prog.attributes) {
  197. gl.disableVertexAttribArray(prog.attributes[attr]);;
  198. }
  199. gl.useProgram(null);
  200. }
  201. /////
  202. var projection = {
  203. 'angle':60,
  204. 'nearfar':new Float32Array([0.1, 100.0]),
  205. 'matrix':Matrix44.createIdentity()
  206. };
  207. var camera = {
  208. 'position':Vector3.create(0, 0, 100),
  209. 'lookat':Vector3.create(0, 0, 0),
  210. 'up':Vector3.create(0, 1, 0),
  211. 'dof':Vector3.create(10.0, 4.0, 8.0),
  212. 'matrix':Matrix44.createIdentity()
  213. };
  214. var pointFlower = {};
  215. var meshFlower = {};
  216. var sceneStandBy = false;
  217. var BlossomParticle = function () {
  218. this.velocity = new Array(3);
  219. this.rotation = new Array(3);
  220. this.position = new Array(3);
  221. this.euler = new Array(3);
  222. this.size = 1.0;
  223. this.alpha = 1.0;
  224. this.zkey = 0.0;
  225. };
  226. BlossomParticle.prototype.setVelocity = function (vx, vy, vz) {
  227. this.velocity[0] = vx;
  228. this.velocity[1] = vy;
  229. this.velocity[2] = vz;
  230. };
  231. BlossomParticle.prototype.setRotation = function (rx, ry, rz) {
  232. this.rotation[0] = rx;
  233. this.rotation[1] = ry;
  234. this.rotation[2] = rz;
  235. };
  236. BlossomParticle.prototype.setPosition = function (nx, ny, nz) {
  237. this.position[0] = nx;
  238. this.position[1] = ny;
  239. this.position[2] = nz;
  240. };
  241. BlossomParticle.prototype.setEulerAngles = function (rx, ry, rz) {
  242. this.euler[0] = rx;
  243. this.euler[1] = ry;
  244. this.euler[2] = rz;
  245. };
  246. BlossomParticle.prototype.setSize = function (s) {
  247. this.size = s;
  248. };
  249. BlossomParticle.prototype.update = function (dt, et) {
  250. this.position[0] += this.velocity[0] * dt;
  251. this.position[1] += this.velocity[1] * dt;
  252. this.position[2] += this.velocity[2] * dt;
  253. this.euler[0] += this.rotation[0] * dt;
  254. this.euler[1] += this.rotation[1] * dt;
  255. this.euler[2] += this.rotation[2] * dt;
  256. };
  257. function createPointFlowers() {
  258. // get point sizes
  259. var prm = gl.getParameter(gl.ALIASED_POINT_SIZE_RANGE);
  260. renderSpec.pointSize = {'min':prm[0], 'max':prm[1]};
  261. var vtxsrc = document.getElementById("sakura_point_vsh").textContent;
  262. var frgsrc = document.getElementById("sakura_point_fsh").textContent;
  263. pointFlower.program = createShader(
  264. vtxsrc, frgsrc,
  265. ['uProjection', 'uModelview', 'uResolution', 'uOffset', 'uDOF', 'uFade'],
  266. ['aPosition', 'aEuler', 'aMisc']
  267. );
  268. useShader(pointFlower.program);
  269. pointFlower.offset = new Float32Array([0.0, 0.0, 0.0]);
  270. pointFlower.fader = Vector3.create(0.0, 10.0, 0.0);
  271. // paramerters: velocity[3], rotate[3]
  272. pointFlower.numFlowers = 1600;
  273. pointFlower.particles = new Array(pointFlower.numFlowers);
  274. // vertex attributes {position[3], euler_xyz[3], size[1]}
  275. pointFlower.dataArray = new Float32Array(pointFlower.numFlowers * (3 + 3 + 2));
  276. pointFlower.positionArrayOffset = 0;
  277. pointFlower.eulerArrayOffset = pointFlower.numFlowers * 3;
  278. pointFlower.miscArrayOffset = pointFlower.numFlowers * 6;
  279. pointFlower.buffer = gl.createBuffer();
  280. gl.bindBuffer(gl.ARRAY_BUFFER, pointFlower.buffer);
  281. gl.bufferData(gl.ARRAY_BUFFER, pointFlower.dataArray, gl.DYNAMIC_DRAW);
  282. gl.bindBuffer(gl.ARRAY_BUFFER, null);
  283. unuseShader(pointFlower.program);
  284. for(var i = 0; i < pointFlower.numFlowers; i++) {
  285. pointFlower.particles[i] = new BlossomParticle();
  286. }
  287. }
  288. function initPointFlowers() {
  289. //area
  290. pointFlower.area = Vector3.create(20.0, 20.0, 20.0);
  291. pointFlower.area.x = pointFlower.area.y * renderSpec.aspect;
  292. pointFlower.fader.x = 10.0; //env fade start
  293. pointFlower.fader.y = pointFlower.area.z; //env fade half
  294. pointFlower.fader.z = 0.1; //near fade start
  295. //particles
  296. var PI2 = Math.PI * 2.0;
  297. var tmpv3 = Vector3.create(0, 0, 0);
  298. var tmpv = 0;
  299. var symmetryrand = function() {return (Math.random() * 2.0 - 1.0);};
  300. for(var i = 0; i < pointFlower.numFlowers; i++) {
  301. var tmpprtcl = pointFlower.particles[i];
  302. //velocity
  303. tmpv3.x = symmetryrand() * 0.3 + 0.8;
  304. tmpv3.y = symmetryrand() * 0.2 - 1.0;
  305. tmpv3.z = symmetryrand() * 0.3 + 0.5;
  306. Vector3.normalize(tmpv3);
  307. tmpv = 2.0 + Math.random() * 1.0;
  308. tmpprtcl.setVelocity(tmpv3.x * tmpv, tmpv3.y * tmpv, tmpv3.z * tmpv);
  309. //rotation
  310. tmpprtcl.setRotation(
  311. symmetryrand() * PI2 * 0.5,
  312. symmetryrand() * PI2 * 0.5,
  313. symmetryrand() * PI2 * 0.5
  314. );
  315. //position
  316. tmpprtcl.setPosition(
  317. symmetryrand() * pointFlower.area.x,
  318. symmetryrand() * pointFlower.area.y,
  319. symmetryrand() * pointFlower.area.z
  320. );
  321. //euler
  322. tmpprtcl.setEulerAngles(
  323. Math.random() * Math.PI * 2.0,
  324. Math.random() * Math.PI * 2.0,
  325. Math.random() * Math.PI * 2.0
  326. );
  327. //size
  328. tmpprtcl.setSize(0.9 + Math.random() * 0.1);
  329. }
  330. }
  331. function renderPointFlowers() {
  332. //update
  333. var PI2 = Math.PI * 2.0;
  334. var limit = [pointFlower.area.x, pointFlower.area.y, pointFlower.area.z];
  335. var repeatPos = function (prt, cmp, limit) {
  336. if(Math.abs(prt.position[cmp]) - prt.size * 0.5 > limit) {
  337. //out of area
  338. if(prt.position[cmp] > 0) {
  339. prt.position[cmp] -= limit * 2.0;
  340. }
  341. else {
  342. prt.position[cmp] += limit * 2.0;
  343. }
  344. }
  345. };
  346. var repeatEuler = function (prt, cmp) {
  347. prt.euler[cmp] = prt.euler[cmp] % PI2;
  348. if(prt.euler[cmp] < 0.0) {
  349. prt.euler[cmp] += PI2;
  350. }
  351. };
  352. for(var i = 0; i < pointFlower.numFlowers; i++) {
  353. var prtcl = pointFlower.particles[i];
  354. prtcl.update(timeInfo.delta, timeInfo.elapsed);
  355. repeatPos(prtcl, 0, pointFlower.area.x);
  356. repeatPos(prtcl, 1, pointFlower.area.y);
  357. repeatPos(prtcl, 2, pointFlower.area.z);
  358. repeatEuler(prtcl, 0);
  359. repeatEuler(prtcl, 1);
  360. repeatEuler(prtcl, 2);
  361. prtcl.alpha = 1.0;//(pointFlower.area.z - prtcl.position[2]) * 0.5;
  362. prtcl.zkey = (camera.matrix[2] * prtcl.position[0]
  363. + camera.matrix[6] * prtcl.position[1]
  364. + camera.matrix[10] * prtcl.position[2]
  365. + camera.matrix[14]);
  366. }
  367. // sort
  368. pointFlower.particles.sort(function(p0, p1){return p0.zkey - p1.zkey;});
  369. // update data
  370. var ipos = pointFlower.positionArrayOffset;
  371. var ieuler = pointFlower.eulerArrayOffset;
  372. var imisc = pointFlower.miscArrayOffset;
  373. for(var i = 0; i < pointFlower.numFlowers; i++) {
  374. var prtcl = pointFlower.particles[i];
  375. pointFlower.dataArray[ipos] = prtcl.position[0];
  376. pointFlower.dataArray[ipos + 1] = prtcl.position[1];
  377. pointFlower.dataArray[ipos + 2] = prtcl.position[2];
  378. ipos += 3;
  379. pointFlower.dataArray[ieuler] = prtcl.euler[0];
  380. pointFlower.dataArray[ieuler + 1] = prtcl.euler[1];
  381. pointFlower.dataArray[ieuler + 2] = prtcl.euler[2];
  382. ieuler += 3;
  383. pointFlower.dataArray[imisc] = prtcl.size;
  384. pointFlower.dataArray[imisc + 1] = prtcl.alpha;
  385. imisc += 2;
  386. }
  387. //draw
  388. gl.enable(gl.BLEND);
  389. //gl.disable(gl.DEPTH_TEST);
  390. gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
  391. var prog = pointFlower.program;
  392. useShader(prog);
  393. gl.uniformMatrix4fv(prog.uniforms.uProjection, false, projection.matrix);
  394. gl.uniformMatrix4fv(prog.uniforms.uModelview, false, camera.matrix);
  395. gl.uniform3fv(prog.uniforms.uResolution, renderSpec.array);
  396. gl.uniform3fv(prog.uniforms.uDOF, Vector3.arrayForm(camera.dof));
  397. gl.uniform3fv(prog.uniforms.uFade, Vector3.arrayForm(pointFlower.fader));
  398. gl.bindBuffer(gl.ARRAY_BUFFER, pointFlower.buffer);
  399. gl.bufferData(gl.ARRAY_BUFFER, pointFlower.dataArray, gl.DYNAMIC_DRAW);
  400. gl.vertexAttribPointer(prog.attributes.aPosition, 3, gl.FLOAT, false, 0, pointFlower.positionArrayOffset * Float32Array.BYTES_PER_ELEMENT);
  401. gl.vertexAttribPointer(prog.attributes.aEuler, 3, gl.FLOAT, false, 0, pointFlower.eulerArrayOffset * Float32Array.BYTES_PER_ELEMENT);
  402. gl.vertexAttribPointer(prog.attributes.aMisc, 2, gl.FLOAT, false, 0, pointFlower.miscArrayOffset * Float32Array.BYTES_PER_ELEMENT);
  403. // doubler
  404. for(var i = 1; i < 2; i++) {
  405. var zpos = i * -2.0;
  406. pointFlower.offset[0] = pointFlower.area.x * -1.0;
  407. pointFlower.offset[1] = pointFlower.area.y * -1.0;
  408. pointFlower.offset[2] = pointFlower.area.z * zpos;
  409. gl.uniform3fv(prog.uniforms.uOffset, pointFlower.offset);
  410. gl.drawArrays(gl.POINT, 0, pointFlower.numFlowers);
  411. pointFlower.offset[0] = pointFlower.area.x * -1.0;
  412. pointFlower.offset[1] = pointFlower.area.y * 1.0;
  413. pointFlower.offset[2] = pointFlower.area.z * zpos;
  414. gl.uniform3fv(prog.uniforms.uOffset, pointFlower.offset);
  415. gl.drawArrays(gl.POINT, 0, pointFlower.numFlowers);
  416. pointFlower.offset[0] = pointFlower.area.x * 1.0;
  417. pointFlower.offset[1] = pointFlower.area.y * -1.0;
  418. pointFlower.offset[2] = pointFlower.area.z * zpos;
  419. gl.uniform3fv(prog.uniforms.uOffset, pointFlower.offset);
  420. gl.drawArrays(gl.POINT, 0, pointFlower.numFlowers);
  421. pointFlower.offset[0] = pointFlower.area.x * 1.0;
  422. pointFlower.offset[1] = pointFlower.area.y * 1.0;
  423. pointFlower.offset[2] = pointFlower.area.z * zpos;
  424. gl.uniform3fv(prog.uniforms.uOffset, pointFlower.offset);
  425. gl.drawArrays(gl.POINT, 0, pointFlower.numFlowers);
  426. }
  427. //main
  428. pointFlower.offset[0] = 0.0;
  429. pointFlower.offset[1] = 0.0;
  430. pointFlower.offset[2] = 0.0;
  431. gl.uniform3fv(prog.uniforms.uOffset, pointFlower.offset);
  432. gl.drawArrays(gl.POINT, 0, pointFlower.numFlowers);
  433. gl.bindBuffer(gl.ARRAY_BUFFER, null);
  434. unuseShader(prog);
  435. gl.enable(gl.DEPTH_TEST);
  436. gl.disable(gl.BLEND);
  437. }
  438. // effects
  439. //common util
  440. function createEffectProgram(vtxsrc, frgsrc, exunifs, exattrs) {
  441. var ret = {};
  442. var unifs = ['uResolution', 'uSrc', 'uDelta'];
  443. if(exunifs) {
  444. unifs = unifs.concat(exunifs);
  445. }
  446. var attrs = ['aPosition'];
  447. if(exattrs) {
  448. attrs = attrs.concat(exattrs);
  449. }
  450. ret.program = createShader(vtxsrc, frgsrc, unifs, attrs);
  451. useShader(ret.program);
  452. ret.dataArray = new Float32Array([
  453. -1.0, -1.0,
  454. 1.0, -1.0,
  455. -1.0, 1.0,
  456. 1.0, 1.0
  457. ]);
  458. ret.buffer = gl.createBuffer();
  459. gl.bindBuffer(gl.ARRAY_BUFFER, ret.buffer);
  460. gl.bufferData(gl.ARRAY_BUFFER, ret.dataArray, gl.STATIC_DRAW);
  461. gl.bindBuffer(gl.ARRAY_BUFFER, null);
  462. unuseShader(ret.program);
  463. return ret;
  464. }
  465. // basic usage
  466. // useEffect(prog, srctex({'texture':texid, 'dtxArray':(f32)[dtx, dty]})); //basic initialize
  467. // gl.uniform**(...); //additional uniforms
  468. // drawEffect()
  469. // unuseEffect(prog)
  470. // TEXTURE0 makes src
  471. function useEffect(fxobj, srctex) {
  472. var prog = fxobj.program;
  473. useShader(prog);
  474. gl.uniform3fv(prog.uniforms.uResolution, renderSpec.array);
  475. if(srctex != null) {
  476. gl.uniform2fv(prog.uniforms.uDelta, srctex.dtxArray);
  477. gl.uniform1i(prog.uniforms.uSrc, 0);
  478. gl.activeTexture(gl.TEXTURE0);
  479. gl.bindTexture(gl.TEXTURE_2D, srctex.texture);
  480. }
  481. }
  482. function drawEffect(fxobj) {
  483. gl.bindBuffer(gl.ARRAY_BUFFER, fxobj.buffer);
  484. gl.vertexAttribPointer(fxobj.program.attributes.aPosition, 2, gl.FLOAT, false, 0, 0);
  485. gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
  486. }
  487. function unuseEffect(fxobj) {
  488. unuseShader(fxobj.program);
  489. }
  490. var effectLib = {};
  491. function createEffectLib() {
  492. var vtxsrc, frgsrc;
  493. //common
  494. var cmnvtxsrc = document.getElementById("fx_common_vsh").textContent;
  495. //background
  496. frgsrc = document.getElementById("bg_fsh").textContent;
  497. effectLib.sceneBg = createEffectProgram(cmnvtxsrc, frgsrc, ['uTimes'], null);
  498. // make brightpixels buffer
  499. frgsrc = document.getElementById("fx_brightbuf_fsh").textContent;
  500. effectLib.mkBrightBuf = createEffectProgram(cmnvtxsrc, frgsrc, null, null);
  501. // direction blur
  502. frgsrc = document.getElementById("fx_dirblur_r4_fsh").textContent;
  503. effectLib.dirBlur = createEffectProgram(cmnvtxsrc, frgsrc, ['uBlurDir'], null);
  504. //final composite
  505. vtxsrc = document.getElementById("pp_final_vsh").textContent;
  506. frgsrc = document.getElementById("pp_final_fsh").textContent;
  507. effectLib.finalComp = createEffectProgram(vtxsrc, frgsrc, ['uBloom'], null);
  508. }
  509. // background
  510. function createBackground() {
  511. //console.log("create background");
  512. }
  513. function initBackground() {
  514. //console.log("init background");
  515. }
  516. function renderBackground() {
  517. gl.disable(gl.DEPTH_TEST);
  518. useEffect(effectLib.sceneBg, null);
  519. gl.uniform2f(effectLib.sceneBg.program.uniforms.uTimes, timeInfo.elapsed, timeInfo.delta);
  520. drawEffect(effectLib.sceneBg);
  521. unuseEffect(effectLib.sceneBg);
  522. gl.enable(gl.DEPTH_TEST);
  523. }
  524. // post process
  525. var postProcess = {};
  526. function createPostProcess() {
  527. //console.log("create post process");
  528. }
  529. function initPostProcess() {
  530. //console.log("init post process");
  531. }
  532. function renderPostProcess() {
  533. gl.enable(gl.TEXTURE_2D);
  534. gl.disable(gl.DEPTH_TEST);
  535. var bindRT = function (rt, isclear) {
  536. gl.bindFramebuffer(gl.FRAMEBUFFER, rt.frameBuffer);
  537. gl.viewport(0, 0, rt.width, rt.height);
  538. if(isclear) {
  539. gl.clearColor(0, 0, 0, 0);
  540. gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  541. }
  542. };
  543. //make bright buff
  544. bindRT(renderSpec.wHalfRT0, true);
  545. useEffect(effectLib.mkBrightBuf, renderSpec.mainRT);
  546. drawEffect(effectLib.mkBrightBuf);
  547. unuseEffect(effectLib.mkBrightBuf);
  548. // make bloom
  549. for(var i = 0; i < 2; i++) {
  550. var p = 1.5 + 1 * i;
  551. var s = 2.0 + 1 * i;
  552. bindRT(renderSpec.wHalfRT1, true);
  553. useEffect(effectLib.dirBlur, renderSpec.wHalfRT0);
  554. gl.uniform4f(effectLib.dirBlur.program.uniforms.uBlurDir, p, 0.0, s, 0.0);
  555. drawEffect(effectLib.dirBlur);
  556. unuseEffect(effectLib.dirBlur);
  557. bindRT(renderSpec.wHalfRT0, true);
  558. useEffect(effectLib.dirBlur, renderSpec.wHalfRT1);
  559. gl.uniform4f(effectLib.dirBlur.program.uniforms.uBlurDir, 0.0, p, 0.0, s);
  560. drawEffect(effectLib.dirBlur);
  561. unuseEffect(effectLib.dirBlur);
  562. }
  563. //display
  564. gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  565. gl.viewport(0, 0, renderSpec.width, renderSpec.height);
  566. gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  567. useEffect(effectLib.finalComp, renderSpec.mainRT);
  568. gl.uniform1i(effectLib.finalComp.program.uniforms.uBloom, 1);
  569. gl.activeTexture(gl.TEXTURE1);
  570. gl.bindTexture(gl.TEXTURE_2D, renderSpec.wHalfRT0.texture);
  571. drawEffect(effectLib.finalComp);
  572. unuseEffect(effectLib.finalComp);
  573. gl.enable(gl.DEPTH_TEST);
  574. }
  575. /////
  576. var SceneEnv = {};
  577. function createScene() {
  578. createEffectLib();
  579. createBackground();
  580. createPointFlowers();
  581. createPostProcess();
  582. sceneStandBy = true;
  583. }
  584. function initScene() {
  585. initBackground();
  586. initPointFlowers();
  587. initPostProcess();
  588. //camera.position.z = 17.320508;
  589. camera.position.z = pointFlower.area.z + projection.nearfar[0];
  590. projection.angle = Math.atan2(pointFlower.area.y, camera.position.z + pointFlower.area.z) * 180.0 / Math.PI * 2.0;
  591. Matrix44.loadProjection(projection.matrix, renderSpec.aspect, projection.angle, projection.nearfar[0], projection.nearfar[1]);
  592. }
  593. function renderScene() {
  594. //draw
  595. Matrix44.loadLookAt(camera.matrix, camera.position, camera.lookat, camera.up);
  596. gl.enable(gl.DEPTH_TEST);
  597. //gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  598. gl.bindFramebuffer(gl.FRAMEBUFFER, renderSpec.mainRT.frameBuffer);
  599. gl.viewport(0, 0, renderSpec.mainRT.width, renderSpec.mainRT.height);
  600. gl.clearColor(0.005, 0, 0.05, 0);
  601. gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  602. renderBackground();
  603. renderPointFlowers();
  604. renderPostProcess();
  605. }
  606. /////
  607. function onResize(e) {
  608. makeCanvasFullScreen(document.getElementById("sakura"));
  609. setViewports();
  610. if(sceneStandBy) {
  611. initScene();
  612. }
  613. }
  614. function setViewports() {
  615. renderSpec.setSize(gl.canvas.width, gl.canvas.height);
  616. gl.clearColor(0.2, 0.2, 0.5, 1.0);
  617. gl.viewport(0, 0, renderSpec.width, renderSpec.height);
  618. var rtfunc = function (rtname, rtw, rth) {
  619. var rt = renderSpec[rtname];
  620. if(rt) deleteRenderTarget(rt);
  621. renderSpec[rtname] = createRenderTarget(rtw, rth);
  622. };
  623. rtfunc('mainRT', renderSpec.width, renderSpec.height);
  624. rtfunc('wFullRT0', renderSpec.width, renderSpec.height);
  625. rtfunc('wFullRT1', renderSpec.width, renderSpec.height);
  626. rtfunc('wHalfRT0', renderSpec.halfWidth, renderSpec.halfHeight);
  627. rtfunc('wHalfRT1', renderSpec.halfWidth, renderSpec.halfHeight);
  628. }
  629. function render() {
  630. renderScene();
  631. }
  632. var animating = true;
  633. function toggleAnimation(elm) {
  634. animating ^= true;
  635. if(animating) animate();
  636. if(elm) {
  637. elm.innerHTML = animating? "Stop":"Start";
  638. }
  639. }
  640. function stepAnimation() {
  641. if(!animating) animate();
  642. }
  643. function animate() {
  644. var curdate = new Date();
  645. timeInfo.elapsed = (curdate - timeInfo.start) / 1000.0;
  646. timeInfo.delta = (curdate - timeInfo.prev) / 1000.0;
  647. timeInfo.prev = curdate;
  648. if(animating) requestAnimationFrame(animate);
  649. render();
  650. }
  651. function makeCanvasFullScreen(canvas) {
  652. var b = document.body;
  653. var d = document.documentElement;
  654. fullw = Math.max(b.clientWidth , b.scrollWidth, d.scrollWidth, d.clientWidth);
  655. fullh = Math.max(b.clientHeight , b.scrollHeight, d.scrollHeight, d.clientHeight);
  656. canvas.width = fullw;
  657. canvas.height = fullh;
  658. }
  659. window.addEventListener('load', function(e) {
  660. var canvas = document.getElementById("sakura");
  661. try {
  662. makeCanvasFullScreen(canvas);
  663. gl = canvas.getContext('experimental-webgl');
  664. } catch(e) {
  665. alert("WebGL not supported." + e);
  666. console.error(e);
  667. return;
  668. }
  669. window.addEventListener('resize', onResize);
  670. setViewports();
  671. createScene();
  672. initScene();
  673. timeInfo.start = new Date();
  674. timeInfo.prev = timeInfo.start;
  675. animate();
  676. });
  677. //set window.requestAnimationFrame
  678. (function (w, r) {
  679. w['r'+r] = w['r'+r] || w['webkitR'+r] || w['mozR'+r] || w['msR'+r] || w['oR'+r] || function(c){ w.setTimeout(c, 1000 / 60); };
  680. })(window, 'equestAnimationFrame');