demo.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. import * as THREE from 'three';
  2. import { LazyBrush } from 'lazy-brush';
  3. import { Pane } from 'tweakpane';
  4. import Stats from 'three/examples/jsm/libs/stats.module'
  5. const cascade0_Dims = 2.0;
  6. const cascade0_Range = 1.0;
  7. const aspect = 16.0 / 9.0;
  8. const SCENE_RES = new THREE.Vector2(1920, 1080);
  9. const CASCADE_RES = new THREE.Vector2(1024 * aspect, 1024);
  10. const LAZY_RADIUS = 60;
  11. class SimonDevGLSLCourse {
  12. constructor() {
  13. }
  14. async initialize() {
  15. this.threejs_ = new THREE.WebGLRenderer();
  16. document.body.appendChild(this.threejs_.domElement);
  17. this.params_ = {
  18. brush: {
  19. radius: {
  20. radius: 20.0,
  21. min: 10.0,
  22. max: 400.0,
  23. },
  24. colour: {
  25. colour: { r: 1.0, g: 1.0, b: 1.0 },
  26. },
  27. friction: {
  28. friction: 5,
  29. min: 1,
  30. max: 100,
  31. step: 1.
  32. },
  33. }
  34. }
  35. const pane = new Pane({
  36. title: 'Brush',
  37. });
  38. pane.addBinding(this.params_.brush.radius, 'radius', {
  39. min: this.params_.brush.radius.min,
  40. max: this.params_.brush.radius.max,
  41. step: 1,
  42. });
  43. pane.addBinding(this.params_.brush.friction, 'friction', {
  44. min: this.params_.brush.friction.min,
  45. max: this.params_.brush.friction.max,
  46. step: this.params_.brush.friction.step,
  47. });
  48. pane.addBinding(this.params_.brush.colour, 'colour', {
  49. color: {type: 'float'},
  50. });
  51. this.stats_ = Stats()
  52. // document.body.appendChild(this.stats_.dom);
  53. window.addEventListener('resize', () => {
  54. this.onWindowResize_();
  55. }, false);
  56. this.camera_ = new THREE.OrthographicCamera(0, 1, 1, 0, 0.1, 1000);
  57. this.camera_.position.set(0, 0, 1);
  58. this.materials_ = [];
  59. this.targets_ = [];
  60. this.setupBrush_();
  61. await this.setupProject_();
  62. this.previousRAF_ = null;
  63. this.onWindowResize_();
  64. this.raf_();
  65. }
  66. setupBrush_() {
  67. this.lazyBrush_ = new LazyBrush({
  68. enabled: true,
  69. radius: LAZY_RADIUS
  70. });
  71. this.brushCoords_ = {
  72. x: -1,
  73. y: -1,
  74. current: null,
  75. previous: null,
  76. touching: false,
  77. points: [],
  78. };
  79. this.threejs_.domElement.addEventListener('mousemove', (e) => {
  80. const x = (e.clientX / window.innerWidth) * SCENE_RES.x;
  81. const y = (e.clientY / window.innerHeight) * SCENE_RES.y;
  82. this.brushCoords_.x = x;
  83. this.brushCoords_.y = y;
  84. });
  85. this.threejs_.domElement.addEventListener('touchstart', (e) => {
  86. this.brushCoords_.touching = true;
  87. });
  88. this.threejs_.domElement.addEventListener('mousedown', (e) => {
  89. this.brushCoords_.touching = true;
  90. });
  91. this.threejs_.domElement.addEventListener('mouseup', (e) => {
  92. this.brushCoords_.touching = false;
  93. this.brushCoords_.points = [];
  94. this.brushCoords_.current = null;
  95. this.brushCoords_.previous = null;
  96. });
  97. this.threejs_.domElement.addEventListener('touchend', (e) => {
  98. this.brushCoords_.touching = false;
  99. this.brushCoords_.points = [];
  100. this.brushCoords_.current = null;
  101. this.brushCoords_.previous = null;
  102. });
  103. }
  104. async setupProject_() {
  105. const common = await fetch('./shaders/common.glsl');
  106. const noise = await fetch('./shaders/noise.glsl');
  107. const oklab = await fetch('./shaders/oklab.glsl');
  108. const header = await fetch('./shaders/header.glsl');
  109. const cascades = await fetch('./shaders/cascades.glsl');
  110. const vshScene = await fetch('./shaders/scene-vertex-shader.glsl');
  111. const fshScene = await fetch('./shaders/scene-fragment-shader.glsl');
  112. const vshCopy = await fetch('./shaders/copy-vertex-shader.glsl');
  113. const fshCopy = await fetch('./shaders/copy-fragment-shader.glsl');
  114. const fshCopySDF = await fetch('./shaders/copy-sdf-fragment-shader.glsl');
  115. const vshCascade = await fetch('./shaders/compute-cascade-vertex-shader.glsl');
  116. const fshCascade = await fetch('./shaders/compute-cascade-fragment-shader.glsl');
  117. const vshMerge = await fetch('./shaders/merge-cascades-vertex-shader.glsl');
  118. const fshMerge = await fetch('./shaders/merge-cascades-fragment-shader.glsl');
  119. const vshRadianceField = await fetch('./shaders/radiance-field-vertex-shader.glsl');
  120. const fshRadianceField = await fetch('./shaders/radiance-field-fragment-shader.glsl');
  121. const fshFinalCompose = await fetch('./shaders/final-compose-fragment-shader.glsl');
  122. const commonText = await common.text() + '\n';
  123. const noiseText = await noise.text() + '\n';
  124. const oklabText = await oklab.text() + '\n';
  125. const headerText = await header.text() + '\n';
  126. const cascadesText = await cascades.text() + '\n';
  127. const libsText = headerText + oklabText + commonText + noiseText;
  128. const vshSceneText = libsText + await vshScene.text();
  129. const fshSceneText = libsText + await fshScene.text();
  130. const vshCopyText = libsText + await vshCopy.text();
  131. const fshCopyText = libsText + await fshCopy.text();
  132. const fshCopySDFText = libsText + await fshCopySDF.text();
  133. const vshCascadeText = libsText + await vshCascade.text();
  134. const fshCascadeText = libsText + cascadesText + await fshCascade.text();
  135. const vshMergeText = libsText + await vshMerge.text();
  136. const fshMergeText = libsText + cascadesText + await fshMerge.text();
  137. const vshRadianceFieldText = libsText + cascadesText + await vshRadianceField.text();
  138. const fshRadianceFieldText = libsText + cascadesText + await fshRadianceField.text();
  139. const fshFinalComposeText = libsText + cascadesText + await fshFinalCompose.text();
  140. // First pass
  141. this.scene_ = new THREE.Scene();
  142. this.sceneMaterial_ = new THREE.ShaderMaterial({
  143. uniforms: {
  144. brushPos: { value: new THREE.Vector2(0, 0) },
  145. brushRadius: { value: 0 },
  146. brushColour: { value: new THREE.Vector3(1, 1, 1) },
  147. sdfTexture: { value: null },
  148. time: { value: 0 },
  149. resolution: { value: new THREE.Vector2(1, 1) },
  150. },
  151. vertexShader: vshSceneText,
  152. fragmentShader: fshSceneText,
  153. side: THREE.FrontSide
  154. });
  155. const screenQuad = new THREE.PlaneGeometry(1, 1);
  156. const sceneQuad = new THREE.Mesh(screenQuad, this.sceneMaterial_);
  157. sceneQuad.position.set(0.5, 0.5, 0);
  158. this.scene_.add(sceneQuad);
  159. this.materials_.push(this.sceneMaterial_);
  160. const nearestOpts = {
  161. minFilter: THREE.NearestFilter,
  162. magFilter: THREE.NearestFilter,
  163. format: THREE.RGBAFormat,
  164. type: THREE.HalfFloatType,
  165. };
  166. const sceneOpts = {
  167. minFilter: THREE.LinearMipMapLinearFilter,
  168. magFilter: THREE.LinearFilter,
  169. format: THREE.RGBAFormat,
  170. type: THREE.HalfFloatType,
  171. generateMipmaps: true,
  172. };
  173. const radianceOpts = {
  174. minFilter: THREE.LinearFilter,
  175. magFilter: THREE.LinearFilter,
  176. format: THREE.RGBAFormat,
  177. type: THREE.HalfFloatType,
  178. };
  179. this.sdfTargets_ = [
  180. new THREE.WebGLRenderTarget(SCENE_RES.x, SCENE_RES.y, nearestOpts),
  181. new THREE.WebGLRenderTarget(SCENE_RES.x, SCENE_RES.y, nearestOpts)
  182. ];
  183. this.sdfFinalTarget_ = new THREE.WebGLRenderTarget(SCENE_RES.x, SCENE_RES.y, nearestOpts);
  184. this.sdfIndex_ = 0;
  185. this.threejs_.setRenderTarget(this.sdfTargets_[0]);
  186. this.threejs_.setClearColor(0x000000, 1000);
  187. this.threejs_.clear();
  188. this.threejs_.setRenderTarget(this.sdfTargets_[1]);
  189. this.threejs_.clear();
  190. this.threejs_.setClearColor(0x000000, 0);
  191. // Compute cascades
  192. const factor = 4.0;
  193. const diagonalLength = (SCENE_RES.x ** 2 + SCENE_RES.y ** 2) ** 0.5;
  194. let numCascadeLevels = Math.ceil(Math.log(diagonalLength / cascade0_Range) / Math.log(factor)) - 1;
  195. console.log('numCascadeLevels: ' + numCascadeLevels);
  196. console.log('diagonalLength: ' + diagonalLength);
  197. for (let i = 0; true; ++i) {
  198. const cascadeLevel = i;
  199. const cascadeN_Start_Pixels = (cascade0_Range * (1.0 - (factor ** cascadeLevel))) / (1.0 - factor);
  200. const cascadeN_End_Pixels = (cascade0_Range * (1.0 - (factor ** (cascadeLevel + 1)))) / (1.0 - factor);
  201. if (cascadeN_End_Pixels > diagonalLength) {
  202. console.log('ACTUAL FUCKING LEVEL: ', i);
  203. numCascadeLevels = i + 1;
  204. break;
  205. }
  206. }
  207. this.cascadeRealTargets_ = [];
  208. for (let i = 0; i < numCascadeLevels; i++) {
  209. this.cascadeRealTargets_.push(new THREE.WebGLRenderTarget(CASCADE_RES.x, CASCADE_RES.y, nearestOpts));
  210. }
  211. this.cascadeMaterial_ = new THREE.ShaderMaterial({
  212. uniforms: {
  213. time: { value: 0 },
  214. resolution: { value: new THREE.Vector2(1, 1) },
  215. sceneResolution: { value: new THREE.Vector2(SCENE_RES.x, SCENE_RES.y) },
  216. sceneTexture: { value: null },
  217. sdfTexture: { value: null },
  218. cascadeLevel: { value: 0.0 },
  219. cascade0_Range: { value: cascade0_Range },
  220. cascade0_Dims: { value: cascade0_Dims },
  221. cascadeResolution: { value: new THREE.Vector2(CASCADE_RES.x, CASCADE_RES.y) },
  222. },
  223. vertexShader: vshCascadeText,
  224. fragmentShader: fshCascadeText,
  225. });
  226. const cascadeQuad = new THREE.Mesh(screenQuad, this.cascadeMaterial_);
  227. cascadeQuad.position.set(0.5, 0.5, 0);
  228. this.cascadeQuad_ = cascadeQuad;
  229. this.cascadeScene_ = new THREE.Scene();
  230. this.cascadeScene_.add(cascadeQuad);
  231. for (let cascadeLevel = 0; cascadeLevel < numCascadeLevels; cascadeLevel++) {
  232. const cascadeN_Dims = cascade0_Dims * (2.0 ** cascadeLevel);
  233. // const cascadeN_Start_Pixels = cascade0_Range * (factor ** cascadeLevel) - 1;
  234. // const cascadeN_End_Pixels = cascade0_Range * (factor ** (cascadeLevel + 1)) - 1;
  235. // interval0 * (1.0 - pow(4.0, factor))) / (1.0 - 4.0)
  236. const cascadeN_Start_Pixels = (cascade0_Range * (1.0 - (factor ** cascadeLevel))) / (1.0 - factor);
  237. const cascadeN_End_Pixels = (cascade0_Range * (1.0 - (factor ** (cascadeLevel + 1)))) / (1.0 - factor);
  238. console.log('cascade level: ' + cascadeLevel);
  239. console.log('start: ' + cascadeN_Start_Pixels);
  240. console.log('end : ' + cascadeN_End_Pixels);
  241. console.log('dims : ' + cascadeN_Dims);
  242. }
  243. this.materials_.push(this.cascadeMaterial_);
  244. // Merge cascades
  245. this.cascadeMergeMaterial_ = new THREE.ShaderMaterial({
  246. uniforms: {
  247. time: { value: 0 },
  248. resolution: { value: new THREE.Vector2(1, 1) },
  249. sdfTexture: { value: null },
  250. sceneResolution: { value: new THREE.Vector2(SCENE_RES.x, SCENE_RES.y) },
  251. cascadeRealTexture: { value: null },
  252. nextCascadeMergedTexture: { value: null },
  253. prevCascadeTexture: { value: null },
  254. currentCascadeLevel: { value: 0 },
  255. numCascadeLevels: { value: numCascadeLevels },
  256. cascade0_Range: { value: cascade0_Range },
  257. cascade0_Dims: { value: cascade0_Dims },
  258. cascadeResolution: { value: new THREE.Vector2(CASCADE_RES.x, CASCADE_RES.y) },
  259. },
  260. vertexShader: vshMergeText,
  261. fragmentShader: fshMergeText,
  262. });
  263. const cascade0_ProbesX = Math.floor(CASCADE_RES.x);
  264. const cascade0_ProbesY = CASCADE_RES.y;
  265. this.cascadeMergeTargets_ = [];
  266. for (let i = 0; i < numCascadeLevels; i++) {
  267. this.cascadeMergeTargets_.push(new THREE.WebGLRenderTarget(CASCADE_RES.x, CASCADE_RES.y, nearestOpts));
  268. }
  269. this.cascadeMergeMesh_ = new THREE.Mesh(screenQuad, this.cascadeMergeMaterial_);
  270. this.cascadeMergeMesh_.position.set(0.5, 0.5, 0);
  271. this.cascadeMergeScene_ = new THREE.Scene();
  272. this.cascadeMergeScene_.add(this.cascadeMergeMesh_);
  273. this.materials_.push(this.cascadeMergeMaterial_);
  274. console.log('cascade0_ProbesX: ' + cascade0_ProbesX);
  275. console.log('cascade0_ProbesY: ' + cascade0_ProbesY);
  276. // Final pass to create radiance field
  277. this.radianceFieldMat_ = new THREE.ShaderMaterial({
  278. uniforms: {
  279. resolution: { value: new THREE.Vector2(1, 1) },
  280. time: { value: 0 },
  281. cascade0_Dims: { value: cascade0_Dims },
  282. cascadeResolution: { value: new THREE.Vector2(CASCADE_RES.x, CASCADE_RES.y) },
  283. mergedCascade0Texture: { value: this.cascadeMergeTargets_[0].texture },
  284. sceneResolution: { value: new THREE.Vector2(SCENE_RES.x, SCENE_RES.y) },
  285. },
  286. vertexShader: vshRadianceFieldText,
  287. fragmentShader: fshRadianceFieldText,
  288. });
  289. this.radianceFieldTarget_ = new THREE.WebGLRenderTarget(
  290. CASCADE_RES.x / cascade0_Dims,
  291. CASCADE_RES.y / cascade0_Dims,
  292. radianceOpts);
  293. this.radianceFieldMesh_ = new THREE.Mesh(screenQuad, this.radianceFieldMat_);
  294. this.radianceFieldMesh_.position.set(0.5, 0.5, 0);
  295. this.radianceFieldScene_ = new THREE.Scene();
  296. this.radianceFieldScene_.add(this.radianceFieldMesh_);
  297. this.materials_.push(this.radianceFieldMat_);
  298. // Final compose pass
  299. this.finalComposeMat_ = new THREE.ShaderMaterial({
  300. uniforms: {
  301. radianceTexture: { value: null },
  302. sceneTexture: { value: null },
  303. sdfTexture: { value: this.sdfTargets_[0].texture },
  304. resolution: { value: new THREE.Vector2(1, 1) },
  305. time: { value: 0 },
  306. },
  307. vertexShader: vshCopyText,
  308. fragmentShader: fshFinalComposeText,
  309. side: THREE.FrontSide
  310. });
  311. this.finalComposeMesh_ = new THREE.Mesh(screenQuad, this.finalComposeMat_);
  312. this.finalComposeMesh_.position.set(0.5, 0.5, 0);
  313. this.finalComposeScene_ = new THREE.Scene();
  314. this.finalComposeScene_.add(this.finalComposeMesh_);
  315. this.materials_.push(this.finalComposeMat_);
  316. // Copy pass
  317. this.copyMat_ = new THREE.ShaderMaterial({
  318. uniforms: {
  319. diffuse: { value: null },
  320. resolution: { value: new THREE.Vector2(1, 1) },
  321. time: { value: 0 },
  322. },
  323. vertexShader: vshCopyText,
  324. fragmentShader: fshCopyText,
  325. side: THREE.FrontSide
  326. });
  327. this.copyMesh_ = new THREE.Mesh(screenQuad, this.copyMat_);
  328. this.copyMesh_.position.set(0.5, 0.5, 0);
  329. this.copyScene_ = new THREE.Scene();
  330. this.copyScene_.add(this.copyMesh_);
  331. this.materials_.push(this.copyMat_);
  332. // Copy SDF pass
  333. this.copySDFMat_ = new THREE.ShaderMaterial({
  334. uniforms: {
  335. brushPos1: { value: new THREE.Vector2(0, 0) },
  336. brushPos2: { value: new THREE.Vector2(0, 0) },
  337. brushRadius: { value: 0 },
  338. brushColour: { value: new THREE.Vector3(1, 1, 1) },
  339. sdfSource: { value: null },
  340. resolution: { value: new THREE.Vector2(1, 1) },
  341. time: { value: 0 },
  342. },
  343. vertexShader: vshCopyText,
  344. fragmentShader: fshCopySDFText,
  345. side: THREE.FrontSide
  346. });
  347. this.copySDFMesh_ = new THREE.Mesh(screenQuad, this.copySDFMat_);
  348. this.copySDFMesh_.position.set(0.5, 0.5, 0);
  349. this.copySDFScene_ = new THREE.Scene();
  350. this.copySDFScene_.add(this.copySDFMesh_);
  351. this.materials_.push(this.copySDFMat_);
  352. this.totalTime_ = 0;
  353. this.onWindowResize_();
  354. }
  355. onWindowResize_() {
  356. const dpr = window.devicePixelRatio;
  357. const canvas = this.threejs_.domElement;
  358. canvas.style.width = window.innerWidth + 'px';
  359. canvas.style.height = window.innerHeight + 'px';
  360. const w = canvas.clientWidth;
  361. const h = canvas.clientHeight;
  362. this.threejs_.setSize(w * dpr, h * dpr, false);
  363. for (let m of this.materials_) {
  364. m.uniforms.resolution.value.set(w * dpr, h * dpr);
  365. }
  366. this.copySDFMat_.uniforms.resolution.value.set(SCENE_RES.x, SCENE_RES.y);
  367. this.radianceFieldMat_.uniforms.resolution.value.set(
  368. CASCADE_RES.x / cascade0_Dims, CASCADE_RES.y / cascade0_Dims);
  369. }
  370. raf_() {
  371. requestAnimationFrame((t) => {
  372. if (this.previousRAF_ === null) {
  373. this.previousRAF_ = t;
  374. }
  375. this.step_(t - this.previousRAF_);
  376. this.render_();
  377. this.raf_();
  378. this.previousRAF_ = t;
  379. });
  380. }
  381. render_() {
  382. const coords = this.lazyBrush_.getBrushCoordinates();
  383. this.sceneMaterial_.uniforms.brushPos.value = new THREE.Vector2(
  384. coords.x / SCENE_RES.x, 1 - coords.y / SCENE_RES.y);
  385. this.sceneMaterial_.uniforms.brushRadius.value = this.params_.brush.radius.radius;
  386. this.sceneMaterial_.uniforms.brushColour.value = new THREE.Vector3(
  387. this.params_.brush.colour.colour.r,
  388. this.params_.brush.colour.colour.g,
  389. this.params_.brush.colour.colour.b);
  390. this.sceneMaterial_.uniforms.sdfTexture.value = this.sdfTargets_[(this.sdfIndex_ + 1) % 2].texture;
  391. this.sceneMaterial_.uniforms.resolution.value = new THREE.Vector2(SCENE_RES.x, SCENE_RES.y);
  392. this.threejs_.setRenderTarget(this.sdfFinalTarget_);
  393. this.threejs_.render(this.scene_, this.camera_);
  394. // Create radiance cascades
  395. // These are stored separately for debugging.
  396. for (let i = 0; i < this.cascadeRealTargets_.length; i++) {
  397. const cascadeLevel = i;
  398. this.cascadeMaterial_.uniforms.cascadeLevel.value = cascadeLevel;
  399. this.cascadeMaterial_.uniforms.sdfTexture.value = this.sdfFinalTarget_.texture;
  400. this.threejs_.setRenderTarget(this.cascadeRealTargets_[i]);
  401. this.threejs_.render(this.cascadeScene_, this.camera_);
  402. }
  403. // merged5 RT0 = cascade5 + merged6
  404. // merged4 RT1 = cascade4 + merged5 RT0
  405. // merged3 RT0 = cascade3 + merged4 RT1
  406. // Merge radiance cascades
  407. for (let i = this.cascadeRealTargets_.length - 1; i >= 0; i--) {
  408. this.cascadeMergeMaterial_.uniforms.currentCascadeLevel.value = i;
  409. this.cascadeMergeMaterial_.uniforms.cascadeRealTexture.value = this.cascadeRealTargets_[i].texture;
  410. this.cascadeMergeMaterial_.uniforms.sdfTexture.value = this.sdfFinalTarget_.texture;
  411. this.cascadeMergeMaterial_.needsUpdate = true;
  412. if (i < this.cascadeRealTargets_.length - 1) {
  413. this.cascadeMergeMaterial_.uniforms.nextCascadeMergedTexture.value = this.cascadeMergeTargets_[i + 1].texture;
  414. }
  415. if (i > 0) {
  416. this.cascadeMergeMaterial_.uniforms.prevCascadeTexture.value = this.cascadeRealTargets_[i - 1].texture;
  417. }
  418. this.threejs_.setRenderTarget(this.cascadeMergeTargets_[i]);
  419. this.threejs_.render(this.cascadeMergeScene_, this.camera_);
  420. }
  421. // Generate radiance field
  422. this.radianceFieldMat_.uniforms.mergedCascade0Texture.value = this.cascadeMergeTargets_[0].texture;
  423. this.radianceFieldMat_.uniforms.resolution.value = new THREE.Vector2(
  424. this.radianceFieldTarget_.width, this.radianceFieldTarget_.height);
  425. this.threejs_.setRenderTarget(this.radianceFieldTarget_);
  426. this.threejs_.render(this.radianceFieldScene_, this.camera_);
  427. // Final copy to screen
  428. this.finalComposeMat_.uniforms.radianceTexture.value = this.radianceFieldTarget_.texture;
  429. this.finalComposeMat_.uniforms.sdfTexture.value = this.sdfFinalTarget_.texture;
  430. this.threejs_.setRenderTarget(null);
  431. this.threejs_.render(this.finalComposeScene_, this.camera_);
  432. }
  433. step_(timeElapsed) {
  434. const timeElapsedS = timeElapsed * 0.001;
  435. this.totalTime_ += timeElapsedS;
  436. for (let m of this.materials_) {
  437. m.uniforms.time.value = this.totalTime_;
  438. }
  439. this.updateBrush_(timeElapsed);
  440. this.stats_.update();
  441. }
  442. updateBrush_(_) {
  443. const hasChanged = this.lazyBrush_.update(
  444. { x: this.brushCoords_.x, y: this.brushCoords_.y },
  445. { friction: this.brushCoords_.touching ? this.params_.brush.friction.friction / 100 : 1 }
  446. )
  447. const isDisabled = !this.lazyBrush_.isEnabled();
  448. const hasMoved = this.lazyBrush_.brushHasMoved();
  449. if (!hasMoved) {
  450. // return
  451. }
  452. if (!this.brushCoords_.touching) {
  453. return;
  454. }
  455. this.brushCoords_.points.push(this.lazyBrush_.getBrushCoordinates());
  456. this.brushCoords_.points.push(this.lazyBrush_.getBrushCoordinates());
  457. this.updateBrushSDF_();
  458. }
  459. updateBrushSDF_() {
  460. const p = this.lazyBrush_.getBrushCoordinates();
  461. if (this.brushCoords_.current == null) {
  462. this.brushCoords_.current = { x: p.x, y: p.y };
  463. this.brushCoords_.previous = { x: p.x, y: p.y };
  464. }
  465. this.brushCoords_.current = { x: p.x, y: p.y };
  466. const p1 = this.brushCoords_.current;
  467. const p2 = this.brushCoords_.previous;
  468. this.threejs_.setRenderTarget(this.sdfTargets_[this.sdfIndex_]);
  469. this.copySDFMat_.uniforms.brushPos1.value = new THREE.Vector2(
  470. p1.x / SCENE_RES.x, 1 - p1.y / SCENE_RES.y);
  471. this.copySDFMat_.uniforms.brushPos2.value = new THREE.Vector2(
  472. p2.x / SCENE_RES.x, 1 - p2.y / SCENE_RES.y);
  473. this.copySDFMat_.uniforms.brushRadius.value = this.params_.brush.radius.radius;
  474. this.copySDFMat_.uniforms.brushColour.value = new THREE.Vector3(
  475. this.params_.brush.colour.colour.r,
  476. this.params_.brush.colour.colour.g,
  477. this.params_.brush.colour.colour.b);
  478. this.copySDFMat_.uniforms.sdfSource.value = this.sdfTargets_[1 - this.sdfIndex_].texture;
  479. this.threejs_.render(this.copySDFScene_, this.camera_);
  480. this.sdfIndex_ = (this.sdfIndex_ + 1) % 2;
  481. this.brushCoords_.previous = this.brushCoords_.current;
  482. }
  483. }
  484. let APP_ = null;
  485. window.addEventListener('DOMContentLoaded', async () => {
  486. APP_ = new SimonDevGLSLCourse();
  487. await APP_.initialize();
  488. });