123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575 |
- import * as THREE from 'three';
- import { LazyBrush } from 'lazy-brush';
- import { Pane } from 'tweakpane';
- import Stats from 'three/examples/jsm/libs/stats.module'
- const cascade0_Dims = 2.0;
- const cascade0_Range = 1.0;
- const aspect = 16.0 / 9.0;
- const SCENE_RES = new THREE.Vector2(1920, 1080);
- const CASCADE_RES = new THREE.Vector2(1024 * aspect, 1024);
- const LAZY_RADIUS = 60;
- class SimonDevGLSLCourse {
- constructor() {
- }
- async initialize() {
- this.threejs_ = new THREE.WebGLRenderer();
- document.body.appendChild(this.threejs_.domElement);
- this.params_ = {
- brush: {
- radius: {
- radius: 20.0,
- min: 10.0,
- max: 400.0,
- },
- colour: {
- colour: { r: 1.0, g: 1.0, b: 1.0 },
- },
- friction: {
- friction: 5,
- min: 1,
- max: 100,
- step: 1.
- },
- }
- }
- const pane = new Pane({
- title: 'Brush',
- });
- pane.addBinding(this.params_.brush.radius, 'radius', {
- min: this.params_.brush.radius.min,
- max: this.params_.brush.radius.max,
- step: 1,
- });
- pane.addBinding(this.params_.brush.friction, 'friction', {
- min: this.params_.brush.friction.min,
- max: this.params_.brush.friction.max,
- step: this.params_.brush.friction.step,
- });
- pane.addBinding(this.params_.brush.colour, 'colour', {
- color: {type: 'float'},
- });
- this.stats_ = Stats()
- // document.body.appendChild(this.stats_.dom);
- window.addEventListener('resize', () => {
- this.onWindowResize_();
- }, false);
- this.camera_ = new THREE.OrthographicCamera(0, 1, 1, 0, 0.1, 1000);
- this.camera_.position.set(0, 0, 1);
- this.materials_ = [];
- this.targets_ = [];
- this.setupBrush_();
- await this.setupProject_();
- this.previousRAF_ = null;
- this.onWindowResize_();
- this.raf_();
- }
- setupBrush_() {
- this.lazyBrush_ = new LazyBrush({
- enabled: true,
- radius: LAZY_RADIUS
- });
- this.brushCoords_ = {
- x: -1,
- y: -1,
- current: null,
- previous: null,
- touching: false,
- points: [],
- };
- this.threejs_.domElement.addEventListener('mousemove', (e) => {
- const x = (e.clientX / window.innerWidth) * SCENE_RES.x;
- const y = (e.clientY / window.innerHeight) * SCENE_RES.y;
- this.brushCoords_.x = x;
- this.brushCoords_.y = y;
- });
- this.threejs_.domElement.addEventListener('touchstart', (e) => {
- this.brushCoords_.touching = true;
- });
- this.threejs_.domElement.addEventListener('mousedown', (e) => {
- this.brushCoords_.touching = true;
- });
- this.threejs_.domElement.addEventListener('mouseup', (e) => {
- this.brushCoords_.touching = false;
- this.brushCoords_.points = [];
- this.brushCoords_.current = null;
- this.brushCoords_.previous = null;
- });
- this.threejs_.domElement.addEventListener('touchend', (e) => {
- this.brushCoords_.touching = false;
- this.brushCoords_.points = [];
- this.brushCoords_.current = null;
- this.brushCoords_.previous = null;
- });
- }
- async setupProject_() {
- const common = await fetch('./shaders/common.glsl');
- const noise = await fetch('./shaders/noise.glsl');
- const oklab = await fetch('./shaders/oklab.glsl');
- const header = await fetch('./shaders/header.glsl');
- const cascades = await fetch('./shaders/cascades.glsl');
- const vshScene = await fetch('./shaders/scene-vertex-shader.glsl');
- const fshScene = await fetch('./shaders/scene-fragment-shader.glsl');
- const vshCopy = await fetch('./shaders/copy-vertex-shader.glsl');
- const fshCopy = await fetch('./shaders/copy-fragment-shader.glsl');
- const fshCopySDF = await fetch('./shaders/copy-sdf-fragment-shader.glsl');
- const vshCascade = await fetch('./shaders/compute-cascade-vertex-shader.glsl');
- const fshCascade = await fetch('./shaders/compute-cascade-fragment-shader.glsl');
- const vshMerge = await fetch('./shaders/merge-cascades-vertex-shader.glsl');
- const fshMerge = await fetch('./shaders/merge-cascades-fragment-shader.glsl');
- const vshRadianceField = await fetch('./shaders/radiance-field-vertex-shader.glsl');
- const fshRadianceField = await fetch('./shaders/radiance-field-fragment-shader.glsl');
- const fshFinalCompose = await fetch('./shaders/final-compose-fragment-shader.glsl');
- const commonText = await common.text() + '\n';
- const noiseText = await noise.text() + '\n';
- const oklabText = await oklab.text() + '\n';
- const headerText = await header.text() + '\n';
- const cascadesText = await cascades.text() + '\n';
- const libsText = headerText + oklabText + commonText + noiseText;
- const vshSceneText = libsText + await vshScene.text();
- const fshSceneText = libsText + await fshScene.text();
- const vshCopyText = libsText + await vshCopy.text();
- const fshCopyText = libsText + await fshCopy.text();
- const fshCopySDFText = libsText + await fshCopySDF.text();
- const vshCascadeText = libsText + await vshCascade.text();
- const fshCascadeText = libsText + cascadesText + await fshCascade.text();
- const vshMergeText = libsText + await vshMerge.text();
- const fshMergeText = libsText + cascadesText + await fshMerge.text();
- const vshRadianceFieldText = libsText + cascadesText + await vshRadianceField.text();
- const fshRadianceFieldText = libsText + cascadesText + await fshRadianceField.text();
- const fshFinalComposeText = libsText + cascadesText + await fshFinalCompose.text();
- // First pass
- this.scene_ = new THREE.Scene();
- this.sceneMaterial_ = new THREE.ShaderMaterial({
- uniforms: {
- brushPos: { value: new THREE.Vector2(0, 0) },
- brushRadius: { value: 0 },
- brushColour: { value: new THREE.Vector3(1, 1, 1) },
- sdfTexture: { value: null },
- time: { value: 0 },
- resolution: { value: new THREE.Vector2(1, 1) },
- },
- vertexShader: vshSceneText,
- fragmentShader: fshSceneText,
- side: THREE.FrontSide
- });
- const screenQuad = new THREE.PlaneGeometry(1, 1);
- const sceneQuad = new THREE.Mesh(screenQuad, this.sceneMaterial_);
- sceneQuad.position.set(0.5, 0.5, 0);
- this.scene_.add(sceneQuad);
- this.materials_.push(this.sceneMaterial_);
- const nearestOpts = {
- minFilter: THREE.NearestFilter,
- magFilter: THREE.NearestFilter,
- format: THREE.RGBAFormat,
- type: THREE.HalfFloatType,
- };
- const sceneOpts = {
- minFilter: THREE.LinearMipMapLinearFilter,
- magFilter: THREE.LinearFilter,
- format: THREE.RGBAFormat,
- type: THREE.HalfFloatType,
- generateMipmaps: true,
- };
- const radianceOpts = {
- minFilter: THREE.LinearFilter,
- magFilter: THREE.LinearFilter,
- format: THREE.RGBAFormat,
- type: THREE.HalfFloatType,
- };
- this.sdfTargets_ = [
- new THREE.WebGLRenderTarget(SCENE_RES.x, SCENE_RES.y, nearestOpts),
- new THREE.WebGLRenderTarget(SCENE_RES.x, SCENE_RES.y, nearestOpts)
- ];
- this.sdfFinalTarget_ = new THREE.WebGLRenderTarget(SCENE_RES.x, SCENE_RES.y, nearestOpts);
- this.sdfIndex_ = 0;
- this.threejs_.setRenderTarget(this.sdfTargets_[0]);
- this.threejs_.setClearColor(0x000000, 1000);
- this.threejs_.clear();
- this.threejs_.setRenderTarget(this.sdfTargets_[1]);
- this.threejs_.clear();
- this.threejs_.setClearColor(0x000000, 0);
- // Compute cascades
- const factor = 4.0;
- const diagonalLength = (SCENE_RES.x ** 2 + SCENE_RES.y ** 2) ** 0.5;
- let numCascadeLevels = Math.ceil(Math.log(diagonalLength / cascade0_Range) / Math.log(factor)) - 1;
- console.log('numCascadeLevels: ' + numCascadeLevels);
- console.log('diagonalLength: ' + diagonalLength);
- for (let i = 0; true; ++i) {
- const cascadeLevel = i;
- const cascadeN_Start_Pixels = (cascade0_Range * (1.0 - (factor ** cascadeLevel))) / (1.0 - factor);
- const cascadeN_End_Pixels = (cascade0_Range * (1.0 - (factor ** (cascadeLevel + 1)))) / (1.0 - factor);
- if (cascadeN_End_Pixels > diagonalLength) {
- console.log('ACTUAL FUCKING LEVEL: ', i);
- numCascadeLevels = i + 1;
- break;
- }
- }
- this.cascadeRealTargets_ = [];
- for (let i = 0; i < numCascadeLevels; i++) {
- this.cascadeRealTargets_.push(new THREE.WebGLRenderTarget(CASCADE_RES.x, CASCADE_RES.y, nearestOpts));
- }
- this.cascadeMaterial_ = new THREE.ShaderMaterial({
- uniforms: {
- time: { value: 0 },
- resolution: { value: new THREE.Vector2(1, 1) },
- sceneResolution: { value: new THREE.Vector2(SCENE_RES.x, SCENE_RES.y) },
- sceneTexture: { value: null },
- sdfTexture: { value: null },
- cascadeLevel: { value: 0.0 },
- cascade0_Range: { value: cascade0_Range },
- cascade0_Dims: { value: cascade0_Dims },
- cascadeResolution: { value: new THREE.Vector2(CASCADE_RES.x, CASCADE_RES.y) },
- },
- vertexShader: vshCascadeText,
- fragmentShader: fshCascadeText,
- });
- const cascadeQuad = new THREE.Mesh(screenQuad, this.cascadeMaterial_);
- cascadeQuad.position.set(0.5, 0.5, 0);
- this.cascadeQuad_ = cascadeQuad;
- this.cascadeScene_ = new THREE.Scene();
- this.cascadeScene_.add(cascadeQuad);
- for (let cascadeLevel = 0; cascadeLevel < numCascadeLevels; cascadeLevel++) {
- const cascadeN_Dims = cascade0_Dims * (2.0 ** cascadeLevel);
- // const cascadeN_Start_Pixels = cascade0_Range * (factor ** cascadeLevel) - 1;
- // const cascadeN_End_Pixels = cascade0_Range * (factor ** (cascadeLevel + 1)) - 1;
- // interval0 * (1.0 - pow(4.0, factor))) / (1.0 - 4.0)
- const cascadeN_Start_Pixels = (cascade0_Range * (1.0 - (factor ** cascadeLevel))) / (1.0 - factor);
- const cascadeN_End_Pixels = (cascade0_Range * (1.0 - (factor ** (cascadeLevel + 1)))) / (1.0 - factor);
-
- console.log('cascade level: ' + cascadeLevel);
- console.log('start: ' + cascadeN_Start_Pixels);
- console.log('end : ' + cascadeN_End_Pixels);
- console.log('dims : ' + cascadeN_Dims);
- }
- this.materials_.push(this.cascadeMaterial_);
- // Merge cascades
- this.cascadeMergeMaterial_ = new THREE.ShaderMaterial({
- uniforms: {
- time: { value: 0 },
- resolution: { value: new THREE.Vector2(1, 1) },
- sdfTexture: { value: null },
- sceneResolution: { value: new THREE.Vector2(SCENE_RES.x, SCENE_RES.y) },
- cascadeRealTexture: { value: null },
- nextCascadeMergedTexture: { value: null },
- prevCascadeTexture: { value: null },
- currentCascadeLevel: { value: 0 },
- numCascadeLevels: { value: numCascadeLevels },
- cascade0_Range: { value: cascade0_Range },
- cascade0_Dims: { value: cascade0_Dims },
- cascadeResolution: { value: new THREE.Vector2(CASCADE_RES.x, CASCADE_RES.y) },
- },
- vertexShader: vshMergeText,
- fragmentShader: fshMergeText,
- });
- const cascade0_ProbesX = Math.floor(CASCADE_RES.x);
- const cascade0_ProbesY = CASCADE_RES.y;
- this.cascadeMergeTargets_ = [];
- for (let i = 0; i < numCascadeLevels; i++) {
- this.cascadeMergeTargets_.push(new THREE.WebGLRenderTarget(CASCADE_RES.x, CASCADE_RES.y, nearestOpts));
- }
- this.cascadeMergeMesh_ = new THREE.Mesh(screenQuad, this.cascadeMergeMaterial_);
- this.cascadeMergeMesh_.position.set(0.5, 0.5, 0);
- this.cascadeMergeScene_ = new THREE.Scene();
- this.cascadeMergeScene_.add(this.cascadeMergeMesh_);
- this.materials_.push(this.cascadeMergeMaterial_);
- console.log('cascade0_ProbesX: ' + cascade0_ProbesX);
- console.log('cascade0_ProbesY: ' + cascade0_ProbesY);
-
- // Final pass to create radiance field
- this.radianceFieldMat_ = new THREE.ShaderMaterial({
- uniforms: {
- resolution: { value: new THREE.Vector2(1, 1) },
- time: { value: 0 },
- cascade0_Dims: { value: cascade0_Dims },
- cascadeResolution: { value: new THREE.Vector2(CASCADE_RES.x, CASCADE_RES.y) },
- mergedCascade0Texture: { value: this.cascadeMergeTargets_[0].texture },
- sceneResolution: { value: new THREE.Vector2(SCENE_RES.x, SCENE_RES.y) },
- },
- vertexShader: vshRadianceFieldText,
- fragmentShader: fshRadianceFieldText,
- });
- this.radianceFieldTarget_ = new THREE.WebGLRenderTarget(
- CASCADE_RES.x / cascade0_Dims,
- CASCADE_RES.y / cascade0_Dims,
- radianceOpts);
- this.radianceFieldMesh_ = new THREE.Mesh(screenQuad, this.radianceFieldMat_);
- this.radianceFieldMesh_.position.set(0.5, 0.5, 0);
- this.radianceFieldScene_ = new THREE.Scene();
- this.radianceFieldScene_.add(this.radianceFieldMesh_);
- this.materials_.push(this.radianceFieldMat_);
- // Final compose pass
- this.finalComposeMat_ = new THREE.ShaderMaterial({
- uniforms: {
- radianceTexture: { value: null },
- sceneTexture: { value: null },
- sdfTexture: { value: this.sdfTargets_[0].texture },
- resolution: { value: new THREE.Vector2(1, 1) },
- time: { value: 0 },
- },
- vertexShader: vshCopyText,
- fragmentShader: fshFinalComposeText,
- side: THREE.FrontSide
- });
- this.finalComposeMesh_ = new THREE.Mesh(screenQuad, this.finalComposeMat_);
- this.finalComposeMesh_.position.set(0.5, 0.5, 0);
- this.finalComposeScene_ = new THREE.Scene();
- this.finalComposeScene_.add(this.finalComposeMesh_);
- this.materials_.push(this.finalComposeMat_);
- // Copy pass
- this.copyMat_ = new THREE.ShaderMaterial({
- uniforms: {
- diffuse: { value: null },
- resolution: { value: new THREE.Vector2(1, 1) },
- time: { value: 0 },
- },
- vertexShader: vshCopyText,
- fragmentShader: fshCopyText,
- side: THREE.FrontSide
- });
- this.copyMesh_ = new THREE.Mesh(screenQuad, this.copyMat_);
- this.copyMesh_.position.set(0.5, 0.5, 0);
- this.copyScene_ = new THREE.Scene();
- this.copyScene_.add(this.copyMesh_);
- this.materials_.push(this.copyMat_);
- // Copy SDF pass
- this.copySDFMat_ = new THREE.ShaderMaterial({
- uniforms: {
- brushPos1: { value: new THREE.Vector2(0, 0) },
- brushPos2: { value: new THREE.Vector2(0, 0) },
- brushRadius: { value: 0 },
- brushColour: { value: new THREE.Vector3(1, 1, 1) },
- sdfSource: { value: null },
- resolution: { value: new THREE.Vector2(1, 1) },
- time: { value: 0 },
- },
- vertexShader: vshCopyText,
- fragmentShader: fshCopySDFText,
- side: THREE.FrontSide
- });
- this.copySDFMesh_ = new THREE.Mesh(screenQuad, this.copySDFMat_);
- this.copySDFMesh_.position.set(0.5, 0.5, 0);
- this.copySDFScene_ = new THREE.Scene();
- this.copySDFScene_.add(this.copySDFMesh_);
- this.materials_.push(this.copySDFMat_);
- this.totalTime_ = 0;
- this.onWindowResize_();
- }
- onWindowResize_() {
- const dpr = window.devicePixelRatio;
- const canvas = this.threejs_.domElement;
- canvas.style.width = window.innerWidth + 'px';
- canvas.style.height = window.innerHeight + 'px';
- const w = canvas.clientWidth;
- const h = canvas.clientHeight;
- this.threejs_.setSize(w * dpr, h * dpr, false);
- for (let m of this.materials_) {
- m.uniforms.resolution.value.set(w * dpr, h * dpr);
- }
- this.copySDFMat_.uniforms.resolution.value.set(SCENE_RES.x, SCENE_RES.y);
- this.radianceFieldMat_.uniforms.resolution.value.set(
- CASCADE_RES.x / cascade0_Dims, CASCADE_RES.y / cascade0_Dims);
- }
- raf_() {
- requestAnimationFrame((t) => {
- if (this.previousRAF_ === null) {
- this.previousRAF_ = t;
- }
- this.step_(t - this.previousRAF_);
- this.render_();
- this.raf_();
- this.previousRAF_ = t;
- });
- }
- render_() {
- const coords = this.lazyBrush_.getBrushCoordinates();
- this.sceneMaterial_.uniforms.brushPos.value = new THREE.Vector2(
- coords.x / SCENE_RES.x, 1 - coords.y / SCENE_RES.y);
- this.sceneMaterial_.uniforms.brushRadius.value = this.params_.brush.radius.radius;
- this.sceneMaterial_.uniforms.brushColour.value = new THREE.Vector3(
- this.params_.brush.colour.colour.r,
- this.params_.brush.colour.colour.g,
- this.params_.brush.colour.colour.b);
- this.sceneMaterial_.uniforms.sdfTexture.value = this.sdfTargets_[(this.sdfIndex_ + 1) % 2].texture;
- this.sceneMaterial_.uniforms.resolution.value = new THREE.Vector2(SCENE_RES.x, SCENE_RES.y);
- this.threejs_.setRenderTarget(this.sdfFinalTarget_);
- this.threejs_.render(this.scene_, this.camera_);
- // Create radiance cascades
- // These are stored separately for debugging.
- for (let i = 0; i < this.cascadeRealTargets_.length; i++) {
- const cascadeLevel = i;
- this.cascadeMaterial_.uniforms.cascadeLevel.value = cascadeLevel;
- this.cascadeMaterial_.uniforms.sdfTexture.value = this.sdfFinalTarget_.texture;
- this.threejs_.setRenderTarget(this.cascadeRealTargets_[i]);
- this.threejs_.render(this.cascadeScene_, this.camera_);
- }
- // merged5 RT0 = cascade5 + merged6
- // merged4 RT1 = cascade4 + merged5 RT0
- // merged3 RT0 = cascade3 + merged4 RT1
- // Merge radiance cascades
- for (let i = this.cascadeRealTargets_.length - 1; i >= 0; i--) {
- this.cascadeMergeMaterial_.uniforms.currentCascadeLevel.value = i;
- this.cascadeMergeMaterial_.uniforms.cascadeRealTexture.value = this.cascadeRealTargets_[i].texture;
- this.cascadeMergeMaterial_.uniforms.sdfTexture.value = this.sdfFinalTarget_.texture;
- this.cascadeMergeMaterial_.needsUpdate = true;
- if (i < this.cascadeRealTargets_.length - 1) {
- this.cascadeMergeMaterial_.uniforms.nextCascadeMergedTexture.value = this.cascadeMergeTargets_[i + 1].texture;
- }
- if (i > 0) {
- this.cascadeMergeMaterial_.uniforms.prevCascadeTexture.value = this.cascadeRealTargets_[i - 1].texture;
- }
- this.threejs_.setRenderTarget(this.cascadeMergeTargets_[i]);
- this.threejs_.render(this.cascadeMergeScene_, this.camera_);
- }
- // Generate radiance field
- this.radianceFieldMat_.uniforms.mergedCascade0Texture.value = this.cascadeMergeTargets_[0].texture;
- this.radianceFieldMat_.uniforms.resolution.value = new THREE.Vector2(
- this.radianceFieldTarget_.width, this.radianceFieldTarget_.height);
- this.threejs_.setRenderTarget(this.radianceFieldTarget_);
- this.threejs_.render(this.radianceFieldScene_, this.camera_);
- // Final copy to screen
- this.finalComposeMat_.uniforms.radianceTexture.value = this.radianceFieldTarget_.texture;
- this.finalComposeMat_.uniforms.sdfTexture.value = this.sdfFinalTarget_.texture;
- this.threejs_.setRenderTarget(null);
- this.threejs_.render(this.finalComposeScene_, this.camera_);
- }
- step_(timeElapsed) {
- const timeElapsedS = timeElapsed * 0.001;
- this.totalTime_ += timeElapsedS;
- for (let m of this.materials_) {
- m.uniforms.time.value = this.totalTime_;
- }
- this.updateBrush_(timeElapsed);
- this.stats_.update();
- }
- updateBrush_(_) {
- const hasChanged = this.lazyBrush_.update(
- { x: this.brushCoords_.x, y: this.brushCoords_.y },
- { friction: this.brushCoords_.touching ? this.params_.brush.friction.friction / 100 : 1 }
- )
- const isDisabled = !this.lazyBrush_.isEnabled();
- const hasMoved = this.lazyBrush_.brushHasMoved();
-
- if (!hasMoved) {
- // return
- }
-
- if (!this.brushCoords_.touching) {
- return;
- }
-
- this.brushCoords_.points.push(this.lazyBrush_.getBrushCoordinates());
- this.brushCoords_.points.push(this.lazyBrush_.getBrushCoordinates());
- this.updateBrushSDF_();
- }
- updateBrushSDF_() {
- const p = this.lazyBrush_.getBrushCoordinates();
- if (this.brushCoords_.current == null) {
- this.brushCoords_.current = { x: p.x, y: p.y };
- this.brushCoords_.previous = { x: p.x, y: p.y };
- }
- this.brushCoords_.current = { x: p.x, y: p.y };
- const p1 = this.brushCoords_.current;
- const p2 = this.brushCoords_.previous;
- this.threejs_.setRenderTarget(this.sdfTargets_[this.sdfIndex_]);
- this.copySDFMat_.uniforms.brushPos1.value = new THREE.Vector2(
- p1.x / SCENE_RES.x, 1 - p1.y / SCENE_RES.y);
- this.copySDFMat_.uniforms.brushPos2.value = new THREE.Vector2(
- p2.x / SCENE_RES.x, 1 - p2.y / SCENE_RES.y);
- this.copySDFMat_.uniforms.brushRadius.value = this.params_.brush.radius.radius;
- this.copySDFMat_.uniforms.brushColour.value = new THREE.Vector3(
- this.params_.brush.colour.colour.r,
- this.params_.brush.colour.colour.g,
- this.params_.brush.colour.colour.b);
- this.copySDFMat_.uniforms.sdfSource.value = this.sdfTargets_[1 - this.sdfIndex_].texture;
- this.threejs_.render(this.copySDFScene_, this.camera_);
- this.sdfIndex_ = (this.sdfIndex_ + 1) % 2;
- this.brushCoords_.previous = this.brushCoords_.current;
- }
- }
- let APP_ = null;
- window.addEventListener('DOMContentLoaded', async () => {
- APP_ = new SimonDevGLSLCourse();
- await APP_.initialize();
- });
|