Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968
  1. /*
  2. This demo is rendered using WebGL code
  3. Check the MARTINS.js code below!
  4. */
  5. /*
  6. WebGL low-level code:
  7. */
  8. class Entity
  9. {
  10. constructor(gl)
  11. {
  12. this._gl = gl;
  13. this._program = this._compile(gl, this.vertexShader, this.fragmentShader);
  14. this._uniformLocation = {
  15. 'time': gl.getUniformLocation(this._program, 'time'),
  16. 'resolution': gl.getUniformLocation(this._program, 'resolution'),
  17. 'projectionMatrix': gl.getUniformLocation(this._program, 'projectionMatrix'),
  18. 'modelViewMatrix': gl.getUniformLocation(this._program, 'modelViewMatrix'),
  19. };
  20. this.projectionMatrix = new Float32Array([1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]);
  21. this.modelViewMatrix = new Float32Array([1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]);
  22. }
  23. render(time = 0)
  24. {
  25. const gl = this._gl, u = this._uniformLocation;
  26. gl.useProgram(this._program);
  27. gl.uniform1f(u.time, time);
  28. gl.uniform2f(u.resolution, gl.canvas.width, gl.canvas.height);
  29. gl.uniformMatrix4fv(u.projectionMatrix, false, this.projectionMatrix);
  30. gl.uniformMatrix4fv(u.modelViewMatrix, false, this.modelViewMatrix);
  31. gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  32. this._render(time);
  33. }
  34. _render(time)
  35. {
  36. const gl = this._gl;
  37. gl.drawArrays(gl.TRIANGLES, 0, 3 * this.numberOfTriangles);
  38. }
  39. get numberOfTriangles()
  40. {
  41. throw new Error();
  42. }
  43. get vertexShader()
  44. {
  45. throw new Error();
  46. }
  47. get fragmentShader()
  48. {
  49. throw new Error();
  50. }
  51. get _includeShaderUtils()
  52. {
  53. return `
  54. mat4 translate(vec3 offset)
  55. {
  56. float x = offset.x, y = offset.y, z = offset.z;
  57. return mat4(
  58. 1, 0, 0, 0,
  59. 0, 1, 0, 0,
  60. 0, 0, 1, 0,
  61. x, y, z, 1
  62. );
  63. }
  64. mat4 scale(vec3 factor)
  65. {
  66. float x = factor.x, y = factor.y, z = factor.z;
  67. return mat4(
  68. x, 0, 0, 0,
  69. 0, y, 0, 0,
  70. 0, 0, z, 0,
  71. 0, 0, 0, 1
  72. );
  73. }
  74. mat4 rotateX(float rad)
  75. {
  76. float s = sin(rad), c = cos(rad);
  77. return mat4(
  78. 1, 0, 0, 0,
  79. 0, c, s, 0,
  80. 0,-s, c, 0,
  81. 0, 0, 0, 1
  82. );
  83. }
  84. mat4 rotateY(float rad)
  85. {
  86. float s = sin(rad), c = cos(rad);
  87. return mat4(
  88. c, 0,-s, 0,
  89. 0, 1, 0, 0,
  90. s, 0, c, 0,
  91. 0, 0, 0, 1
  92. );
  93. }
  94. mat4 rotateZ(float rad)
  95. {
  96. float s = sin(rad), c = cos(rad);
  97. return mat4(
  98. c, s, 0, 0,
  99. -s, c, 0, 0,
  100. 0, 0, 1, 0,
  101. 0, 0, 0, 1
  102. );
  103. }
  104. mat4 rotate(vec3 euler)
  105. {
  106. return rotateZ(euler.z) * rotateY(euler.y) * rotateX(euler.x);
  107. }
  108. `;
  109. }
  110. get _includeVertexShaderUtils()
  111. {
  112. return this._includeShaderUtils + this._transform;
  113. }
  114. get _includeFragmentShaderUtils()
  115. {
  116. return this._includeShaderUtils + this._colorize;
  117. }
  118. get _transform()
  119. {
  120. return `
  121. vec4 transform(vec4 v)
  122. {
  123. return v;
  124. }
  125. `;
  126. }
  127. get _colorize()
  128. {
  129. return `
  130. vec4 colorize(vec4 p)
  131. {
  132. return p;
  133. }
  134. `;
  135. }
  136. _createShader(gl, shaderType, shaderSource)
  137. {
  138. const shader = gl.createShader(shaderType);
  139. gl.shaderSource(shader, shaderSource);
  140. gl.compileShader(shader);
  141. if(!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
  142. const message = gl.getShaderInfoLog(shader);
  143. gl.deleteShader(shader);
  144. throw new Error(message);
  145. }
  146. return shader;
  147. }
  148. _createProgram(gl, vs, fs)
  149. {
  150. const program = gl.createProgram();
  151. gl.attachShader(program, vs);
  152. gl.attachShader(program, fs);
  153. gl.linkProgram(program);
  154. if(!gl.getProgramParameter(program, gl.LINK_STATUS)) {
  155. const message = gl.getProgramInfoLog(program);
  156. gl.deleteProgram(program);
  157. throw new Error(message);
  158. }
  159. return program;
  160. }
  161. _compile(gl, vsSource, fsSource)
  162. {
  163. const vs = this._createShader(gl, gl.VERTEX_SHADER, vsSource);
  164. const fs = this._createShader(gl, gl.FRAGMENT_SHADER, fsSource);
  165. const program = this._createProgram(gl, vs, fs);
  166. return program;
  167. }
  168. }
  169. class Pyramid extends Entity
  170. {
  171. get numberOfTriangles()
  172. {
  173. return 4;
  174. }
  175. get vertexShader()
  176. {
  177. return `#version 300 es
  178. uniform mat4 projectionMatrix;
  179. uniform mat4 modelViewMatrix;
  180. uniform float time;
  181. uniform vec2 resolution;
  182. flat out int triangleID;
  183. out vec2 control;
  184. const float VERTEX[] = float[](
  185. 0.5, -0.25, 0.25,
  186. 0.0, 0.25, 0.0,
  187. -0.5, -0.25, 0.25,
  188. -0.5, -0.25, 0.25,
  189. 0.0, 0.25, 0.0,
  190. 0.0, -0.25, -0.5,
  191. 0.0, -0.25, -0.5,
  192. 0.0, 0.25, 0.0,
  193. 0.5, -0.25, 0.25,
  194. 0.0, -0.25, -0.5,
  195. 0.5, -0.25, 0.25,
  196. -0.5, -0.25, 0.25
  197. );
  198. const vec3 CENTROID = vec3(
  199. 0.0, -0.125, 0.0
  200. );
  201. const vec2 UV_CONTROL_POINT[] = vec2[](
  202. vec2(0.0, 1.0),
  203. vec2(1.0, -1.0),
  204. vec2(-1.0, -1.0)
  205. );
  206. ${this._includeVertexShaderUtils}
  207. void main()
  208. {
  209. int base = gl_VertexID * 3;
  210. vec4 vertex = vec4(VERTEX[base], VERTEX[base+1], VERTEX[base+2], 1.0);
  211. gl_Position = projectionMatrix * modelViewMatrix * transform(vertex);
  212. triangleID = gl_VertexID / 3;
  213. control = UV_CONTROL_POINT[gl_VertexID % 3];
  214. }
  215. `;
  216. }
  217. get fragmentShader()
  218. {
  219. return `#version 300 es
  220. precision mediump float;
  221. flat in int triangleID;
  222. out vec4 color;
  223. const vec3 COLOR[] = vec3[](
  224. vec3(0,1,1),
  225. vec3(1,1,0),
  226. vec3(1,0,1),
  227. vec3(0,1,0)
  228. );
  229. ${this._includeFragmentShaderUtils}
  230. void main()
  231. {
  232. vec4 pixel = vec4(COLOR[triangleID], 1.0);
  233. color = colorize(pixel);
  234. }
  235. `;
  236. }
  237. get _colorize()
  238. {
  239. // create black borders
  240. return `
  241. const float THICKNESS = 0.05;
  242. in vec2 control;
  243. vec4 colorize(vec4 p)
  244. {
  245. const float SQRT5 = float(${Math.sqrt(5.0)});
  246. float x = control.x, y = control.y;
  247. float d = abs(y + 1.0);
  248. d = min(d, abs(2.0 * x - y + 1.0) / SQRT5);
  249. d = min(d, abs(-2.0 * x - y + 1.0) / SQRT5);
  250. p.rgb *= step(THICKNESS, d);
  251. return p;
  252. }
  253. `;
  254. }
  255. }
  256. class AnimatedPyramid extends Pyramid
  257. {
  258. get _transform()
  259. {
  260. // rotate around the centroid
  261. return `
  262. const float CYCLE_DURATION = 3.0;
  263. const vec3 POSITION = vec3(0.0, 0.0, 0.5);
  264. const vec3 SCALE = vec3(1.5);
  265. vec4 transform(vec4 v)
  266. {
  267. const float PI = float(${Math.PI});
  268. float rad = -(2.0 * PI / CYCLE_DURATION) * time;
  269. v = translate(-CENTROID) * v;
  270. v = rotate(vec3(rad, rad, 0.0)) * v;
  271. v = translate(CENTROID) * v;
  272. v = scale(SCALE) * v;
  273. v = translate(POSITION) * v;
  274. return v;
  275. }
  276. `;
  277. }
  278. }
  279. class Cube extends Entity
  280. {
  281. get numberOfTriangles()
  282. {
  283. return 12; // 6 faces * 2 triangles per face
  284. }
  285. get vertexShader()
  286. {
  287. return `#version 300 es
  288. uniform mat4 projectionMatrix;
  289. uniform mat4 modelViewMatrix;
  290. uniform float time;
  291. uniform vec2 resolution;
  292. flat out int faceID;
  293. out vec2 control;
  294. const float VERTEX[] = float[](
  295. 1.0, 1.0, 1.0,
  296. -1.0, 1.0, 1.0,
  297. -1.0, -1.0, 1.0,
  298. -1.0, -1.0, 1.0,
  299. 1.0, -1.0, 1.0,
  300. 1.0, 1.0, 1.0,
  301. 1.0, 1.0, -1.0,
  302. -1.0, 1.0, -1.0,
  303. -1.0, -1.0, -1.0,
  304. -1.0, -1.0, -1.0,
  305. 1.0, -1.0, -1.0,
  306. 1.0, 1.0, -1.0,
  307. 1.0, 1.0, 1.0,
  308. -1.0, 1.0, 1.0,
  309. -1.0, 1.0, -1.0,
  310. -1.0, 1.0, -1.0,
  311. 1.0, 1.0, -1.0,
  312. 1.0, 1.0, 1.0,
  313. 1.0, -1.0, 1.0,
  314. -1.0, -1.0, 1.0,
  315. -1.0, -1.0, -1.0,
  316. -1.0, -1.0, -1.0,
  317. 1.0, -1.0, -1.0,
  318. 1.0, -1.0, 1.0,
  319. 1.0, 1.0, 1.0,
  320. 1.0, -1.0, 1.0,
  321. 1.0, -1.0, -1.0,
  322. 1.0, -1.0, -1.0,
  323. 1.0, 1.0, -1.0,
  324. 1.0, 1.0, 1.0,
  325. -1.0, 1.0, 1.0,
  326. -1.0, -1.0, 1.0,
  327. -1.0, -1.0, -1.0,
  328. -1.0, -1.0, -1.0,
  329. -1.0, 1.0, -1.0,
  330. -1.0, 1.0, 1.0
  331. );
  332. const vec3 CENTROID = vec3(
  333. 0.0, 0.0, 0.0
  334. );
  335. const vec2 UV_CONTROL_POINT[] = vec2[](
  336. vec2(1.0, 1.0),
  337. vec2(0.0, 1.0),
  338. vec2(0.0, 0.0),
  339. vec2(0.0, 0.0),
  340. vec2(1.0, 0.0),
  341. vec2(1.0, 1.0)
  342. );
  343. ${this._includeVertexShaderUtils}
  344. void main()
  345. {
  346. int base = gl_VertexID * 3;
  347. vec4 vertex = vec4(VERTEX[base], VERTEX[base+1], VERTEX[base+2], 1.0);
  348. gl_Position = projectionMatrix * modelViewMatrix * transform(vertex);
  349. faceID = gl_VertexID / 6;
  350. control = UV_CONTROL_POINT[gl_VertexID % 6];
  351. }
  352. `;
  353. }
  354. get fragmentShader()
  355. {
  356. return `#version 300 es
  357. precision mediump float;
  358. flat in int faceID;
  359. out vec4 color;
  360. const vec3 COLOR[] = vec3[](
  361. vec3(1,0,1),
  362. vec3(1,1,0),
  363. vec3(0,1,1),
  364. vec3(1,0,0),
  365. vec3(0,0,1),
  366. vec3(0,1,0)
  367. );
  368. ${this._includeFragmentShaderUtils}
  369. void main()
  370. {
  371. vec4 pixel = vec4(COLOR[faceID], 1.0);
  372. color = colorize(pixel);
  373. }
  374. `;
  375. }
  376. get _colorize()
  377. {
  378. // create black borders
  379. return `
  380. const float THICKNESS = 0.03;
  381. in vec2 control;
  382. vec4 colorize(vec4 p)
  383. {
  384. float x = control.x, y = control.y;
  385. vec4 d4 = abs(vec4(x, y, x - 1.0, y - 1.0));
  386. vec2 d2 = min(d4.xy, d4.zw);
  387. float d = min(d2.x, d2.y);
  388. p.rgb *= step(THICKNESS, d);
  389. return p;
  390. }
  391. `;
  392. }
  393. }
  394. class AnimatedCube extends Cube
  395. {
  396. get _transform()
  397. {
  398. // rotate around the centroid
  399. return `
  400. const float CYCLE_DURATION = 3.0;
  401. const vec3 POSITION = vec3(-0.5, -1.5, 2.0);
  402. const vec3 SCALE = vec3(0.5);
  403. vec4 transform(vec4 v)
  404. {
  405. const float PI = float(${Math.PI});
  406. float rad = -(2.0 * PI / CYCLE_DURATION) * time;
  407. v = translate(-CENTROID) * v;
  408. v = rotateY(rad) * v;
  409. v = translate(CENTROID) * v;
  410. v = scale(SCALE) * v;
  411. v = translate(POSITION) * v;
  412. return v;
  413. }
  414. `;
  415. }
  416. }
  417. class Quad extends Entity
  418. {
  419. get numberOfTriangles()
  420. {
  421. return 2;
  422. }
  423. get vertexShader()
  424. {
  425. return `#version 300 es
  426. uniform mat4 projectionMatrix;
  427. uniform mat4 modelViewMatrix;
  428. uniform float time;
  429. uniform vec2 resolution;
  430. out vec2 texCoord;
  431. const float UV[] = float[](
  432. 0.0, 0.0,
  433. 1.0, 0.0,
  434. 0.0, 1.0,
  435. 0.0, 1.0,
  436. 1.0, 0.0,
  437. 1.0, 1.0
  438. );
  439. const float QUAD[] = float[](
  440. -1.0,-1.0,
  441. 1.0,-1.0,
  442. -1.0, 1.0,
  443. -1.0, 1.0,
  444. 1.0,-1.0,
  445. 1.0, 1.0
  446. );
  447. ${this._includeVertexShaderUtils}
  448. ${this._rectify}
  449. ${this._rectifyUV}
  450. void main()
  451. {
  452. int base = gl_VertexID * 2;
  453. vec4 vertex = vec4(QUAD[base], QUAD[base+1], 0.0, 1.0);
  454. vec4 v = rectify(vertex);
  455. gl_Position = projectionMatrix * modelViewMatrix * transform(v);
  456. vec2 uv = vec2(UV[base], UV[base+1]) * vec2(1,-1);
  457. texCoord = rectifyUV(uv);
  458. }
  459. `;
  460. }
  461. get _rectify()
  462. {
  463. return `
  464. vec4 rectify(vec4 v)
  465. {
  466. return v;
  467. }
  468. `;
  469. }
  470. get _rectifyUV()
  471. {
  472. return `
  473. vec2 rectifyUV(vec2 v)
  474. {
  475. return v;
  476. }
  477. `;
  478. }
  479. }
  480. class ImageQuad extends Quad
  481. {
  482. constructor(gl)
  483. {
  484. super(gl);
  485. this._uniformLocation['image'] = gl.getUniformLocation(this._program, 'image');
  486. this._texture = gl.createTexture();
  487. this._uploaded = false;
  488. this._image = null;
  489. if(this._imageURL != '') {
  490. this._image = new Image();
  491. this._image.onload = () => this.upload(this._image);
  492. this._image.src = this._imageURL;
  493. }
  494. }
  495. upload(data)
  496. {
  497. const gl = this._gl;
  498. gl.bindTexture(gl.TEXTURE_2D, this._texture);
  499. gl.texImage2D(gl.TEXTURE_2D,
  500. 0, // mipmap level
  501. gl.RGBA, // internal format
  502. gl.RGBA, // data format
  503. gl.UNSIGNED_BYTE, // data type
  504. data // data
  505. );
  506. gl.generateMipmap(gl.TEXTURE_2D);
  507. gl.bindTexture(gl.TEXTURE_2D, null);
  508. this._uploaded = true;
  509. }
  510. _render(time)
  511. {
  512. const gl = this._gl;
  513. if(!this._uploaded)
  514. return;
  515. gl.bindTexture(gl.TEXTURE_2D, this._texture);
  516. gl.activeTexture(gl.TEXTURE0 + 0);
  517. gl.uniform1i(this._uniformLocation['image'], 0);
  518. super._render(time);
  519. gl.bindTexture(gl.TEXTURE_2D, null);
  520. }
  521. get _imageURL()
  522. {
  523. return '';
  524. }
  525. get _rectify()
  526. {
  527. return `
  528. uniform sampler2D image;
  529. vec4 rectify(vec4 v)
  530. {
  531. ivec2 size = textureSize(image, 0);
  532. float imageAspect = size.y > 0 ? float(size.x) / float(size.y) : 1.0;
  533. vec4 u = imageAspect > 1.0 ?
  534. vec4(1.0, 1.0 / imageAspect, 1.0, 1.0) :
  535. vec4(imageAspect, 1.0, 1.0, 1.0);
  536. return u * v;
  537. }
  538. `;
  539. }
  540. get fragmentShader()
  541. {
  542. return `#version 300 es
  543. precision mediump float;
  544. uniform sampler2D image;
  545. in vec2 texCoord;
  546. out vec4 color;
  547. ${this._includeFragmentShaderUtils}
  548. void main()
  549. {
  550. vec4 pixel = texture(image, texCoord);
  551. color = colorize(pixel);
  552. }
  553. `;
  554. }
  555. }
  556. class Sprite extends ImageQuad
  557. {
  558. get _numberOfFrames()
  559. {
  560. return 1;
  561. }
  562. get _framesPerSecond()
  563. {
  564. return 8;
  565. }
  566. get _initialFrame()
  567. {
  568. return 0;
  569. }
  570. get _isHorizontalSpritesheet()
  571. {
  572. return true;
  573. }
  574. get _rectify()
  575. {
  576. return `
  577. uniform sampler2D image;
  578. vec4 rectify(vec4 v)
  579. {
  580. const int NUMBER_OF_FRAMES = int(${this._numberOfFrames});
  581. const bool HORIZONTAL = bool(${this._isHorizontalSpritesheet});
  582. ivec2 size = textureSize(image, 0);
  583. size /= HORIZONTAL ? ivec2(NUMBER_OF_FRAMES, 1) : ivec2(1, NUMBER_OF_FRAMES);
  584. float imageAspect = size.y > 0 ? float(size.x) / float(size.y) : 1.0;
  585. vec4 u = imageAspect > 1.0 ?
  586. vec4(1.0, 1.0 / imageAspect, 1.0, 1.0) :
  587. vec4(imageAspect, 1.0, 1.0, 1.0);
  588. return u * v;
  589. }
  590. `;
  591. }
  592. get _rectifyUV()
  593. {
  594. return `
  595. vec2 rectifyUV(vec2 v)
  596. {
  597. const bool HORIZONTAL = bool(${this._isHorizontalSpritesheet});
  598. const float NUMBER_OF_FRAMES = float(${this._numberOfFrames});
  599. const float INITIAL_FRAME = float(${this._initialFrame});
  600. const float FPS = float(${this._framesPerSecond});
  601. float frame = mod(time * FPS + INITIAL_FRAME, NUMBER_OF_FRAMES);
  602. float base = floor(frame) / NUMBER_OF_FRAMES;
  603. vec2 offset = v / NUMBER_OF_FRAMES;
  604. return HORIZONTAL ?
  605. vec2(base + offset.x, v.y) :
  606. vec2(v.x, base + offset.y);
  607. }
  608. `;
  609. }
  610. }
  611. class ItWorks extends ImageQuad
  612. {
  613. constructor(gl)
  614. {
  615. super(gl);
  616. this._image = document.getElementById('it-works');
  617. this.upload(this._image);
  618. }
  619. get _transform()
  620. {
  621. return `
  622. const vec3 POSITION = vec3(0.0, 1.0, 0.0);
  623. const vec3 SCALE = vec3(2.25);
  624. vec4 transform(vec4 v)
  625. {
  626. return translate(POSITION) * scale(SCALE) * v;
  627. }
  628. `;
  629. }
  630. get _colorize()
  631. {
  632. return `
  633. const vec4 COLOR = vec4(173, 255, 47, 255) / 255.0;
  634. vec4 colorize(vec4 p)
  635. {
  636. return p * COLOR;
  637. }
  638. `;
  639. }
  640. }
  641. class Bird extends Sprite
  642. {
  643. constructor(gl)
  644. {
  645. Bird._count = Bird._count || 0;
  646. ++Bird._count;
  647. super(gl);
  648. this._image = document.getElementById('bird');
  649. this.upload(this._image);
  650. }
  651. get _numberOfFrames()
  652. {
  653. return 8;
  654. }
  655. get _framesPerSecond()
  656. {
  657. return 20;
  658. }
  659. get _initialFrame()
  660. {
  661. const n = 2;
  662. return (Bird._count % n) * Math.floor(this._numberOfFrames / n);
  663. }
  664. get _transform()
  665. {
  666. return `
  667. const float PI = float(${Math.PI});
  668. const float INITIAL_PHASE = PI * float(${Bird._count});
  669. const vec3 INITIAL_POSITION = vec3(1.25 * cos(INITIAL_PHASE), -0.25, 2.0);
  670. const vec3 SCALE = vec3(0.7);
  671. vec4 transform(vec4 v)
  672. {
  673. float z = 0.6 * cos(INITIAL_PHASE);
  674. float y = 0.1 * cos(2.0 * PI * time + INITIAL_PHASE);
  675. vec3 position = vec3(0.0, y, z) + INITIAL_POSITION;
  676. return translate(position) * scale(SCALE) * v;
  677. }
  678. `;
  679. }
  680. }
  681. /*
  682. MARTINS.js + WebGL code:
  683. */
  684. window.addEventListener('load', async function() {
  685. try {
  686. const session = await startARSession();
  687. const gl = initGL(session.viewport.canvas);
  688. const scene = [
  689. new AnimatedPyramid(gl),
  690. new AnimatedCube(gl),
  691. new ItWorks(gl),
  692. new Bird(gl),
  693. new Bird(gl),
  694. ];
  695. function initGL(canvas)
  696. {
  697. const gl = canvas.getContext('webgl2', {
  698. alpha: true
  699. });
  700. if(!gl)
  701. throw new Error(`Can't create WebGL2 context`);
  702. gl.enable(gl.DEPTH_TEST);
  703. gl.enable(gl.BLEND);
  704. gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
  705. return gl;
  706. }
  707. function clear()
  708. {
  709. gl.clearColor(0, 0, 0, 0);
  710. gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  711. }
  712. function render(elapsedTimeInSeconds, projectionMatrix, modelViewMatrix)
  713. {
  714. for(const entity of scene) {
  715. entity.projectionMatrix.set(projectionMatrix);
  716. entity.modelViewMatrix.set(modelViewMatrix);
  717. entity.render(elapsedTimeInSeconds);
  718. }
  719. }
  720. function animate(time, frame)
  721. {
  722. clear();
  723. for(const result of frame.results) {
  724. if('image-tracker' == result.tracker.type) {
  725. if(result.trackables.length > 0) {
  726. const trackable = result.trackables[0];
  727. const projectionMatrix = result.viewer.view.projectionMatrix;
  728. const modelViewMatrix = result.viewer.convertToViewerSpace(trackable.pose).transform.matrix;
  729. render(frame.session.time.elapsed, projectionMatrix.read(), modelViewMatrix.read());
  730. }
  731. }
  732. }
  733. session.requestAnimationFrame(animate);
  734. }
  735. session.requestAnimationFrame(animate);
  736. }
  737. catch(error) {
  738. alert(error.message);
  739. }
  740. async function startARSession()
  741. {
  742. if(!Martins.isSupported()) {
  743. throw new Error(
  744. 'Use a browser/device compatible with WebGL2 and WebAssembly. ' +
  745. 'Your user agent is ' + navigator.userAgent
  746. );
  747. }
  748. //Martins.Settings.powerPreference = 'low-power';
  749. const tracker = Martins.Tracker.ImageTracker();
  750. await tracker.database.add([{
  751. name: 'my-reference-image',
  752. image: document.getElementById('my-reference-image')
  753. }]);
  754. const viewport = Martins.Viewport({
  755. container: document.getElementById('ar-viewport'),
  756. hudContainer: document.getElementById('ar-hud')
  757. });
  758. const source = Martins.Source.Camera({
  759. resolution: 'md'
  760. });
  761. const session = await Martins.startSession({
  762. mode: 'immersive',
  763. viewport: viewport,
  764. trackers: [ tracker ],
  765. sources: [ source ],
  766. stats: true,
  767. gizmos: true,
  768. });
  769. const scan = document.getElementById('scan');
  770. tracker.addEventListener('targetfound', event => {
  771. session.gizmos.visible = false;
  772. if(scan)
  773. scan.hidden = true;
  774. });
  775. tracker.addEventListener('targetlost', event => {
  776. session.gizmos.visible = true;
  777. if(scan)
  778. scan.hidden = false;
  779. });
  780. return session;
  781. }
  782. });