├── src ├── webxr.d.ts ├── dummy.ts ├── nodes │ ├── common │ │ └── UITag.ts │ ├── PlexusScene │ │ └── constants.ts │ ├── ParticlesRingScene │ │ └── constants.ts │ ├── TrailsScene │ │ ├── Trails │ │ │ └── constants.ts │ │ └── TrailsScene.ts │ ├── FluidScene │ │ ├── constants.ts │ │ └── shaders │ │ │ ├── fluidClampToGrid.ts │ │ │ ├── fluidFrameFrag.ts │ │ │ ├── fluidUvToPos.ts │ │ │ ├── defFluidSampleNearest3D.ts │ │ │ ├── defFluidSampleLinear3D.ts │ │ │ └── fluidAdvectionFrag.ts │ ├── MetaballScene │ │ ├── MetaballParticles │ │ │ ├── constants.ts │ │ │ └── shaders │ │ │ │ └── metaballParticlesRenderFrag.ts │ │ └── defMetaballMap.ts │ ├── CameraStack │ │ ├── deferredConstants.ts │ │ ├── DoF │ │ │ └── shaders │ │ │ │ ├── dofCalcCoC.ts │ │ │ │ ├── dofTileGatherFrag.ts │ │ │ │ ├── dofPresortFrag.ts │ │ │ │ └── dofPostFrag.ts │ │ └── mainCameraStackResources.ts │ ├── PostStack │ │ ├── Vectorscope │ │ │ └── shaders │ │ │ │ ├── vectorscopeFrag.ts │ │ │ │ └── vectorscopeVert.ts │ │ ├── Bloom │ │ │ └── shaders │ │ │ │ └── bloomUpFrag.ts │ │ └── CharRenderer │ │ │ └── shaders │ │ │ └── charRendererFrag.ts │ ├── SevenSegScene │ │ ├── vec3UniformSphere.ts │ │ ├── quatRandom.ts │ │ └── shaders │ │ │ ├── sevenSegWireFrag.ts │ │ │ └── sevenSegFrag.ts │ ├── HistogramScatter │ │ └── shaders │ │ │ ├── histogramGatherFrag.ts │ │ │ ├── histogramGatherVert.ts │ │ │ └── histogramPlotVert.ts │ ├── utils │ │ ├── createShaderRenderTarget.ts │ │ ├── createCubemapUniformsLambda.ts │ │ ├── createRaymarchCameraUniformsLambda.ts │ │ ├── CanvasTexture.ts │ │ └── ShaderRenderTarget.ts │ ├── LoadingScreen │ │ └── shaders │ │ │ ├── ditherFrag.ts │ │ │ └── noiseFrag.ts │ ├── SpongeScene │ │ └── Sponge │ │ │ └── Sponge.ts │ ├── Mixer │ │ └── shaders │ │ │ └── mixerFrag.ts │ ├── MoonScene │ │ └── shaders │ │ │ └── moonTexModFrag.ts │ ├── IBLLUTCalc │ │ └── IBLLUTCalc.ts │ ├── OBSVRLogoBScene │ │ ├── shaders │ │ │ └── obsvrLogoBFrag.ts │ │ └── OBSVRLogoBScene.ts │ ├── NoisePlaneScene │ │ ├── shaders │ │ │ └── noisePlaneFrag.ts │ │ └── NoisePlaneScene.ts │ ├── PillarGridScene │ │ └── PillarGrid │ │ │ └── shaders │ │ │ └── pillarGridFrameFrag.ts │ ├── Lights │ │ └── shaders │ │ │ └── shadowBlurFrag.ts │ ├── WormTunnelScene │ │ └── WormTunnel │ │ │ └── WormTunnel.ts │ ├── KansokushaScene │ │ ├── assets │ │ │ └── kansokusha.svg │ │ └── shaders │ │ │ └── kansokushaFrag.ts │ ├── WireCubeScene │ │ └── WireCubeScene.ts │ ├── CubemapNode │ │ └── shaders │ │ │ └── cubemapMergeFrag.ts │ ├── LineRings3DScene │ │ └── LineRings3DScene.ts │ ├── LineRhombusesScene │ │ └── LineRhombusesScene.ts │ ├── LineTriTunnelScene │ │ └── LineTriTunnelScene.ts │ ├── LineWaveScene │ │ └── LineWaveScene.ts │ ├── LineRingsScene │ │ └── LineRingsScene.ts │ └── Dust │ │ └── shaders │ │ └── dustRenderFrag.ts ├── vite-env.d.ts ├── utils │ ├── Observer.ts │ ├── sleep.ts │ ├── genToken.ts │ ├── arraySetIntersects.ts │ ├── createDebounce.ts │ ├── downloadBlob.ts │ ├── arraySetIntersection.ts │ ├── poll.ts │ ├── injectCodeToShader.ts │ ├── createPromiseSVGImage.ts │ ├── vdc.ts │ ├── MapOfSet.ts │ ├── applyMixins.ts │ ├── Cache.ts │ ├── Memo.ts │ ├── getYugoppText.ts │ ├── vec3AzimuthAltitude.ts │ ├── constants.ts │ └── RandomTexture.ts ├── globals │ ├── automaton-fxs │ │ └── fxDefinitions.ts │ ├── music.ts │ ├── glslMusicEditor.ts │ ├── canvasRenderTarget.ts │ ├── gui │ │ └── NullMeasureHandler.ts │ ├── mixerTarget.ts │ ├── moonTexGen.ts │ ├── zeroTexture.ts │ ├── cameraStackTargets.ts │ ├── audio.ts │ ├── randomTexture.ts │ ├── dummyRenderTarget.ts │ ├── ibllutCalc.ts │ ├── canvas.ts │ ├── globalObservers.ts │ ├── postTarget.ts │ ├── quadGeometry.ts │ ├── preparationTasks.ts │ ├── audioReverb.ts │ ├── audioAnalyzer.ts │ ├── quad3DGeometry.ts │ └── swapShadowMap.ts ├── worklet.d.ts ├── tweakpane-plugin-profiler.d.ts ├── gl │ ├── GLBlitFilter.ts │ ├── GLTextureMagFilterType.ts │ ├── GLCullFaceType.ts │ ├── GLIndexType.ts │ ├── GLTextureWrapType.ts │ ├── GLBlitMask.ts │ ├── glDrawBuffersByNumber.ts │ ├── GLDrawMode.ts │ ├── glClear.ts │ ├── glVertexArrayBindIndexbuffer.ts │ ├── GLTextureMinFilterType.ts │ ├── glCreateTexture.ts │ ├── GLBufferUsage.ts │ ├── glTextureWrap.ts │ ├── glCreateIndexbuffer.ts │ ├── glCreateVertexbuffer.ts │ ├── glWaitGPUCommandsCompleteAsync.ts │ ├── glVertexArrayBindVertexbuffer.ts │ ├── glTextureFilter.ts │ ├── glSetTextureFromBitmap.ts │ └── GLBlendFactor.ts ├── music │ ├── GLSLMusicEditorRange.ts │ ├── MusicEngine.ts │ ├── withinGLSLMusicEditorRange.ts │ ├── shaderchunks.ts │ ├── constants.ts │ ├── utils │ │ ├── findMatchingCloseBracket.ts │ │ └── findNearestChar.ts │ ├── BufferReaderProcessor.js │ └── BufferReaderNode.ts ├── shaders │ ├── modules │ │ ├── bayerMatrix4.ts │ │ ├── cis.ts │ │ ├── maxOfVec2.ts │ │ ├── maxOfVec3.ts │ │ ├── minOfVec3.ts │ │ ├── defineFs.ts │ │ ├── glslGaussian.ts │ │ ├── maxOfVec4.ts │ │ ├── isValidUv.ts │ │ ├── vKelemen.ts │ │ ├── bayerPattern4.ts │ │ ├── fresnelSchlick.ts │ │ ├── glslSaturate.ts │ │ ├── taylorInvSqrt.ts │ │ ├── mod289.ts │ │ ├── calcL.ts │ │ ├── sRGBEOTF.ts │ │ ├── sRGBOETF.ts │ │ ├── randomSphere.ts │ │ ├── isectMin.ts │ │ ├── pcg2df.ts │ │ ├── pcg3df.ts │ │ ├── pcg4df.ts │ │ ├── randomHemisphere.ts │ │ ├── rotate2D.ts │ │ ├── invCalcDepth.ts │ │ ├── minkowski2d.ts │ │ ├── minkowski3d.ts │ │ ├── phongSpecular.ts │ │ ├── glslTri.ts │ │ ├── tonemapACESNarkowicz.ts │ │ ├── isectPlane.ts │ │ ├── boxMuller.ts │ │ ├── sdcapsule.ts │ │ ├── vNeubelt.ts │ │ ├── sdbox2.ts │ │ ├── calcAlbedoF0.ts │ │ ├── sdtorus.ts │ │ ├── dGGX.ts │ │ ├── orthBas.ts │ │ ├── glslGradient.ts │ │ ├── equimapUV.ts │ │ ├── sortVec3Components.ts │ │ ├── defDoSomethingUsingSamplerArray.ts │ │ ├── glslLofi.ts │ │ ├── uniformSphere.ts │ │ ├── sdbox.ts │ │ ├── setupRoRd.ts │ │ ├── glslLofir.ts │ │ ├── smax.ts │ │ ├── smin.ts │ │ ├── triplanarMapping.ts │ │ ├── upsampleTap9.ts │ │ ├── calcShadowDepth.ts │ │ ├── cubemapUVMip.ts │ │ ├── dCharlie.ts │ │ ├── foldSortXYZ.ts │ │ ├── sampleLambert.ts │ │ ├── sdsellipse2.ts │ │ ├── isectInBox.ts │ │ ├── downsampleTap13.ts │ │ ├── calcNormal.ts │ │ ├── normalTransform.ts │ │ ├── isectSphere.ts │ │ ├── vGGX.ts │ │ ├── glslLinearstep.ts │ │ ├── isectBox.ts │ │ ├── sampleGGX.ts │ │ ├── glslSmootherstep.ts │ │ ├── brdfSheen.ts │ │ ├── tonemapACESHill.ts │ │ ├── pcg2d.ts │ │ ├── cyclicNoise.ts │ │ ├── glslDefRandom.ts │ │ ├── brdfClearcoat.ts │ │ ├── pcg3d.ts │ │ ├── voronoi3d.ts │ │ ├── perlin2d.ts │ │ ├── voronoi2d.ts │ │ ├── turboColormap.ts │ │ ├── forEachLights.ts │ │ ├── pcg4d.ts │ │ ├── calcSS.ts │ │ └── liftGammaGain.ts │ └── common │ │ ├── colorFrag.ts │ │ ├── uvFrag.ts │ │ ├── depthFrag.ts │ │ ├── dryFrag.ts │ │ ├── textureFrag.ts │ │ ├── quadVert.ts │ │ ├── deferredUvFrag.ts │ │ ├── deferredWhiteUnlitFrag.ts │ │ ├── deferredColorFrag.ts │ │ └── deferredTextureFrag.ts ├── config.ts ├── automaton.json.d.ts ├── heck │ ├── utils │ │ └── ancestorsToPath.ts │ ├── RenderTarget.ts │ ├── components │ │ ├── LogTransform.ts │ │ ├── Lambda.ts │ │ └── SceneNode.ts │ ├── CanvasRenderTarget.ts │ ├── BufferMipmapTextureRenderTarget.ts │ └── Dog.ts ├── textures │ ├── shaders │ │ ├── cellFrag.ts │ │ └── perlinFBMFrag.ts │ ├── cellTextureTarget.ts │ └── perlinFBMTextureTarget.ts ├── webgl-memory.d.ts └── geometries │ └── genWireCube.ts ├── .env ├── .env.prod ├── index.html ├── .eslintignore ├── memo.md ├── .gitignore ├── tsconfig.json ├── terserMinifyOptions.ts ├── vite-plugins ├── vite-automaton-minifier-plugin.ts └── vite-worklet-minifier-plugin.ts ├── package.json └── vite.config.ts /src/webxr.d.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | NODE_ENV=development 2 | DEV=true 3 | -------------------------------------------------------------------------------- /src/dummy.ts: -------------------------------------------------------------------------------- 1 | export default undefined; 2 | -------------------------------------------------------------------------------- /.env.prod: -------------------------------------------------------------------------------- 1 | NODE_ENV=production 2 | DEV=false 3 | -------------------------------------------------------------------------------- /src/nodes/common/UITag.ts: -------------------------------------------------------------------------------- 1 | export const UITag = Symbol(); 2 | -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/utils/Observer.ts: -------------------------------------------------------------------------------- 1 | export type Observer = ( arg: T ) => void; 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /dist/** 2 | /node_modules/** 3 | **/*.js 4 | vite.config.ts 5 | tests 6 | -------------------------------------------------------------------------------- /src/globals/automaton-fxs/fxDefinitions.ts: -------------------------------------------------------------------------------- 1 | const fxDefinitions = {}; 2 | 3 | export { fxDefinitions }; 4 | -------------------------------------------------------------------------------- /src/worklet.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*?worklet' { 2 | const src: string; 3 | export default src; 4 | } 5 | -------------------------------------------------------------------------------- /src/tweakpane-plugin-profiler.d.ts: -------------------------------------------------------------------------------- 1 | declare module '@0b5vr/tweakpane-plugin-profiler' { 2 | export class plugin {} 3 | } 4 | -------------------------------------------------------------------------------- /src/globals/music.ts: -------------------------------------------------------------------------------- 1 | import { Music } from '../music/Music'; 2 | 3 | const music: Music = new Music(); 4 | 5 | export { music }; 6 | -------------------------------------------------------------------------------- /src/globals/glslMusicEditor.ts: -------------------------------------------------------------------------------- 1 | import { GLSLMusicEditor } from '../music/GLSLMusicEditor'; 2 | 3 | export const glslMusicEditor = new GLSLMusicEditor(); 4 | -------------------------------------------------------------------------------- /src/gl/GLBlitFilter.ts: -------------------------------------------------------------------------------- 1 | import { GL_LINEAR, GL_NEAREST } from './constants'; 2 | 3 | export type GLBlitFilter = 4 | | typeof GL_NEAREST 5 | | typeof GL_LINEAR; 6 | -------------------------------------------------------------------------------- /src/globals/canvasRenderTarget.ts: -------------------------------------------------------------------------------- 1 | import { CanvasRenderTarget } from '../heck/CanvasRenderTarget'; 2 | 3 | export const canvasRenderTarget = new CanvasRenderTarget(); 4 | -------------------------------------------------------------------------------- /src/globals/gui/NullMeasureHandler.ts: -------------------------------------------------------------------------------- 1 | export class NullMeasureHandler { 2 | public measure( fn: () => void ): number { 3 | fn(); 4 | return 0.0; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/music/GLSLMusicEditorRange.ts: -------------------------------------------------------------------------------- 1 | export type GLSLMusicEditorRange = [ 2 | startLine: number, 3 | startRow: number, 4 | endLine: number, 5 | endRow: number, 6 | ]; 7 | -------------------------------------------------------------------------------- /src/utils/sleep.ts: -------------------------------------------------------------------------------- 1 | export function sleep( ms: number ): Promise { 2 | return new Promise( ( resolve ) => { 3 | setTimeout( () => resolve(), ms ); 4 | } ); 5 | } 6 | -------------------------------------------------------------------------------- /src/gl/GLTextureMagFilterType.ts: -------------------------------------------------------------------------------- 1 | import { GL_LINEAR, GL_NEAREST } from './constants'; 2 | 3 | export type GLTextureMagFilterType = 4 | | typeof GL_NEAREST 5 | | typeof GL_LINEAR; 6 | -------------------------------------------------------------------------------- /src/globals/mixerTarget.ts: -------------------------------------------------------------------------------- 1 | import { BufferTextureRenderTarget } from '../heck/BufferTextureRenderTarget'; 2 | 3 | export const mixerTarget = new BufferTextureRenderTarget( 4, 4 ); 4 | -------------------------------------------------------------------------------- /src/nodes/PlexusScene/constants.ts: -------------------------------------------------------------------------------- 1 | export const PLEXUS_PARTICLES_CBRT = 16; 2 | export const PLEXUS_PARTICLES 3 | = PLEXUS_PARTICLES_CBRT * PLEXUS_PARTICLES_CBRT * PLEXUS_PARTICLES_CBRT; 4 | -------------------------------------------------------------------------------- /src/globals/moonTexGen.ts: -------------------------------------------------------------------------------- 1 | import { MoonTexGen } from '../nodes/MoonScene/MoonTexGen'; 2 | 3 | export const moonTexGen = new MoonTexGen(); 4 | 5 | export const moonTexture = moonTexGen.texture; 6 | -------------------------------------------------------------------------------- /src/globals/zeroTexture.ts: -------------------------------------------------------------------------------- 1 | import { glCreateTexture } from '../gl/glCreateTexture'; 2 | 3 | export const zeroTexture = glCreateTexture( 4 | 1, 5 | 1, 6 | new Uint8Array( [ 0, 0, 0, 0 ] ), 7 | ); 8 | -------------------------------------------------------------------------------- /src/shaders/modules/bayerMatrix4.ts: -------------------------------------------------------------------------------- 1 | import { mat4 } from '../shaderBuilder'; 2 | 3 | export const bayerMatrix4 = mat4( 4 | 0, 8, 2, 10, 5 | 12, 4, 14, 6, 6 | 3, 11, 1, 9, 7 | 15, 7, 13, 5, 8 | ); 9 | -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- 1 | export const 2 | AO_ITER = 16, 3 | IBLLUT_ITER = 400, 4 | IBLLUT_SIZE = 256, 5 | NEAR = 0.1, 6 | FAR = 30.0, 7 | RANDOM_TEXTURE_SIZE = 64, 8 | STATIC_RANDOM_TEXTURE_SIZE = 2048; 9 | -------------------------------------------------------------------------------- /src/nodes/ParticlesRingScene/constants.ts: -------------------------------------------------------------------------------- 1 | export const PARTICLES_COUNT_SQRT = 256; 2 | export const PARTICLES_COUNT = PARTICLES_COUNT_SQRT * PARTICLES_COUNT_SQRT; 3 | export const PARTICLES_SPAWN_LENGTH = 4.0; 4 | -------------------------------------------------------------------------------- /src/utils/genToken.ts: -------------------------------------------------------------------------------- 1 | export const genToken = ( tokenIndex: number ): string => ( 2 | ( tokenIndex > 25 ? genToken( ~~( tokenIndex / 26 - 1 ) ) : '' ) + String.fromCharCode( ( tokenIndex % 26 ) + 97 ) 3 | ); 4 | -------------------------------------------------------------------------------- /src/gl/GLCullFaceType.ts: -------------------------------------------------------------------------------- 1 | import { GL_BACK, GL_FRONT, GL_FRONT_AND_BACK } from './constants'; 2 | 3 | export type GLCullFaceType = 4 | | typeof GL_BACK 5 | | typeof GL_FRONT 6 | | typeof GL_FRONT_AND_BACK; 7 | -------------------------------------------------------------------------------- /src/nodes/TrailsScene/Trails/constants.ts: -------------------------------------------------------------------------------- 1 | export const TRAILS_COUNT = 1024; 2 | export const TRAILS_LENGTH = 64; 3 | export const REC_TRAILS_LENGTH = 1.0 / TRAILS_LENGTH; 4 | export const TRAILS_SPAWN_LENGTH = 2.0; 5 | -------------------------------------------------------------------------------- /src/nodes/FluidScene/constants.ts: -------------------------------------------------------------------------------- 1 | export const GRID_RESO_SQRT = 10; 2 | export const GRID_RESO = GRID_RESO_SQRT * GRID_RESO_SQRT; 3 | export const BUFFER_RESO = GRID_RESO * GRID_RESO_SQRT; 4 | export const CURL = 8.0; 5 | -------------------------------------------------------------------------------- /src/automaton.json.d.ts: -------------------------------------------------------------------------------- 1 | import type { SerializedAutomatonWithGUI } from '@0b5vr/automaton-with-gui'; 2 | 3 | declare module './automaton.json' { 4 | const data: SerializedAutomatonWithGUI; 5 | export default data; 6 | } 7 | -------------------------------------------------------------------------------- /src/utils/arraySetIntersects.ts: -------------------------------------------------------------------------------- 1 | import { arraySetHas } from '@0b5vr/experimental'; 2 | 3 | export function arraySetIntersects( a: Array, b: Array ): boolean { 4 | return a.some( ( v ) => arraySetHas( b, v ) ); 5 | } 6 | -------------------------------------------------------------------------------- /memo.md: -------------------------------------------------------------------------------- 1 | ### SVG 2 | 3 | - Remove translation props from curves, usually can be done by applying union 4 | - `svgo -p 0 image.svg` 5 | - ``: perserve `viewBox` and `xmlns`, remove everything else 6 | - ``: edit fill and stroke 7 | -------------------------------------------------------------------------------- /src/gl/GLIndexType.ts: -------------------------------------------------------------------------------- 1 | import { GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, GL_UNSIGNED_SHORT } from './constants'; 2 | 3 | export type GLIndexType = 4 | | typeof GL_UNSIGNED_BYTE 5 | | typeof GL_UNSIGNED_SHORT 6 | | typeof GL_UNSIGNED_INT; 7 | -------------------------------------------------------------------------------- /src/gl/GLTextureWrapType.ts: -------------------------------------------------------------------------------- 1 | import { GL_CLAMP_TO_EDGE, GL_MIRRORED_REPEAT, GL_REPEAT } from './constants'; 2 | 3 | export type GLTextureWrapType = 4 | | typeof GL_REPEAT 5 | | typeof GL_CLAMP_TO_EDGE 6 | | typeof GL_MIRRORED_REPEAT; 7 | -------------------------------------------------------------------------------- /src/shaders/modules/cis.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, cos, sin, vec2 } from '../shaderBuilder'; 2 | 3 | export const cis: ( x: GLSLFloatExpression ) => GLSLExpression<'vec2'> 4 | = ( x ) => vec2( cos( x ), sin( x ) ); 5 | -------------------------------------------------------------------------------- /src/utils/createDebounce.ts: -------------------------------------------------------------------------------- 1 | export function createDebounce(): ( func: () => void ) => void { 2 | let id: NodeJS.Timeout; 3 | 4 | return ( func: () => void ) => { 5 | clearTimeout( id ); 6 | id = setTimeout( func, 1 ); 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /src/gl/GLBlitMask.ts: -------------------------------------------------------------------------------- 1 | import { GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT } from './constants'; 2 | 3 | export type GLBlitMask = 4 | | typeof GL_COLOR_BUFFER_BIT 5 | | typeof GL_DEPTH_BUFFER_BIT 6 | | typeof GL_STENCIL_BUFFER_BIT; 7 | -------------------------------------------------------------------------------- /src/heck/utils/ancestorsToPath.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '../components/Component'; 2 | 3 | export function ancestorsToPath( ancestors: Component[] ): string { 4 | return '/' + ancestors.map( ( ancestor ) => ancestor.name ?? '(no name)' ).join( '/' ); 5 | } 6 | -------------------------------------------------------------------------------- /src/globals/cameraStackTargets.ts: -------------------------------------------------------------------------------- 1 | import { BufferTextureRenderTarget } from '../heck/BufferTextureRenderTarget'; 2 | 3 | export const cameraStackATarget = new BufferTextureRenderTarget( 4, 4 ); 4 | export const cameraStackBTarget = new BufferTextureRenderTarget( 4, 4 ); 5 | -------------------------------------------------------------------------------- /src/nodes/MetaballScene/MetaballParticles/constants.ts: -------------------------------------------------------------------------------- 1 | export const METABALL_PARTICLES_COUNT_SQRT = 512; 2 | export const METABALL_PARTICLES_COUNT 3 | = METABALL_PARTICLES_COUNT_SQRT * METABALL_PARTICLES_COUNT_SQRT; 4 | export const METABALL_PARTICLES_SPAWN_LENGTH = 4.0; 5 | -------------------------------------------------------------------------------- /src/shaders/modules/maxOfVec2.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, def, max, sw } from '../shaderBuilder'; 2 | 3 | export const maxOfVec2 = ( v: GLSLExpression<'vec2'> ): GLSLExpression<'float'> => { 4 | const vt = def( 'vec2', v ); 5 | return max( sw( vt, 'x' ), sw( vt, 'y' ) ); 6 | }; 7 | -------------------------------------------------------------------------------- /src/nodes/CameraStack/deferredConstants.ts: -------------------------------------------------------------------------------- 1 | export const MTL_NONE = 0; 2 | 3 | /** 4 | * no need to set params 5 | */ 6 | export const MTL_UNLIT = 1; 7 | 8 | /** 9 | * vec4( roughness, metallic, emissive, cubemap ) 10 | */ 11 | export const MTL_PBR_ROUGHNESS_METALLIC = 2; 12 | -------------------------------------------------------------------------------- /src/shaders/modules/maxOfVec3.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, def, max, sw } from '../shaderBuilder'; 2 | 3 | export const maxOfVec3 = ( v: GLSLExpression<'vec3'> ): GLSLExpression<'float'> => { 4 | const vt = def( 'vec3', v ); 5 | return max( sw( vt, 'x' ), max( sw( vt, 'y' ), sw( vt, 'z' ) ) ); 6 | }; 7 | -------------------------------------------------------------------------------- /src/shaders/modules/minOfVec3.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, def, min, sw } from '../shaderBuilder'; 2 | 3 | export const minOfVec3 = ( v: GLSLExpression<'vec3'> ): GLSLExpression<'float'> => { 4 | const vt = def( 'vec3', v ); 5 | return min( sw( vt, 'x' ), min( sw( vt, 'y' ), sw( vt, 'z' ) ) ); 6 | }; 7 | -------------------------------------------------------------------------------- /src/utils/downloadBlob.ts: -------------------------------------------------------------------------------- 1 | export function downloadBlob( blob: Blob, name: string ): void { 2 | const url = URL.createObjectURL( blob ); 3 | 4 | const a = document.createElement( 'a' ); 5 | a.href = url; 6 | a.download = name; 7 | a.click(); 8 | 9 | URL.revokeObjectURL( url ); 10 | } 11 | -------------------------------------------------------------------------------- /src/shaders/modules/defineFs.ts: -------------------------------------------------------------------------------- 1 | import { genToken, insertTop } from '../shaderBuilder'; 2 | 3 | export function defineFs(): 4 | ( x: string ) => string { 5 | const token = genToken(); 6 | insertTop( `\n#define ${ token }(x) fract(sin((x)*114.514)*1919.810)\n` ); 7 | return ( x ) => `(${ token }(${ x }))`; 8 | } 9 | -------------------------------------------------------------------------------- /src/shaders/modules/glslGaussian.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, div, exp, mul, sq } from '../shaderBuilder'; 2 | 3 | export const glslGaussian = ( 4 | x: GLSLFloatExpression, 5 | rho: GLSLFloatExpression, 6 | ): GLSLExpression<'float'> => ( 7 | exp( div( sq( x ), mul( -2.0, rho, rho ) ) ) 8 | ) as any; 9 | -------------------------------------------------------------------------------- /src/shaders/modules/maxOfVec4.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, def, max, sw } from '../shaderBuilder'; 2 | 3 | export const maxOfVec4 = ( v: GLSLExpression<'vec4'> ): GLSLExpression<'float'> => { 4 | const vt = def( 'vec4', v ); 5 | return max( max( sw( vt, 'x' ), sw( vt, 'y' ) ), max( sw( vt, 'z' ), sw( vt, 'w' ) ) ); 6 | }; 7 | -------------------------------------------------------------------------------- /src/globals/audio.ts: -------------------------------------------------------------------------------- 1 | import { promiseGui } from './gui'; 2 | 3 | export const audio = new AudioContext(); 4 | export const sampleRate = audio.sampleRate; 5 | 6 | promiseGui.then( ( gui ) => { 7 | gui.button( 'audio/resume', { title: 'audio.resume();' } ).on( 'click', () => { 8 | audio.resume(); 9 | } ); 10 | } ); 11 | -------------------------------------------------------------------------------- /src/utils/arraySetIntersection.ts: -------------------------------------------------------------------------------- 1 | import { arraySetHas } from '@0b5vr/experimental'; 2 | 3 | export function arraySetIntersection( a: Array, b: Array ): Array { 4 | const out: Array = []; 5 | a.map( ( v ) => { 6 | if ( arraySetHas( b, v ) ) { 7 | out.push( v ); 8 | } 9 | } ); 10 | return out; 11 | } 12 | -------------------------------------------------------------------------------- /src/music/MusicEngine.ts: -------------------------------------------------------------------------------- 1 | export interface MusicEngine { 2 | get isPlaying(): boolean; 3 | get time(): number; 4 | set time( time: number ); 5 | get deltaTime(): number; 6 | get cueStatus(): 'none' | 'compiling' | 'applying'; 7 | get gainNode(): GainNode; 8 | 9 | play(): void; 10 | pause(): void; 11 | update(): void; 12 | } 13 | -------------------------------------------------------------------------------- /src/heck/RenderTarget.ts: -------------------------------------------------------------------------------- 1 | export abstract class RenderTarget { 2 | public abstract viewport: [ number, number, number, number ]; 3 | 4 | public get width(): number { 5 | return this.viewport[ 2 ]; 6 | } 7 | 8 | public get height(): number { 9 | return this.viewport[ 3 ]; 10 | } 11 | 12 | public abstract bind(): void; 13 | } 14 | -------------------------------------------------------------------------------- /src/utils/poll.ts: -------------------------------------------------------------------------------- 1 | export function poll( func: () => boolean, ms = 10 ): Promise { 2 | return new Promise( ( resolve ) => { 3 | const a = (): void => { 4 | if ( func() ) { 5 | resolve(); 6 | return; 7 | } 8 | 9 | setTimeout( a, ms ); 10 | }; 11 | 12 | setTimeout( a, ms ); 13 | } ); 14 | } 15 | -------------------------------------------------------------------------------- /src/shaders/modules/isValidUv.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, and, gt, lt, sw } from '../shaderBuilder'; 2 | 3 | export const isValidUv = ( v: GLSLExpression<'vec2'> ): GLSLExpression<'bool'> => { 4 | return and( 5 | gt( sw( v, 'x' ), 0.0 ), 6 | lt( sw( v, 'x' ), 1.0 ), 7 | gt( sw( v, 'y' ), 0.0 ), 8 | lt( sw( v, 'y' ), 1.0 ), 9 | ); 10 | }; 11 | -------------------------------------------------------------------------------- /src/gl/glDrawBuffersByNumber.ts: -------------------------------------------------------------------------------- 1 | import { GL_COLOR_ATTACHMENT0 } from './constants'; 2 | import { arraySerial } from '@0b5vr/experimental'; 3 | import { gl } from '../globals/canvas'; 4 | 5 | export function glDrawBuffersByNumber( numBuffers: number ): void { 6 | gl.drawBuffers( 7 | arraySerial( numBuffers ).map( ( i ) => GL_COLOR_ATTACHMENT0 + i ) 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /src/nodes/FluidScene/shaders/fluidClampToGrid.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, add, clamp, div, sub } from '../../../shaders/shaderBuilder'; 2 | import { GRID_RESO } from '../constants'; 3 | 4 | export const fluidClampToGrid = ( pos: GLSLExpression<'vec3'> ): GLSLExpression<'vec3'> => ( 5 | clamp( pos, add( -0.5, div( 0.5, GRID_RESO ) ), sub( 0.5, div( 0.5, GRID_RESO ) ) ) 6 | ); 7 | -------------------------------------------------------------------------------- /src/shaders/modules/vKelemen.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, div, mul } from '../shaderBuilder'; 2 | 3 | // Ref: https://google.github.io/filament/Filament.md.html#materialsystem/clearcoatmodelconst symbol = Symbol(); 4 | export function vKelemen( 5 | dotLH: GLSLFloatExpression, 6 | ): GLSLExpression<'float'> { 7 | return div( 0.25, mul( dotLH, dotLH ) ); 8 | } 9 | -------------------------------------------------------------------------------- /src/utils/injectCodeToShader.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Assuming the first line is #version... 3 | * @param code The original shader code 4 | * @param inject The code you want to inject 5 | */ 6 | export function injectCodeToShader( code: string, inject: string ): string { 7 | const lines = code.split( '\n' ); 8 | lines.splice( 1, 0, inject ); 9 | return lines.join( '\n' ); 10 | } 11 | -------------------------------------------------------------------------------- /src/gl/GLDrawMode.ts: -------------------------------------------------------------------------------- 1 | import { GL_LINES, GL_LINE_LOOP, GL_LINE_STRIP, GL_POINTS, GL_TRIANGLES, GL_TRIANGLE_FAN, GL_TRIANGLE_STRIP } from './constants'; 2 | 3 | export type GLDrawMode = 4 | | typeof GL_POINTS 5 | | typeof GL_LINES 6 | | typeof GL_LINE_LOOP 7 | | typeof GL_LINE_STRIP 8 | | typeof GL_TRIANGLES 9 | | typeof GL_TRIANGLE_FAN 10 | | typeof GL_TRIANGLE_STRIP; 11 | -------------------------------------------------------------------------------- /src/utils/createPromiseSVGImage.ts: -------------------------------------------------------------------------------- 1 | export function createPromiseSVGImage( svgContent: string ): Promise { 2 | return new Promise( ( resolve ) => { 3 | const image = new Image(); 4 | image.onload = () => { 5 | resolve( image ); 6 | }; 7 | image.src = `data:image/svg+xml;charset=utf8,${ encodeURIComponent( svgContent ) }`; 8 | } ); 9 | } 10 | -------------------------------------------------------------------------------- /src/shaders/modules/bayerPattern4.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, glFragCoord, ivec2, sw } from '../shaderBuilder'; 2 | import { bayerMatrix4 } from './bayerMatrix4'; 3 | 4 | export function bayerPattern4( v?: GLSLExpression<'ivec2'> ): GLSLExpression<'float'> { 5 | v ??= ivec2( sw( glFragCoord, 'xy' ) ); 6 | return `${ bayerMatrix4 }[${ v }.x%4][${ v }.y%4]` as GLSLExpression<'float'>; 7 | } 8 | -------------------------------------------------------------------------------- /src/nodes/FluidScene/shaders/fluidFrameFrag.ts: -------------------------------------------------------------------------------- 1 | import { assign, build, defOutNamed, insert, main, vec4 } from '../../../shaders/shaderBuilder'; 2 | 3 | export const fluidFrameFrag = build( () => { 4 | insert( 'precision highp float;' ); 5 | 6 | const fragColor = defOutNamed( 'vec4', 'fragColor' ); 7 | 8 | main( () => { 9 | assign( fragColor, vec4( 1.0 ) ); 10 | } ); 11 | } ); 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | 26 | # size analysis 27 | /stats.json 28 | -------------------------------------------------------------------------------- /src/gl/glClear.ts: -------------------------------------------------------------------------------- 1 | import { GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT } from './constants'; 2 | import { gl } from '../globals/canvas'; 3 | 4 | export function glClear( red = 0.0, green = 0.0, blue = 0.0, alpha = 1.0, depth = 1.0 ): void { 5 | gl.clearColor( red, green, blue, alpha ); 6 | gl.clearDepth( depth ); 7 | gl.depthMask( true ); 8 | gl.clear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 9 | } 10 | -------------------------------------------------------------------------------- /src/shaders/common/colorFrag.ts: -------------------------------------------------------------------------------- 1 | import { assign, build, defOutNamed, defUniformNamed, insert, main } from '../shaderBuilder'; 2 | 3 | export const colorFrag = build( () => { 4 | insert( 'precision highp float;' ); 5 | 6 | const fragColor = defOutNamed( 'vec4', 'fragColor' ); 7 | const color = defUniformNamed( 'vec4', 'color' ); 8 | 9 | main( () => { 10 | assign( fragColor, color ); 11 | } ); 12 | } ); 13 | -------------------------------------------------------------------------------- /src/gl/glVertexArrayBindIndexbuffer.ts: -------------------------------------------------------------------------------- 1 | import { GL_ELEMENT_ARRAY_BUFFER } from './constants'; 2 | import { gl } from '../globals/canvas'; 3 | 4 | export function glVertexArrayBindIndexbuffer( 5 | vertexArray: WebGLVertexArrayObject, 6 | buffer: WebGLBuffer, 7 | ): void { 8 | gl.bindVertexArray( vertexArray ); 9 | 10 | gl.bindBuffer( GL_ELEMENT_ARRAY_BUFFER, buffer ); 11 | 12 | gl.bindVertexArray( null ); 13 | } 14 | -------------------------------------------------------------------------------- /src/shaders/modules/fresnelSchlick.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, max, mix, pow, sub } from '../shaderBuilder'; 2 | 3 | export function fresnelSchlick( 4 | dotVH: GLSLFloatExpression, 5 | f0: GLSLExpression, 6 | f90: GLSLExpression, 7 | ): GLSLExpression { 8 | const fresnel = pow( max( 0.0, sub( 1.0, dotVH ) ), 5.0 ); 9 | return mix( f0, f90, fresnel ); 10 | } 11 | -------------------------------------------------------------------------------- /src/gl/GLTextureMinFilterType.ts: -------------------------------------------------------------------------------- 1 | import { GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST, GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST_MIPMAP_NEAREST } from './constants'; 2 | 3 | export type GLTextureMinFilterType = 4 | | typeof GL_NEAREST 5 | | typeof GL_LINEAR 6 | | typeof GL_NEAREST_MIPMAP_NEAREST 7 | | typeof GL_LINEAR_MIPMAP_NEAREST 8 | | typeof GL_NEAREST_MIPMAP_LINEAR 9 | | typeof GL_LINEAR_MIPMAP_LINEAR; 10 | -------------------------------------------------------------------------------- /src/shaders/common/uvFrag.ts: -------------------------------------------------------------------------------- 1 | import { assign, build, defInNamed, defOutNamed, fract, insert, main, pow, vec4 } from '../shaderBuilder'; 2 | 3 | export const uvFrag = build( () => { 4 | insert( 'precision highp float;' ); 5 | 6 | const vUv = defInNamed( 'vec2', 'vUv' ); 7 | const fragColor = defOutNamed( 'vec4', 'fragColor' ); 8 | 9 | main( () => { 10 | assign( fragColor, pow( fract( vec4( vUv, 0.5, 1.0 ) ), vec4( 2.2 ) ) ); 11 | } ); 12 | } ); 13 | -------------------------------------------------------------------------------- /src/shaders/modules/glslSaturate.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, clamp } from '../shaderBuilder'; 2 | 3 | export const glslSaturate: { 4 | ( val: GLSLFloatExpression ): GLSLExpression<'float'>, 5 | ( val: GLSLExpression<'vec2'> ): GLSLExpression<'vec2'>, 6 | ( val: GLSLExpression<'vec3'> ): GLSLExpression<'vec3'>, 7 | ( val: GLSLExpression<'vec4'> ): GLSLExpression<'vec4'>, 8 | } = ( val: string | number ) => clamp( val as any, 0.0, 1.0 ) as any; 9 | -------------------------------------------------------------------------------- /src/gl/glCreateTexture.ts: -------------------------------------------------------------------------------- 1 | import { GLTextureFormatStuff, glSetTexture } from './glSetTexture'; 2 | import { gl } from '../globals/canvas'; 3 | 4 | export function glCreateTexture( 5 | width: number, 6 | height: number, 7 | source: ArrayBufferView | null, 8 | formatstuff?: GLTextureFormatStuff, 9 | ): WebGLTexture { 10 | const texture = gl.createTexture()!; 11 | glSetTexture( texture, width, height, source, formatstuff ); 12 | 13 | return texture; 14 | } 15 | -------------------------------------------------------------------------------- /src/shaders/modules/taylorInvSqrt.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, mul, sub } from '../shaderBuilder'; 2 | 3 | export const taylorInvSqrt: { 4 | ( r: GLSLExpression<'float'> ): GLSLExpression<'float'>; 5 | ( r: GLSLExpression<'vec2'> ): GLSLExpression<'vec2'>; 6 | ( r: GLSLExpression<'vec3'> ): GLSLExpression<'vec3'>; 7 | ( r: GLSLExpression<'vec4'> ): GLSLExpression<'vec4'>; 8 | } = ( r: any ): any => ( 9 | sub( 1.79284291400159, mul( 0.85373472095314, r ) ) 10 | ); 11 | -------------------------------------------------------------------------------- /src/shaders/modules/mod289.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, sub } from '../shaderBuilder'; 2 | import { glslLofi } from './glslLofi'; 3 | 4 | export const mod289: { 5 | ( x: GLSLExpression<'float'> ): GLSLExpression<'float'>; 6 | ( x: GLSLExpression<'vec2'> ): GLSLExpression<'vec2'>; 7 | ( x: GLSLExpression<'vec3'> ): GLSLExpression<'vec3'>; 8 | ( x: GLSLExpression<'vec4'> ): GLSLExpression<'vec4'>; 9 | } = ( x: any ): any => ( 10 | sub( x, glslLofi( x, 289.0 ) ) 11 | ); 12 | -------------------------------------------------------------------------------- /src/globals/randomTexture.ts: -------------------------------------------------------------------------------- 1 | import { RANDOM_TEXTURE_SIZE, STATIC_RANDOM_TEXTURE_SIZE } from '../config'; 2 | import { RandomTexture } from '../utils/RandomTexture'; 3 | 4 | export const randomTexture = new RandomTexture( 5 | RANDOM_TEXTURE_SIZE, 6 | RANDOM_TEXTURE_SIZE 7 | ); 8 | randomTexture.update(); 9 | 10 | export const randomTextureStatic = new RandomTexture( 11 | STATIC_RANDOM_TEXTURE_SIZE, 12 | STATIC_RANDOM_TEXTURE_SIZE 13 | ); 14 | randomTextureStatic.update(); 15 | -------------------------------------------------------------------------------- /src/nodes/CameraStack/DoF/shaders/dofCalcCoC.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, abs, defUniformNamed, div, min, mul, sub, sw } from '../../../../shaders/shaderBuilder'; 2 | 3 | export function dofCalcCoC( 4 | depth: GLSLExpression<'float'>, 5 | ): GLSLExpression<'float'> { 6 | const dofDepthSize = defUniformNamed( 'vec2', 'dofDepthSize' ); 7 | return mul( 8 | sw( dofDepthSize, 'y' ), 9 | min( 1.0, abs( div( sub( depth, sw( dofDepthSize, 'x' ) ), depth ) ) ), 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /src/shaders/modules/calcL.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLToken, def, divAssign, length, max, sub } from '../shaderBuilder'; 2 | 3 | export function calcL( 4 | lightPos: GLSLExpression<'vec3'>, 5 | surfacePos: GLSLExpression<'vec3'>, 6 | ): [ L: GLSLToken<'vec3'>, lenL: GLSLToken<'float'> ] { 7 | const L = def( 'vec3', sub( lightPos, surfacePos ) ); 8 | const lenL = def( 'float', length( L ) ); 9 | divAssign( L, max( 1E-3, lenL ) ); 10 | 11 | return [ L, lenL ]; 12 | } 13 | -------------------------------------------------------------------------------- /src/shaders/modules/sRGBEOTF.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, add, def, div, mix, pow, step, vec3 } from '../shaderBuilder'; 2 | import { glslSaturate } from './glslSaturate'; 3 | 4 | export function sRGBEOTF( x: GLSLExpression<'vec3'> ): GLSLExpression<'vec3'> { 5 | const x_ = def( 'vec3', glslSaturate( x ) as GLSLExpression<'vec3'> ); 6 | return mix( 7 | div( x_, 12.92 ), 8 | pow( div( add( x_, 0.055 ), 1.055 ), vec3( 2.4 ) ), 9 | step( 0.04045, x_ ) 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /src/utils/vdc.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Generate a number using Van der Corput sequence. 3 | * e.g. vdc(i, 2) = 1/2, 1/4, 3/4, 1/8, 5/8, 3/8, 7/8, 1/16, ... 4 | * @param i Index of the sequence 5 | * @param base Base of the sequence 6 | */ 7 | export function vdc( i: number, base: number ): number { 8 | let r = 0; 9 | let denom = 1; 10 | 11 | while ( 0 < i ) { 12 | denom *= base; 13 | r += ( i % base ) / denom; 14 | i = ~~( i / base ); 15 | } 16 | 17 | return r; 18 | } 19 | -------------------------------------------------------------------------------- /src/shaders/modules/sRGBOETF.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, def, mix, mul, pow, step, sub, vec3 } from '../shaderBuilder'; 2 | import { glslSaturate } from './glslSaturate'; 3 | 4 | export function sRGBOETF( x: GLSLExpression<'vec3'> ): GLSLExpression<'vec3'> { 5 | const x_ = def( 'vec3', glslSaturate( x ) as GLSLExpression<'vec3'> ); 6 | return mix( 7 | mul( x_, 12.92 ), 8 | sub( mul( pow( x_, vec3( 0.4167 ) ), 1.055 ), 0.055 ), 9 | step( 0.0031308, x_ ) 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "strict": true, 7 | "sourceMap": false, 8 | "resolveJsonModule": true, 9 | "isolatedModules": true, 10 | "esModuleInterop": true, 11 | "noEmit": true, 12 | "noUnusedLocals": true, 13 | "noUnusedParameters": true, 14 | "noImplicitReturns": true, 15 | "skipLibCheck": true 16 | }, 17 | "include": ["src"] 18 | } 19 | -------------------------------------------------------------------------------- /src/nodes/PostStack/Vectorscope/shaders/vectorscopeFrag.ts: -------------------------------------------------------------------------------- 1 | import { assign, build, defOut, glPointCoord, insert, length, main, smoothstep, sub, vec4 } from '../../../../shaders/shaderBuilder'; 2 | 3 | export const vectorscopeFrag = build( () => { 4 | insert( 'precision highp float;' ); 5 | 6 | const fragColor = defOut( 'vec4' ); 7 | 8 | main( () => { 9 | assign( fragColor, vec4( smoothstep( 0.5, 0.0, length( sub( 0.5, glPointCoord ) ) ) ) ); 10 | return; 11 | } ); 12 | } ); 13 | -------------------------------------------------------------------------------- /src/nodes/SevenSegScene/vec3UniformSphere.ts: -------------------------------------------------------------------------------- 1 | import { RawVector3, Xorshift } from '@0b5vr/experimental'; 2 | import { TAU } from '../../utils/constants'; 3 | 4 | export function vec3UniformSphere( rng: Xorshift ): RawVector3 { 5 | const phi = TAU * rng.gen(); 6 | const sinTheta = 1.0 - 2.0 * rng.gen(); 7 | const cosTheta = Math.sqrt( 1.0 - sinTheta * sinTheta ); 8 | 9 | return [ 10 | cosTheta * Math.cos( phi ), 11 | cosTheta * Math.sin( phi ), 12 | sinTheta, 13 | ]; 14 | } 15 | -------------------------------------------------------------------------------- /src/shaders/common/depthFrag.ts: -------------------------------------------------------------------------------- 1 | import { assign, build, defInNamed, defOut, insert, main } from '../shaderBuilder'; 2 | import { calcShadowDepth } from '../modules/calcShadowDepth'; 3 | 4 | export const depthFrag = build( () => { 5 | insert( 'precision highp float;' ); 6 | 7 | const vProjPosition = defInNamed( 'vec4', 'vProjPosition' ); 8 | 9 | const fragColor = defOut( 'vec4' ); 10 | 11 | main( () => { 12 | assign( fragColor, calcShadowDepth( vProjPosition ) ); 13 | } ); 14 | } ); 15 | -------------------------------------------------------------------------------- /src/shaders/common/dryFrag.ts: -------------------------------------------------------------------------------- 1 | import { assign, build, defInNamed, defOut, defUniformNamed, insert, main, texture } from '../shaderBuilder'; 2 | 3 | export const dryFrag = build( () => { 4 | insert( 'precision highp float;' ); 5 | 6 | const vUv = defInNamed( 'vec2', 'vUv' ); 7 | 8 | const fragColor = defOut( 'vec4' ); 9 | 10 | const sampler0 = defUniformNamed( 'sampler2D', 'sampler0' ); 11 | 12 | main( () => { 13 | assign( fragColor, texture( sampler0, vUv ) ); 14 | } ); 15 | } ); 16 | -------------------------------------------------------------------------------- /src/shaders/common/textureFrag.ts: -------------------------------------------------------------------------------- 1 | import { assign, build, defInNamed, defOut, defUniformNamed, insert, main, texture } from '../shaderBuilder'; 2 | 3 | export const textureFrag = build( () => { 4 | insert( 'precision highp float;' ); 5 | 6 | const vUv = defInNamed( 'vec2', 'vUv' ); 7 | const fragColor = defOut( 'vec4' ); 8 | 9 | const sampler0 = defUniformNamed( 'sampler2D', 'sampler0' ); 10 | 11 | main( () => { 12 | assign( fragColor, texture( sampler0, vUv ) ); 13 | } ); 14 | } ); 15 | -------------------------------------------------------------------------------- /src/utils/MapOfSet.ts: -------------------------------------------------------------------------------- 1 | export class MapOfSet { 2 | public readonly map: Map>; 3 | 4 | public constructor() { 5 | this.map = new Map(); 6 | } 7 | 8 | public get( key: K ): Set { 9 | return this.map.get( key ) ?? new Set(); 10 | } 11 | 12 | public add( key: K, value: V ): void { 13 | let set = this.map.get( key ); 14 | if ( set == null ) { 15 | set = new Set(); 16 | this.map.set( key, set ); 17 | } 18 | set.add( value ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/gl/GLBufferUsage.ts: -------------------------------------------------------------------------------- 1 | import { GL_DYNAMIC_COPY, GL_DYNAMIC_DRAW, GL_DYNAMIC_READ, GL_STATIC_COPY, GL_STATIC_DRAW, GL_STATIC_READ, GL_STREAM_COPY, GL_STREAM_DRAW, GL_STREAM_READ } from './constants'; 2 | 3 | export type GLBufferUsage = 4 | | typeof GL_STATIC_DRAW 5 | | typeof GL_DYNAMIC_DRAW 6 | | typeof GL_STREAM_DRAW 7 | | typeof GL_STATIC_READ 8 | | typeof GL_DYNAMIC_READ 9 | | typeof GL_STREAM_READ 10 | | typeof GL_STATIC_COPY 11 | | typeof GL_DYNAMIC_COPY 12 | | typeof GL_STREAM_COPY; 13 | -------------------------------------------------------------------------------- /src/shaders/modules/randomSphere.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, cache, defFn, retFn } from '../shaderBuilder'; 2 | import { glslDefRandom } from './glslDefRandom'; 3 | import { uniformSphere } from './uniformSphere'; 4 | 5 | const symbol = Symbol(); 6 | 7 | export function randomSphere(): GLSLExpression<'vec3'> { 8 | const { random2 } = glslDefRandom(); 9 | 10 | const f = cache( symbol, () => defFn( 'vec3', [], () => { 11 | retFn( uniformSphere( random2() ) ); 12 | } ) ); 13 | 14 | return f(); 15 | } 16 | -------------------------------------------------------------------------------- /src/shaders/modules/isectMin.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, cache, defFn, lt, retFn, sw, tern } from '../shaderBuilder'; 2 | 3 | const symbol = Symbol(); 4 | 5 | export function isectMin( 6 | a: GLSLExpression<'vec4'>, 7 | b: GLSLExpression<'vec4'>, 8 | ): GLSLExpression<'vec4'> { 9 | const f = cache( symbol, () => defFn( 'vec4', [ 'vec4', 'vec4' ], ( a, b ) => { 10 | retFn( tern( 11 | lt( sw( a, 'w' ), sw( b, 'w' ) ), 12 | a, 13 | b, 14 | ) ); 15 | } ) ); 16 | 17 | return f( a, b ); 18 | } 19 | -------------------------------------------------------------------------------- /src/shaders/modules/pcg2df.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, cache, defFn, div, float, floatBitsToUint, retFn, vec2 } from '../shaderBuilder'; 2 | import { pcg2d } from './pcg2d'; 3 | 4 | const symbol = Symbol(); 5 | 6 | export function pcg2df( v: GLSLExpression<'vec2'> ): GLSLExpression<'vec2'> { 7 | const f = cache( symbol, () => defFn( 'vec2', [ 'vec2' ], ( v ) => { 8 | const h = vec2( pcg2d( floatBitsToUint( v ) ) ); 9 | retFn( div( h, float( '0xffffffffu' as GLSLExpression<'uint'> ) ) ); 10 | } ) ); 11 | 12 | return f( v ); 13 | } 14 | -------------------------------------------------------------------------------- /src/shaders/modules/pcg3df.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, cache, defFn, div, float, floatBitsToUint, retFn, vec3 } from '../shaderBuilder'; 2 | import { pcg3d } from './pcg3d'; 3 | 4 | const symbol = Symbol(); 5 | 6 | export function pcg3df( v: GLSLExpression<'vec3'> ): GLSLExpression<'vec3'> { 7 | const f = cache( symbol, () => defFn( 'vec3', [ 'vec3' ], ( v ) => { 8 | const h = vec3( pcg3d( floatBitsToUint( v ) ) ); 9 | retFn( div( h, float( '0xffffffffu' as GLSLExpression<'uint'> ) ) ); 10 | } ) ); 11 | 12 | return f( v ); 13 | } 14 | -------------------------------------------------------------------------------- /src/shaders/modules/pcg4df.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, cache, defFn, div, float, floatBitsToUint, retFn, vec4 } from '../shaderBuilder'; 2 | import { pcg4d } from './pcg4d'; 3 | 4 | const symbol = Symbol(); 5 | 6 | export function pcg4df( v: GLSLExpression<'vec4'> ): GLSLExpression<'vec4'> { 7 | const f = cache( symbol, () => defFn( 'vec4', [ 'vec4' ], ( v ) => { 8 | const h = vec4( pcg4d( floatBitsToUint( v ) ) ); 9 | retFn( div( h, float( '0xffffffffu' as GLSLExpression<'uint'> ) ) ); 10 | } ) ); 11 | 12 | return f( v ); 13 | } 14 | -------------------------------------------------------------------------------- /src/shaders/modules/randomHemisphere.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, cache, def, defFn, dot, lt, neg, retFn, tern } from '../shaderBuilder'; 2 | import { randomSphere } from './randomSphere'; 3 | 4 | const symbol = Symbol(); 5 | 6 | export function randomHemisphere( n: GLSLExpression<'vec3'> ): GLSLExpression<'vec3'> { 7 | const f = cache( symbol, () => defFn( 'vec3', [ 'vec3' ], ( n ) => { 8 | const d = def( 'vec3', randomSphere() ); 9 | retFn( tern( lt( dot( d, n ), 0.0 ), neg( d ), d ) ); 10 | } ) ); 11 | 12 | return f( n ); 13 | } 14 | -------------------------------------------------------------------------------- /src/shaders/modules/rotate2D.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, cache, cos, def, defFn, mat2, neg, num, retFn, sin } from '../shaderBuilder'; 2 | 3 | const symbol = Symbol(); 4 | 5 | export function rotate2D( 6 | v: GLSLFloatExpression, 7 | ): GLSLExpression<'mat2'> { 8 | const f = cache( symbol, () => defFn( 'mat2', [ 'float' ], ( t ) => { 9 | const c = def( 'float', cos( t ) ); 10 | const s = def( 'float', sin( t ) ); 11 | retFn( mat2( c, s, neg( s ), c ) ); 12 | } ) ); 13 | 14 | return f( num( v ) ); 15 | } 16 | -------------------------------------------------------------------------------- /src/globals/dummyRenderTarget.ts: -------------------------------------------------------------------------------- 1 | import { BufferTextureRenderTarget } from '../heck/BufferTextureRenderTarget'; 2 | 3 | export const dummyRenderTarget1 = new BufferTextureRenderTarget( 1, 1 ); 4 | export const dummyRenderTarget2 = new BufferTextureRenderTarget( 1, 1, 2 ); 5 | export const dummyRenderTarget4 = new BufferTextureRenderTarget( 1, 1, 4 ); 6 | 7 | if ( import.meta.env.DEV ) { 8 | dummyRenderTarget1.name = 'dummyRenderTarget1'; 9 | dummyRenderTarget2.name = 'dummyRenderTarget2'; 10 | dummyRenderTarget4.name = 'dummyRenderTarget4'; 11 | } 12 | -------------------------------------------------------------------------------- /src/nodes/SevenSegScene/quatRandom.ts: -------------------------------------------------------------------------------- 1 | import { RawQuaternion, Xorshift } from '@0b5vr/experimental'; 2 | import { TAU } from '../../utils/constants'; 3 | 4 | export function quatRandom( rng: Xorshift ): RawQuaternion { 5 | const u = rng.gen(); 6 | const v = TAU * rng.gen(); 7 | const w = TAU * rng.gen(); 8 | 9 | const sqrtU = Math.sqrt( u ); 10 | const sqrt1U = Math.sqrt( 1.0 - u ); 11 | 12 | return [ 13 | sqrt1U * Math.sin( v ), 14 | sqrt1U * Math.cos( v ), 15 | sqrtU * Math.sin( w ), 16 | sqrtU * Math.cos( w ), 17 | ]; 18 | } 19 | -------------------------------------------------------------------------------- /src/utils/applyMixins.ts: -------------------------------------------------------------------------------- 1 | export function applyMixins( derivedCtor: any, baseCtors: any[] ): void { 2 | baseCtors.forEach( ( baseCtor ) => { 3 | Object.getOwnPropertyNames( baseCtor.prototype ).forEach( ( name ) => { 4 | // we should not use constructor otherwise the class name will be changed 5 | if ( name !== 'constructor' ) { 6 | Object.defineProperty( 7 | derivedCtor.prototype, 8 | name, 9 | Object.getOwnPropertyDescriptor( baseCtor.prototype, name )! 10 | ); 11 | } 12 | } ); 13 | } ); 14 | } 15 | -------------------------------------------------------------------------------- /src/shaders/modules/invCalcDepth.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, defUniformNamed, div, mul, sub, sw } from '../shaderBuilder'; 2 | 3 | /** 4 | * It probably returns a negative value. 5 | */ 6 | export function invCalcDepth( 7 | depth: GLSLExpression<'float'>, 8 | ): GLSLExpression<'float'> { 9 | const cameraNearFar = defUniformNamed( 'vec2', 'cameraNearFar' ); 10 | 11 | const near = sw( cameraNearFar, 'x' ); 12 | const far = sw( cameraNearFar, 'y' ); 13 | return div( 14 | mul( 2.0, near, far ), 15 | sub( mul( depth, sub( far, near ) ), far, near ), 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /src/music/withinGLSLMusicEditorRange.ts: -------------------------------------------------------------------------------- 1 | import { GLSLMusicEditorRange } from './GLSLMusicEditorRange'; 2 | 3 | export function withinGLSLMusicEditorRange( 4 | [ startLine, startCol, endLine, endCol ]: GLSLMusicEditorRange, 5 | line: number, 6 | col: number, 7 | ): boolean { 8 | if ( startLine === endLine ) { 9 | return startLine === line && ( startCol <= col && col < endCol ); 10 | } 11 | 12 | return ( 13 | ( startLine === line && startCol <= col ) || 14 | ( startLine < line && line < endLine ) || 15 | ( endLine === line && col < endCol ) 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /src/shaders/modules/minkowski2d.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, abs, cache, defFn, div, dot, num, pow, retFn, vec2 } from '../shaderBuilder'; 2 | 3 | const symbol = Symbol(); 4 | 5 | export function minkowski2d( 6 | v: GLSLExpression<'vec2'>, 7 | p: GLSLFloatExpression, 8 | ): GLSLExpression<'float'> { 9 | const f = cache( symbol, () => defFn( 'float', [ 'vec2', 'float' ], ( v, p ) => { 10 | retFn( pow( 11 | dot( pow( abs( v ), vec2( p ) ), vec2( 1.0 ) ), 12 | div( 1.0, p ) 13 | ) ); 14 | } ) ); 15 | 16 | return f( v, num( p ) ); 17 | } 18 | -------------------------------------------------------------------------------- /src/shaders/modules/minkowski3d.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, abs, cache, defFn, div, dot, num, pow, retFn, vec3 } from '../shaderBuilder'; 2 | 3 | const symbol = Symbol(); 4 | 5 | export function minkowski3d( 6 | v: GLSLExpression<'vec3'>, 7 | p: GLSLFloatExpression, 8 | ): GLSLExpression<'float'> { 9 | const f = cache( symbol, () => defFn( 'float', [ 'vec3', 'float' ], ( v, p ) => { 10 | retFn( pow( 11 | dot( pow( abs( v ), vec3( p ) ), vec3( 1.0 ) ), 12 | div( 1.0, p ) 13 | ) ); 14 | } ) ); 15 | 16 | return f( v, num( p ) ); 17 | } 18 | -------------------------------------------------------------------------------- /src/gl/glTextureWrap.ts: -------------------------------------------------------------------------------- 1 | import { GLTextureWrapType } from './GLTextureWrapType'; 2 | import { GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T } from './constants'; 3 | import { gl } from '../globals/canvas'; 4 | 5 | export function glTextureWrap( 6 | texture: WebGLTexture, 7 | wrap: GLTextureWrapType, 8 | ): WebGLTexture { 9 | gl.bindTexture( GL_TEXTURE_2D, texture ); 10 | gl.texParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap ); 11 | gl.texParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap ); 12 | gl.bindTexture( GL_TEXTURE_2D, null ); 13 | 14 | return texture; 15 | } 16 | -------------------------------------------------------------------------------- /src/gl/glCreateIndexbuffer.ts: -------------------------------------------------------------------------------- 1 | import { GLBufferUsage } from './GLBufferUsage'; 2 | import { GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW } from './constants'; 3 | import { gl } from '../globals/canvas'; 4 | 5 | export function glCreateIndexbuffer( 6 | source: BufferSource | null, 7 | usage: GLBufferUsage = GL_STATIC_DRAW, 8 | ): WebGLBuffer { 9 | const buffer = gl.createBuffer()!; 10 | 11 | gl.bindBuffer( GL_ELEMENT_ARRAY_BUFFER, buffer ); 12 | gl.bufferData( GL_ELEMENT_ARRAY_BUFFER, source, usage ); 13 | gl.bindBuffer( GL_ELEMENT_ARRAY_BUFFER, null ); 14 | 15 | return buffer; 16 | } 17 | -------------------------------------------------------------------------------- /src/globals/ibllutCalc.ts: -------------------------------------------------------------------------------- 1 | import { GL_NEAREST } from '../gl/constants'; 2 | import { IBLLUTCalc } from '../nodes/IBLLUTCalc/IBLLUTCalc'; 3 | import { glTextureFilter } from '../gl/glTextureFilter'; 4 | 5 | export const ibllutCalc = new IBLLUTCalc(); 6 | 7 | export const ibllutTexture = ibllutCalc.swap.i.texture; 8 | 9 | glTextureFilter( ibllutCalc.swap.i.texture, GL_NEAREST ); 10 | glTextureFilter( ibllutCalc.swap.o.texture, GL_NEAREST ); 11 | 12 | if ( import.meta.env.DEV ) { 13 | ibllutCalc.swap.i.name = 'ibllutTexture/swap0'; 14 | ibllutCalc.swap.o.name = 'ibllutTexture/swap1'; 15 | } 16 | -------------------------------------------------------------------------------- /src/music/shaderchunks.ts: -------------------------------------------------------------------------------- 1 | export const shaderchunkPre = `#version 300 es 2 | 3 | precision highp float; 4 | 5 | #define _PI 3.14159265359 6 | 7 | uniform float bpm; 8 | uniform vec4 timeLength; 9 | uniform float sampleRate; 10 | uniform vec4 timeHead; 11 | 12 | in float off; 13 | 14 | out float outL; 15 | out float outR; 16 | `; 17 | 18 | export const shaderchunkPreLines = shaderchunkPre.split( '\n' ).length; 19 | 20 | export const shaderchunkPost = `void main() { 21 | vec2 out2 = mainaudio( mod( timeHead + off / sampleRate, timeLength ) ); 22 | outL = out2.x; 23 | outR = out2.y; 24 | }`; 25 | -------------------------------------------------------------------------------- /src/gl/glCreateVertexbuffer.ts: -------------------------------------------------------------------------------- 1 | import { GLBufferUsage } from './GLBufferUsage'; 2 | import { GL_ARRAY_BUFFER, GL_STATIC_DRAW } from './constants'; 3 | import { gl } from '../globals/canvas'; 4 | 5 | export function glCreateVertexbuffer( 6 | source: BufferSource | null, 7 | usage: GLBufferUsage = GL_STATIC_DRAW, 8 | ): WebGLBuffer { 9 | const buffer = gl.createBuffer()!; 10 | 11 | if ( source ) { 12 | gl.bindBuffer( GL_ARRAY_BUFFER, buffer ); 13 | gl.bufferData( GL_ARRAY_BUFFER, source, usage ); 14 | gl.bindBuffer( GL_ARRAY_BUFFER, null ); 15 | } 16 | 17 | return buffer; 18 | } 19 | -------------------------------------------------------------------------------- /src/globals/canvas.ts: -------------------------------------------------------------------------------- 1 | import 'webgl-memory'; 2 | 3 | import { GL_BLEND, GL_LEQUAL, GL_POLYGON_OFFSET_FILL } from '../gl/constants'; 4 | 5 | export const canvas = document.createElement( 'canvas' ); 6 | 7 | export const gl = canvas.getContext( 'webgl2', { antialias: false } )!; 8 | gl.depthFunc( GL_LEQUAL ); 9 | gl.enable( GL_BLEND ); 10 | gl.enable( GL_POLYGON_OFFSET_FILL ); 11 | 12 | gl.getExtension( 'EXT_color_buffer_float' ); 13 | gl.getExtension( 'EXT_float_blend' ); 14 | gl.getExtension( 'OES_texture_float_linear' ); 15 | export const extParallel = gl.getExtension( 'KHR_parallel_shader_compile' )!; 16 | -------------------------------------------------------------------------------- /src/nodes/HistogramScatter/shaders/histogramGatherFrag.ts: -------------------------------------------------------------------------------- 1 | import { assign, build, defInNamed, defOut, eq, insert, main, tern, vec4 } from '../../../shaders/shaderBuilder'; 2 | 3 | export const histogramGatherFrag = build( () => { 4 | insert( 'precision highp float;' ); 5 | 6 | const vC = defInNamed( 'float', 'vC' ); 7 | 8 | const fragColor = defOut( 'vec4' ); 9 | 10 | main( () => { 11 | assign( fragColor, vec4( 12 | tern( eq( vC, 0.0 ), 1.0, 0.0 ), 13 | tern( eq( vC, 1.0 ), 1.0, 0.0 ), 14 | tern( eq( vC, 2.0 ), 1.0, 0.0 ), 15 | 1.0, 16 | ) ); 17 | } ); 18 | } ); 19 | -------------------------------------------------------------------------------- /src/nodes/utils/createShaderRenderTarget.ts: -------------------------------------------------------------------------------- 1 | import { BufferRenderTargetOptions, RawBufferRenderTarget } from '../../heck/RawBufferRenderTarget'; 2 | import { Material } from '../../heck/Material'; 3 | import { Quad } from '../../heck/components/Quad'; 4 | 5 | export function createShaderRenderTarget( 6 | material: Material, 7 | options: BufferRenderTargetOptions, 8 | ): RawBufferRenderTarget { 9 | const target = new RawBufferRenderTarget( options ); 10 | 11 | const quad = new Quad( { 12 | material, 13 | target, 14 | } ); 15 | quad.drawImmediate(); 16 | 17 | return target; 18 | } 19 | -------------------------------------------------------------------------------- /src/shaders/common/quadVert.ts: -------------------------------------------------------------------------------- 1 | import { add, assign, build, defIn, defOutNamed, defUniformNamed, glPosition, main, mix, mul, sw, vec4 } from '../shaderBuilder'; 2 | 3 | export const quadVert = build( () => { 4 | const position = defIn( 'vec2', 0 ); 5 | 6 | const vUv = defOutNamed( 'vec2', 'vUv' ); 7 | 8 | const range = defUniformNamed( 'vec4', 'range' ); 9 | 10 | main( () => { 11 | assign( vUv, add( 0.5, mul( 0.5, position ) ) ); 12 | assign( glPosition, vec4( 13 | mix( sw( range, 'xy' ), sw( range, 'zw' ), vUv ), 14 | 0.0, 15 | 1.0, 16 | ) ); 17 | } ); 18 | } ); 19 | -------------------------------------------------------------------------------- /src/heck/components/LogTransform.ts: -------------------------------------------------------------------------------- 1 | import { Component, ComponentOptions, ComponentUpdateEvent } from './Component'; 2 | 3 | export class LogTransform extends Component { 4 | public constructor( options?: ComponentOptions ) { 5 | super( options ); 6 | 7 | this.visible = false; 8 | } 9 | 10 | protected __updateImpl( event: ComponentUpdateEvent ): void { 11 | console.info( ` 12 | Position: ${ event.globalTransform.position } 13 | Rotation: ${ event.globalTransform.rotation } 14 | Scale: ${ event.globalTransform.scale } 15 | Matrix: ${ event.globalTransform.matrix } 16 | ` ); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/globals/globalObservers.ts: -------------------------------------------------------------------------------- 1 | import { ComponentUpdateEvent } from '../heck/components/Component'; 2 | import { Observer } from '../utils/Observer'; 3 | 4 | export const resizeObservers: Observer<[ width: number, height: number ]>[] = []; 5 | export const editorVisibleObservers: Observer[] = []; 6 | export const musicRendererStatusObservers: Observer<'none' | 'compiling' | 'applying'>[] = []; 7 | export const preparationProgressObservers: Observer[] = []; 8 | export const audioAnalyzerObservers: Observer[] = []; 9 | export const componentUpdateObservers: Observer[] = []; 10 | -------------------------------------------------------------------------------- /src/nodes/FluidScene/shaders/fluidUvToPos.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, add, div, dot, floor, fract, mul, sub, vec2, vec3 } from '../../../shaders/shaderBuilder'; 2 | import { GRID_RESO, GRID_RESO_SQRT } from '../constants'; 3 | import { fluidClampToGrid } from './fluidClampToGrid'; 4 | 5 | export const fluidUvToPos = ( uv: GLSLExpression<'vec2'> ): GLSLExpression<'vec3'> => { 6 | const uvInGrid = mul( uv, GRID_RESO_SQRT ); 7 | 8 | return fluidClampToGrid( sub( vec3( 9 | fract( uvInGrid ), 10 | div( add( dot( floor( uvInGrid ), vec2( 1.0, GRID_RESO_SQRT ) ), 0.5 ), GRID_RESO ) 11 | ), 0.5 ) ); 12 | }; 13 | -------------------------------------------------------------------------------- /src/shaders/modules/phongSpecular.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, cache, defFn, dot, max, normalize, num, pow, retFn } from '../shaderBuilder'; 2 | 3 | const symbol = Symbol(); 4 | 5 | export function phongSpecular( 6 | v: GLSLExpression<'vec3'>, 7 | dir: GLSLExpression<'vec3'>, 8 | p: GLSLFloatExpression, 9 | ): GLSLExpression<'float'> { 10 | const f = cache( symbol, () => defFn( 'float', [ 'vec3', 'vec3', 'float' ], ( v, dir, p ) => { 11 | const d = max( 0.0, dot( v, normalize( dir ) ) ); 12 | retFn( pow( d, p ) ); 13 | } ) ); 14 | 15 | return f( v, dir, num( p ) ); 16 | } 17 | -------------------------------------------------------------------------------- /src/globals/postTarget.ts: -------------------------------------------------------------------------------- 1 | import { BufferTextureRenderTarget } from '../heck/BufferTextureRenderTarget'; 2 | import { GLTextureFormatStuffRGBA8 } from '../gl/glSetTexture'; 3 | import { GL_NEAREST } from '../gl/constants'; 4 | import { canvasRenderTarget } from './canvasRenderTarget'; 5 | import { glTextureFilter } from '../gl/glTextureFilter'; 6 | 7 | let postTarget = canvasRenderTarget; 8 | 9 | if ( import.meta.env.DEV ) { 10 | const target = postTarget = new BufferTextureRenderTarget( 4, 4, 1, GLTextureFormatStuffRGBA8 ); 11 | glTextureFilter( target.texture, GL_NEAREST ); 12 | } 13 | 14 | export { postTarget }; 15 | -------------------------------------------------------------------------------- /src/utils/Cache.ts: -------------------------------------------------------------------------------- 1 | export class Cache { 2 | private __cache: T; 3 | public needsUpdate: boolean; 4 | public update: () => T; 5 | 6 | public constructor( init: T, update: () => T ) { 7 | this.__cache = init; 8 | this.needsUpdate = false; 9 | this.update = update; 10 | } 11 | 12 | public get value(): T { 13 | if ( this.needsUpdate ) { 14 | this.__cache = this.update(); 15 | this.needsUpdate = false; 16 | } 17 | 18 | return this.__cache; 19 | } 20 | 21 | public setValue( value: T ): void { 22 | this.__cache = value; 23 | this.needsUpdate = false; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/music/constants.ts: -------------------------------------------------------------------------------- 1 | export const MUSIC_BPM = 140.0; 2 | 3 | export const BEAT = 60.0 / MUSIC_BPM; 4 | export const BAR = 240.0 / MUSIC_BPM; 5 | export const SIXTEEN_BAR = 3840.0 / MUSIC_BPM; 6 | 7 | export const BLOCK_SIZE = 128; 8 | 9 | // == variables for offline ======================================================================== 10 | export const MUSIC_LENGTH = 441; 11 | 12 | // == variables for realtime ======================================================================= 13 | export const BLOCKS_PER_RENDER = 32; 14 | export const FRAMES_PER_RENDER = BLOCK_SIZE * BLOCKS_PER_RENDER; 15 | export const LATENCY_BLOCKS = 64; 16 | -------------------------------------------------------------------------------- /src/shaders/modules/glslTri.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { GLSLExpression, GLSLFloatExpression, asin, mul, sin } from '../shaderBuilder'; 4 | import { PI, TAU } from '../../utils/constants'; 5 | 6 | export function glslTri( x: GLSLFloatExpression ): GLSLExpression<'float'>; 7 | export function glslTri( x: GLSLExpression<'vec2'> ): GLSLExpression<'vec2'>; 8 | export function glslTri( x: GLSLExpression<'vec3'> ): GLSLExpression<'vec3'>; 9 | export function glslTri( x: GLSLExpression<'vec4'> ): GLSLExpression<'vec4'>; 10 | export function glslTri( x: string | number ): string { 11 | return mul( asin( sin( mul( TAU, x as any ) ) ), 2.0 / PI ); 12 | } 13 | -------------------------------------------------------------------------------- /src/shaders/modules/tonemapACESNarkowicz.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, add, div, mul } from '../shaderBuilder'; 2 | import { glslSaturate } from './glslSaturate'; 3 | 4 | /*! 5 | * The ACES tone mapping part is taken from Krzysztof Narkowicz's blog 6 | * 7 | * https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/ 8 | */ 9 | 10 | export function tonemapACESNarkowicz( 11 | x: GLSLExpression<'vec3'>, 12 | ): GLSLExpression<'vec3'> { 13 | return glslSaturate( div( 14 | mul( x, add( mul( 0.45, x ), 0.02 ) ), 15 | add( mul( x, add( mul( 0.45, x ), 0.07 ) ), 0.2 ), 16 | ) ) as GLSLExpression<'vec3'>; 17 | } 18 | -------------------------------------------------------------------------------- /src/globals/quadGeometry.ts: -------------------------------------------------------------------------------- 1 | import { GL_TRIANGLE_STRIP } from '../gl/constants'; 2 | import { Geometry } from '../heck/Geometry'; 3 | import { TRIANGLE_STRIP_QUAD } from '@0b5vr/experimental'; 4 | import { glCreateVertexbuffer } from '../gl/glCreateVertexbuffer'; 5 | import { glVertexArrayBindVertexbuffer } from '../gl/glVertexArrayBindVertexbuffer'; 6 | 7 | export const quadBuffer = glCreateVertexbuffer( new Float32Array( TRIANGLE_STRIP_QUAD ) ); 8 | 9 | export const quadGeometry = new Geometry(); 10 | glVertexArrayBindVertexbuffer( quadGeometry.vao, quadBuffer, 0, 2 ); 11 | 12 | quadGeometry.count = 4; 13 | quadGeometry.mode = GL_TRIANGLE_STRIP; 14 | -------------------------------------------------------------------------------- /src/shaders/modules/isectPlane.ts: -------------------------------------------------------------------------------- 1 | import { FAR } from '../../config'; 2 | import { GLSLExpression, cache, def, defFn, div, dot, lt, retFn, tern } from '../shaderBuilder'; 3 | 4 | const symbol = Symbol(); 5 | 6 | export function isectPlane( 7 | ro: GLSLExpression<'vec3'>, 8 | rd: GLSLExpression<'vec3'>, 9 | n: GLSLExpression<'vec3'>, 10 | ): GLSLExpression<'float'> { 11 | const f = cache( symbol, () => defFn( 'float', [ 'vec3', 'vec3', 'vec3' ], ( ro, rd, n ) => { 12 | const t = def( 'float', div( dot( ro, n ), -1.0, dot( rd, n ) ) ); 13 | retFn( tern( lt( t, 0.0 ), FAR, t ) ); 14 | } ) ); 15 | 16 | return f( ro, rd, n ); 17 | } 18 | -------------------------------------------------------------------------------- /src/globals/preparationTasks.ts: -------------------------------------------------------------------------------- 1 | import { notifyObservers } from '@0b5vr/experimental'; 2 | import { preparationProgressObservers } from './globalObservers'; 3 | import { sleep } from '../utils/sleep'; 4 | 5 | export const preparationTasks: ( () => Promise )[] = []; 6 | 7 | export const prepare = async (): Promise => { 8 | let completed = 0; 9 | 10 | // Promise.all does not work, tasks must be executed in serial with a sleep 11 | for ( const task of preparationTasks ) { 12 | await task(); 13 | completed ++; 14 | notifyObservers( preparationProgressObservers, completed / preparationTasks.length ); 15 | await sleep( 1 ); 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /src/utils/Memo.ts: -------------------------------------------------------------------------------- 1 | export class Memo< 2 | TValue, 3 | TArgs extends any[] = [], 4 | > { 5 | public gen: ( ...args: TArgs ) => TValue; 6 | private __map: Map; 7 | 8 | public constructor( gen: ( ...args: TArgs ) => TValue ) { 9 | this.gen = gen; 10 | this.__map = new Map(); 11 | } 12 | 13 | public get( 14 | key: symbol | undefined, 15 | ...args: Parameters<( ...args: TArgs ) => TValue> 16 | ): TValue { 17 | let value = key && this.__map.get( key ); 18 | 19 | if ( !value ) { 20 | value = this.gen( ...args ); 21 | key && this.__map.set( key, value ); 22 | } 23 | 24 | return value; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/shaders/modules/boxMuller.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, cache, cos, defFn, log, mul, retFn, sin, sqrt, sw, vec2 } from '../shaderBuilder'; 2 | import { TAU } from '../../utils/constants'; 3 | 4 | const symbol = Symbol(); 5 | 6 | export function boxMuller( xi: GLSLExpression<'vec2'> ): GLSLExpression<'vec2'> { 7 | const f = cache( 8 | symbol, 9 | () => defFn( 10 | 'vec2', 11 | [ 'vec2' ], 12 | ( xi ) => { 13 | const r = sqrt( mul( -2.0, log( sw( xi, 'x' ) ) ) ); 14 | const t = mul( TAU, sw( xi, 'y' ) ); 15 | retFn( mul( r, vec2( cos( t ), sin( t ) ) ) ); 16 | } 17 | ) 18 | ); 19 | 20 | return f( xi ); 21 | } 22 | -------------------------------------------------------------------------------- /src/shaders/modules/sdcapsule.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, div, dot, length, mul, sub } from '../shaderBuilder'; 2 | import { glslSaturate } from './glslSaturate'; 3 | 4 | /** 5 | * SDF of capsule. 6 | * See: https://iquilezles.untergrund.net/www/articles/distfunctions/distfunctions.htm 7 | */ 8 | export const sdcapsule: { 9 | ( p: GLSLExpression<'vec2'>, tail: GLSLExpression<'vec2'> ): GLSLExpression<'float'>, 10 | ( p: GLSLExpression<'vec3'>, tail: GLSLExpression<'vec3'> ): GLSLExpression<'float'>, 11 | } = ( p: any, tail: any ) => { 12 | const h = glslSaturate( div( dot( p, tail ), dot( tail, tail ) ) ); 13 | return length( sub( p, mul( tail, h ) ) as any ); 14 | }; 15 | -------------------------------------------------------------------------------- /src/shaders/modules/vNeubelt.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, add, cache, defFn, div, mul, neg, num, retFn } from '../shaderBuilder'; 2 | 3 | const symbol = Symbol(); 4 | 5 | export function vNeubelt( 6 | dotNL: GLSLFloatExpression, 7 | dotNV: GLSLFloatExpression, 8 | ): GLSLExpression<'float'> { 9 | const f = cache( 10 | symbol, 11 | () => defFn( 'float', [ 'float', 'float' ], ( dotNL, dotNV ) => { 12 | retFn( div( 13 | 1.0, 14 | mul( 15 | 4.0, 16 | add( dotNL, dotNV, neg( mul( dotNL, dotNV ) ) ), 17 | ) 18 | ) ); 19 | } ) 20 | ); 21 | 22 | return f( num( dotNL ), num( dotNV ) ); 23 | } 24 | -------------------------------------------------------------------------------- /src/gl/glWaitGPUCommandsCompleteAsync.ts: -------------------------------------------------------------------------------- 1 | import { gl } from '../globals/canvas'; 2 | 3 | export function glWaitGPUCommandsCompleteAsync(): Promise { 4 | const sync = gl.fenceSync( gl.SYNC_GPU_COMMANDS_COMPLETE, 0 )!; 5 | 6 | return new Promise( ( resolve, reject ) => { 7 | const test = (): void => { 8 | const res = gl.clientWaitSync( sync, 0, 0 ); 9 | if ( res === gl.WAIT_FAILED ) { 10 | reject(); 11 | return; 12 | } 13 | if ( res === gl.TIMEOUT_EXPIRED ) { 14 | setTimeout( test, 10 ); 15 | return; 16 | } 17 | gl.deleteSync( sync ); 18 | resolve(); 19 | }; 20 | 21 | test(); 22 | } ); 23 | } 24 | -------------------------------------------------------------------------------- /src/shaders/modules/sdbox2.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, abs, add, cache, def, defFn, length, max, min, retFn, sub, sw } from '../shaderBuilder'; 2 | 3 | const symbol = Symbol(); 4 | 5 | export function sdbox2( 6 | p: GLSLExpression<'vec2'>, 7 | s: GLSLExpression<'vec2'>, 8 | ): GLSLExpression<'float'> { 9 | const f = cache( symbol, () => defFn( 'float', [ 'vec2', 'vec2' ], ( p, s ) => { 10 | const d = def( 'vec2', sub( abs( p ), s ) ); 11 | const inside = min( 12 | max( sw( d, 'x' ), sw( d, 'y' ) ), 13 | 0.0, 14 | ); 15 | const outside = length( max( d, 0.0 ) ); 16 | retFn( add( inside, outside ) ); 17 | } ) ); 18 | 19 | return f( p, s ); 20 | } 21 | -------------------------------------------------------------------------------- /src/shaders/modules/calcAlbedoF0.ts: -------------------------------------------------------------------------------- 1 | import { DIELECTRIC_SPECULAR, ONE_SUB_DIELECTRIC_SPECULAR } from '../../utils/constants'; 2 | import { GLSLExpression, GLSLFloatExpression, GLSLToken, def, mix, mul, vec3 } from '../shaderBuilder'; 3 | 4 | export function calcAlbedoF0( 5 | baseColor: GLSLExpression<'vec3'>, 6 | metallic: GLSLFloatExpression, 7 | ): { 8 | albedo: GLSLToken<'vec3'>, 9 | f0: GLSLToken<'vec3'>, 10 | } { 11 | return { 12 | albedo: def( 'vec3', ( 13 | mix( mul( baseColor, ONE_SUB_DIELECTRIC_SPECULAR ), vec3( 0.0 ), metallic ) 14 | ) ), 15 | f0: def( 'vec3', ( 16 | mix( DIELECTRIC_SPECULAR, baseColor, metallic ) 17 | ) ), 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /src/gl/glVertexArrayBindVertexbuffer.ts: -------------------------------------------------------------------------------- 1 | import { GL_ARRAY_BUFFER, GL_FLOAT } from './constants'; 2 | import { gl } from '../globals/canvas'; 3 | 4 | export function glVertexArrayBindVertexbuffer( 5 | vertexArray: WebGLVertexArrayObject, 6 | buffer: WebGLBuffer, 7 | location: number, 8 | size: number, 9 | divisor = 0, 10 | stride = 0, 11 | offset = 0, 12 | ): void { 13 | gl.bindVertexArray( vertexArray ); 14 | 15 | gl.bindBuffer( GL_ARRAY_BUFFER, buffer ); 16 | gl.enableVertexAttribArray( location ); 17 | gl.vertexAttribPointer( location, size, GL_FLOAT, false, stride, offset ); 18 | gl.vertexAttribDivisor( location, divisor ); 19 | 20 | gl.bindVertexArray( null ); 21 | } 22 | -------------------------------------------------------------------------------- /src/globals/audioReverb.ts: -------------------------------------------------------------------------------- 1 | import { audio, sampleRate } from './audio'; 2 | 3 | const samples = 4.0 * sampleRate; 4 | const buffer = audio.createBuffer( 2, samples, sampleRate ); 5 | 6 | for ( let iCh = 0; iCh < 2; iCh ++ ) { 7 | const ch = buffer.getChannelData( iCh ); 8 | 9 | for ( let i = 0; i < samples; i ++ ) { 10 | const t = i / sampleRate; 11 | ch[ i ] = ( Math.random() - 0.5 ) * Math.exp( -5.0 * t ); 12 | } 13 | } 14 | 15 | const convolver = audio.createConvolver(); 16 | convolver.buffer = buffer; 17 | 18 | convolver.connect( audio.destination ); 19 | 20 | export const audioReverb = audio.createGain(); 21 | audioReverb.gain.value = 0.04; 22 | audioReverb.connect( convolver ); 23 | -------------------------------------------------------------------------------- /src/shaders/modules/sdtorus.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, cache, defFn, length, num, retFn, sub, sw, vec2 } from '../shaderBuilder'; 2 | 3 | const symbol = Symbol(); 4 | 5 | // Ref: https://www.iquilezles.org/www/articles/normalsSDF/normalsSDF.htm 6 | export function sdtorus( 7 | p: GLSLExpression<'vec3'>, 8 | R: GLSLFloatExpression, 9 | r: GLSLFloatExpression, 10 | ): GLSLExpression<'float'> { 11 | const f = cache( symbol, () => defFn( 'float', [ 'vec3', 'float', 'float' ], ( p, R, r ) => { 12 | const v = vec2( sub( length( sw( p, 'xy' ) ), R ), sw( p, 'z' ) ); 13 | retFn( sub( length( v ), r ) ); 14 | } ) ); 15 | 16 | return f( p, num( R ), num( r ) ); 17 | } 18 | -------------------------------------------------------------------------------- /src/nodes/LoadingScreen/shaders/ditherFrag.ts: -------------------------------------------------------------------------------- 1 | import { assign, build, defInNamed, defOut, glFragCoord, insert, main, sq, step, sub, sw, vec3, vec4 } from '../../../shaders/shaderBuilder'; 2 | import { pcg3df } from '../../../shaders/modules/pcg3df'; 3 | 4 | export const ditherFrag = build( () => { 5 | insert( 'precision highp float;' ); 6 | 7 | const vUv = defInNamed( 'vec2', 'vUv' ); 8 | const fragColor = defOut( 'vec4' ); 9 | 10 | main( () => { 11 | const dither = sw( pcg3df( sw( glFragCoord, 'xyy' ) ), 'x' ); 12 | const threshold = sq( sw( vUv, 'x' ) ); 13 | const c = step( 0.0, sub( threshold, dither ) ); 14 | assign( fragColor, vec4( vec3( c ), 1.0 ) ); 15 | } ); 16 | } ); 17 | -------------------------------------------------------------------------------- /src/utils/getYugoppText.ts: -------------------------------------------------------------------------------- 1 | export function getYugoppText( text: string, phase: number ): string { 2 | if ( phase >= 1.5 ) { return text; } 3 | if ( phase < 0.0 ) { return ''; } 4 | 5 | const displayTween = Math.min( Math.max( phase, 0.0 ), 1.0 ); 6 | const fixTween = Math.min( Math.max( phase - 0.5, 0.0 ), 1.0 ); 7 | 8 | const fixLength = Math.floor( text.length * fixTween ); 9 | const randomLength = Math.floor( text.length * ( displayTween - fixTween ) + 1.0 ); 10 | const randomStr = [ ...new Array( randomLength ) ] 11 | .map( () => String.fromCharCode( 33 + Math.floor( 93 * Math.random() ) ) ) 12 | .join( '' ); 13 | 14 | return text.substring( 0, fixLength ) + randomStr; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/shaders/modules/dGGX.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, add, cache, def, defFn, div, mul, num, retFn, sub } from '../shaderBuilder'; 2 | import { PI } from '../../utils/constants'; 3 | 4 | const symbol = Symbol(); 5 | 6 | export function dGGX( 7 | dotNH: GLSLFloatExpression, 8 | roughnessSq: GLSLFloatExpression, 9 | ): GLSLExpression<'float'> { 10 | const f = cache( 11 | symbol, 12 | () => defFn( 'float', [ 'float', 'float' ], ( dotNH, roughnessSq ) => { 13 | const f = def( 'float', add( mul( dotNH, dotNH, sub( roughnessSq, 1.0 ) ), 1.0 ) ); 14 | retFn( div( roughnessSq, mul( PI, f, f ) ) ); 15 | } ) 16 | ); 17 | 18 | return f( num( dotNH ), num( roughnessSq ) ); 19 | } 20 | -------------------------------------------------------------------------------- /src/gl/glTextureFilter.ts: -------------------------------------------------------------------------------- 1 | import { GLTextureMagFilterType } from './GLTextureMagFilterType'; 2 | import { GLTextureMinFilterType } from './GLTextureMinFilterType'; 3 | import { GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_TEXTURE_MIN_FILTER } from './constants'; 4 | import { gl } from '../globals/canvas'; 5 | 6 | export function glTextureFilter( 7 | texture: WebGLTexture, 8 | mag: GLTextureMagFilterType, 9 | min: GLTextureMinFilterType = mag, 10 | ): WebGLTexture { 11 | gl.bindTexture( GL_TEXTURE_2D, texture ); 12 | gl.texParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag ); 13 | gl.texParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min ); 14 | gl.bindTexture( GL_TEXTURE_2D, null ); 15 | 16 | return texture; 17 | } 18 | -------------------------------------------------------------------------------- /src/shaders/modules/orthBas.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, abs, assign, cache, cross, def, defFn, mat3, normalize, retFn, sq, sub, sw, vec3 } from '../shaderBuilder'; 2 | 3 | const symbol = Symbol(); 4 | 5 | export function orthBas( z: GLSLExpression<'vec3'> ): GLSLExpression<'mat3'> { 6 | const f = cache( symbol, () => defFn( 'mat3', [ 'vec3' ], ( z ) => { 7 | assign( z, normalize( z ) ); 8 | const zy = sw( z, 'y' ); 9 | const up = vec3( 0.0, sub( 1.0, sq( zy ) ), abs( zy ) ); 10 | // const up = tern( gt( abs( sw( z, 'y' ) ), 0.999 ), vec3( 0, 0, 1 ), vec3( 0, 1, 0 ) ); 11 | const x = def( 'vec3', normalize( cross( up, z ) ) ); 12 | retFn( mat3( x, cross( z, x ), z ) ); 13 | } ) ); 14 | 15 | return f( z ); 16 | } 17 | -------------------------------------------------------------------------------- /src/shaders/modules/glslGradient.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, assign, def, mix, mul } from '../shaderBuilder'; 2 | import { glslLinearstep } from './glslLinearstep'; 3 | 4 | export const glslGradient = ( 5 | x: GLSLFloatExpression, 6 | points: GLSLExpression<'vec3'>[], 7 | ): GLSLExpression<'vec3'> => { 8 | const result = def( 'vec3' ); 9 | let prevPoint: GLSLExpression<'vec3'> | undefined; 10 | const xt = mul( x, points.length - 1.0 ); 11 | points.map( ( point, i ) => { 12 | if ( prevPoint ) { 13 | assign( result, mix( prevPoint, point, glslLinearstep( i - 1.0, i, xt ) ) ); 14 | prevPoint = result; 15 | } else { 16 | prevPoint = point; 17 | } 18 | } ); 19 | return result; 20 | }; 21 | -------------------------------------------------------------------------------- /src/shaders/modules/equimapUV.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, acos, cache, cos, defFn, mul, retFn, sin, sub, sw, vec3 } from '../shaderBuilder'; 2 | import { TAU } from '../../utils/constants'; 3 | 4 | const symbol = Symbol(); 5 | 6 | export function equimapUV( 7 | uv: GLSLExpression<'vec2'>, 8 | ): GLSLExpression<'vec3'> { 9 | const f = cache( 10 | symbol, 11 | () => defFn( 'vec3', [ 'vec2' ], ( uv ) => { 12 | const phi = mul( TAU, sw( uv, 'x' ) ); 13 | const theta = acos( sub( mul( 2.0, sw( uv, 'y' ) ), 1.0 ) ); 14 | retFn( vec3( 15 | mul( cos( phi ), sin( theta ) ), 16 | cos( theta ), 17 | mul( sin( phi ), sin( theta ) ), 18 | ) ); 19 | } ), 20 | ); 21 | 22 | return f( uv ); 23 | } 24 | -------------------------------------------------------------------------------- /src/shaders/modules/sortVec3Components.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLToken, Swizzle2ComponentsVec3, SwizzleComponentVec3, assign, def, lt, sw, tern } from '../shaderBuilder'; 2 | 3 | export function sortVec3Components( x: GLSLExpression<'vec3'> ): GLSLToken<'vec3'> { 4 | const v = def( 'vec3', x ); 5 | 6 | const compare = ( a: SwizzleComponentVec3, b: SwizzleComponentVec3 ): void => assign( 7 | sw( v, ( a + b ) as Swizzle2ComponentsVec3 ), 8 | tern( 9 | lt( sw( v, a ), sw( v, b ) ), 10 | sw( v, ( a + b ) as Swizzle2ComponentsVec3 ), 11 | sw( v, ( b + a ) as Swizzle2ComponentsVec3 ) 12 | ), 13 | ); 14 | 15 | compare( 'x', 'y' ); 16 | compare( 'x', 'z' ); 17 | compare( 'y', 'z' ); 18 | 19 | return v; 20 | } 21 | -------------------------------------------------------------------------------- /src/gl/glSetTextureFromBitmap.ts: -------------------------------------------------------------------------------- 1 | import { GLTextureFormatStuff, GLTextureFormatStuffRGBA8 } from './glSetTexture'; 2 | import { GL_TEXTURE_2D } from './constants'; 3 | import { gl } from '../globals/canvas'; 4 | 5 | export function glSetTextureFromBitmap( 6 | texture: WebGLTexture, 7 | bitmap: TexImageSource, 8 | formatstuff: GLTextureFormatStuff = GLTextureFormatStuffRGBA8, 9 | ): WebGLTexture { 10 | gl.bindTexture( GL_TEXTURE_2D, texture ); 11 | gl.texImage2D( 12 | GL_TEXTURE_2D, // target 13 | 0, // level 14 | formatstuff[ 0 ], // internalformat 15 | formatstuff[ 1 ], // format 16 | formatstuff[ 2 ], // type 17 | bitmap, // source 18 | ); 19 | gl.bindTexture( GL_TEXTURE_2D, null ); 20 | 21 | return texture; 22 | } 23 | -------------------------------------------------------------------------------- /src/shaders/modules/defDoSomethingUsingSamplerArray.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, arrayIndex, eq, int, ternChain } from '../shaderBuilder'; 2 | 3 | export const defDoSomethingUsingSamplerArray = ( 4 | samplerArray: GLSLExpression<'sampler2D[]'>, 5 | arrayLength: number, 6 | ) => ( 7 | index: GLSLExpression<'int'>, 8 | something: ( sampler: GLSLExpression<'sampler2D'> ) => T, 9 | ): T => ( 10 | ternChain( 11 | something( arrayIndex( samplerArray, int( 0 ) ) ), 12 | ...[ ...new Array( arrayLength ) ].map( 13 | ( _, i ) => [ 14 | eq( index, int( i ) ), 15 | something( arrayIndex( samplerArray, int( i ) ) ), 16 | ] as [ GLSLExpression<'bool'>, T ] 17 | ) 18 | ) 19 | ); 20 | -------------------------------------------------------------------------------- /src/shaders/modules/glslLofi.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, div, floor, mul } from '../shaderBuilder'; 2 | 3 | export function glslLofi( x: GLSLFloatExpression, y: GLSLFloatExpression ): GLSLExpression<'float'>; 4 | export function glslLofi( x: GLSLExpression<'vec2'>, y: GLSLExpression<'vec2'> | GLSLFloatExpression ): GLSLExpression<'vec2'>; 5 | export function glslLofi( x: GLSLExpression<'vec3'>, y: GLSLExpression<'vec3'> | GLSLFloatExpression ): GLSLExpression<'vec3'>; 6 | export function glslLofi( x: GLSLExpression<'vec4'>, y: GLSLExpression<'vec4'> | GLSLFloatExpression ): GLSLExpression<'vec4'>; 7 | export function glslLofi( x: string | number, y: string | number ): string { 8 | return mul( floor( div( x as any, y as any ) ), y as any ); 9 | } 10 | -------------------------------------------------------------------------------- /src/shaders/modules/uniformSphere.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, cache, cos, def, defFn, mul, retFn, sin, sqrt, sub, sw, vec3 } from '../shaderBuilder'; 2 | import { PI } from '../../utils/constants'; 3 | 4 | const symbol = Symbol(); 5 | 6 | export function uniformSphere( xi: GLSLExpression<'vec2'> ): GLSLExpression<'vec3'> { 7 | const f = cache( symbol, () => defFn( 'vec3', [ 'vec2' ], ( xi ) => { 8 | const phi = def( 'float', mul( sw( xi, 'x' ), 2.0 * PI ) ); 9 | const cosTheta = def( 'float', sub( mul( 2.0, sw( xi, 'y' ) ), 1.0 ) ); 10 | const sinTheta = def( 'float', sqrt( sub( 1.0, mul( cosTheta, cosTheta ) ) ) ); 11 | retFn( vec3( mul( sinTheta, cos( phi ) ), mul( sinTheta, sin( phi ) ), cosTheta ) ); 12 | } ) ); 13 | 14 | return f( xi ); 15 | } 16 | -------------------------------------------------------------------------------- /src/utils/vec3AzimuthAltitude.ts: -------------------------------------------------------------------------------- 1 | import { RawVector3 } from '@0b5vr/experimental'; 2 | 3 | /** 4 | * Create a unit vector out of an azimuth and an altitude. 5 | * 6 | * If both values are zero, it returns `[1, 0, 0]` . 7 | * Azimuth represents an angle around Y axis. 8 | * Altitude represents an angle around Z axis. 9 | * It is rotated in intrinsic Y-Z order. 10 | * 11 | * @param azimuth The azimuth 12 | * @param altitude The altitude 13 | * @returns A vector created from the azimuth and the altitude 14 | */ 15 | export function vec3AzimuthAltitude( azimuth: number, altitude: number ): RawVector3 { 16 | return [ 17 | Math.cos( altitude ) * Math.cos( azimuth ), 18 | Math.sin( altitude ), 19 | -Math.cos( altitude ) * Math.sin( azimuth ), 20 | ]; 21 | } 22 | -------------------------------------------------------------------------------- /src/textures/shaders/cellFrag.ts: -------------------------------------------------------------------------------- 1 | import { assign, build, def, defInNamed, defOut, div, insert, main, mul, vec2, vec4 } from '../../shaders/shaderBuilder'; 2 | import { voronoi2d } from '../../shaders/modules/voronoi2d'; 3 | import { voronoi2dBorder } from '../../shaders/modules/voronoi2dBorder'; 4 | 5 | export const cellFrag = build( () => { 6 | insert( 'precision highp float;' ); 7 | 8 | const vUv = defInNamed( 'vec2', 'vUv' ); 9 | 10 | const fragColor = defOut( 'vec4' ); 11 | 12 | main( () => { 13 | const p = def( 'vec2', mul( vUv, 32.0 ) ); 14 | 15 | const voronoi = voronoi2d( p, vec2( 32.0 ) ); 16 | const border = voronoi2dBorder( voronoi, p, vec2( 32.0 ) ); 17 | 18 | assign( fragColor, vec4( div( mul( border ), 32.0 ), 1.0 ) ); 19 | } ); 20 | } ); 21 | -------------------------------------------------------------------------------- /src/shaders/modules/sdbox.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, abs, add, cache, def, defFn, length, max, min, retFn, sub, sw } from '../shaderBuilder'; 2 | 3 | const symbol = Symbol(); 4 | 5 | // Ref: https://www.iquilezles.org/www/articles/normalsSDF/normalsSDF.htm 6 | export function sdbox( 7 | p: GLSLExpression<'vec3'>, 8 | s: GLSLExpression<'vec3'>, 9 | ): GLSLExpression<'float'> { 10 | const f = cache( symbol, () => defFn( 'float', [ 'vec3', 'vec3' ], ( p, s ) => { 11 | const d = def( 'vec3', sub( abs( p ), s ) ); 12 | const inside = min( 13 | max( sw( d, 'x' ), max( sw( d, 'y' ), sw( d, 'z' ) ) ), 14 | 0.0, 15 | ); 16 | const outside = length( max( d, 0.0 ) ); 17 | retFn( add( inside, outside ) ); 18 | } ) ); 19 | 20 | return f( p, s ); 21 | } 22 | -------------------------------------------------------------------------------- /src/shaders/modules/setupRoRd.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLToken, def, defFn, defUniformNamed, div, mul, normalize, retFn, sub, sw, vec4 } from '../shaderBuilder'; 2 | 3 | export function setupRoRd( p: GLSLExpression<'vec2'> ): [ 4 | ro: GLSLToken<'vec3'>, 5 | rd: GLSLToken<'vec3'>, 6 | ] { 7 | const inversePVM = defUniformNamed( 'mat4', 'inversePVM' ); 8 | 9 | const divideByW = defFn( 'vec3', [ 'vec4' ], ( v ) => { 10 | retFn( div( sw( v, 'xyz' ), sw( v, 'w' ) ) ); 11 | } ); 12 | 13 | const ro = def( 'vec3', divideByW( mul( inversePVM, vec4( p, 0.0, 1.0 ) ) ) ); 14 | const farPos = def( 'vec3', divideByW( mul( inversePVM, vec4( p, 1.0, 1.0 ) ) ) ); 15 | 16 | return [ 17 | ro, 18 | def( 'vec3', normalize( sub( farPos, ro ) ) ), // rd 19 | ]; 20 | } 21 | -------------------------------------------------------------------------------- /src/textures/cellTextureTarget.ts: -------------------------------------------------------------------------------- 1 | import { ShaderRenderTarget } from '../nodes/utils/ShaderRenderTarget'; 2 | import { cellFrag } from './shaders/cellFrag'; 3 | import { quadVert } from '../shaders/common/quadVert'; 4 | 5 | /** 6 | * sex 7 | */ 8 | export const cellTextureTarget = new ShaderRenderTarget( 9 | 2048, 10 | 2048, 11 | cellFrag, 12 | ); 13 | 14 | if ( import.meta.env.DEV ) { 15 | cellTextureTarget.name = 'cell'; 16 | } 17 | 18 | if ( import.meta.hot ) { 19 | import.meta.hot.accept( 20 | './shaders/cellFrag', 21 | ( { cellFrag } ) => { 22 | cellTextureTarget.material.replaceShader( 23 | quadVert, 24 | cellFrag, 25 | ).then( () => { 26 | cellTextureTarget.quad.drawImmediate(); 27 | } ); 28 | }, 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /src/shaders/modules/glslLofir.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, add, div, floor, mul } from '../shaderBuilder'; 2 | 3 | export function glslLofir( x: GLSLFloatExpression, y: GLSLFloatExpression ): GLSLExpression<'float'>; 4 | export function glslLofir( x: GLSLExpression<'vec2'>, y: GLSLExpression<'vec2'> | GLSLFloatExpression ): GLSLExpression<'vec2'>; 5 | export function glslLofir( x: GLSLExpression<'vec3'>, y: GLSLExpression<'vec3'> | GLSLFloatExpression ): GLSLExpression<'vec3'>; 6 | export function glslLofir( x: GLSLExpression<'vec4'>, y: GLSLExpression<'vec4'> | GLSLFloatExpression ): GLSLExpression<'vec4'>; 7 | export function glslLofir( x: string | number, y: string | number ): string { 8 | return mul( floor( add( div( x as any, y as any ), 0.5 ) ), y as any ); 9 | } 10 | -------------------------------------------------------------------------------- /src/heck/CanvasRenderTarget.ts: -------------------------------------------------------------------------------- 1 | import { GL_BACK, GL_FRAMEBUFFER } from '../gl/constants'; 2 | import { RenderTarget } from './RenderTarget'; 3 | import { canvas, gl } from '../globals/canvas'; 4 | 5 | export interface CanvasRenderTargetOptions { 6 | viewport?: [ number, number, number, number ]; 7 | } 8 | 9 | export class CanvasRenderTarget extends RenderTarget { 10 | public viewport: [ number, number, number, number ]; 11 | 12 | public constructor( options?: CanvasRenderTargetOptions ) { 13 | super(); 14 | 15 | this.viewport = options?.viewport ?? [ 0, 0, canvas.width, canvas.height ]; 16 | } 17 | 18 | public bind(): void { 19 | gl.bindFramebuffer( GL_FRAMEBUFFER, null ); 20 | gl.drawBuffers( [ GL_BACK ] ); 21 | gl.viewport( ...this.viewport ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/shaders/modules/smax.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, abs, add, def, div, max, mul, sub } from '../shaderBuilder'; 2 | 3 | export const smax: { 4 | ( a: GLSLFloatExpression, b: GLSLFloatExpression, k: GLSLFloatExpression ): GLSLExpression<'float'>; 5 | ( a: GLSLExpression<'vec2'>, b: GLSLExpression<'vec2'>, k: GLSLFloatExpression ): GLSLExpression<'vec2'>; 6 | ( a: GLSLExpression<'vec3'>, b: GLSLExpression<'vec3'>, k: GLSLFloatExpression ): GLSLExpression<'vec3'>; 7 | ( a: GLSLExpression<'vec4'>, b: GLSLExpression<'vec4'>, k: GLSLFloatExpression ): GLSLExpression<'vec4'>; 8 | } = ( a: any, b: any, k: any ): any => { 9 | const h = def( 'float', div( max( sub( k, abs( sub( a, b ) ) ), 0.0 ), k ) ); 10 | return add( max( a, b ), mul( h, h, h, k, 1.0 / 6.0 ) ); 11 | }; 12 | -------------------------------------------------------------------------------- /src/shaders/modules/smin.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, abs, def, div, max, min, mul, sub } from '../shaderBuilder'; 2 | 3 | export const smin: { 4 | ( a: GLSLFloatExpression, b: GLSLFloatExpression, k: GLSLFloatExpression ): GLSLExpression<'float'>; 5 | ( a: GLSLExpression<'vec2'>, b: GLSLExpression<'vec2'>, k: GLSLFloatExpression ): GLSLExpression<'vec2'>; 6 | ( a: GLSLExpression<'vec3'>, b: GLSLExpression<'vec3'>, k: GLSLFloatExpression ): GLSLExpression<'vec3'>; 7 | ( a: GLSLExpression<'vec4'>, b: GLSLExpression<'vec4'>, k: GLSLFloatExpression ): GLSLExpression<'vec4'>; 8 | } = ( a: any, b: any, k: any ): any => { 9 | const h = def( 'float', div( max( sub( k, abs( sub( a, b ) ) ), 0.0 ), k ) ); 10 | return sub( min( a, b ), mul( h, h, h, k, 1.0 / 6.0 ) ); 11 | }; 12 | -------------------------------------------------------------------------------- /src/shaders/modules/triplanarMapping.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, abs, add, div, dot, mul, pow, sw, vec3 } from '../shaderBuilder'; 2 | 3 | export function triplanarMapping | GLSLExpression<'vec2'> | GLSLExpression<'vec3'> | GLSLExpression<'vec4'>>( 4 | p: GLSLExpression<'vec3'>, 5 | N: GLSLExpression<'vec3'>, 6 | smoothFactor: GLSLFloatExpression, 7 | fn: ( uv: GLSLExpression<'vec2'> ) => T, 8 | ): T { 9 | const nPowered = pow( abs( N ), vec3( smoothFactor ) ); 10 | 11 | return div( add( 12 | mul( fn( sw( p, 'zy' ) ) as any, sw( nPowered, 'x' ) ), 13 | mul( fn( sw( p, 'xz' ) ) as any, sw( nPowered, 'y' ) ), 14 | mul( fn( sw( p, 'yx' ) ) as any, sw( nPowered, 'z' ) ), 15 | ), dot( nPowered, vec3( 1.0 ) ) ) as any; 16 | } 17 | -------------------------------------------------------------------------------- /src/webgl-memory.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'webgl-memory' { 2 | // nothing here 3 | } 4 | 5 | declare interface GMAN_webgl_memory { 6 | getMemoryInfo(): { 7 | memory: { 8 | buffer: number; 9 | texture: number; 10 | renderbuffer: number; 11 | drawingbuffer: number; 12 | total: number; 13 | }; 14 | resources: { 15 | buffer: number; 16 | renderbuffer: number; 17 | program: number; 18 | query: number; 19 | sampler: number; 20 | shader: number; 21 | sync: number; 22 | texture: number; 23 | transformFeedback: number; 24 | vertexArray: number; 25 | }; 26 | }; 27 | } 28 | 29 | declare interface WebGLRenderingContextBase { 30 | getExtension( extensionName: 'GMAN_webgl_memory' ): GMAN_webgl_memory | null; 31 | } 32 | -------------------------------------------------------------------------------- /src/shaders/modules/upsampleTap9.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, vec2 } from '../shaderBuilder'; 2 | 3 | const WEIGHT_1 = 1.0 / 16.0; 4 | const WEIGHT_2 = 2.0 / 16.0; 5 | const WEIGHT_4 = 4.0 / 16.0; 6 | 7 | /** 8 | * Ref: http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare 9 | */ 10 | export function upsampleTap9( 11 | fn: ( weight: number, offset: GLSLExpression<'vec2'> ) => void 12 | ): void { 13 | fn( WEIGHT_1, vec2( -1.0, -1.0 ) ); 14 | fn( WEIGHT_2, vec2( 0.0, -1.0 ) ); 15 | fn( WEIGHT_1, vec2( 1.0, -1.0 ) ); 16 | fn( WEIGHT_2, vec2( -1.0, 0.0 ) ); 17 | fn( WEIGHT_4, vec2( 0.0, 0.0 ) ); 18 | fn( WEIGHT_2, vec2( 1.0, 0.0 ) ); 19 | fn( WEIGHT_1, vec2( -1.0, 1.0 ) ); 20 | fn( WEIGHT_2, vec2( 0.0, 1.0 ) ); 21 | fn( WEIGHT_1, vec2( 1.0, 1.0 ) ); 22 | } 23 | -------------------------------------------------------------------------------- /src/shaders/modules/calcShadowDepth.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, def, defUniformNamed, sq, sw, vec4 } from '../shaderBuilder'; 2 | import { glslLinearstep } from './glslLinearstep'; 3 | 4 | /** 5 | * Returns `linearstep( near, far, depth )`, and its square. 6 | * Intended to be used for depth buffer. 7 | * 8 | * @param projPos Give me a `vProjPosition` 9 | * @returns `vec4( depth, depth * depth, 0.0, 0.0 )` 10 | */ 11 | export function calcShadowDepth( projPos: GLSLExpression<'vec4'> ): GLSLExpression<'vec4'> { 12 | const cameraNearFar = defUniformNamed( 'vec2', 'cameraNearFar' ); 13 | 14 | const depth = def( 'float', glslLinearstep( 15 | sw( cameraNearFar, 'x' ), 16 | sw( cameraNearFar, 'y' ), 17 | sw( projPos, 'w' ), 18 | ) as GLSLExpression<'float'> ); 19 | return vec4( depth, sq( depth ), 0.0, 0.0 ); 20 | } 21 | -------------------------------------------------------------------------------- /src/shaders/modules/cubemapUVMip.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, add, assign, cache, def, defFn, div, min, mul, pow, retFn, sub, vec2 } from '../shaderBuilder'; 2 | import { cubemapUV } from './cubemapUV'; 3 | 4 | const symbol = Symbol(); 5 | 6 | export function cubemapUVMip( 7 | v: GLSLExpression<'vec3'>, 8 | lv: GLSLExpression<'float'>, 9 | ): GLSLExpression<'vec2'> { 10 | const f = cache( symbol, () => defFn( 'vec2', [ 'vec3', 'float' ], ( v, lv ) => { 11 | const p = def( 'float', pow( 0.5, lv ) ); 12 | const scale = sub( 1.0, div( 1.0 / 256.0, p ) ); 13 | 14 | const offset = def( 'vec2', vec2( 0.0, sub( 1.0, mul( 2.0, p ) ) ) ); 15 | 16 | assign( p, pow( 0.5, min( lv, 5.0 ) ) ); // max level is 5 17 | retFn( add( mul( cubemapUV( v, scale ), p ), offset ) ); 18 | } ) ); 19 | 20 | return f( v, lv ); 21 | } 22 | -------------------------------------------------------------------------------- /src/nodes/SpongeScene/Sponge/Sponge.ts: -------------------------------------------------------------------------------- 1 | import { RaymarcherNode } from '../../utils/RaymarcherNode'; 2 | import { genCube } from '../../../geometries/genCube'; 3 | import { objectVert } from '../../../shaders/common/objectVert'; 4 | import { spongeFrag } from './shaders/spongeFrag'; 5 | 6 | export class Sponge extends RaymarcherNode { 7 | public constructor() { 8 | const geometry = genCube(); 9 | 10 | super( spongeFrag, { geometry } ); 11 | 12 | if ( import.meta.hot ) { 13 | import.meta.hot.accept( 14 | './shaders/spongeFrag', 15 | ( { spongeFrag } ) => { 16 | const { deferred, depth } = this.materials; 17 | 18 | deferred.replaceShader( objectVert, spongeFrag( 'deferred' ) ); 19 | depth.replaceShader( objectVert, spongeFrag( 'depth' ) ); 20 | }, 21 | ); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/textures/perlinFBMTextureTarget.ts: -------------------------------------------------------------------------------- 1 | import { ShaderRenderTarget } from '../nodes/utils/ShaderRenderTarget'; 2 | import { perlinFBMFrag } from './shaders/perlinFBMFrag'; 3 | import { quadVert } from '../shaders/common/quadVert'; 4 | 5 | /** 6 | * the classic fbm 7 | */ 8 | export const perlinFBMTextureTarget = new ShaderRenderTarget( 9 | 2048, 10 | 2048, 11 | perlinFBMFrag, 12 | ); 13 | 14 | if ( import.meta.env.DEV ) { 15 | perlinFBMTextureTarget.name = 'perlinFBM'; 16 | } 17 | 18 | if ( import.meta.hot ) { 19 | import.meta.hot.accept( 20 | './shaders/perlinFBMFrag', 21 | ( { perlinFBMFrag } ) => { 22 | perlinFBMTextureTarget.material.replaceShader( 23 | quadVert, 24 | perlinFBMFrag, 25 | ).then( () => { 26 | perlinFBMTextureTarget.quad.drawImmediate(); 27 | } ); 28 | }, 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /src/nodes/CameraStack/mainCameraStackResources.ts: -------------------------------------------------------------------------------- 1 | import { createCameraStackResources, resizeCameraStackResources } from './CameraStackResources'; 2 | import { resizeObservers } from '../../globals/globalObservers'; 3 | 4 | export const mainCameraStackResources = createCameraStackResources( true, true, true ); 5 | 6 | if ( import.meta.env.DEV ) { 7 | mainCameraStackResources[ 1 ]!.name = 'aoTarget'; 8 | mainCameraStackResources[ 2 ]!.i.name = 'aoDenoiserSwap0'; 9 | mainCameraStackResources[ 2 ]!.o.name = 'aoDenoiserSwap1'; 10 | mainCameraStackResources[ 3 ]!.name = 'shadeTarget'; 11 | mainCameraStackResources[ 4 ]!.i.name = 'denoiserSwap0'; 12 | mainCameraStackResources[ 4 ]!.o.name = 'denoiserSwap1'; 13 | } 14 | 15 | resizeObservers.push( ( [ width, height ] ) => ( 16 | resizeCameraStackResources( mainCameraStackResources, width, height ) 17 | ) ); 18 | -------------------------------------------------------------------------------- /src/gl/GLBlendFactor.ts: -------------------------------------------------------------------------------- 1 | import { GL_CONSTANT_ALPHA, GL_CONSTANT_COLOR, GL_DST_ALPHA, GL_DST_COLOR, GL_ONE, GL_ONE_MINUS_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_COLOR, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_SRC_ALPHA_SATURATE, GL_SRC_COLOR, GL_ZERO } from './constants'; 2 | 3 | export type GLBlendFactor = 4 | | typeof GL_ZERO 5 | | typeof GL_ONE 6 | | typeof GL_SRC_COLOR 7 | | typeof GL_ONE_MINUS_SRC_COLOR 8 | | typeof GL_DST_COLOR 9 | | typeof GL_ONE_MINUS_DST_COLOR 10 | | typeof GL_SRC_ALPHA 11 | | typeof GL_ONE_MINUS_SRC_ALPHA 12 | | typeof GL_DST_ALPHA 13 | | typeof GL_ONE_MINUS_DST_ALPHA 14 | | typeof GL_CONSTANT_COLOR 15 | | typeof GL_ONE_MINUS_CONSTANT_COLOR 16 | | typeof GL_CONSTANT_ALPHA 17 | | typeof GL_ONE_MINUS_CONSTANT_ALPHA 18 | | typeof GL_SRC_ALPHA_SATURATE; 19 | -------------------------------------------------------------------------------- /terserMinifyOptions.ts: -------------------------------------------------------------------------------- 1 | import { MinifyOptions } from 'terser'; 2 | import { domprops } from './domprops'; 3 | 4 | export const terserMinifyOptions: MinifyOptions = { 5 | compress: { 6 | arguments: true, 7 | booleans_as_integers: true, 8 | drop_console: true, 9 | keep_fargs: false, 10 | passes: 2, 11 | unsafe_arrows: true, 12 | unsafe_math: true, 13 | unsafe_symbols: true, 14 | }, 15 | mangle: { 16 | properties: { 17 | builtins: true, 18 | regex: /.+/, 19 | keep_quoted: true, 20 | reserved: [ 21 | // material tags 22 | 'forward', 23 | 'deferred', 24 | 'depth', 25 | 26 | // dom props 27 | ...domprops, 28 | ], 29 | }, 30 | }, 31 | format: { 32 | ascii_only: true, 33 | comments: false, 34 | }, 35 | module: true, 36 | toplevel: true, 37 | }; 38 | -------------------------------------------------------------------------------- /src/shaders/modules/dCharlie.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, add, cache, def, defFn, div, max, mul, num, pow, retFn, sq, sub } from '../shaderBuilder'; 2 | import { INV_TAU } from '../../utils/constants'; 3 | 4 | const symbol = Symbol(); 5 | 6 | export function dCharlie( 7 | dotNH: GLSLFloatExpression, 8 | roughnessSq: GLSLFloatExpression, 9 | ): GLSLExpression<'float'> { 10 | const f = cache( 11 | symbol, 12 | () => defFn( 'float', [ 'float', 'float' ], ( dotNH, roughnessSq ) => { 13 | const invRoughnessSq = def( 'float', div( 1.0, roughnessSq ) ); 14 | const sin2h = max( sub( 1.0, sq( dotNH ) ), 0.078125 ); 15 | retFn( mul( 16 | add( 2.0, invRoughnessSq ), 17 | pow( sin2h, mul( 0.5, invRoughnessSq ) ), 18 | INV_TAU, 19 | ) ); 20 | } ) 21 | ); 22 | 23 | return f( num( dotNH ), num( roughnessSq ) ); 24 | } 25 | -------------------------------------------------------------------------------- /src/utils/constants.ts: -------------------------------------------------------------------------------- 1 | import { sub, vec3 } from '../shaders/shaderBuilder'; 2 | 3 | export const PI = Math.acos( -1.0 ); 4 | export const INV_PI = 1.0 / PI; 5 | export const HALF_PI = PI / 2.0; 6 | export const QUARTER_PI = PI / 4.0; 7 | export const TAU = 2.0 * PI; 8 | export const INV_TAU = 1.0 / TAU; 9 | export const GOLDEN_ANGLE = 2.3999632; 10 | export const HALF_SQRT_TWO = Math.sqrt( 2.0 ) / 2.0; 11 | export const SQRT3 = Math.sqrt( 3.0 ); 12 | export const HALF_SQRT3 = 0.5 * SQRT3; 13 | export const REC_SQRT3 = 1.0 / SQRT3; 14 | export const DIELECTRIC_SPECULAR = vec3( 0.04 ); 15 | export const ONE_SUB_DIELECTRIC_SPECULAR = sub( 1.0, DIELECTRIC_SPECULAR ); 16 | export const ONE_POINT_FIVE_POW_I = [ ...new Array( 64 ) ].map( ( _, i ) => Math.pow( 0.5, i ) ); 17 | export const ONE_SUB_ONE_POINT_FIVE_POW_I = [ ...new Array( 64 ) ].map( 18 | ( _, i ) => 1.0 - Math.pow( 0.5, i ) 19 | ); 20 | -------------------------------------------------------------------------------- /src/nodes/Mixer/shaders/mixerFrag.ts: -------------------------------------------------------------------------------- 1 | import { addAssign, assign, build, def, defInNamed, defOut, defUniformNamed, insert, main, mix, mul, texture } from '../../../shaders/shaderBuilder'; 2 | 3 | export const mixerFrag = build( () => { 4 | insert( 'precision highp float;' ); 5 | 6 | const vUv = defInNamed( 'vec2', 'vUv' ); 7 | const fragColor = defOut( 'vec4' ); 8 | 9 | const sampler0 = defUniformNamed( 'sampler2D', 'sampler0' ); 10 | const sampler1 = defUniformNamed( 'sampler2D', 'sampler1' ); 11 | const blendAdd = defUniformNamed( 'float', 'blendAdd' ); 12 | const blendMix = defUniformNamed( 'float', 'blendMix' ); 13 | 14 | main( () => { 15 | const a = def( 'vec4', texture( sampler0, vUv ) ); 16 | const b = def( 'vec4', texture( sampler1, vUv ) ); 17 | 18 | assign( fragColor, mix( a, b, blendMix ) ); 19 | addAssign( fragColor, mul( b, blendAdd ) ); 20 | } ); 21 | } ); 22 | -------------------------------------------------------------------------------- /src/shaders/modules/foldSortXYZ.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, assign, cache, defFn, lt, retFn, sw, tern } from '../shaderBuilder'; 2 | 3 | const symbol = Symbol(); 4 | 5 | export function foldSortXYZ( 6 | v: GLSLExpression<'vec3'>, 7 | ): GLSLExpression<'vec3'> { 8 | const f = cache( 9 | symbol, 10 | () => defFn( 'vec3', [ 'vec3' ], ( v ) => { 11 | assign( sw( v, 'xz' ), tern( 12 | lt( sw( v, 'x' ), sw( v, 'z' ) ), 13 | sw( v, 'xz' ), 14 | sw( v, 'zx' ), 15 | ) ); 16 | assign( sw( v, 'xy' ), tern( 17 | lt( sw( v, 'x' ), sw( v, 'y' ) ), 18 | sw( v, 'xy' ), 19 | sw( v, 'yx' ), 20 | ) ); 21 | assign( sw( v, 'yz' ), tern( 22 | lt( sw( v, 'y' ), sw( v, 'z' ) ), 23 | sw( v, 'yz' ), 24 | sw( v, 'zy' ), 25 | ) ); 26 | 27 | retFn( v ); 28 | } ), 29 | ); 30 | 31 | return f( v ); 32 | } 33 | -------------------------------------------------------------------------------- /src/shaders/modules/sampleLambert.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, cache, cos, def, defFn, mul, retFn, sin, sqrt, sub, vec3 } from '../shaderBuilder'; 2 | import { TAU } from '../../utils/constants'; 3 | import { glslDefRandom } from './glslDefRandom'; 4 | import { orthBas } from './orthBas'; 5 | 6 | const symbol = Symbol(); 7 | 8 | export function sampleLambert( n: GLSLExpression<'vec3'> ): GLSLExpression<'vec3'> { 9 | const { random } = glslDefRandom(); 10 | 11 | const f = cache( symbol, () => defFn( 'vec3', [ 'vec3' ], ( n ) => { 12 | const phi = def( 'float', mul( random(), TAU ) ); 13 | const cosTheta = def( 'float', sqrt( random() ) ); 14 | const sinTheta = def( 'float', sub( 1.0, mul( cosTheta, cosTheta ) ) ); 15 | retFn( mul( 16 | orthBas( n ), 17 | vec3( mul( sinTheta, cos( phi ) ), mul( sinTheta, sin( phi ) ), cosTheta ), 18 | ) ); 19 | } ) ); 20 | 21 | return f( n ); 22 | } 23 | -------------------------------------------------------------------------------- /src/shaders/modules/sdsellipse2.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, abs, add, cache, defFn, div, num, pow, retFn, sw } from '../shaderBuilder'; 2 | 3 | /*! 4 | * The superellipse SDF is taken from iq's shadertoy 5 | * (c) 2022 Inigo Quilez, MIT License 6 | * 7 | * https://www.shadertoy.com/view/7stcR4 8 | */ 9 | 10 | const symbol = Symbol(); 11 | 12 | /** 13 | * Return an sdf of superellipse. 14 | * You may want to subtract a "radius" from the result. 15 | */ 16 | export function sdsellipse2( 17 | p: GLSLExpression<'vec2'>, 18 | n: GLSLFloatExpression, 19 | ): GLSLExpression<'float'> { 20 | const f = cache( symbol, () => defFn( 'float', [ 'vec2', 'float' ], ( p, n ) => { 21 | retFn( pow( 22 | add( 23 | pow( abs( sw( p, 'x' ) ), n ), 24 | pow( abs( sw( p, 'y' ) ), n ), 25 | ), 26 | div( 1.0, n ), 27 | ) ); 28 | } ) ); 29 | 30 | return f( p, num( n ) ); 31 | } 32 | -------------------------------------------------------------------------------- /src/nodes/MoonScene/shaders/moonTexModFrag.ts: -------------------------------------------------------------------------------- 1 | import { addAssign, assign, build, def, defInNamed, defOut, defUniformNamed, insert, main, mul, pow, sin, subAssign, sw, texture } from '../../../shaders/shaderBuilder'; 2 | 3 | export const moonTexModFrag = build( () => { 4 | insert( 'precision highp float;' ); 5 | 6 | const vUv = defInNamed( 'vec2', 'vUv' ); 7 | 8 | const fragColor = defOut( 'vec4' ); 9 | 10 | const sampler0 = defUniformNamed( 'sampler2D', 'sampler0' ); 11 | 12 | main( () => { 13 | const height = sw( fragColor, 'x' ); 14 | 15 | const tex = def( 'vec4', texture( sampler0, vUv ) ); 16 | 17 | addAssign( height, mul( 0.6, pow( sin( mul( 3.0, sw( tex, 'x' ) ) ), 20.0 ) ) ); 18 | addAssign( height, mul( 0.3, pow( sin( mul( 2.4, sw( tex, 'y' ) ) ), 10.0 ) ) ); 19 | subAssign( height, mul( 0.1, sw( tex, 'z' ) ) ); 20 | 21 | assign( sw( fragColor, 'z' ), sw( tex, 'z' ) ); 22 | } ); 23 | } ); 24 | -------------------------------------------------------------------------------- /src/globals/audioAnalyzer.ts: -------------------------------------------------------------------------------- 1 | import { audio } from './audio'; 2 | import { audioAnalyzerObservers } from './globalObservers'; 3 | import { notifyObservers } from '@0b5vr/experimental'; 4 | 5 | export const audioAnalyzerSplitter = audio.createChannelSplitter( 2 ); 6 | 7 | const audioAnalyzerL = audio.createAnalyser(); 8 | const audioAnalyzerR = audio.createAnalyser(); 9 | 10 | audioAnalyzerL.fftSize = 4096; 11 | audioAnalyzerR.fftSize = 4096; 12 | 13 | audioAnalyzerSplitter.connect( audioAnalyzerL, 0 ); 14 | audioAnalyzerSplitter.connect( audioAnalyzerR, 1 ); 15 | 16 | export const audioAnalyzerTimeDomainL = new Float32Array( 1024 ); 17 | export const audioAnalyzerTimeDomainR = new Float32Array( 1024 ); 18 | 19 | export function updateAudioAnalyzer(): void { 20 | audioAnalyzerL.getFloatTimeDomainData( audioAnalyzerTimeDomainL ); 21 | audioAnalyzerR.getFloatTimeDomainData( audioAnalyzerTimeDomainR ); 22 | notifyObservers( audioAnalyzerObservers ); 23 | } 24 | -------------------------------------------------------------------------------- /src/nodes/IBLLUTCalc/IBLLUTCalc.ts: -------------------------------------------------------------------------------- 1 | import { Accumulator } from '../common/Accumulator'; 2 | import { IBLLUT_ITER, IBLLUT_SIZE } from '../../config'; 3 | import { Lambda } from '../../heck/components/Lambda'; 4 | import { iblLutFrag } from './shaders/iblLutFrag'; 5 | import { vdc } from '../../utils/vdc'; 6 | 7 | export class IBLLUTCalc extends Accumulator { 8 | public constructor() { 9 | super( { 10 | width: IBLLUT_SIZE, 11 | height: IBLLUT_SIZE, 12 | frag: iblLutFrag, 13 | iter: IBLLUT_ITER, 14 | } ); 15 | 16 | // -- vdc setter ------------------------------------------------------------------------------- 17 | const vdcSetter = new Lambda( { 18 | onUpdate: () => { 19 | this.material.addUniform( 'vdc', '1f', vdc( this.samples, 2.0 ) ); 20 | }, 21 | } ); 22 | 23 | if ( import.meta.env.DEV ) { 24 | vdcSetter.name = 'vdcSetter'; 25 | } 26 | 27 | this.children.unshift( vdcSetter ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/shaders/modules/isectInBox.ts: -------------------------------------------------------------------------------- 1 | import { FAR } from '../../config'; 2 | import { GLSLExpression, abs, add, cache, def, defFn, div, ifThen, lt, min, mul, neg, retFn, sign, step, sw, vec3, vec4 } from '../shaderBuilder'; 3 | 4 | const symbol = Symbol(); 5 | 6 | export function isectInBox( 7 | ro: GLSLExpression<'vec3'>, 8 | rd: GLSLExpression<'vec3'>, 9 | s: GLSLExpression<'vec3'>, 10 | ): GLSLExpression<'vec4'> { 11 | const f = cache( symbol, () => defFn( 'vec4', [ 'vec3', 'vec3', 'vec3' ], ( ro, rd, s ) => { 12 | const src = neg( div( ro, rd ) ); 13 | const dst = abs( div( s, rd ) ); 14 | const b = def( 'vec3', add( src, dst ) ); 15 | const bl = min( sw( b, 'x' ), min( sw( b, 'y' ), sw( b, 'z' ) ) ); 16 | ifThen( lt( bl, 0.0 ), () => retFn( vec4( FAR ) ) ); 17 | const n = mul( 18 | -1.0, 19 | sign( rd ), 20 | step( b, vec3( bl ) ), 21 | ); 22 | retFn( vec4( n, bl ) ); 23 | } ) ); 24 | 25 | return f( ro, rd, s ); 26 | } 27 | -------------------------------------------------------------------------------- /vite-plugins/vite-automaton-minifier-plugin.ts: -------------------------------------------------------------------------------- 1 | import { AutomatonWithGUI, MinimizeOptions } from '@0b5vr/automaton-with-gui'; 2 | import { Plugin } from 'vite'; 3 | 4 | const fileRegex = /automaton\.json$/; 5 | 6 | export interface AutomatonMinifierPluginOptions { 7 | minify: boolean; 8 | minimizeOptions: MinimizeOptions; 9 | } 10 | 11 | export const automatonMinifierPlugin: ( 12 | options: AutomatonMinifierPluginOptions 13 | ) => Plugin = ( { minify, minimizeOptions } ) => { 14 | return { 15 | name: 'automaton-minifier', 16 | enforce: 'pre', 17 | transform( src: string, id: string ) { 18 | if ( !minify ) { 19 | return null; 20 | } 21 | 22 | if ( fileRegex.test( id ) ) { 23 | const data = JSON.parse( src ); 24 | const minified = AutomatonWithGUI.minimizeData( data, minimizeOptions ); 25 | 26 | return { 27 | code: JSON.stringify( minified ), 28 | }; 29 | } 30 | } 31 | }; 32 | }; 33 | -------------------------------------------------------------------------------- /src/shaders/modules/downsampleTap13.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, vec2 } from '../shaderBuilder'; 2 | 3 | const WEIGHT_1 = 1.0 / 16.0; 4 | const WEIGHT_2 = 2.0 / 16.0; 5 | const WEIGHT_4 = 4.0 / 16.0; 6 | 7 | /** 8 | * Ref: http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare 9 | */ 10 | export function downsampleTap13( 11 | fn: ( weight: number, offset: GLSLExpression<'vec2'> ) => void 12 | ): void { 13 | fn( WEIGHT_1, vec2( -1.0, -1.0 ) ); 14 | fn( WEIGHT_2, vec2( 0.0, -1.0 ) ); 15 | fn( WEIGHT_1, vec2( 1.0, -1.0 ) ); 16 | fn( WEIGHT_4, vec2( -0.5, -0.5 ) ); 17 | fn( WEIGHT_4, vec2( 0.5, -0.5 ) ); 18 | fn( WEIGHT_2, vec2( -1.0, 0.0 ) ); 19 | fn( WEIGHT_4, vec2( 0.0, 0.0 ) ); 20 | fn( WEIGHT_2, vec2( 1.0, 0.0 ) ); 21 | fn( WEIGHT_4, vec2( -0.5, 0.5 ) ); 22 | fn( WEIGHT_4, vec2( 0.5, 0.5 ) ); 23 | fn( WEIGHT_1, vec2( -1.0, 1.0 ) ); 24 | fn( WEIGHT_2, vec2( 0.0, 1.0 ) ); 25 | fn( WEIGHT_1, vec2( 1.0, 1.0 ) ); 26 | } 27 | -------------------------------------------------------------------------------- /src/shaders/modules/calcNormal.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, GLSLToken, Swizzle3ComponentsVec2, add, def, normalize, sub, sw, vec2, vec3 } from '../shaderBuilder'; 2 | 3 | // Ref: https://www.iquilezles.org/www/articles/normalsSDF/normalsSDF.htm 4 | export function calcNormal( { 5 | rp, 6 | map, 7 | delta, 8 | }: { 9 | rp: GLSLExpression<'vec3'>, 10 | map: ( p: GLSLExpression<'vec3'> ) => GLSLExpression<'vec4'>, 11 | delta?: GLSLFloatExpression, 12 | } ): GLSLToken<'vec3'> { 13 | const d = vec2( 0.0, delta ?? 1E-4 ); 14 | 15 | return def( 'vec3', normalize( vec3( 16 | ...( [ 17 | 'yxx', 18 | 'xyx', 19 | 'xxy', 20 | ] as Swizzle3ComponentsVec2[] ).map( 21 | ( s: Swizzle3ComponentsVec2 ): GLSLExpression<'float'> => sw( sub( 22 | map( add( rp, sw( d, s ) ) ), 23 | map( sub( rp, sw( d, s ) ) ), 24 | ), 'x' ) 25 | ) as [ GLSLExpression<'float'>, GLSLExpression<'float'>, GLSLExpression<'float'> ] 26 | ) ) ); 27 | } 28 | -------------------------------------------------------------------------------- /src/shaders/modules/normalTransform.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, arrayIndex, def, div, dot, int, mat3, mul, normalize, vec3 } from '../shaderBuilder'; 2 | 3 | /** 4 | * Transform a normal using a model matrix (without shearing). 5 | * No "normal matrix" required. 6 | * 7 | * Ref: https://github.com/mrdoob/three.js/issues/18497#issuecomment-583771048 8 | * 9 | * @param matrix The model matrix 10 | * @param normal The normal you want to transform 11 | * @returns The transformed normal 12 | */ 13 | export function normalTransform( 14 | matrix: GLSLExpression<'mat4'>, 15 | normal: GLSLExpression<'vec3'>, 16 | ): GLSLExpression<'vec3'> { 17 | const m = def( 'mat3', mat3( matrix ) ); 18 | 19 | const s2 = vec3( 20 | dot( arrayIndex( m, int( 0 ) ), arrayIndex( m, int( 0 ) ) ), 21 | dot( arrayIndex( m, int( 1 ) ), arrayIndex( m, int( 1 ) ) ), 22 | dot( arrayIndex( m, int( 2 ) ), arrayIndex( m, int( 2 ) ) ), 23 | ); 24 | 25 | return normalize( mul( m, div( normal, s2 ) ) ); 26 | } 27 | -------------------------------------------------------------------------------- /src/shaders/common/deferredUvFrag.ts: -------------------------------------------------------------------------------- 1 | import { assign, build, defInNamed, defOut, div, insert, main, sw, vec4 } from '../shaderBuilder'; 2 | 3 | export const deferredUvFrag = build( () => { 4 | insert( 'precision highp float;' ); 5 | 6 | const vPosition = defInNamed( 'vec4', 'vPosition' ); 7 | const vProjPosition = defInNamed( 'vec4', 'vProjPosition' ); 8 | const vNormal = defInNamed( 'vec3', 'vNormal' ); 9 | const vUv = defInNamed( 'vec2', 'vUv' ); 10 | 11 | const fragColor = defOut( 'vec4' ); 12 | const fragPosition = defOut( 'vec4', 1 ); 13 | const fragNormal = defOut( 'vec4', 2 ); 14 | const fragMisc = defOut( 'vec4', 3 ); 15 | 16 | main( () => { 17 | const depth = div( sw( vProjPosition, 'z' ), sw( vProjPosition, 'w' ) ); 18 | 19 | assign( fragColor, vec4( vUv, 0.5, 1.0 ) ); 20 | assign( fragPosition, vec4( sw( vPosition, 'xyz' ), depth ) ); 21 | assign( fragNormal, vec4( vNormal, 1.0 ) ); 22 | assign( fragMisc, vec4( 0.0 ) ); 23 | return; 24 | } ); 25 | } ); 26 | -------------------------------------------------------------------------------- /src/globals/quad3DGeometry.ts: -------------------------------------------------------------------------------- 1 | import { GL_TRIANGLE_STRIP } from '../gl/constants'; 2 | import { Geometry } from '../heck/Geometry'; 3 | import { TRIANGLE_STRIP_QUAD_3D, TRIANGLE_STRIP_QUAD_NORMAL, TRIANGLE_STRIP_QUAD_UV } from '@0b5vr/experimental'; 4 | import { glCreateVertexbuffer } from '../gl/glCreateVertexbuffer'; 5 | import { glVertexArrayBindVertexbuffer } from '../gl/glVertexArrayBindVertexbuffer'; 6 | 7 | const position = glCreateVertexbuffer( new Float32Array( TRIANGLE_STRIP_QUAD_3D ) ); 8 | const normal = glCreateVertexbuffer( new Float32Array( TRIANGLE_STRIP_QUAD_NORMAL ) ); 9 | const uv = glCreateVertexbuffer( new Float32Array( TRIANGLE_STRIP_QUAD_UV ) ); 10 | 11 | export const quad3DGeometry = new Geometry(); 12 | glVertexArrayBindVertexbuffer( quad3DGeometry.vao, position, 0, 3 ); 13 | glVertexArrayBindVertexbuffer( quad3DGeometry.vao, normal, 1, 3 ); 14 | glVertexArrayBindVertexbuffer( quad3DGeometry.vao, uv, 2, 2 ); 15 | 16 | quad3DGeometry.count = 4; 17 | quad3DGeometry.mode = GL_TRIANGLE_STRIP; 18 | -------------------------------------------------------------------------------- /src/textures/shaders/perlinFBMFrag.ts: -------------------------------------------------------------------------------- 1 | import { addAssign, assign, build, def, defInNamed, defOut, insert, main, mul, unrollLoop, vec2, vec4 } from '../../shaders/shaderBuilder'; 2 | import { perlin2d } from '../../shaders/modules/perlin2d'; 3 | 4 | export const perlinFBMFrag = build( () => { 5 | insert( 'precision highp float;' ); 6 | 7 | const vUv = defInNamed( 'vec2', 'vUv' ); 8 | 9 | const fragColor = defOut( 'vec4' ); 10 | 11 | main( () => { 12 | const sum = def( 'vec4', vec4( 0.5 ) ); 13 | 14 | unrollLoop( 4, ( i ) => { 15 | const h = Math.pow( 2.0, i ); 16 | addAssign( sum, mul( 17 | vec4( 18 | perlin2d( mul( 1.0 * h, vUv ), vec2( 1.0 * h ) ), 19 | perlin2d( mul( 4.0 * h, vUv ), vec2( 4.0 * h ) ), 20 | perlin2d( mul( 16.0 * h, vUv ), vec2( 16.0 * h ) ), 21 | perlin2d( mul( 64.0 * h, vUv ), vec2( 64.0 * h ) ), 22 | ), 23 | 0.5 / h, 24 | ) ); 25 | } ); 26 | 27 | assign( fragColor, sum ); 28 | } ); 29 | } ); 30 | -------------------------------------------------------------------------------- /src/heck/components/Lambda.ts: -------------------------------------------------------------------------------- 1 | import { Component, ComponentDrawEvent, ComponentOptions, ComponentUpdateEvent } from './Component'; 2 | 3 | export interface LambdaOptions extends ComponentOptions { 4 | onUpdate?: ( event: ComponentUpdateEvent ) => void; 5 | onDraw?: ( event: ComponentDrawEvent ) => void; 6 | } 7 | 8 | export class Lambda extends Component { 9 | public onUpdate?: ( event: ComponentUpdateEvent ) => void; 10 | public onDraw?: ( event: ComponentDrawEvent ) => void; 11 | 12 | public constructor( options?: LambdaOptions ) { 13 | super( options ); 14 | 15 | const { onUpdate, onDraw } = options ?? {}; 16 | 17 | this.onUpdate = onUpdate; 18 | this.active = onUpdate != null; 19 | 20 | this.onDraw = onDraw; 21 | this.visible = onDraw != null; 22 | } 23 | 24 | protected __updateImpl( event: ComponentUpdateEvent ): void { 25 | this.onUpdate && this.onUpdate( event ); 26 | } 27 | 28 | protected __drawImpl( event: ComponentDrawEvent ): void { 29 | this.onDraw && this.onDraw( event ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/nodes/utils/createCubemapUniformsLambda.ts: -------------------------------------------------------------------------------- 1 | import { CubemapNode } from '../CubemapNode/CubemapNode'; 2 | import { GL_TEXTURE_2D } from '../../gl/constants'; 3 | import { Lambda } from '../../heck/components/Lambda'; 4 | import { Material } from '../../heck/Material'; 5 | import { ibllutTexture } from '../../globals/ibllutCalc'; 6 | 7 | export function createCubemapUniformsLambda( 8 | cubemapNode: CubemapNode, 9 | materials: Material[], 10 | ): Lambda { 11 | const lambda = (): void => { 12 | materials.map( ( material ) => { 13 | material.addUniformTextures( 'samplerIBLLUT', GL_TEXTURE_2D, ibllutTexture ); 14 | 15 | material.addUniformTextures( 16 | 'samplerEnvDry', 17 | GL_TEXTURE_2D, 18 | cubemapNode.targetDry.texture, 19 | ); 20 | material.addUniformTextures( 21 | 'samplerEnvWet', 22 | GL_TEXTURE_2D, 23 | cubemapNode.targetWet.texture, 24 | ); 25 | } ); 26 | }; 27 | 28 | return new Lambda( { 29 | onUpdate: lambda, 30 | onDraw: lambda, 31 | } ); 32 | } 33 | -------------------------------------------------------------------------------- /src/nodes/HistogramScatter/shaders/histogramGatherVert.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, assign, build, defIn, defOutNamed, defUniformNamed, glPointSize, glPosition, main, mix, texture, vec2, vec4 } from '../../../shaders/shaderBuilder'; 2 | 3 | export const histogramGatherVert = build( () => { 4 | const u = defIn( 'float' ); 5 | const v = defIn( 'float', 1 ); 6 | const c = defIn( 'float', 2 ); 7 | 8 | const vC = defOutNamed( 'float', 'vC' ); 9 | 10 | const sampler0 = defUniformNamed( 'sampler2D', 'sampler0' ); 11 | 12 | main( () => { 13 | // -- fetch texture ---------------------------------------------------------------------------- 14 | const uv = vec2( u, v ); 15 | const tex0 = ( texture( sampler0, uv ) + `[int(${ c })]` ) as GLSLExpression<'float'>; 16 | 17 | // -- render ----------------------------------------------------------------------------------- 18 | assign( vC, c ); 19 | assign( glPosition, vec4( mix( -127.5 / 128.0, 127.5 / 128.0, tex0 ), 0.0, 0.0, 1.0 ) ); 20 | assign( glPointSize, 1.0 ); 21 | } ); 22 | } ); 23 | -------------------------------------------------------------------------------- /src/shaders/modules/isectSphere.ts: -------------------------------------------------------------------------------- 1 | import { FAR } from '../../config'; 2 | import { GLSLExpression, GLSLFloatExpression, add, assign, cache, def, defFn, dot, ifThen, lt, mad, neg, normalize, num, retFn, sq, sqrt, sub, vec4 } from '../shaderBuilder'; 3 | 4 | const symbol = Symbol(); 5 | 6 | export function isectSphere( 7 | ro: GLSLExpression<'vec3'>, 8 | rd: GLSLExpression<'vec3'>, 9 | r: GLSLFloatExpression, 10 | ): GLSLExpression<'vec4'> { 11 | const f = cache( symbol, () => defFn( 'vec4', [ 'vec3', 'vec3', 'float' ], ( ro, rd, r ) => { 12 | const b = def( 'float', dot( ro, rd ) ); 13 | const c = sub( dot( ro, ro ), sq( r ) ); 14 | const h = def( 'float', sub( sq( b ), c ) ); 15 | 16 | ifThen( lt( h, 0.0 ), () => retFn( vec4( FAR ) ) ); 17 | 18 | assign( h, sqrt( h ) ); 19 | const d = def( 'float', neg( add( b, h ) ) ); 20 | ifThen( lt( d, 0.0 ), () => retFn( vec4( FAR ) ) ); 21 | 22 | const N = normalize( mad( d, rd, ro ) ); 23 | retFn( vec4( N, d ) ); 24 | } ) ); 25 | 26 | return f( ro, rd, num( r ) ); 27 | } 28 | -------------------------------------------------------------------------------- /src/shaders/modules/vGGX.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, add, cache, def, defFn, div, gt, mul, num, retFn, sqrt, sub, tern } from '../shaderBuilder'; 2 | 3 | const symbol = Symbol(); 4 | 5 | // The famous "V_SmithGGXCorrelated" 6 | export function vGGX( 7 | dotNL: GLSLFloatExpression, 8 | dotNV: GLSLFloatExpression, 9 | roughnessSq: GLSLFloatExpression, 10 | ): GLSLExpression<'float'> { 11 | const f = cache( 12 | symbol, 13 | () => defFn( 'float', [ 'float', 'float', 'float' ], ( dotNL, dotNV, roughnessSq ) => { 14 | const ggxv = mul( 15 | dotNL, 16 | sqrt( add( mul( dotNV, dotNV, sub( 1.0, roughnessSq ) ), roughnessSq ) ) 17 | ); 18 | const ggxl = mul( 19 | dotNV, 20 | sqrt( add( mul( dotNL, dotNL, sub( 1.0, roughnessSq ) ), roughnessSq ) ) 21 | ); 22 | const ggx = def( 'float', add( ggxv, ggxl ) ); 23 | retFn( ( tern( gt( ggx, 0.0 ), div( 0.5, ggx ), 0.0 ) ) ); 24 | } ) 25 | ); 26 | 27 | return f( num( dotNL ), num( dotNV ), num( roughnessSq ) ); 28 | } 29 | -------------------------------------------------------------------------------- /src/music/utils/findMatchingCloseBracket.ts: -------------------------------------------------------------------------------- 1 | export function findMatchingCloseBracket( 2 | lines: string[], 3 | [ row, col ]: [ number, number ], 4 | ): [ number, number ] | null { 5 | let result: [ number, number ] | null = null; 6 | let nest = 1; 7 | 8 | lines.slice( row ) 9 | .find( ( line, deltaRow ): boolean | void => { 10 | let colOffset = 0; 11 | 12 | if ( deltaRow === 0 ) { 13 | line = line.substring( col + 1 ); 14 | colOffset += col + 1; 15 | } 16 | 17 | for ( ;; ) { 18 | const match = line.match( /[{}]/ ); 19 | 20 | if ( !match ) { 21 | break; 22 | } 23 | 24 | const deltaCol = match.index!; 25 | 26 | nest += match[ 0 ] === '{' ? 1 : -1; 27 | 28 | if ( nest === 0 ) { 29 | result = [ row + deltaRow, deltaCol + colOffset ]; 30 | return true; 31 | } else { 32 | line = line.substring( deltaCol + 1 ); 33 | colOffset += deltaCol + 1; 34 | } 35 | } 36 | } ); 37 | 38 | return result; 39 | } 40 | -------------------------------------------------------------------------------- /src/nodes/OBSVRLogoBScene/shaders/obsvrLogoBFrag.ts: -------------------------------------------------------------------------------- 1 | import { abs, add, assign, build, def, defInNamed, defOutNamed, defUniformNamed, insert, mad, main, mix, mul, mulAssign, step, sw, vec3, vec4 } from '../../../shaders/shaderBuilder'; 2 | 3 | export const obsvrLogoBFrag = build( () => { 4 | insert( 'precision highp float;' ); 5 | 6 | const vUv = defInNamed( 'vec2', 'vUv' ); 7 | 8 | const fragColor = defOutNamed( 'vec4', 'fragColor' ); 9 | 10 | const aspect = defUniformNamed( 'float', 'aspect' ); 11 | 12 | main( () => { 13 | const p = def( 'vec2', mad( 2.0, vUv, -1.0 ) ); 14 | mulAssign( sw( p, 'x' ), aspect ); 15 | mulAssign( p, 4.0 ); 16 | 17 | assign( p, abs( p ) ); 18 | assign( p, mix( p, sw( p, 'yx' ), step( sw( p, 'x' ), sw( p, 'y' ) ) ) ); 19 | 20 | const shape = add( 21 | step( sw( p, 'x' ), 0.1 ), 22 | mul( 23 | step( 0.3, sw( p, 'x' ) ), 24 | step( sw( p, 'x' ), 0.5 ), 25 | step( sw( p, 'y' ), 0.3 ), 26 | ), 27 | ); 28 | 29 | assign( fragColor, vec4( vec3( shape ), 1.0 ) ); 30 | } ); 31 | } ); 32 | -------------------------------------------------------------------------------- /src/shaders/modules/glslLinearstep.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, div, sub } from '../shaderBuilder'; 2 | import { glslSaturate } from './glslSaturate'; 3 | 4 | export const glslLinearstep: { 5 | ( 6 | a: GLSLFloatExpression, 7 | b: GLSLFloatExpression, 8 | x: GLSLFloatExpression, 9 | ): GLSLExpression<'float'>; 10 | ( 11 | a: GLSLFloatExpression | GLSLExpression<'vec2'>, 12 | b: GLSLFloatExpression | GLSLExpression<'vec2'>, 13 | x: GLSLFloatExpression | GLSLExpression<'vec2'>, 14 | ): GLSLExpression<'vec2'>; 15 | ( 16 | a: GLSLFloatExpression | GLSLExpression<'vec3'>, 17 | b: GLSLFloatExpression | GLSLExpression<'vec3'>, 18 | x: GLSLFloatExpression | GLSLExpression<'vec3'>, 19 | ): GLSLExpression<'vec3'>; 20 | ( 21 | a: GLSLFloatExpression | GLSLExpression<'vec4'>, 22 | b: GLSLFloatExpression | GLSLExpression<'vec4'>, 23 | x: GLSLFloatExpression | GLSLExpression<'vec4'>, 24 | ): GLSLExpression<'vec4'>; 25 | } = ( a: any, b: any, x: any ) => glslSaturate( div( 26 | sub( x, a ), 27 | sub( b, a ), 28 | ) ) as any; 29 | -------------------------------------------------------------------------------- /src/nodes/FluidScene/shaders/defFluidSampleNearest3D.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, add, addAssign, cache, def, defFn, div, floor, mod, mul, retFn, sw, texture, vec2 } from '../../../shaders/shaderBuilder'; 2 | import { GRID_RESO, GRID_RESO_SQRT } from '../constants'; 3 | import { glslSaturate } from '../../../shaders/modules/glslSaturate'; 4 | 5 | const symbol = Symbol(); 6 | 7 | export const defFluidSampleNearest3D: { 8 | (): ( 9 | sampler: GLSLExpression<'sampler2D'>, 10 | pos: GLSLExpression<'vec3'>, 11 | ) => GLSLExpression<'vec4'> 12 | } = () => cache( 13 | symbol, 14 | () => defFn( 'vec4', [ 'sampler2D', 'vec3' ], ( sampler, pos ) => { 15 | const uv = def( 'vec2', div( 16 | glslSaturate( add( sw( pos, 'xy' ), 0.5 ) ), 17 | GRID_RESO_SQRT, 18 | ) ); 19 | const z = def( 'float', glslSaturate( add( sw( pos, 'z' ), 0.5 ) ) ); 20 | addAssign( uv, div( vec2( 21 | mod( floor( mul( z, GRID_RESO ) ), GRID_RESO_SQRT ), 22 | floor( mul( z, GRID_RESO_SQRT ) ), 23 | ), GRID_RESO_SQRT ) ); 24 | 25 | retFn( texture( sampler, uv ) ); 26 | } ) 27 | ); 28 | -------------------------------------------------------------------------------- /src/shaders/common/deferredWhiteUnlitFrag.ts: -------------------------------------------------------------------------------- 1 | import { MTL_UNLIT } from '../../nodes/CameraStack/deferredConstants'; 2 | import { assign, build, defInNamed, defOut, defUniformNamed, div, exp2, insert, main, sw, vec4 } from '../shaderBuilder'; 3 | 4 | export const deferredWhiteUnlitFrag = build( () => { 5 | insert( 'precision highp float;' ); 6 | 7 | const vPosition = defInNamed( 'vec4', 'vPosition' ); 8 | const vProjPosition = defInNamed( 'vec4', 'vProjPosition' ); 9 | 10 | const fragColor = defOut( 'vec4' ); 11 | const fragPosition = defOut( 'vec4', 1 ); 12 | const fragNormal = defOut( 'vec4', 2 ); 13 | const fragMisc = defOut( 'vec4', 3 ); 14 | 15 | const strength = defUniformNamed( 'float', 'strength' ); 16 | 17 | main( () => { 18 | const depth = div( sw( vProjPosition, 'z' ), sw( vProjPosition, 'w' ) ); 19 | 20 | assign( fragColor, vec4( exp2( strength ) ) ); 21 | assign( fragPosition, vec4( sw( vPosition, 'xyz' ), depth ) ); 22 | assign( fragNormal, vec4( 0.0, 0.0, 1.0, MTL_UNLIT ) ); 23 | assign( fragMisc, vec4( 0.0 ) ); 24 | return; 25 | } ); 26 | } ); 27 | -------------------------------------------------------------------------------- /src/shaders/modules/isectBox.ts: -------------------------------------------------------------------------------- 1 | import { FAR } from '../../config'; 2 | import { GLSLExpression, abs, add, cache, def, defFn, div, ifThen, lt, max, min, mul, neg, or, retFn, sign, step, sub, sw, vec3, vec4 } from '../shaderBuilder'; 3 | 4 | const symbol = Symbol(); 5 | 6 | export function isectBox( 7 | ro: GLSLExpression<'vec3'>, 8 | rd: GLSLExpression<'vec3'>, 9 | s: GLSLExpression<'vec3'>, 10 | ): GLSLExpression<'vec4'> { 11 | const f = cache( symbol, () => defFn( 'vec4', [ 'vec3', 'vec3', 'vec3' ], ( ro, rd, s ) => { 12 | const src = neg( div( ro, rd ) ); 13 | const dst = abs( div( s, rd ) ); 14 | const f = def( 'vec3', sub( src, dst ) ); 15 | const b = def( 'vec3', add( src, dst ) ); 16 | const fl = def( 'float', max( sw( f, 'x' ), max( sw( f, 'y' ), sw( f, 'z' ) ) ) ); 17 | const bl = min( sw( b, 'x' ), min( sw( b, 'y' ), sw( b, 'z' ) ) ); 18 | ifThen( or( lt( bl, fl ), lt( fl, 0.0 ) ), () => retFn( vec4( FAR ) ) ); 19 | const n = mul( 20 | -1.0, 21 | sign( rd ), 22 | step( vec3( fl ), f ), 23 | ); 24 | retFn( vec4( n, fl ) ); 25 | } ) ); 26 | 27 | return f( ro, rd, s ); 28 | } 29 | -------------------------------------------------------------------------------- /src/nodes/NoisePlaneScene/shaders/noisePlaneFrag.ts: -------------------------------------------------------------------------------- 1 | import { addAssign, assign, build, def, defInNamed, defOutNamed, defUniformNamed, insert, mad, main, mul, mulAssign, normalize, pow, sw, vec3, vec4 } from '../../../shaders/shaderBuilder'; 2 | import { cyclicNoise } from '../../../shaders/modules/cyclicNoise'; 3 | 4 | export const noisePlaneFrag = build( () => { 5 | insert( 'precision highp float;' ); 6 | 7 | const vUv = defInNamed( 'vec2', 'vUv' ); 8 | 9 | const fragColor = defOutNamed( 'vec4', 'fragColor' ); 10 | 11 | const time = defUniformNamed( 'float', 'time' ); 12 | const aspect = defUniformNamed( 'float', 'aspect' ); 13 | 14 | main( () => { 15 | const p = def( 'vec2', mad( 2.0, vUv, -1.0 ) ); 16 | mulAssign( sw( p, 'x' ), aspect ); 17 | 18 | const pt = def( 'vec3', mul( 2.0, normalize( vec3( p, 0.3 ) ) ) ); 19 | addAssign( sw( pt, 'z' ), time ); 20 | addAssign( pt, mul( 0.5, cyclicNoise( pt ) ) ); 21 | 22 | const haha = def( 23 | 'float', 24 | mad( 0.5, sw( cyclicNoise( pt ), 'x' ), 0.5 ), 25 | ); 26 | 27 | assign( fragColor, vec4( vec3( pow( haha, 4.0 ) ), 1.0 ) ); 28 | } ); 29 | } ); 30 | -------------------------------------------------------------------------------- /src/music/utils/findNearestChar.ts: -------------------------------------------------------------------------------- 1 | export function findNearestChar( 2 | lines: string[], 3 | [ row, col ]: [ number, number ], 4 | dir: -1 | 1, 5 | char: string, 6 | ): [ number, number ] | null { 7 | let result: [ number, number ] | null = null; 8 | 9 | if ( dir < 0 ) { 10 | lines.slice( 0, row + 1 ) 11 | .reverse() 12 | .find( ( line, deltaRow ): boolean | void => { 13 | line = ( deltaRow === 0 ? line.substring( 0, col ) : line ); 14 | const iCol = line.lastIndexOf( char ); 15 | 16 | if ( iCol !== -1 ) { 17 | result = [ row - deltaRow, iCol ]; 18 | return true; 19 | } 20 | } ); 21 | 22 | } else { 23 | lines.slice( row ) 24 | .find( ( line, deltaRow ): boolean | void => { 25 | line = ( deltaRow === 0 ? line.substring( col + 1 ) : line ); 26 | const colOffset = deltaRow === 0 ? col + 1 : 0; 27 | const deltaCol = line.indexOf( char ); 28 | 29 | if ( deltaCol !== -1 ) { 30 | result = [ row + deltaRow, deltaCol + colOffset ]; 31 | return true; 32 | } 33 | } ); 34 | } 35 | 36 | return result; 37 | } 38 | -------------------------------------------------------------------------------- /src/nodes/PillarGridScene/PillarGrid/shaders/pillarGridFrameFrag.ts: -------------------------------------------------------------------------------- 1 | import { MTL_UNLIT } from '../../../CameraStack/deferredConstants'; 2 | import { assign, build, defInNamed, defOut, div, insert, main, mul, smoothstep, sw, vec3, vec4 } from '../../../../shaders/shaderBuilder'; 3 | 4 | export const pillarGridFrameFrag = build( () => { 5 | insert( 'precision highp float;' ); 6 | 7 | const vPosition = defInNamed( 'vec4', 'vPosition' ); 8 | const vProjPosition = defInNamed( 'vec4', 'vProjPosition' ); 9 | 10 | const fragColor = defOut( 'vec4' ); 11 | const fragPosition = defOut( 'vec4', 1 ); 12 | const fragNormal = defOut( 'vec4', 2 ); 13 | const fragMisc = defOut( 'vec4', 3 ); 14 | 15 | main( () => { 16 | const depth = div( sw( vProjPosition, 'z' ), sw( vProjPosition, 'w' ) ); 17 | 18 | assign( fragColor, vec4( 19 | vec3( mul( 0.5, smoothstep( 0.5, 0.8, sw( vPosition, 'z' ) ) ) ), 20 | 1.0, 21 | ) ); 22 | assign( fragPosition, vec4( sw( vPosition, 'xyz' ), depth ) ); 23 | assign( fragNormal, vec4( vec3( 0.0, 0.0, 1.0 ), MTL_UNLIT ) ); 24 | assign( fragMisc, vec4( 0.0 ) ); 25 | return; 26 | } ); 27 | } ); 28 | -------------------------------------------------------------------------------- /src/shaders/modules/sampleGGX.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, add, cache, cos, def, defFn, div, mul, num, retFn, sin, sqrt, sub, sw, vec3 } from '../shaderBuilder'; 2 | import { PI } from '../../utils/constants'; 3 | import { orthBas } from './orthBas'; 4 | 5 | const symbol = Symbol(); 6 | 7 | export function sampleGGX( 8 | Xi: GLSLExpression<'vec2'>, 9 | N: GLSLExpression<'vec3'>, 10 | roughnessSq: GLSLFloatExpression, 11 | ): GLSLExpression<'vec3'> { 12 | const f = cache( 13 | symbol, 14 | () => defFn( 'vec3', [ 'vec2', 'vec3', 'float' ], ( Xi, N, roughnessSq ) => { 15 | const phi = def( 'float', mul( sw( Xi, 'x' ), 2.0 * PI ) ); 16 | const cosTheta = def( 'float', sqrt( div( 17 | sub( 1.0, sw( Xi, 'y' ) ), 18 | add( 1.0, mul( sub( roughnessSq, 1.0 ), sw( Xi, 'y' ) ) ) 19 | ) ) ); 20 | const sinTheta = def( 'float', sub( 1.0, mul( cosTheta, cosTheta ) ) ); 21 | retFn( mul( 22 | orthBas( N ), 23 | vec3( mul( sinTheta, cos( phi ) ), mul( sinTheta, sin( phi ) ), cosTheta ), 24 | ) ); 25 | } ) 26 | ); 27 | 28 | return f( Xi, N, num( roughnessSq ) ); 29 | } 30 | -------------------------------------------------------------------------------- /src/nodes/MetaballScene/MetaballParticles/shaders/metaballParticlesRenderFrag.ts: -------------------------------------------------------------------------------- 1 | import { MTL_PBR_ROUGHNESS_METALLIC } from '../../../CameraStack/deferredConstants'; 2 | import { assign, build, defInNamed, defOut, div, insert, main, normalize, sw, vec4 } from '../../../../shaders/shaderBuilder'; 3 | 4 | export const metaballParticlesRenderFrag = build( () => { 5 | insert( 'precision highp float;' ); 6 | 7 | const vPosition = defInNamed( 'vec4', 'vPosition' ); 8 | const vProjPosition = defInNamed( 'vec4', 'vProjPosition' ); 9 | const vNormal = defInNamed( 'vec3', 'vNormal' ); 10 | 11 | const fragColor = defOut( 'vec4' ); 12 | const fragPosition = defOut( 'vec4', 1 ); 13 | const fragNormal = defOut( 'vec4', 2 ); 14 | const fragMisc = defOut( 'vec4', 3 ); 15 | 16 | main( () => { 17 | const depth = div( sw( vProjPosition, 'z' ), sw( vProjPosition, 'w' ) ); 18 | 19 | assign( fragColor, vec4( 0.8 ) ); 20 | assign( fragPosition, vec4( sw( vPosition, 'xyz' ), depth ) ); 21 | assign( fragNormal, vec4( normalize( vNormal ), MTL_PBR_ROUGHNESS_METALLIC ) ); 22 | assign( fragMisc, vec4( 0.1, 0.0, 0.0, 1.0 ) ); 23 | return; 24 | } ); 25 | } ); 26 | -------------------------------------------------------------------------------- /src/shaders/modules/glslSmootherstep.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, add, mul, sub } from '../shaderBuilder'; 2 | import { glslLinearstep } from './glslLinearstep'; 3 | 4 | export const glslSmootherstep: { 5 | ( 6 | a: GLSLFloatExpression, 7 | b: GLSLFloatExpression, 8 | x: GLSLFloatExpression, 9 | ): GLSLExpression<'float'>; 10 | ( 11 | a: GLSLFloatExpression | GLSLExpression<'vec2'>, 12 | b: GLSLFloatExpression | GLSLExpression<'vec2'>, 13 | x: GLSLFloatExpression | GLSLExpression<'vec2'>, 14 | ): GLSLExpression<'vec2'>; 15 | ( 16 | a: GLSLFloatExpression | GLSLExpression<'vec3'>, 17 | b: GLSLFloatExpression | GLSLExpression<'vec3'>, 18 | x: GLSLFloatExpression | GLSLExpression<'vec3'>, 19 | ): GLSLExpression<'vec3'>; 20 | ( 21 | a: GLSLFloatExpression | GLSLExpression<'vec4'>, 22 | b: GLSLFloatExpression | GLSLExpression<'vec4'>, 23 | x: GLSLFloatExpression | GLSLExpression<'vec4'>, 24 | ): GLSLExpression<'vec4'>; 25 | } = ( a: any, b: any, x: any ) => { 26 | const t = glslLinearstep( a, b, x ); 27 | return ( mul( t, t, t, add( mul( t, sub( mul( t, 6.0 ), 15.0 ) ), 10.0 ) ) ) as any; 28 | }; 29 | -------------------------------------------------------------------------------- /src/nodes/FluidScene/shaders/defFluidSampleLinear3D.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, add, addAssign, cache, def, defFn, div, fract, mix, mul, neg, retFn, subAssign, sw } from '../../../shaders/shaderBuilder'; 2 | import { GRID_RESO } from '../constants'; 3 | import { defFluidSampleNearest3D } from './defFluidSampleNearest3D'; 4 | 5 | const symbol = Symbol(); 6 | 7 | export const defFluidSampleLinear3D: { 8 | (): ( 9 | sampler: GLSLExpression<'sampler2D'>, 10 | pos: GLSLExpression<'vec3'>, 11 | ) => GLSLExpression<'vec4'> 12 | } = () => cache( 13 | symbol, 14 | () => defFn( 'vec4', [ 'sampler2D', 'vec3' ], ( sampler, pos ) => { 15 | const fluidSample3DNearest = defFluidSampleNearest3D(); 16 | 17 | const t = fract( 18 | mul( add( sw( pos, 'z' ), neg( div( 0.5, GRID_RESO ) ), 0.5 ), GRID_RESO ) 19 | ); 20 | const a = def( 'vec3', pos ); 21 | subAssign( sw( a, 'z' ), div( t, GRID_RESO ) ); 22 | const b = def( 'vec3', a ); 23 | addAssign( sw( b, 'z' ), div( 1.0, GRID_RESO ) ); 24 | 25 | retFn( mix( 26 | fluidSample3DNearest( sampler, a ), 27 | fluidSample3DNearest( sampler, b ), 28 | t 29 | ) ); 30 | } ) 31 | ); 32 | -------------------------------------------------------------------------------- /src/shaders/common/deferredColorFrag.ts: -------------------------------------------------------------------------------- 1 | import { assign, build, defInNamed, defOut, defUniformNamed, div, insert, main, normalize, sw, vec4 } from '../shaderBuilder'; 2 | 3 | export const deferredColorFrag = build( () => { 4 | insert( 'precision highp float;' ); 5 | 6 | const vPosition = defInNamed( 'vec4', 'vPosition' ); 7 | const vProjPosition = defInNamed( 'vec4', 'vProjPosition' ); 8 | const vNormal = defInNamed( 'vec3', 'vNormal' ); 9 | 10 | const fragColor = defOut( 'vec4' ); 11 | const fragPosition = defOut( 'vec4', 1 ); 12 | const fragNormal = defOut( 'vec4', 2 ); 13 | const fragMisc = defOut( 'vec4', 3 ); 14 | 15 | const color = defUniformNamed( 'vec4', 'color' ); 16 | const mtlKind = defUniformNamed( 'float', 'mtlKind' ); 17 | const mtlParams = defUniformNamed( 'vec4', 'mtlParams' ); 18 | 19 | main( () => { 20 | const depth = div( sw( vProjPosition, 'z' ), sw( vProjPosition, 'w' ) ); 21 | 22 | assign( fragColor, color ); 23 | assign( fragPosition, vec4( sw( vPosition, 'xyz' ), depth ) ); 24 | assign( fragNormal, vec4( normalize( vNormal ), mtlKind ) ); 25 | assign( fragMisc, mtlParams ); 26 | return; 27 | } ); 28 | } ); 29 | -------------------------------------------------------------------------------- /src/heck/BufferMipmapTextureRenderTarget.ts: -------------------------------------------------------------------------------- 1 | import { GLTextureFormatStuff } from '../gl/glSetTexture'; 2 | import { RawBufferRenderTarget } from './RawBufferRenderTarget'; 3 | import { glLazyMipmapFramebuffers } from '../gl/glLazyMipmapFramebuffers'; 4 | 5 | export class BufferMipmapTextureRenderTarget extends RawBufferRenderTarget { 6 | public readonly texture: WebGLTexture; 7 | public readonly mipmapTargets: RawBufferRenderTarget[] | null; 8 | 9 | public constructor( 10 | width: number, 11 | height: number, 12 | levels: number, 13 | format?: GLTextureFormatStuff, 14 | ) { 15 | const { framebuffers, texture } = glLazyMipmapFramebuffers( width, height, levels, format ); 16 | 17 | super( { 18 | viewport: [ 0, 0, width, height ], 19 | framebuffer: framebuffers[ 0 ], 20 | } ); 21 | 22 | this.texture = texture; 23 | 24 | this.mipmapTargets = framebuffers.map( ( framebuffer ) => { 25 | const rt = new RawBufferRenderTarget( { 26 | viewport: [ 0, 0, width, height ], 27 | framebuffer, 28 | } ); 29 | 30 | width /= 2.0; 31 | height /= 2.0; 32 | 33 | return rt; 34 | } ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/heck/Dog.ts: -------------------------------------------------------------------------------- 1 | import { Component } from './components/Component'; 2 | import { MapOfSet } from '../utils/MapOfSet'; 3 | import { SceneNode } from './components/SceneNode'; 4 | import { Transform } from './Transform'; 5 | import { music } from '../globals/music'; 6 | 7 | /** 8 | * And what a WONDERFUL Dog they are!! 9 | */ 10 | export class Dog { 11 | public root: SceneNode; 12 | public active: boolean; 13 | 14 | private __frameCount = 0; 15 | 16 | public constructor() { 17 | this.root = new SceneNode(); 18 | this.active = true; 19 | 20 | if ( import.meta.env.DEV ) { 21 | this.root.name = 'root'; 22 | } 23 | } 24 | 25 | public update(): void { 26 | if ( this.active ) { 27 | this.root.update( { 28 | frameCount: this.__frameCount ++, 29 | time: music.time, 30 | deltaTime: music.deltaTime, 31 | globalTransform: new Transform(), 32 | componentsByTag: new MapOfSet(), 33 | ancestors: [], 34 | } ); 35 | } 36 | 37 | if ( import.meta.env.DEV ) { 38 | Component.updateHaveReachedBreakpoint = false; 39 | Component.drawHaveReachedBreakpoint = false; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/shaders/modules/brdfSheen.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, add, cache, def, defFn, dot, max, mul, normalize, num, retFn, sq } from '../shaderBuilder'; 2 | import { dCharlie } from './dCharlie'; 3 | import { vNeubelt } from './vNeubelt'; 4 | 5 | const symbol = Symbol(); 6 | 7 | export function brdfSheen( 8 | L: GLSLExpression<'vec3'>, 9 | V: GLSLExpression<'vec3'>, 10 | N: GLSLExpression<'vec3'>, 11 | roughness: GLSLFloatExpression, 12 | tint: GLSLExpression<'vec3'>, 13 | ): GLSLExpression<'vec3'> { 14 | const f = cache( 15 | symbol, 16 | () => defFn( 17 | 'vec3', 18 | [ 'vec3', 'vec3', 'vec3', 'float', 'vec3' ], 19 | ( L, V, N, roughness, tint ) => { 20 | const H = def( 'vec3', normalize( add( L, V ) ) ); 21 | const dotNL = def( 'float', max( dot( N, L ), 1E-3 ) ); 22 | const dotNV = def( 'float', max( dot( N, V ), 1E-3 ) ); 23 | const dotNH = def( 'float', max( dot( N, H ), 1E-3 ) ); 24 | 25 | const Vis = vNeubelt( dotNL, dotNV ); 26 | const D = dCharlie( dotNH, sq( roughness ) ); 27 | 28 | retFn( mul( tint, Vis, D ) ); 29 | } 30 | ) 31 | ); 32 | 33 | return f( L, V, N, num( roughness ), tint ); 34 | } 35 | -------------------------------------------------------------------------------- /src/nodes/utils/createRaymarchCameraUniformsLambda.ts: -------------------------------------------------------------------------------- 1 | import { Lambda } from '../../heck/components/Lambda'; 2 | import { Material } from '../../heck/Material'; 3 | import { mat4Inverse, mat4Multiply } from '@0b5vr/experimental'; 4 | 5 | export function createRaymarchCameraUniformsLambda( materials: Material[] ): Lambda { 6 | const lambda = new Lambda( { 7 | onDraw: ( event ) => { 8 | materials.map( ( material ) => { 9 | material.addUniform( 10 | 'cameraNearFar', 11 | '2f', 12 | event.camera.near, 13 | event.camera.far 14 | ); 15 | 16 | const pvm = mat4Multiply( 17 | event.projectionMatrix, 18 | event.viewMatrix, 19 | event.globalTransform.matrix 20 | ); 21 | 22 | material.addUniformMatrixVector( 23 | 'pvm', 24 | 'Matrix4fv', 25 | pvm, 26 | ); 27 | 28 | material.addUniformMatrixVector( 29 | 'inversePVM', 30 | 'Matrix4fv', 31 | mat4Inverse( pvm ), 32 | ); 33 | } ); 34 | }, 35 | } ); 36 | 37 | if ( import.meta.env.DEV ) { 38 | lambda.name = 'lambdaRaymarchCameraUniforms'; 39 | } 40 | 41 | return lambda; 42 | } 43 | -------------------------------------------------------------------------------- /src/music/BufferReaderProcessor.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | const BLOCK_SIZE = 128; 4 | const CHANNELS = 2; 5 | const BUFFER_SIZE_PER_CHANNEL = 65536; 6 | 7 | class BufferReaderProcessor extends AudioWorkletProcessor { 8 | constructor() { 9 | super(); 10 | 11 | this.active = false; 12 | this.blocks = 0; 13 | this.buffer = new Float32Array( CHANNELS * BUFFER_SIZE_PER_CHANNEL ); 14 | 15 | this.port.onmessage = ( { data } ) => { 16 | if ( Array.isArray( data ) ) { 17 | this.buffer.set( ...data ); 18 | } else { 19 | this.active = data; 20 | } 21 | }; 22 | } 23 | 24 | process( inputs, outputs, parameters ) { 25 | if ( !this.active ) { return true; } 26 | 27 | const buffer = this.buffer; 28 | 29 | const head = ( BLOCK_SIZE * this.blocks ) % BUFFER_SIZE_PER_CHANNEL; 30 | 31 | outputs[ 0 ].map( ( ch, iCh ) => { 32 | const chHead = BUFFER_SIZE_PER_CHANNEL * iCh + head; 33 | ch.set( buffer.subarray( chHead, chHead + BLOCK_SIZE ) ); 34 | } ); 35 | 36 | this.blocks ++; 37 | 38 | this.port.postMessage( this.blocks ); 39 | 40 | return true; 41 | } 42 | } 43 | 44 | registerProcessor( 'buffer-reader-processor', BufferReaderProcessor ); 45 | -------------------------------------------------------------------------------- /src/nodes/HistogramScatter/shaders/histogramPlotVert.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, assign, build, defIn, defOutNamed, defUniformNamed, div, eq, glPosition, main, mix, tern, texture, vec2, vec4 } from '../../../shaders/shaderBuilder'; 2 | 3 | export const histogramPlotVert = build( () => { 4 | const y = defIn( 'float' ); 5 | const u = defIn( 'float', 1 ); 6 | const c = defIn( 'float', 2 ); 7 | 8 | const vC = defOutNamed( 'float', 'vC' ); 9 | 10 | const sampler0 = defUniformNamed( 'sampler2D', 'sampler0' ); 11 | 12 | main( () => { 13 | // -- fetch texture ---------------------------------------------------------------------------- 14 | const uv = vec2( u, 0.5 ); 15 | const tex0 = ( texture( sampler0, uv ) + `[int(${ c })]` ) as GLSLExpression<'float'>; 16 | 17 | // -- geometry --------------------------------------------------------------------------------- 18 | const yt = tern( 19 | eq( y, 0.0 ), 20 | -1.0, 21 | mix( -1.0, 1.0, div( tex0, 4096.0 ) ), 22 | ); 23 | 24 | // -- render ----------------------------------------------------------------------------------- 25 | assign( vC, c ); 26 | assign( glPosition, vec4( mix( -1.0, 1.0, u ), yt, 0.0, 1.0 ) ); 27 | } ); 28 | } ); 29 | -------------------------------------------------------------------------------- /src/shaders/common/deferredTextureFrag.ts: -------------------------------------------------------------------------------- 1 | import { assign, build, defInNamed, defOut, defUniformNamed, div, insert, main, sw, texture, vec4 } from '../shaderBuilder'; 2 | 3 | export const deferredTextureFrag = build( () => { 4 | insert( 'precision highp float;' ); 5 | 6 | const vPosition = defInNamed( 'vec4', 'vPosition' ); 7 | const vProjPosition = defInNamed( 'vec4', 'vProjPosition' ); 8 | const vNormal = defInNamed( 'vec3', 'vNormal' ); 9 | const vUv = defInNamed( 'vec2', 'vUv' ); 10 | 11 | const fragColor = defOut( 'vec4' ); 12 | const fragPosition = defOut( 'vec4', 1 ); 13 | const fragNormal = defOut( 'vec4', 2 ); 14 | const fragMisc = defOut( 'vec4', 3 ); 15 | 16 | const mtlKind = defUniformNamed( 'float', 'mtlKind' ); 17 | const mtlParams = defUniformNamed( 'vec4', 'mtlParams' ); 18 | const sampler0 = defUniformNamed( 'sampler2D', 'sampler0' ); 19 | 20 | main( () => { 21 | const depth = div( sw( vProjPosition, 'z' ), sw( vProjPosition, 'w' ) ); 22 | 23 | assign( fragColor, texture( sampler0, vUv ) ); 24 | assign( fragPosition, vec4( sw( vPosition, 'xyz' ), depth ) ); 25 | assign( fragNormal, vec4( vNormal, mtlKind ) ); 26 | assign( fragMisc, mtlParams ); 27 | return; 28 | } ); 29 | } ); 30 | -------------------------------------------------------------------------------- /src/nodes/CameraStack/DoF/shaders/dofTileGatherFrag.ts: -------------------------------------------------------------------------------- 1 | import { add, assign, build, def, defInNamed, defOut, defUniformNamed, div, float, floor, forLoop, insert, main, max, min, mod, mul, sub, sw, texture, vec2, vec4 } from '../../../../shaders/shaderBuilder'; 2 | 3 | export const dofTileGatherFrag = build( () => { 4 | insert( 'precision highp float;' ); 5 | 6 | const vUv = defInNamed( 'vec2', 'vUv' ); 7 | const fragColor = defOut( 'vec4' ); 8 | 9 | const resolution = defUniformNamed( 'vec2', 'resolution' ); 10 | const sampler0 = defUniformNamed( 'sampler2D', 'sampler0' ); 11 | 12 | main( () => { 13 | const depthNearest = def( 'float', 1E9 ); 14 | const cocMax = def( 'float', 0.0 ); 15 | 16 | forLoop( 9, ( i ) => { 17 | const uv = add( 18 | vUv, 19 | div( 20 | sub( vec2( mod( float( i ), 3.0 ), floor( mul( float( i ), 0.34 ) ) ), 1.0 ), 21 | resolution, 22 | ), 23 | ); 24 | 25 | const tex = def( 'vec4', texture( sampler0, uv ) ); 26 | assign( depthNearest, min( depthNearest, sw( tex, 'x' ) ) ); 27 | assign( cocMax, max( cocMax, sw( tex, 'y' ) ) ); 28 | } ); 29 | 30 | assign( fragColor, vec4( depthNearest, cocMax, 0.0, 0.0 ) ); 31 | } ); 32 | } ); 33 | -------------------------------------------------------------------------------- /src/nodes/SevenSegScene/shaders/sevenSegWireFrag.ts: -------------------------------------------------------------------------------- 1 | import { MTL_UNLIT } from '../../CameraStack/deferredConstants'; 2 | import { add, assign, build, defInNamed, defOut, discard, div, ifThen, insert, lt, main, sw, vec4 } from '../../../shaders/shaderBuilder'; 3 | import { bayerPattern4 } from '../../../shaders/modules/bayerPattern4'; 4 | 5 | export const sevenSegWireFrag = build( () => { 6 | insert( 'precision highp float;' ); 7 | 8 | const vPosition = defInNamed( 'vec4', 'vPosition' ); 9 | const vProjPosition = defInNamed( 'vec4', 'vProjPosition' ); 10 | 11 | const fragColor = defOut( 'vec4' ); 12 | const fragPosition = defOut( 'vec4', 1 ); 13 | const fragNormal = defOut( 'vec4', 2 ); 14 | const fragMisc = defOut( 'vec4', 3 ); 15 | 16 | main( () => { 17 | const depth = div( sw( vProjPosition, 'z' ), sw( vProjPosition, 'w' ) ); 18 | 19 | ifThen( 20 | lt( add( div( bayerPattern4(), 16.0 ), sw( vProjPosition, 'w' ) ), 2.0 ), 21 | () => discard(), 22 | ); 23 | 24 | assign( fragColor, vec4( 1.0 ) ); 25 | assign( fragPosition, vec4( sw( vPosition, 'xyz' ), depth ) ); 26 | assign( fragNormal, vec4( MTL_UNLIT ) ); 27 | assign( fragMisc, vec4( 0.0, 0.0, 0.0, 0.0 ) ); 28 | return; 29 | } ); 30 | } ); 31 | -------------------------------------------------------------------------------- /vite-plugins/vite-worklet-minifier-plugin.ts: -------------------------------------------------------------------------------- 1 | import * as Terser from 'terser'; 2 | import { Plugin } from 'vite'; 3 | 4 | const fileRegex = /\?worklet$/; 5 | 6 | export interface WorkletMinifierPluginOptions { 7 | minify: boolean; 8 | minifyOptions: Terser.MinifyOptions; 9 | } 10 | 11 | export const workletMinifierPlugin: ( 12 | options: WorkletMinifierPluginOptions 13 | ) => Plugin = ( { minify, minifyOptions } ) => { 14 | return { 15 | name: 'worklet-minifier', 16 | enforce: 'pre', 17 | async transform( src: string, id: string ) { 18 | if ( fileRegex.test( id ) ) { 19 | if ( !minify ) { 20 | return `export default \`${ src }\`;`; 21 | } 22 | 23 | // AudioWorkletProcessor.process have to return `true` or `false`, 24 | // which does not accept `0` or `1`. 25 | // `options.compress.booleans_as_integers` have to be disabled 26 | const newMinifyOptions = JSON.parse( JSON.stringify( minifyOptions ) ); 27 | newMinifyOptions.compress.booleans_as_integers = false; 28 | 29 | const result = await Terser.minify( src, newMinifyOptions ); 30 | 31 | return { 32 | code: `export default '${ result.code }';`, 33 | }; 34 | } 35 | } 36 | }; 37 | }; 38 | -------------------------------------------------------------------------------- /src/nodes/Lights/shaders/shadowBlurFrag.ts: -------------------------------------------------------------------------------- 1 | import { add, addAssign, assign, build, def, defInNamed, defOutNamed, defUniformNamed, div, insert, main, mul, sub, sw, texture, vec2, vec4 } from '../../../shaders/shaderBuilder'; 2 | 3 | export const shadowBlurFrag = ( isVert: boolean ): string => build( () => { 4 | insert( 'precision highp float;' ); 5 | 6 | const vUv = defInNamed( 'vec2', 'vUv' ); 7 | 8 | const fragColor = defOutNamed( 'vec4', 'fragColor' ); 9 | 10 | const resolution = defUniformNamed( 'vec2', 'resolution' ); 11 | const sampler0 = defUniformNamed( 'sampler2D', 'sampler0' ); 12 | 13 | main( () => { 14 | const deltaTexel = div( 1.0, resolution ); 15 | 16 | const bv = mul( deltaTexel, isVert ? vec2( 0.0, 1.0 ) : vec2( 1.0, 0.0 ) ); 17 | const sum = def( 'vec4', vec4( 0.0 ) ); 18 | 19 | const tex = texture( sampler0, vUv ); 20 | 21 | addAssign( sum, mul( 0.29411764705882354, tex ) ); 22 | let uvt = sub( vUv, mul( bv, 1.3333333333333333 ) ); 23 | addAssign( sum, mul( 0.35294117647058826, texture( sampler0, uvt ) ) ); 24 | uvt = add( vUv, mul( bv, 1.3333333333333333 ) ); 25 | addAssign( sum, mul( 0.35294117647058826, texture( sampler0, uvt ) ) ); 26 | 27 | assign( fragColor, vec4( sw( sum, 'xy' ), sw( tex, 'z' ), 1.0 ) ); 28 | } ); 29 | } ); 30 | -------------------------------------------------------------------------------- /src/nodes/LoadingScreen/shaders/noiseFrag.ts: -------------------------------------------------------------------------------- 1 | import { abs, add, addAssign, assign, build, def, defInNamed, defOut, glFragCoord, insert, main, mul, pow, smoothstep, sw, vec3, vec4 } from '../../../shaders/shaderBuilder'; 2 | import { cyclicNoise } from '../../../shaders/modules/cyclicNoise'; 3 | import { pcg3df } from '../../../shaders/modules/pcg3df'; 4 | 5 | export const noiseFrag = build( () => { 6 | insert( 'precision highp float;' ); 7 | 8 | const vUv = defInNamed( 'vec2', 'vUv' ); 9 | const fragColor = defOut( 'vec4' ); 10 | 11 | main( () => { 12 | const p = def( 'vec2', vUv ); 13 | 14 | addAssign( p, mul( 15 | 0.8, 16 | sw( cyclicNoise( 17 | vec3( mul( 0.4, p ), 8.0 ), 18 | { warp: 0.3, pump: 1.2 }, 19 | ), 'xy' ), 20 | ) ); 21 | 22 | let n = sw( cyclicNoise( 23 | vec3( mul( 3.0, p ), 0.0 ), 24 | { warp: 0.4 }, 25 | ), 'x' ); 26 | const n2 = pow( abs( sw( cyclicNoise( 27 | vec3( mul( 6.0, p ), 0.0 ), 28 | { warp: 0.9, pump: 1.0 }, 29 | ), 'x' ) ), 6.0 ); 30 | 31 | n = add( 32 | n2, 33 | n, 34 | mul( 0.2, sw( pcg3df( sw( glFragCoord, 'xyy' ) ), 'x' ) ), 35 | ); 36 | n = smoothstep( -0.5, 1.5, n ); 37 | 38 | assign( fragColor, vec4( vec3( n ), 1.0 ) ); 39 | } ); 40 | } ); 41 | -------------------------------------------------------------------------------- /src/shaders/modules/tonemapACESHill.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, add, div, mat3, mul, sub } from '../shaderBuilder'; 2 | import { glslSaturate } from './glslSaturate'; 3 | 4 | /*! 5 | * The ACES tone mapping part is taken from Baking Lab 6 | * (c) MJP and David Neubelt, MIT License 7 | * 8 | * https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl 9 | * 10 | * The original fit was done by Stephen Hill (@self_shadow) 11 | */ 12 | 13 | const ACESInputMat = mat3( 14 | 0.59719, 0.07600, 0.02840, 15 | 0.35458, 0.90834, 0.13383, 16 | 0.04823, 0.01566, 0.83777, 17 | ); 18 | 19 | const ACESOutputMat = mat3( 20 | 1.60475, -0.10208, -0.00327, 21 | -0.53108, 1.10813, -0.07276, 22 | -0.07367, -0.00605, 1.07602, 23 | ); 24 | 25 | function RRTAndODTFit( v: GLSLExpression<'vec3'> ): GLSLExpression<'vec3'> { 26 | const a = sub( mul( v, add( v, 0.0245786 ) ), 0.000090537 ); 27 | const b = add( mul( v, add( mul( 0.983729, v ), 0.4329510 ) ), 0.238081 ); 28 | return div( a, b ); 29 | } 30 | 31 | export function tonemapACESHill( 32 | sRGB: GLSLExpression<'vec3'>, 33 | ): GLSLExpression<'vec3'> { 34 | const input = mul( ACESInputMat, sRGB ); 35 | const fitted = RRTAndODTFit( input ); 36 | const output = mul( ACESOutputMat, fitted ); 37 | return glslSaturate( output ); 38 | } 39 | -------------------------------------------------------------------------------- /src/shaders/modules/pcg2d.ts: -------------------------------------------------------------------------------- 1 | /* ! 2 | * pcg2d 3 | * 4 | * Appearance: 5 | * Mark Jarzynski and Marc Olano, Hash Functions for GPU Rendering, 6 | * Journal of Computer Graphics Techniques (JCGT), vol. 9, no. 3, 21-38, 2020 7 | * 8 | * Ref: https://jcgt.org/published/0009/03/02/ 9 | * Ref: https://www.shadertoy.com/view/XlGcRh 10 | */ 11 | 12 | import { GLSLExpression, add, addAssign, assign, cache, defFn, mul, retFn, rshift, sw, xorAssign } from '../shaderBuilder'; 13 | import { pcgMagic1, pcgMagic2 } from './pcg3d'; 14 | 15 | type Uint = GLSLExpression<'uint'>; 16 | 17 | const symbol = Symbol(); 18 | 19 | export function pcg2d( 20 | v: GLSLExpression<'uvec2'>, 21 | ): GLSLExpression<'uvec2'> { 22 | const f = cache( symbol, () => defFn( 'uvec2', [ 'uvec2' ], ( v ) => { 23 | assign( v, add( mul( v, pcgMagic1 ), pcgMagic2 ) ); 24 | 25 | addAssign( sw( v, 'x' ), mul( sw( v, 'y' ), pcgMagic1 ) ); 26 | addAssign( sw( v, 'y' ), mul( sw( v, 'x' ), pcgMagic1 ) ); 27 | 28 | xorAssign( v, rshift( v, '16u' as Uint ) ); 29 | 30 | addAssign( sw( v, 'x' ), mul( sw( v, 'y' ), pcgMagic1 ) ); 31 | addAssign( sw( v, 'y' ), mul( sw( v, 'x' ), pcgMagic1 ) ); 32 | 33 | xorAssign( v, rshift( v, '16u' as Uint ) ); 34 | 35 | retFn( v ); 36 | } ) ); 37 | 38 | return f( v ); 39 | } 40 | -------------------------------------------------------------------------------- /src/nodes/WormTunnelScene/WormTunnel/WormTunnel.ts: -------------------------------------------------------------------------------- 1 | import { GL_FRONT, GL_TEXTURE_2D } from '../../../gl/constants'; 2 | import { RaymarcherNode } from '../../utils/RaymarcherNode'; 3 | import { cellTextureTarget } from '../../../textures/cellTextureTarget'; 4 | import { genCylinder } from '../../../geometries/genCylinder'; 5 | import { objectVert } from '../../../shaders/common/objectVert'; 6 | import { wormTunnelFrag } from './shaders/wormTunnelFrag'; 7 | 8 | export class WormTunnel extends RaymarcherNode { 9 | public constructor() { 10 | const geometry = genCylinder( { 11 | height: -100.0, 12 | radius: 0.1, 13 | } ); 14 | 15 | super( wormTunnelFrag, { geometry } ); 16 | 17 | this.materials.deferred.addUniformTextures( 18 | 'sampler0', 19 | GL_TEXTURE_2D, 20 | cellTextureTarget.texture, 21 | ); 22 | 23 | this.mesh.cull = GL_FRONT; 24 | 25 | if ( import.meta.hot ) { 26 | import.meta.hot.accept( 27 | './shaders/wormTunnelFrag', 28 | ( { wormTunnelFrag } ) => { 29 | const { deferred, depth } = this.materials; 30 | 31 | deferred.replaceShader( objectVert, wormTunnelFrag( 'deferred' ) ); 32 | depth.replaceShader( objectVert, wormTunnelFrag( 'depth' ) ); 33 | }, 34 | ); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/nodes/CameraStack/DoF/shaders/dofPresortFrag.ts: -------------------------------------------------------------------------------- 1 | import { assign, build, def, defInNamed, defOut, defUniformNamed, div, insert, main, min, mul, neg, smoothstep, sq, sub, sw, texture, vec4 } from '../../../../shaders/shaderBuilder'; 2 | import { dofCalcCoC } from './dofCalcCoC'; 3 | import { invCalcDepth } from '../../../../shaders/modules/invCalcDepth'; 4 | 5 | export const dofPresortFrag = build( () => { 6 | insert( 'precision highp float;' ); 7 | 8 | const vUv = defInNamed( 'vec2', 'vUv' ); 9 | const fragColor = defOut( 'vec4' ); 10 | 11 | const sampler0 = defUniformNamed( 'sampler2D', 'sampler0' ); 12 | const samplerTile = defUniformNamed( 'sampler2D', 'samplerTile' ); 13 | 14 | main( () => { 15 | const tex0 = def( 'vec4', texture( sampler0, vUv ) ); 16 | const texTile = def( 'vec4', texture( samplerTile, vUv ) ); 17 | const depth = def( 'float', neg( invCalcDepth( sw( tex0, 'w' ) ) ) ); 18 | 19 | const coc = def( 'float', dofCalcCoC( depth ) ); 20 | 21 | const alpha = min( div( 1.0, sq( coc ) ), 1.0 ); 22 | 23 | const bg = def( 'float', smoothstep( 0.0, 5.0, sub( depth, sw( texTile, 'x' ) ) ) ); 24 | 25 | assign( fragColor, vec4( 26 | coc, 27 | mul( alpha, bg ), // bg 28 | mul( alpha, sub( 1.0, bg ) ), // fg 29 | 1.0, 30 | ) ); 31 | } ); 32 | } ); 33 | -------------------------------------------------------------------------------- /src/shaders/modules/cyclicNoise.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, addAssign, cache, cos, cross, def, defFn, div, mul, mulAssign, num, retFn, sin, sw, unrollLoop, vec3, vec4 } from '../shaderBuilder'; 2 | import { orthBas } from './orthBas'; 3 | 4 | const symbol = Symbol(); 5 | 6 | export function cyclicNoise( p: GLSLExpression<'vec3'>, { 7 | rot = vec3( -1.0 ), 8 | pump = 2.0, 9 | freq = 2.0, 10 | warp = 1.0, 11 | }: { 12 | rot?: GLSLExpression<'vec3'>, 13 | pump?: GLSLFloatExpression, 14 | freq?: GLSLFloatExpression, 15 | warp?: GLSLFloatExpression, 16 | } = {} ): GLSLExpression<'vec3'> { 17 | const f = cache( symbol, () => defFn( 18 | 'vec3', 19 | [ 'vec3', 'vec3', 'float', 'float', 'float' ], 20 | ( p, rot, pump, freq, warp ) => { 21 | const b = def( 'mat3', orthBas( rot ) ); 22 | const accum = def( 'vec4', vec4( 0.0 ) ); 23 | unrollLoop( 6, () => { 24 | mulAssign( p, mul( b, freq ) ); 25 | addAssign( p, mul( warp, sin( sw( p, 'zxy' ) ) ) ); 26 | addAssign( accum, vec4( cross( cos( p ), sin( sw( p, 'yzx' ) ) ), 1.0 ) ); 27 | mulAssign( accum, pump ); 28 | } ); 29 | retFn( div( sw( accum, 'xyz' ), sw( accum, 'w' ) ) ); 30 | }, 31 | ) ); 32 | 33 | return f( p, rot, num( pump ), num( freq ), num( warp ) ); 34 | } 35 | -------------------------------------------------------------------------------- /src/nodes/TrailsScene/TrailsScene.ts: -------------------------------------------------------------------------------- 1 | import { CameraStack } from '../CameraStack/CameraStack'; 2 | import { PointLightNode } from '../Lights/PointLightNode'; 3 | import { SceneNode } from '../../heck/components/SceneNode'; 4 | import { Trails } from './Trails/Trails'; 5 | import { cameraStackATarget } from '../../globals/cameraStackTargets'; 6 | import { mainCameraStackResources } from '../CameraStack/mainCameraStackResources'; 7 | import { swapShadowMap1 } from '../../globals/swapShadowMap'; 8 | 9 | export class TrailsScene extends SceneNode { 10 | public constructor() { 11 | super(); 12 | 13 | const scene = this; 14 | 15 | const light1 = new PointLightNode( { 16 | scene, 17 | swapShadowMap: swapShadowMap1, 18 | } ); 19 | light1.transform.lookAt( [ 3.0, 3.0, 3.0 ] ); 20 | light1.color = [ 100.0, 100.0, 100.0 ]; 21 | 22 | const trails = new Trails(); 23 | 24 | const camera = new CameraStack( { 25 | scene, 26 | resources: mainCameraStackResources, 27 | target: cameraStackATarget, 28 | useAO: true, 29 | dofParams: [ 1.0, 12.0 ], 30 | } ); 31 | camera.transform.lookAt( 32 | [ 0.0, 0.0, 2.0 ], 33 | [ 0.0, 0.0, 0.0 ], 34 | -0.4 35 | ); 36 | 37 | this.children = [ 38 | light1, 39 | trails, 40 | camera, 41 | ]; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/nodes/MetaballScene/defMetaballMap.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, add, assign, def, defFn, length, mad, mul, retFn, sin, sub, sw, unrollLoop, vec3, vec4 } from '../../shaders/shaderBuilder'; 2 | import { TAU } from '../../utils/constants'; 3 | import { pcg3df } from '../../shaders/modules/pcg3df'; 4 | import { smin } from '../../shaders/modules/smin'; 5 | 6 | export const defMetaballMap: { 7 | ( time: GLSLExpression<'float'> ): ( p: GLSLExpression<'vec3'> ) => GLSLExpression<'vec4'>; 8 | } = ( time ) => { 9 | return defFn( 'vec4', [ 'vec3' ], ( p ) => { 10 | const pt = def( 'vec3', p ); 11 | const d = def( 'float', sub( length( pt ), 0.15 ) ); 12 | 13 | const off = def( 'vec3' ); 14 | const radius = def( 'vec3' ); 15 | 16 | unrollLoop( 7, ( i ) => { 17 | assign( off, sin( vec3( mad( 18 | add( 0.5, pcg3df( vec3( i + 20 ) ) ), 19 | time, 20 | mul( TAU, pcg3df( vec3( i ) ) ), 21 | ) ) ) ); 22 | 23 | assign( radius, mad( 0.07, pcg3df( vec3( i + 40 ) ), 0.05 ) ); 24 | 25 | assign( pt, mad( 0.2, off, p ) ); 26 | assign( d, smin( d, sub( length( pt ), sw( radius, 'x' ) ), 0.15 ) ); 27 | 28 | assign( pt, mad( -0.2, off, p ) ); 29 | assign( d, smin( d, sub( length( pt ), sw( radius, 'y' ) ), 0.15 ) ); 30 | } ); 31 | 32 | retFn( vec4( d, 0, 0, 0 ) ); 33 | } ); 34 | }; 35 | -------------------------------------------------------------------------------- /src/nodes/KansokushaScene/assets/kansokusha.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/nodes/FluidScene/shaders/fluidAdvectionFrag.ts: -------------------------------------------------------------------------------- 1 | import { assign, build, def, defInNamed, defOut, defUniformNamed, exp, insert, main, mul, sub, sw, vec4 } from '../../../shaders/shaderBuilder'; 2 | import { defFluidSampleLinear3D } from './defFluidSampleLinear3D'; 3 | import { defFluidSampleNearest3D } from './defFluidSampleNearest3D'; 4 | import { fluidClampToGrid } from './fluidClampToGrid'; 5 | import { fluidUvToPos } from './fluidUvToPos'; 6 | 7 | export const fluidAdvectionFrag: string = build( () => { 8 | insert( 'precision highp float;' ); 9 | 10 | const vUv = defInNamed( 'vec2', 'vUv' ); 11 | 12 | const fragColor = defOut( 'vec4' ); 13 | 14 | const deltaTime = defUniformNamed( 'float', 'deltaTime' ); 15 | const samplerDensity = defUniformNamed( 'sampler2D', 'samplerDensity' ); 16 | 17 | const sampleNearest3D = defFluidSampleNearest3D(); 18 | const sampleLinear3D = defFluidSampleLinear3D(); 19 | 20 | main( () => { 21 | const pos = def( 'vec3', fluidUvToPos( vUv ) ); 22 | 23 | const vel = sw( sampleNearest3D( samplerDensity, pos ), 'xyz' ); 24 | const samplePos = fluidClampToGrid( sub( pos, mul( deltaTime, vel ) ) ); 25 | const result = sampleLinear3D( samplerDensity, samplePos ); 26 | 27 | const decay = exp( mul( deltaTime, vec4( 0.0, 0.0, 0.0, -1.0 ) ) ); 28 | 29 | assign( fragColor, mul( result, decay ) ); 30 | } ); 31 | } ); 32 | -------------------------------------------------------------------------------- /src/globals/swapShadowMap.ts: -------------------------------------------------------------------------------- 1 | import { BufferTextureRenderTarget } from '../heck/BufferTextureRenderTarget'; 2 | import { GLTextureFormatStuffRG16F } from '../gl/glSetTexture'; 3 | import { Swap } from '@0b5vr/experimental'; 4 | 5 | const SHADOW_MAP_SIZE = 1024; 6 | 7 | export const swapShadowMap1 = new Swap( 8 | new BufferTextureRenderTarget( SHADOW_MAP_SIZE, SHADOW_MAP_SIZE, 1, GLTextureFormatStuffRG16F ), 9 | new BufferTextureRenderTarget( SHADOW_MAP_SIZE, SHADOW_MAP_SIZE, 1, GLTextureFormatStuffRG16F ), 10 | ); 11 | 12 | export const swapShadowMap2 = new Swap( 13 | new BufferTextureRenderTarget( SHADOW_MAP_SIZE, SHADOW_MAP_SIZE, 1, GLTextureFormatStuffRG16F ), 14 | new BufferTextureRenderTarget( SHADOW_MAP_SIZE, SHADOW_MAP_SIZE, 1, GLTextureFormatStuffRG16F ), 15 | ); 16 | 17 | export const swapShadowMap3 = new Swap( 18 | new BufferTextureRenderTarget( SHADOW_MAP_SIZE, SHADOW_MAP_SIZE, 1, GLTextureFormatStuffRG16F ), 19 | new BufferTextureRenderTarget( SHADOW_MAP_SIZE, SHADOW_MAP_SIZE, 1, GLTextureFormatStuffRG16F ), 20 | ); 21 | 22 | if ( import.meta.env.DEV ) { 23 | swapShadowMap1.i.name = 'swapShadowMap1/0'; 24 | swapShadowMap1.o.name = 'swapShadowMap1/1'; 25 | swapShadowMap2.i.name = 'swapShadowMap2/0'; 26 | swapShadowMap2.o.name = 'swapShadowMap2/1'; 27 | swapShadowMap3.i.name = 'swapShadowMap3/0'; 28 | swapShadowMap3.o.name = 'swapShadowMap3/1'; 29 | } 30 | -------------------------------------------------------------------------------- /src/nodes/KansokushaScene/shaders/kansokushaFrag.ts: -------------------------------------------------------------------------------- 1 | import { addAssign, assign, build, def, defInNamed, defOut, defUniformNamed, floor, fract, insert, mad, main, mod, mul, mulAssign, step, sub, subAssign, sw, texture, vec2, vec4 } from '../../../shaders/shaderBuilder'; 2 | 3 | export const kansokushaFrag = build( () => { 4 | insert( 'precision highp float;' ); 5 | 6 | const vUv = defInNamed( 'vec2', 'vUv' ); 7 | const fragColor = defOut( 'vec4' ); 8 | 9 | const time = defUniformNamed( 'float', 'time' ); 10 | const aspect = defUniformNamed( 'float', 'aspect' ); 11 | const sampler0 = defUniformNamed( 'sampler2D', 'sampler0' ); 12 | 13 | main( () => { 14 | const uv = def( 'vec2', vUv ); 15 | mulAssign( uv, vec2( aspect, 3.0 ) ); 16 | subAssign( sw( uv, 'x' ), 0.5 ); 17 | 18 | // scroll 19 | const dir = sub( mod( floor( sw( uv, 'y' ) ), 2.0 ), 0.5 ); 20 | addAssign( sw( uv, 'x' ), mul( 0.5, time, dir ) ); 21 | 22 | // flash 23 | const phase = def( 'float', time ); 24 | addAssign( phase, mul( 0.14, dir, floor( sw( uv, 'x' ) ) ) ); 25 | addAssign( phase, mul( 0.21, floor( sw( uv, 'y' ) ) ) ); 26 | 27 | assign( uv, fract( uv ) ); 28 | 29 | const tex = def( 'vec4', texture( sampler0, uv ) ); 30 | const shape = mad( sw( tex, 'x' ), step( fract( phase ), 0.07 ), sw( tex, 'y' ) ); 31 | assign( fragColor, vec4( shape ) ); 32 | } ); 33 | } ); 34 | -------------------------------------------------------------------------------- /src/nodes/CameraStack/DoF/shaders/dofPostFrag.ts: -------------------------------------------------------------------------------- 1 | import { abs, add, addAssign, assign, band, build, def, defInNamed, defOut, defUniformNamed, div, float, forLoop, insert, int, main, mix, rshift, sub, sw, texture, vec2, vec4 } from '../../../../shaders/shaderBuilder'; 2 | import { glslSaturate } from '../../../../shaders/modules/glslSaturate'; 3 | 4 | export const dofPostFrag = build( () => { 5 | insert( 'precision highp float;' ); 6 | 7 | const vUv = defInNamed( 'vec2', 'vUv' ); 8 | const fragColor = defOut( 'vec4' ); 9 | 10 | const resolution = defUniformNamed( 'vec2', 'resolution' ); 11 | const sampler0 = defUniformNamed( 'sampler2D', 'sampler0' ); 12 | const sampler1 = defUniformNamed( 'sampler2D', 'sampler1' ); 13 | const samplerPresort = defUniformNamed( 'sampler2D', 'samplerPresort' ); 14 | 15 | main( () => { 16 | const wetSum = def( 'vec4', vec4( 0.0 ) ); 17 | 18 | forLoop( 4, ( i ) => { 19 | const off = div( 20 | sub( vec2( 21 | float( band( i, int( 1 ) ) ), 22 | float( rshift( i, int( 1 ) ) ), 23 | ), 0.5 ), 24 | resolution, 25 | ); 26 | addAssign( wetSum, texture( sampler1, add( off, vUv ) ) ); 27 | } ); 28 | 29 | assign( fragColor, mix( 30 | texture( sampler0, vUv ), 31 | div( wetSum, 4.0 ), 32 | glslSaturate( abs( sw( texture( samplerPresort, vUv ), 'x' ) ) ), 33 | ) ); 34 | } ); 35 | } ); 36 | -------------------------------------------------------------------------------- /src/shaders/modules/glslDefRandom.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLToken, assign, cache, defFn, defGlobal, div, float, floatBitsToUint, retFn, sw, vec4 } from '../shaderBuilder'; 2 | import { pcg4d } from './pcg4d'; 3 | 4 | const symbolSeed = Symbol(); 5 | const symbolRandom4 = Symbol(); 6 | const symbolInitRandom = Symbol(); 7 | 8 | export function glslDefRandom(): { 9 | random: () => GLSLExpression<'float'>, 10 | random2: () => GLSLExpression<'vec2'>, 11 | random3: () => GLSLExpression<'vec3'>, 12 | random4: () => GLSLExpression<'vec4'>, 13 | seed: GLSLToken<'uvec4'>, 14 | init: ( seed: GLSLExpression<'vec4'> ) => void, 15 | } { 16 | const seed = cache( symbolSeed, () => defGlobal( 'uvec4' ) ); 17 | 18 | const random4 = cache( symbolRandom4, () => defFn( 'vec4', [], () => { 19 | assign( seed, pcg4d( seed ) ); 20 | retFn( div( vec4( seed ), float( '0xffffffffu' as GLSLExpression<'uint'> ) ) ); 21 | } ) ); 22 | 23 | const random = (): GLSLExpression<'float'> => sw( random4(), 'x' ); 24 | const random2 = (): GLSLExpression<'vec2'> => sw( random4(), 'xy' ); 25 | const random3 = (): GLSLExpression<'vec3'> => sw( random4(), 'xyz' ); 26 | 27 | const init = cache( 28 | symbolInitRandom, 29 | () => ( _seed: GLSLExpression<'vec4'> ) => { 30 | assign( seed, floatBitsToUint( _seed ) ); 31 | } 32 | ); 33 | 34 | return { random, random2, random3, random4, seed, init }; 35 | } 36 | -------------------------------------------------------------------------------- /src/nodes/SevenSegScene/shaders/sevenSegFrag.ts: -------------------------------------------------------------------------------- 1 | import { MTL_PBR_ROUGHNESS_METALLIC } from '../../CameraStack/deferredConstants'; 2 | import { add, assign, build, defInNamed, defOut, discard, div, ifThen, insert, lt, main, mul, normalize, sw, vec4 } from '../../../shaders/shaderBuilder'; 3 | import { bayerPattern4 } from '../../../shaders/modules/bayerPattern4'; 4 | 5 | export const sevenSegFrag = build( () => { 6 | insert( 'precision highp float;' ); 7 | 8 | const vPosition = defInNamed( 'vec4', 'vPosition' ); 9 | const vProjPosition = defInNamed( 'vec4', 'vProjPosition' ); 10 | const vNormal = defInNamed( 'vec3', 'vNormal' ); 11 | const vEmit = defInNamed( 'float', 'vEmit' ); 12 | 13 | const fragColor = defOut( 'vec4' ); 14 | const fragPosition = defOut( 'vec4', 1 ); 15 | const fragNormal = defOut( 'vec4', 2 ); 16 | const fragMisc = defOut( 'vec4', 3 ); 17 | 18 | main( () => { 19 | const depth = div( sw( vProjPosition, 'z' ), sw( vProjPosition, 'w' ) ); 20 | 21 | ifThen( 22 | lt( add( div( bayerPattern4(), 16.0 ), sw( vProjPosition, 'z' ) ), 2.0 ), 23 | () => discard(), 24 | ); 25 | 26 | assign( fragColor, vec4( 0.04, 0.04, 0.04, 1.0 ) ); 27 | assign( fragPosition, vec4( sw( vPosition, 'xyz' ), depth ) ); 28 | assign( fragNormal, vec4( normalize( vNormal ), MTL_PBR_ROUGHNESS_METALLIC ) ); 29 | assign( fragMisc, vec4( 0.5, 0.0, mul( 40.0, vEmit ), 0.0 ) ); 30 | return; 31 | } ); 32 | } ); 33 | -------------------------------------------------------------------------------- /src/shaders/modules/brdfClearcoat.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, add, cache, def, defFn, dot, float, max, mul, normalize, num, retFn, vec3, vec4 } from '../shaderBuilder'; 2 | import { dGGX } from './dGGX'; 3 | import { fresnelSchlick } from './fresnelSchlick'; 4 | import { vKelemen } from './vKelemen'; 5 | 6 | const symbol = Symbol(); 7 | 8 | /** 9 | * the fourth component of return value is fresnel term, 10 | * intended to be used for energy conservation funnies 11 | */ 12 | export function brdfClearcoat( 13 | L: GLSLExpression<'vec3'>, 14 | V: GLSLExpression<'vec3'>, 15 | N: GLSLExpression<'vec3'>, 16 | roughness: GLSLFloatExpression, 17 | ): GLSLExpression<'vec4'> { 18 | const f = cache( 19 | symbol, 20 | () => defFn( 21 | 'vec4', 22 | [ 'vec3', 'vec3', 'vec3', 'float' ], 23 | ( L, V, N, roughness ) => { 24 | const H = def( 'vec3', normalize( add( L, V ) ) ); 25 | const dotNH = def( 'float', max( dot( N, H ), 0.0 ) ); 26 | const dotVH = def( 'float', max( dot( V, H ), 0.0 ) ); 27 | 28 | const roughnessSq = mul( roughness, roughness ); 29 | 30 | const F = fresnelSchlick( dotVH, float( 0.04 ), float( 1.0 ) ); 31 | const Vis = vKelemen( dotVH ); 32 | const D = dGGX( dotNH, roughnessSq ); 33 | 34 | retFn( vec4( vec3( mul( F, Vis, D ) ), F ) ); 35 | } 36 | ) 37 | ); 38 | 39 | return f( L, V, N, num( roughness ) ); 40 | } 41 | -------------------------------------------------------------------------------- /src/shaders/modules/pcg3d.ts: -------------------------------------------------------------------------------- 1 | /* ! 2 | * pcg3d 3 | * 4 | * Appearance: 5 | * Mark Jarzynski and Marc Olano, Hash Functions for GPU Rendering, 6 | * Journal of Computer Graphics Techniques (JCGT), vol. 9, no. 3, 21-38, 2020 7 | * 8 | * Ref: https://jcgt.org/published/0009/03/02/ 9 | * Ref: https://www.shadertoy.com/view/XlGcRh 10 | */ 11 | 12 | import { GLSLExpression, add, addAssign, assign, cache, defFn, mul, retFn, rshift, sw, xorAssign } from '../shaderBuilder'; 13 | 14 | type Uint = GLSLExpression<'uint'>; 15 | 16 | const symbol = Symbol(); 17 | 18 | export const pcgMagic1 = '1664525u' as Uint; 19 | export const pcgMagic2 = '1013904223u' as Uint; 20 | 21 | export function pcg3d( 22 | v: GLSLExpression<'uvec3'>, 23 | ): GLSLExpression<'uvec3'> { 24 | const f = cache( symbol, () => defFn( 'uvec3', [ 'uvec3' ], ( v ) => { 25 | assign( v, add( mul( v, pcgMagic1 ), pcgMagic2 ) ); 26 | 27 | addAssign( sw( v, 'x' ), mul( sw( v, 'y' ), sw( v, 'z' ) ) ); 28 | addAssign( sw( v, 'y' ), mul( sw( v, 'z' ), sw( v, 'x' ) ) ); 29 | addAssign( sw( v, 'z' ), mul( sw( v, 'x' ), sw( v, 'y' ) ) ); 30 | 31 | xorAssign( v, rshift( v, '16u' as Uint ) ); 32 | 33 | addAssign( sw( v, 'x' ), mul( sw( v, 'y' ), sw( v, 'z' ) ) ); 34 | addAssign( sw( v, 'y' ), mul( sw( v, 'z' ), sw( v, 'x' ) ) ); 35 | addAssign( sw( v, 'z' ), mul( sw( v, 'x' ), sw( v, 'y' ) ) ); 36 | 37 | retFn( v ); 38 | } ) ); 39 | 40 | return f( v ); 41 | } 42 | -------------------------------------------------------------------------------- /src/geometries/genWireCube.ts: -------------------------------------------------------------------------------- 1 | import { GL_LINES } from '../gl/constants'; 2 | import { Geometry } from '../heck/Geometry'; 3 | import { glCreateVertexbuffer } from '../gl/glCreateVertexbuffer'; 4 | import { glVertexArrayBindVertexbuffer } from '../gl/glVertexArrayBindVertexbuffer'; 5 | 6 | export function genWireCube( dimension?: [ number, number, number ] ): Geometry { 7 | const [ x, y, z ] = dimension ?? [ 1, 1, 1 ]; 8 | 9 | const arrayPosition = [ 10 | -x, -y, z, 11 | x, -y, z, 12 | x, -y, z, 13 | x, y, z, 14 | x, y, z, 15 | -x, y, z, 16 | -x, y, z, 17 | -x, -y, z, 18 | 19 | -x, -y, -z, 20 | x, -y, -z, 21 | x, -y, -z, 22 | x, y, -z, 23 | x, y, -z, 24 | -x, y, -z, 25 | -x, y, -z, 26 | -x, -y, -z, 27 | 28 | -x, -y, z, 29 | -x, -y, -z, 30 | x, -y, z, 31 | x, -y, -z, 32 | x, y, z, 33 | x, y, -z, 34 | -x, y, z, 35 | -x, y, -z, 36 | ]; 37 | 38 | // -- buffers ------------------------------------------------------------------------------------ 39 | const position = glCreateVertexbuffer( new Float32Array( arrayPosition ) ); 40 | 41 | // -- geometry ----------------------------------------------------------------------------------- 42 | const geometry = new Geometry(); 43 | geometry.count = arrayPosition.length / 3; 44 | geometry.mode = GL_LINES; 45 | 46 | glVertexArrayBindVertexbuffer( geometry.vao, position, 0, 3 ); 47 | 48 | return geometry; 49 | } 50 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "glsl-techno-set", 3 | "private": true, 4 | "version": "0.0.0", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "yarn build-js && yarn build-comp", 8 | "build-js": "vite build --mode prod", 9 | "build-comp": "node bin/compeko.js dist/assets/index.*.js dist/compeko.html", 10 | "lint": "eslint \"src/**/*.ts\"", 11 | "lint-fix": "eslint \"src/**/*.ts\" --fix", 12 | "typecheck": "tsc", 13 | "preview": "vite preview" 14 | }, 15 | "devDependencies": { 16 | "@0b5vr/automaton": "^4.3.0-alpha.3", 17 | "@0b5vr/automaton-with-gui": "^4.3.0-alpha.3", 18 | "@0b5vr/experimental": "^0.9.5", 19 | "@0b5vr/imtweakpane": "^0.1.3", 20 | "@0b5vr/tweakpane-plugin-profiler": "^0.3.0", 21 | "@tweakpane/core": "^1.1.2", 22 | "@types/glob": "^7.2.0", 23 | "@types/node-zopfli": "^2.0.2", 24 | "@types/terser": "^3.12.0", 25 | "@types/webxr": "^0.2.3", 26 | "@typescript-eslint/eslint-plugin": "^5.30.6", 27 | "@typescript-eslint/parser": "^5.30.6", 28 | "eslint": "^8.14.0", 29 | "eslint-plugin-sort-imports-es6-autofix": "^0.6.0", 30 | "glob": "^8.0.1", 31 | "glob-promise": "^4.2.2", 32 | "node-zopfli": "^2.1.4", 33 | "rollup-plugin-visualizer": "^5.6.0", 34 | "terser": "^5.14.2", 35 | "tweakpane": "^3.1.2", 36 | "typescript": "^4.5.4", 37 | "vite": "^2.9.12", 38 | "vite-plugin-inspect": "^0.6.0", 39 | "webgl-memory": "^1.0.11" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/nodes/utils/CanvasTexture.ts: -------------------------------------------------------------------------------- 1 | import { GL_CLAMP_TO_EDGE, GL_LINEAR } from '../../gl/constants'; 2 | import { gl } from '../../globals/canvas'; 3 | import { glSetTextureFromBitmap } from '../../gl/glSetTextureFromBitmap'; 4 | import { glTextureFilter } from '../../gl/glTextureFilter'; 5 | import { glTextureWrap } from '../../gl/glTextureWrap'; 6 | 7 | export class CanvasTexture { 8 | public canvas: HTMLCanvasElement; 9 | public context: CanvasRenderingContext2D; 10 | public texture: WebGLTexture; 11 | 12 | public get width(): number { 13 | return this.canvas.width; 14 | } 15 | 16 | public get height(): number { 17 | return this.canvas.height; 18 | } 19 | 20 | public constructor( width: number, height: number ) { 21 | this.canvas = document.createElement( 'canvas' ); 22 | this.canvas.width = width; 23 | this.canvas.height = height; 24 | 25 | this.context = this.canvas.getContext( '2d' )!; 26 | 27 | this.texture = gl.createTexture()!; 28 | glTextureFilter( this.texture, GL_LINEAR ); 29 | glTextureWrap( this.texture, GL_CLAMP_TO_EDGE ); 30 | } 31 | 32 | public clear(): void { 33 | this.context.clearRect( 0, 0, this.width, this.height ); 34 | } 35 | 36 | public updateTexture(): void { 37 | glSetTextureFromBitmap( this.texture, this.canvas ); 38 | } 39 | 40 | public resize( width: number, height: number ): void { 41 | this.canvas.width = width; 42 | this.canvas.height = height; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/nodes/WireCubeScene/WireCubeScene.ts: -------------------------------------------------------------------------------- 1 | import { CameraStack } from '../CameraStack/CameraStack'; 2 | import { InstancedLines } from '../utils/InstancedLines'; 3 | import { SceneNode } from '../../heck/components/SceneNode'; 4 | import { cameraStackBTarget } from '../../globals/cameraStackTargets'; 5 | import { mainCameraStackResources } from '../CameraStack/mainCameraStackResources'; 6 | import { wireCubeVert } from './shaders/wireCubeVert'; 7 | 8 | export class WireCubeScene extends SceneNode { 9 | public constructor() { 10 | super(); 11 | 12 | // -- lines ------------------------------------------------------------------------------------ 13 | const lines = new InstancedLines( wireCubeVert, 2, 12 * 20 ); 14 | 15 | if ( import.meta.hot ) { 16 | import.meta.hot.accept( 17 | './shaders/wireCubeVert', 18 | ( { wireCubeVert } ) => { 19 | lines.materials.deferred!.replaceShader( wireCubeVert ); 20 | } 21 | ); 22 | } 23 | 24 | // -- camera proxy ----------------------------------------------------------------------------- 25 | const camera = new CameraStack( { 26 | scene: this, 27 | resources: mainCameraStackResources, 28 | target: cameraStackBTarget, 29 | fog: [ 0.0, 3.0, 7.0 ], 30 | } ); 31 | 32 | // -- children --------------------------------------------------------------------------------- 33 | this.children = [ 34 | lines, 35 | camera, 36 | ]; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/nodes/CubemapNode/shaders/cubemapMergeFrag.ts: -------------------------------------------------------------------------------- 1 | import { add, addAssign, assign, build, def, defInNamed, defOutNamed, defUniformNamed, discard, div, floor, forBreak, forLoop, gt, ifThen, insert, log2, main, min, mul, neg, pow, sub, sw, tern, texture, vec4 } from '../../../shaders/shaderBuilder'; 2 | 3 | export const cubemapMergeFrag = build( () => { 4 | insert( 'precision highp float;' ); 5 | 6 | const vUv = defInNamed( 'vec2', 'vUv' ); 7 | const fragColor = defOutNamed( 'vec4', 'fragColor' ); 8 | const samplerCubemap = defUniformNamed( 'sampler2D', 'samplerCubemap' ); 9 | 10 | main( () => { 11 | const lv = def( 'float', floor( neg( log2( sub( 1.0, sw( vUv, 'y' ) ) ) ) ) ); 12 | addAssign( lv, 1.0 ); 13 | assign( lv, min( lv, 5.0 ) ); 14 | 15 | const p = pow( 2.0, lv ); 16 | const pInv = div( 1.0, p ); 17 | 18 | const uv = def( 'vec2', vUv ); 19 | const uvx = sw( uv, 'x' ); 20 | 21 | ifThen( gt( mul( p, uvx ), 1.0 ), () => discard() ); 22 | 23 | const accum = def( 'vec4', texture( samplerCubemap, uv ) ); 24 | 25 | forLoop( 31, () => { 26 | add( uvx, pInv ); 27 | ifThen( gt( uvx, 1.0 ), () => forBreak() ); 28 | addAssign( accum, texture( samplerCubemap, uv ) ); 29 | } ); 30 | 31 | const accumw = sw( accum, 'w' ); 32 | assign( accum, tern( 33 | gt( accumw, 0.001 ), 34 | div( accum, accumw ), 35 | vec4( 0.0, 0.0, 0.0, 1.0 ), 36 | ) ); 37 | 38 | assign( fragColor, accum ); 39 | } ); 40 | } ); 41 | -------------------------------------------------------------------------------- /src/nodes/LineRings3DScene/LineRings3DScene.ts: -------------------------------------------------------------------------------- 1 | import { CameraStack } from '../CameraStack/CameraStack'; 2 | import { InstancedLines } from '../utils/InstancedLines'; 3 | import { SceneNode } from '../../heck/components/SceneNode'; 4 | import { cameraStackBTarget } from '../../globals/cameraStackTargets'; 5 | import { lineRings3DVert } from './shaders/lineRings3DVert'; 6 | import { mainCameraStackResources } from '../CameraStack/mainCameraStackResources'; 7 | 8 | export class LineRings3DScene extends SceneNode { 9 | public constructor() { 10 | super(); 11 | 12 | // -- lines ------------------------------------------------------------------------------------ 13 | const lines = new InstancedLines( lineRings3DVert, 256, 100 ); 14 | 15 | if ( import.meta.hot ) { 16 | import.meta.hot.accept( 17 | './shaders/lineRings3DVert', 18 | ( { lineRings3DVert } ) => { 19 | lines.materials.deferred!.replaceShader( lineRings3DVert ); 20 | } 21 | ); 22 | } 23 | 24 | // -- camera proxy ----------------------------------------------------------------------------- 25 | const camera = new CameraStack( { 26 | scene: this, 27 | resources: mainCameraStackResources, 28 | target: cameraStackBTarget, 29 | fog: [ 0.0, 1.0, 10.0 ], 30 | } ); 31 | 32 | // -- children --------------------------------------------------------------------------------- 33 | this.children = [ 34 | lines, 35 | camera, 36 | ]; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/shaders/modules/voronoi3d.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, add, assign, cache, def, defFn, floor, forLoop, ifThen, lt, num, retFn, sub, vec3, vec4 } from '../shaderBuilder'; 2 | import { minkowski3d } from './minkowski3d'; 3 | import { pcg3df } from './pcg3df'; 4 | 5 | const symbol = Symbol(); 6 | 7 | /** 8 | * @param v vector 9 | * @param p minzowsky p 10 | * @returns vec4( cellOrigin, len ) 11 | */ 12 | export function voronoi3d( 13 | v: GLSLExpression<'vec3'>, 14 | p: GLSLFloatExpression = 2.0, 15 | ): GLSLExpression<'vec4'> { 16 | const f = cache( symbol, () => defFn( 'vec4', [ 'vec3', 'float' ], ( v, p ) => { 17 | const cell = def( 'vec3', floor( v ) ); 18 | 19 | const nearestCell = def( 'vec3' ); 20 | const nearestLen = def( 'float', 1E9 ); 21 | 22 | forLoop( 3, ( iz ) => { 23 | forLoop( 3, ( iy ) => { 24 | forLoop( 3, ( ix ) => { 25 | const currentCell = add( cell, -1.0, vec3( ix, iy, iz ) ); 26 | const cellOrigin = add( 27 | currentCell, 28 | pcg3df( currentCell ), 29 | ); 30 | 31 | const len = def( 'float', minkowski3d( sub( cellOrigin, v ), p ) ); 32 | 33 | ifThen( lt( len, nearestLen ), () => { 34 | assign( nearestCell, currentCell ); 35 | assign( nearestLen, len ); 36 | } ); 37 | } ); 38 | } ); 39 | } ); 40 | 41 | retFn( vec4( nearestCell, nearestLen ) ); 42 | } ) ); 43 | 44 | return f( v, num( p ) ); 45 | } 46 | -------------------------------------------------------------------------------- /src/nodes/PostStack/Bloom/shaders/bloomUpFrag.ts: -------------------------------------------------------------------------------- 1 | import { add, addAssign, assign, build, clamp, def, defInNamed, defOut, defUniformNamed, div, insert, main, mix, mul, sub, sw, texture, vec4 } from '../../../../shaders/shaderBuilder'; 2 | import { upsampleTap9 } from '../../../../shaders/modules/upsampleTap9'; 3 | 4 | export const bloomUpFrag = build( () => { 5 | insert( 'precision highp float;' ); 6 | 7 | const vUv = defInNamed( 'vec2', 'vUv' ); 8 | 9 | const fragColor = defOut( 'vec4' ); 10 | 11 | const srcRange = defUniformNamed( 'vec4', 'srcRange' ); 12 | const resolution = defUniformNamed( 'vec2', 'resolution' ); 13 | const sampler0 = defUniformNamed( 'sampler2D', 'sampler0' ); 14 | 15 | main( () => { 16 | const deltaTexel = def( 'vec2', div( 1.0, resolution ) ); 17 | 18 | const uv0 = sw( srcRange, 'xy' ); 19 | const uv1 = sw( srcRange, 'zw' ); 20 | const uv = def( 'vec2', mix( uv0, uv1, vUv ) ); 21 | assign( uv, clamp( 22 | uv, 23 | add( uv0, mul( 1.5, deltaTexel ) ), 24 | sub( uv1, mul( 1.5, deltaTexel ) ), 25 | ) ); 26 | 27 | // http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare 28 | const accum = def( 'vec4' ); 29 | upsampleTap9( ( weight, offset ) => { 30 | const tex = texture( sampler0, sub( uv, mul( deltaTexel, offset ) ) ); 31 | addAssign( accum, mul( weight, tex ) ); 32 | } ); 33 | 34 | const col = sw( accum, 'rgb' ); 35 | assign( fragColor, vec4( col, 1.0 ) ); 36 | } ); 37 | } ); 38 | -------------------------------------------------------------------------------- /src/nodes/LineRhombusesScene/LineRhombusesScene.ts: -------------------------------------------------------------------------------- 1 | import { CameraStack } from '../CameraStack/CameraStack'; 2 | import { InstancedLines } from '../utils/InstancedLines'; 3 | import { SceneNode } from '../../heck/components/SceneNode'; 4 | import { cameraStackBTarget } from '../../globals/cameraStackTargets'; 5 | import { lineRhombusesVert } from './shaders/lineRhombusesVert'; 6 | import { mainCameraStackResources } from '../CameraStack/mainCameraStackResources'; 7 | 8 | export class LineRhombusesScene extends SceneNode { 9 | public constructor() { 10 | super(); 11 | 12 | // -- lines ------------------------------------------------------------------------------------ 13 | const lines = new InstancedLines( lineRhombusesVert, 5, 800 ); 14 | 15 | if ( import.meta.hot ) { 16 | import.meta.hot.accept( 17 | './shaders/lineRhombusesVert', 18 | ( { lineRhombusesVert } ) => { 19 | lines.materials.deferred!.replaceShader( lineRhombusesVert ); 20 | } 21 | ); 22 | } 23 | 24 | // -- camera proxy ----------------------------------------------------------------------------- 25 | const camera = new CameraStack( { 26 | scene: this, 27 | resources: mainCameraStackResources, 28 | target: cameraStackBTarget, 29 | fog: [ 0.0, 2.0, 10.0 ], 30 | } ); 31 | 32 | // -- children --------------------------------------------------------------------------------- 33 | this.children = [ 34 | lines, 35 | camera, 36 | ]; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/nodes/LineTriTunnelScene/LineTriTunnelScene.ts: -------------------------------------------------------------------------------- 1 | import { CameraStack } from '../CameraStack/CameraStack'; 2 | import { InstancedLines } from '../utils/InstancedLines'; 3 | import { SceneNode } from '../../heck/components/SceneNode'; 4 | import { cameraStackBTarget } from '../../globals/cameraStackTargets'; 5 | import { lineTriTunnelVert } from './shaders/lineTriTunnelVert'; 6 | import { mainCameraStackResources } from '../CameraStack/mainCameraStackResources'; 7 | 8 | export class LineTriTunnelScene extends SceneNode { 9 | public constructor() { 10 | super(); 11 | 12 | // -- lines ------------------------------------------------------------------------------------ 13 | const lines = new InstancedLines( lineTriTunnelVert, 4, 50 ); 14 | 15 | if ( import.meta.hot ) { 16 | import.meta.hot.accept( 17 | './shaders/lineTriTunnelVert', 18 | ( { lineTriTunnelVert } ) => { 19 | lines.materials.deferred!.replaceShader( lineTriTunnelVert ); 20 | } 21 | ); 22 | } 23 | 24 | // -- camera proxy ----------------------------------------------------------------------------- 25 | const camera = new CameraStack( { 26 | scene: this, 27 | resources: mainCameraStackResources, 28 | target: cameraStackBTarget, 29 | fog: [ 0.0, 2.0, 10.0 ], 30 | } ); 31 | 32 | // -- children --------------------------------------------------------------------------------- 33 | this.children = [ 34 | lines, 35 | camera, 36 | ]; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/nodes/LineWaveScene/LineWaveScene.ts: -------------------------------------------------------------------------------- 1 | import { CameraStack } from '../CameraStack/CameraStack'; 2 | import { InstancedLines } from '../utils/InstancedLines'; 3 | import { SceneNode } from '../../heck/components/SceneNode'; 4 | import { cameraStackBTarget } from '../../globals/cameraStackTargets'; 5 | import { lineWaveVert } from './shaders/lineWaveVert'; 6 | import { mainCameraStackResources } from '../CameraStack/mainCameraStackResources'; 7 | 8 | export class LineWaveScene extends SceneNode { 9 | public constructor() { 10 | super(); 11 | 12 | // -- lines ------------------------------------------------------------------------------------ 13 | const lines = new InstancedLines( lineWaveVert, 512, 512 ); 14 | 15 | if ( import.meta.hot ) { 16 | import.meta.hot.accept( 17 | './shaders/lineWaveVert', 18 | ( { lineWaveVert } ) => { 19 | lines.materials.deferred!.replaceShader( lineWaveVert ); 20 | } 21 | ); 22 | } 23 | 24 | // -- camera proxy ----------------------------------------------------------------------------- 25 | const camera = new CameraStack( { 26 | scene: this, 27 | resources: mainCameraStackResources, 28 | target: cameraStackBTarget, 29 | } ); 30 | camera.transform.lookAt( 31 | [ 0.0, -0.8, 0.8 ], 32 | ); 33 | 34 | // -- children --------------------------------------------------------------------------------- 35 | this.children = [ 36 | lines, 37 | camera, 38 | ]; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/shaders/modules/perlin2d.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, add, cache, cos, def, defFn, dot, floor, mix, mod, mul, retFn, sin, sub, sw, vec2, vec3 } from '../shaderBuilder'; 2 | import { TAU } from '../../utils/constants'; 3 | import { glslSmootherstep } from './glslSmootherstep'; 4 | import { pcg3df } from './pcg3df'; 5 | 6 | const symbol = Symbol(); 7 | 8 | export function perlin2d( v: GLSLExpression<'vec2'>, rep?: GLSLExpression<'vec2'> ): GLSLExpression<'float'> { 9 | const f = cache( symbol, () => defFn( 'float', [ 'vec2', 'vec2' ], ( v, rep ) => { 10 | const cell = floor( v ); 11 | const cellCoord = def( 'vec2', sub( v, cell ) ); 12 | const cellIndex = def( 'vec2', floor( cell ) ); 13 | 14 | const cellCoordS = def( 'vec2', glslSmootherstep( 0.0, 1.0, cellCoord ) ); 15 | 16 | const grad = ( off: GLSLExpression<'vec2'> ): GLSLExpression<'float'> => { 17 | const phi = mul( TAU, sw( pcg3df( vec3( mod( add( cellIndex, off ), rep ), 0.0 ) ), 'x' ) ); 18 | return dot( 19 | vec2( cos( phi ), sin( phi ) ), 20 | sub( cellCoord, off ), 21 | ); 22 | }; 23 | 24 | retFn( mix( 25 | mix( 26 | grad( vec2( 0.0, 0.0 ) ), 27 | grad( vec2( 1.0, 0.0 ) ), 28 | sw( cellCoordS, 'x' ), 29 | ), 30 | mix( 31 | grad( vec2( 0.0, 1.0 ) ), 32 | grad( vec2( 1.0, 1.0 ) ), 33 | sw( cellCoordS, 'x' ), 34 | ), 35 | sw( cellCoordS, 'y' ), 36 | ) ); 37 | } ) ); 38 | 39 | return f( v, rep ?? vec2( 65536.0 ) ); 40 | } 41 | -------------------------------------------------------------------------------- /src/nodes/LineRingsScene/LineRingsScene.ts: -------------------------------------------------------------------------------- 1 | import { CameraStack } from '../CameraStack/CameraStack'; 2 | import { InstancedLines } from '../utils/InstancedLines'; 3 | import { SceneNode } from '../../heck/components/SceneNode'; 4 | import { cameraStackBTarget } from '../../globals/cameraStackTargets'; 5 | import { lineRingsVert } from './shaders/lineRingsVert'; 6 | import { mainCameraStackResources } from '../CameraStack/mainCameraStackResources'; 7 | 8 | export class LineRingsScene extends SceneNode { 9 | public constructor() { 10 | super(); 11 | 12 | // -- lines ------------------------------------------------------------------------------------ 13 | const lines = new InstancedLines( lineRingsVert, 512, 256 ); 14 | 15 | if ( import.meta.hot ) { 16 | import.meta.hot.accept( 17 | './shaders/lineRingsVert', 18 | ( { lineRingsVert } ) => { 19 | lines.materials.deferred!.replaceShader( lineRingsVert ); 20 | } 21 | ); 22 | } 23 | 24 | // -- camera proxy ----------------------------------------------------------------------------- 25 | const camera = new CameraStack( { 26 | scene: this, 27 | resources: mainCameraStackResources, 28 | target: cameraStackBTarget, 29 | } ); 30 | camera.transform.lookAt( 31 | [ 0.0, 0.0, 5.0 ], 32 | ); 33 | 34 | // -- children --------------------------------------------------------------------------------- 35 | this.children = [ 36 | lines, 37 | camera, 38 | ]; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/nodes/PostStack/Vectorscope/shaders/vectorscopeVert.ts: -------------------------------------------------------------------------------- 1 | import { add, addAssign, assign, build, def, defIn, defUniformNamed, div, divAssign, floor, glPointSize, glPosition, main, mat2, mul, mulAssign, subAssign, sw, texture, vec2, vec4 } from '../../../../shaders/shaderBuilder'; 2 | 3 | export const vectorscopeVert = build( () => { 4 | const index = defIn( 'float', 0 ); 5 | 6 | const resolution = defUniformNamed( 'vec2', 'resolution' ); 7 | const samplerL = defUniformNamed( 'sampler2D', 'samplerL' ); 8 | const samplerR = defUniformNamed( 'sampler2D', 'samplerR' ); 9 | 10 | // const sinc = ( x: GLSLFloatExpression ): GLSLExpression<'float'> => ( 11 | // tern( eq( x, 0.0 ), 1.0, div( sin( mul( PI, x ) ), PI, x ) ) 12 | // ); 13 | 14 | main( () => { 15 | const position = def( 'vec2', vec2( 0.0 ) ); 16 | 17 | const i0 = floor( add( index, 0.5 ) ); 18 | 19 | const uv = vec2( div( i0, 1024 ), 0.5 ); 20 | addAssign( position, vec2( 21 | sw( texture( samplerL, uv ), 'x' ), 22 | sw( texture( samplerR, uv ), 'x' ), 23 | ) ); 24 | 25 | mulAssign( position, mat2( -0.5, 0.5, 0.5, 0.5 ) ); 26 | 27 | const scale = floor( div( sw( resolution, 'y' ), 360.0 ) ); 28 | 29 | mulAssign( position, mul( 40.0, scale ) ); 30 | addAssign( position, resolution ); 31 | subAssign( position, mul( vec2( 14.0 * 6.0, 13.0 * 7.0 ), scale ) ); 32 | divAssign( position, resolution ); 33 | 34 | assign( glPosition, vec4( position, 0.0, 1.0 ) ); 35 | assign( glPointSize, 2.0 ); 36 | } ); 37 | } ); 38 | -------------------------------------------------------------------------------- /src/music/BufferReaderNode.ts: -------------------------------------------------------------------------------- 1 | import processorCode from './BufferReaderProcessor.js?worklet'; 2 | 3 | const BLOCK_SIZE = 128; 4 | const CHANNELS = 2; 5 | const BUFFER_SIZE_PER_CHANNEL = 65536; 6 | 7 | const processorBlob = new Blob( [ processorCode ], { type: 'text/javascript' } ); 8 | const processorUrl = URL.createObjectURL( processorBlob ); 9 | 10 | export class BufferReaderNode extends AudioWorkletNode { 11 | private __readBlocks: number; 12 | 13 | public get readBlocks(): number { 14 | return this.__readBlocks; 15 | } 16 | 17 | public static addModule( audio: AudioContext ): Promise { 18 | return audio.audioWorklet.addModule( processorUrl ); 19 | } 20 | 21 | public setActive( isActive: boolean ): void { 22 | this.port.postMessage( isActive ); 23 | } 24 | 25 | public constructor( audio: AudioContext ) { 26 | super( audio, 'buffer-reader-processor', { 27 | numberOfInputs: 0, 28 | numberOfOutputs: 1, 29 | outputChannelCount: [ CHANNELS ], 30 | } ); 31 | 32 | this.__readBlocks = 0; 33 | 34 | this.port.onmessage = ( ( { data } ) => { 35 | this.__readBlocks = data; 36 | } ); 37 | } 38 | 39 | public write( channel: number, block: number, offset: number, buffer: ArrayLike ): void { 40 | const totalOffset = ( 41 | BUFFER_SIZE_PER_CHANNEL * channel 42 | + ( BLOCK_SIZE * block ) % BUFFER_SIZE_PER_CHANNEL 43 | + offset 44 | ); 45 | 46 | this.port.postMessage( [ 47 | buffer, 48 | totalOffset, 49 | ] ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/shaders/modules/voronoi2d.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, add, assign, cache, def, defFn, floor, forLoop, ifThen, lt, mod, num, retFn, sub, vec2, vec3 } from '../shaderBuilder'; 2 | import { minkowski2d } from './minkowski2d'; 3 | import { pcg2df } from './pcg2df'; 4 | 5 | const symbol = Symbol(); 6 | 7 | /** 8 | * @param v vector 9 | * @param p minzowsky p 10 | * @param rep repeat 11 | * @returns vec3( cellOrigin, len ) 12 | */ 13 | export function voronoi2d( 14 | v: GLSLExpression<'vec2'>, 15 | rep?: GLSLExpression<'vec2'>, 16 | p: GLSLFloatExpression = 2.0, 17 | ): GLSLExpression<'vec3'> { 18 | const f = cache( symbol, () => defFn( 'vec3', [ 'vec2', 'vec2', 'float' ], ( v, rep, p ) => { 19 | const cell = def( 'vec2', floor( v ) ); 20 | 21 | const nearestCell = def( 'vec2' ); 22 | const nearestLen = def( 'float', 1E9 ); 23 | 24 | forLoop( 3, ( iy ) => { 25 | forLoop( 3, ( ix ) => { 26 | const currentCell = add( cell, -1.0, vec2( ix, iy ) ); 27 | const cellOrigin = add( 28 | currentCell, 29 | pcg2df( mod( currentCell, rep ) ), 30 | ); 31 | 32 | const len = def( 'float', minkowski2d( sub( cellOrigin, v ), p ) ); 33 | 34 | ifThen( lt( len, nearestLen ), () => { 35 | assign( nearestCell, currentCell ); 36 | assign( nearestLen, len ); 37 | } ); 38 | } ); 39 | } ); 40 | 41 | retFn( vec3( nearestCell, nearestLen ) ); 42 | } ) ); 43 | 44 | return f( v, rep ?? vec2( 65536.0 ), num( p ) ); 45 | } 46 | -------------------------------------------------------------------------------- /src/shaders/modules/turboColormap.ts: -------------------------------------------------------------------------------- 1 | /* ! 2 | * Turbo Colormap 3 | * Copyright 2019 Google LLC. 4 | * Apache-2.0 5 | * https://gist.github.com/mikhailov-work/0d177465a8151eb6ede1768d51d476c7 6 | */ 7 | 8 | import { GLSLExpression, add, assign, cache, def, defFn, dot, mul, retFn, sq, sw, vec2, vec3, vec4 } from '../shaderBuilder'; 9 | import { glslSaturate } from './glslSaturate'; 10 | 11 | const K_R_VEC4 = vec4( 0.13572138, 4.61539260, -42.66032258, 132.13108234 ); 12 | const K_G_VEC4 = vec4( 0.09140261, 2.19418839, 4.84296658, -14.18503333 ); 13 | const K_B_VEC4 = vec4( 0.10667330, 12.64194608, -60.58204836, 110.36276771 ); 14 | const K_R_VEC2 = vec2( -152.94239396, 59.28637943 ); 15 | const K_G_VEC2 = vec2( 4.27729857, 2.82956604 ); 16 | const K_B_VEC2 = vec2( -89.90310912, 27.34824973 ); 17 | 18 | const symbol = Symbol(); 19 | 20 | export function turboColormap( 21 | x: GLSLExpression<'float'>, 22 | ): GLSLExpression<'vec3'> { 23 | const f = cache( 24 | symbol, 25 | () => defFn( 26 | 'vec3', 27 | [ 'float' ], 28 | ( x ) => { 29 | assign( x, glslSaturate( x ) ); 30 | const v4 = def( 'vec4', vec4( 1.0, x, sq( x ), mul( x, x, x ) ) ); 31 | const v2 = def( 'vec2', mul( sw( v4, 'zw' ), sw( v4, 'z' ) ) ); 32 | retFn( vec3( 33 | add( dot( v4, K_R_VEC4 ), dot( v2, K_R_VEC2 ) ), 34 | add( dot( v4, K_G_VEC4 ), dot( v2, K_G_VEC2 ) ), 35 | add( dot( v4, K_B_VEC4 ), dot( v2, K_B_VEC2 ) ), 36 | ) ); 37 | } 38 | ) 39 | ); 40 | 41 | return f( x ); 42 | } 43 | -------------------------------------------------------------------------------- /src/heck/components/SceneNode.ts: -------------------------------------------------------------------------------- 1 | import { Component, ComponentDrawEvent, ComponentOptions, ComponentUpdateEvent } from './Component'; 2 | import { Transform } from '../Transform'; 3 | 4 | export interface SceneNodeOptions extends ComponentOptions { 5 | transform?: Transform; 6 | children?: Component[]; 7 | } 8 | 9 | export class SceneNode extends Component { 10 | public transform: Transform; 11 | public globalTransformCache: Transform; 12 | 13 | public children: Component[]; 14 | 15 | public constructor( options?: SceneNodeOptions ) { 16 | super( options ); 17 | 18 | this.transform = options?.transform ?? new Transform(); 19 | this.globalTransformCache = new Transform(); 20 | 21 | this.children = options?.children ?? []; 22 | } 23 | 24 | protected __updateImpl( event: ComponentUpdateEvent ): void { 25 | this.globalTransformCache = event.globalTransform.multiply( this.transform ); 26 | 27 | this.children.map( ( child ) => { 28 | child.update( { 29 | ...event, 30 | globalTransform: this.globalTransformCache, 31 | ancestors: [ ...event.ancestors, this ], 32 | } ); 33 | } ); 34 | } 35 | 36 | protected __drawImpl( event: ComponentDrawEvent ): void { 37 | this.globalTransformCache = event.globalTransform.multiply( this.transform ); 38 | 39 | this.children.map( ( child ) => { 40 | child.draw( { 41 | ...event, 42 | globalTransform: this.globalTransformCache, 43 | ancestors: [ ...event.ancestors, this ], 44 | } ); 45 | } ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/shaders/modules/forEachLights.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, arrayIndex, cache, defUniformArrayNamed, defUniformNamed, forBreak, forLoop, gte, ifThen } from '../shaderBuilder'; 2 | 3 | const symbol = Symbol(); 4 | 5 | export const forEachLights: ( 6 | fn: ( params: { 7 | iLight: GLSLExpression<'int'>, 8 | lightPos: GLSLExpression<'vec3'>, 9 | lightColor: GLSLExpression<'vec3'>, 10 | lightNearFar: GLSLExpression<'vec2'>, 11 | lightParams: GLSLExpression<'vec4'>, 12 | lightPV: GLSLExpression<'mat4'>, 13 | } ) => void, 14 | ) => void = ( fn ) => { 15 | const [ 16 | lightCount, 17 | arrLightPos, 18 | arrLightColor, 19 | arrLightNearFar, 20 | arrLightParams, 21 | arrLightPV, 22 | ] = cache( symbol, () => [ 23 | defUniformNamed( 'int', 'lightCount' ), 24 | defUniformArrayNamed( 'vec3', 'lightPos', 8 ), 25 | defUniformArrayNamed( 'vec3', 'lightColor', 8 ), 26 | defUniformArrayNamed( 'vec2', 'lightNearFar', 8 ), 27 | defUniformArrayNamed( 'vec4', 'lightParams', 8 ), 28 | defUniformArrayNamed( 'mat4', 'lightPV', 8 ), 29 | ] ); 30 | 31 | forLoop( 8, ( iLight ) => { 32 | ifThen( gte( iLight, lightCount ), () => { forBreak(); } ); 33 | 34 | fn( { 35 | iLight, 36 | lightPos: arrayIndex( arrLightPos, iLight ), 37 | lightColor: arrayIndex( arrLightColor, iLight ), 38 | lightNearFar: arrayIndex( arrLightNearFar, iLight ), 39 | lightParams: arrayIndex( arrLightParams, iLight ), 40 | lightPV: arrayIndex( arrLightPV, iLight ), 41 | } ); 42 | } ); 43 | }; 44 | -------------------------------------------------------------------------------- /src/nodes/Dust/shaders/dustRenderFrag.ts: -------------------------------------------------------------------------------- 1 | import { MTL_PBR_ROUGHNESS_METALLIC } from '../../CameraStack/deferredConstants'; 2 | import { assign, build, defInNamed, defOut, defUniformNamed, discard, div, glPointCoord, ifThen, insert, length, lt, main, retFn, sub, sw, vec4 } from '../../../shaders/shaderBuilder'; 3 | import { calcShadowDepth } from '../../../shaders/modules/calcShadowDepth'; 4 | 5 | export const dustRenderFrag = ( tag: 'deferred' | 'depth' ): string => build( () => { 6 | insert( 'precision highp float;' ); 7 | 8 | const vPosition = defInNamed( 'vec4', 'vPosition' ); 9 | const vProjPosition = defInNamed( 'vec4', 'vProjPosition' ); 10 | 11 | const fragColor = defOut( 'vec4' ); 12 | const fragPosition = defOut( 'vec4', 1 ); 13 | const fragNormal = defOut( 'vec4', 2 ); 14 | const fragMisc = defOut( 'vec4', 3 ); 15 | 16 | const emissive = defUniformNamed( 'float', 'emissive' ); 17 | const color = defUniformNamed( 'vec4', 'color' ); 18 | 19 | main( () => { 20 | ifThen( lt( 0.5, length( sub( glPointCoord, 0.5 ) ) ), () => discard() ); 21 | 22 | if ( tag === 'depth' ) { 23 | assign( fragColor, calcShadowDepth( vProjPosition ) ); 24 | retFn(); 25 | 26 | } 27 | 28 | const depth = div( sw( vProjPosition, 'z' ), sw( vProjPosition, 'w' ) ); 29 | 30 | assign( fragColor, color ); 31 | assign( fragPosition, vec4( sw( vPosition, 'xyz' ), depth ) ); 32 | assign( fragNormal, vec4( 0.0, 0.0, 1.0, MTL_PBR_ROUGHNESS_METALLIC ) ); 33 | assign( fragMisc, vec4( 1.0, 0.0, emissive, 0.0 ) ); 34 | 35 | } ); 36 | } ); 37 | -------------------------------------------------------------------------------- /src/shaders/modules/pcg4d.ts: -------------------------------------------------------------------------------- 1 | /* ! 2 | * pcg4d 3 | * 4 | * Appearance: 5 | * Mark Jarzynski and Marc Olano, Hash Functions for GPU Rendering, 6 | * Journal of Computer Graphics Techniques (JCGT), vol. 9, no. 3, 21-38, 2020 7 | * 8 | * Ref: https://jcgt.org/published/0009/03/02/ 9 | * Ref: https://www.shadertoy.com/view/XlGcRh 10 | */ 11 | 12 | import { GLSLExpression, add, addAssign, assign, cache, defFn, mul, retFn, rshift, sw, xorAssign } from '../shaderBuilder'; 13 | 14 | type Uint = GLSLExpression<'uint'>; 15 | 16 | const symbol = Symbol(); 17 | 18 | export const pcgMagic1 = '1664525u' as Uint; 19 | export const pcgMagic2 = '1013904223u' as Uint; 20 | 21 | export function pcg4d( 22 | v: GLSLExpression<'uvec4'>, 23 | ): GLSLExpression<'uvec4'> { 24 | const f = cache( symbol, () => defFn( 'uvec4', [ 'uvec4' ], ( v ) => { 25 | assign( v, add( mul( v, pcgMagic1 ), pcgMagic2 ) ); 26 | 27 | addAssign( sw( v, 'x' ), mul( sw( v, 'y' ), sw( v, 'w' ) ) ); 28 | addAssign( sw( v, 'y' ), mul( sw( v, 'z' ), sw( v, 'x' ) ) ); 29 | addAssign( sw( v, 'z' ), mul( sw( v, 'x' ), sw( v, 'y' ) ) ); 30 | addAssign( sw( v, 'w' ), mul( sw( v, 'y' ), sw( v, 'z' ) ) ); 31 | 32 | xorAssign( v, rshift( v, '16u' as Uint ) ); 33 | 34 | addAssign( sw( v, 'x' ), mul( sw( v, 'y' ), sw( v, 'w' ) ) ); 35 | addAssign( sw( v, 'y' ), mul( sw( v, 'z' ), sw( v, 'x' ) ) ); 36 | addAssign( sw( v, 'z' ), mul( sw( v, 'x' ), sw( v, 'y' ) ) ); 37 | addAssign( sw( v, 'w' ), mul( sw( v, 'y' ), sw( v, 'z' ) ) ); 38 | 39 | retFn( v ); 40 | } ) ); 41 | 42 | return f( v ); 43 | } 44 | -------------------------------------------------------------------------------- /src/nodes/PostStack/CharRenderer/shaders/charRendererFrag.ts: -------------------------------------------------------------------------------- 1 | import { abs, add, assign, build, def, defInNamed, defOutNamed, defUniformNamed, div, floor, insert, main, mix, mixStepChain, mul, mulAssign, step, sub, sw, tern, texture, vec2, vec3, vec4 } from '../../../../shaders/shaderBuilder'; 2 | import { isValidUv } from '../../../../shaders/modules/isValidUv'; 3 | 4 | export const charRendererFrag = build( () => { 5 | insert( 'precision highp float;' ); 6 | 7 | const vCoord = defInNamed( 'vec2', 'vCoord' ); 8 | const vMeta = defInNamed( 'vec4', 'vMeta' ); 9 | 10 | const fragColor = defOutNamed( 'vec4', 'fragColor' ); 11 | 12 | const samplerChar = defUniformNamed( 'sampler2D', 'samplerChar' ); 13 | 14 | main( () => { 15 | const uv = mul( 16 | add( 17 | vCoord, 18 | floor( div( sw( vMeta, 'z' ), vec2( 1.0, 16.0 ) ) ), 19 | ), 20 | 1.0 / 16.0, 21 | ); 22 | 23 | const tex = def( 'float', sw( texture( samplerChar, uv ), 'x' ) ); 24 | mulAssign( tex, tern( isValidUv( vCoord ), 1.0, 0.0 ) ); 25 | 26 | const color = mixStepChain( 27 | abs( sw( vMeta, 'w' ) ), 28 | vec3( 1.0 ), 29 | [ 2.0, vec3( 0.4, 0.5, 0.6 ) ], 30 | [ 3.0, vec3( 1.0, 0.5, 0.6 ) ], 31 | [ 4.0, vec3( 0.7, 0.7, 1.0 ) ], 32 | [ 5.0, vec3( 0.5, 0.9, 1.0 ) ], 33 | [ 6.0, vec3( 1.0 ) ], 34 | ); 35 | 36 | assign( tex, mix( 37 | tex, 38 | sub( 1.0, tex ), 39 | step( sw( vMeta, 'w' ), 0.5 ), 40 | ) ); 41 | 42 | assign( fragColor, vec4( vec3( mul( color, tex ) ), mix( 0.9, 1.0, tex ) ) ); 43 | } ); 44 | } ); 45 | -------------------------------------------------------------------------------- /src/shaders/modules/calcSS.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, GLSLFloatExpression, GLSLToken, add, addAssign, def, div, forLoop, max, mul, neg, num, pow, refract, sub, sw } from '../shaderBuilder'; 2 | import { glslSaturate } from './glslSaturate'; 3 | import { sampleLambert } from './sampleLambert'; 4 | 5 | // https://www.shadertoy.com/view/lllBDM 6 | export function calcSS( { 7 | rp, 8 | rd, 9 | L, 10 | N, 11 | map, 12 | eta, 13 | iter = 50, 14 | lenMultiplier = 0.01, 15 | intensity = 1.0, 16 | power = 3.0, 17 | }: { 18 | rp: GLSLExpression<'vec3'>, 19 | rd: GLSLExpression<'vec3'>, 20 | L: GLSLExpression<'vec3'>, 21 | N: GLSLExpression<'vec3'>, 22 | map: ( p: GLSLExpression<'vec3'> ) => GLSLExpression<'vec4'>, 23 | eta?: GLSLFloatExpression, 24 | iter?: number, 25 | lenMultiplier?: GLSLFloatExpression, 26 | intensity?: GLSLFloatExpression, 27 | power?: GLSLFloatExpression, 28 | } ): GLSLToken<'float'> { 29 | const sd = def( 'vec3', refract( rd, N, eta ?? 1.0 / 1.5 ) ); 30 | const len = def( 'float', num( lenMultiplier ) ); 31 | const accum = def( 'float', 0.0 ); 32 | 33 | forLoop( iter, () => { 34 | addAssign( len, lenMultiplier ); 35 | let samplePoint = add( rp, mul( sampleLambert( sd ), len ) ); 36 | samplePoint = add( samplePoint, mul( sampleLambert( L ), len ) ); 37 | const d = sw( map( samplePoint ), 'x' ); 38 | addAssign( accum, div( max( 0.0, neg( d ) ), len ) ); 39 | } ); 40 | 41 | const v = glslSaturate( sub( 1.0, mul( intensity, div( accum, iter ) ) ) ) as GLSLExpression<'float'>; 42 | return def( 'float', pow( v, power ) ); 43 | } 44 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import { automatonMinifierPlugin } from './vite-plugins/vite-automaton-minifier-plugin'; 3 | import { visualizer } from 'rollup-plugin-visualizer'; 4 | import { workletMinifierPlugin } from './vite-plugins/vite-worklet-minifier-plugin'; 5 | import { terserMinifyOptions } from './terserMinifyOptions'; 6 | import Inspect from 'vite-plugin-inspect'; 7 | 8 | export default defineConfig( ( { mode } ) => { 9 | return { 10 | resolve: { 11 | alias: { 12 | ...( mode === 'prod' ? { 13 | 'webgl-memory': `${ __dirname }/src/dummy.ts`, // don't want to import webgl-memory when it's prod build 14 | } : {} ), 15 | }, 16 | }, 17 | build: { 18 | target: 'esnext', 19 | minify: mode === 'prod' ? 'terser' : false, 20 | terserOptions: mode === 'prod' ? terserMinifyOptions : undefined, 21 | sourcemap: true, 22 | polyfillModulePreload: false, // size 23 | rollupOptions: { 24 | plugins: [ 25 | visualizer( { 26 | json: true, 27 | gzipSize: true, 28 | brotliSize: true, 29 | } ), 30 | ], 31 | } 32 | }, 33 | plugins: [ 34 | Inspect(), 35 | automatonMinifierPlugin( { 36 | minify: mode === 'prod', 37 | minimizeOptions: { 38 | precisionTime: 3, 39 | precisionValue: 3, 40 | }, 41 | } ), 42 | workletMinifierPlugin( { 43 | minify: mode === 'prod', 44 | minifyOptions: terserMinifyOptions, 45 | } ), 46 | ] 47 | }; 48 | } ); 49 | -------------------------------------------------------------------------------- /src/nodes/NoisePlaneScene/NoisePlaneScene.ts: -------------------------------------------------------------------------------- 1 | import { Material } from '../../heck/Material'; 2 | import { Quad } from '../../heck/components/Quad'; 3 | import { SceneNode } from '../../heck/components/SceneNode'; 4 | import { cameraStackBTarget } from '../../globals/cameraStackTargets'; 5 | import { dummyRenderTarget1 } from '../../globals/dummyRenderTarget'; 6 | import { noisePlaneFrag } from './shaders/noisePlaneFrag'; 7 | import { quadGeometry } from '../../globals/quadGeometry'; 8 | import { quadVert } from '../../shaders/common/quadVert'; 9 | 10 | export class NoisePlaneScene extends SceneNode { 11 | public constructor() { 12 | super(); 13 | 14 | // -- material --------------------------------------------------------------------------------- 15 | const material = new Material( 16 | quadVert, 17 | noisePlaneFrag, 18 | { 19 | initOptions: { target: dummyRenderTarget1, geometry: quadGeometry }, 20 | }, 21 | ); 22 | 23 | if ( import.meta.hot ) { 24 | import.meta.hot.accept( 25 | './shaders/noisePlaneFrag', 26 | ( { noisePlaneFrag } ) => { 27 | material.replaceShader( undefined, noisePlaneFrag ); 28 | }, 29 | ); 30 | } 31 | 32 | // -- quad ------------------------------------------------------------------------------------- 33 | const quad = new Quad( { 34 | target: cameraStackBTarget, 35 | material, 36 | } ); 37 | 38 | // -- children --------------------------------------------------------------------------------- 39 | this.children = [ 40 | quad, 41 | ]; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/nodes/OBSVRLogoBScene/OBSVRLogoBScene.ts: -------------------------------------------------------------------------------- 1 | import { Material } from '../../heck/Material'; 2 | import { Quad } from '../../heck/components/Quad'; 3 | import { SceneNode } from '../../heck/components/SceneNode'; 4 | import { cameraStackBTarget } from '../../globals/cameraStackTargets'; 5 | import { dummyRenderTarget1 } from '../../globals/dummyRenderTarget'; 6 | import { obsvrLogoBFrag } from './shaders/obsvrLogoBFrag'; 7 | import { quadGeometry } from '../../globals/quadGeometry'; 8 | import { quadVert } from '../../shaders/common/quadVert'; 9 | 10 | export class OBSVRLogoBScene extends SceneNode { 11 | public constructor() { 12 | super(); 13 | 14 | // -- material --------------------------------------------------------------------------------- 15 | const material = new Material( 16 | quadVert, 17 | obsvrLogoBFrag, 18 | { 19 | initOptions: { geometry: quadGeometry, target: dummyRenderTarget1 }, 20 | }, 21 | ); 22 | 23 | if ( import.meta.hot ) { 24 | import.meta.hot.accept( 25 | './shaders/obsvrLogoBFrag', 26 | ( { obsvrLogoBFrag } ) => { 27 | material.replaceShader( undefined, obsvrLogoBFrag ); 28 | }, 29 | ); 30 | } 31 | 32 | // -- quad ------------------------------------------------------------------------------------- 33 | const quad = new Quad( { 34 | target: cameraStackBTarget, 35 | material, 36 | } ); 37 | 38 | // -- children --------------------------------------------------------------------------------- 39 | this.children = [ 40 | quad, 41 | ]; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/nodes/utils/ShaderRenderTarget.ts: -------------------------------------------------------------------------------- 1 | import { BufferTextureRenderTarget } from '../../heck/BufferTextureRenderTarget'; 2 | import { GL_LINEAR, GL_REPEAT } from '../../gl/constants'; 3 | import { Lambda } from '../../heck/components/Lambda'; 4 | import { Material } from '../../heck/Material'; 5 | import { Quad } from '../../heck/components/Quad'; 6 | import { dummyRenderTarget1 } from '../../globals/dummyRenderTarget'; 7 | import { glTextureFilter } from '../../gl/glTextureFilter'; 8 | import { glTextureWrap } from '../../gl/glTextureWrap'; 9 | import { quadGeometry } from '../../globals/quadGeometry'; 10 | import { quadVert } from '../../shaders/common/quadVert'; 11 | 12 | export class ShaderRenderTarget extends BufferTextureRenderTarget { 13 | public material: Material; 14 | public quad: Quad; 15 | 16 | public constructor( width: number, height: number, frag: string ) { 17 | super( width, height ); 18 | glTextureWrap( this.texture, GL_REPEAT ); 19 | glTextureFilter( this.texture, GL_LINEAR ); 20 | 21 | const material = this.material = new Material( 22 | quadVert, 23 | frag, 24 | { initOptions: { geometry: quadGeometry, target: dummyRenderTarget1 } }, 25 | ); 26 | 27 | const quad = this.quad = new Quad( { 28 | material, 29 | target: this, 30 | } ); 31 | 32 | material.onReady = () => quad.drawImmediate(); 33 | } 34 | 35 | public createUpdateLambda(): Lambda { 36 | return new Lambda( { 37 | onUpdate: ( { time, deltaTime } ) => this.quad.drawImmediate( { 38 | time, 39 | deltaTime, 40 | } ), 41 | } ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/shaders/modules/liftGammaGain.ts: -------------------------------------------------------------------------------- 1 | import { GLSLExpression, abs, add, addAssign, assign, def, div, dot, log2, max, mix, mul, mulAssign, pow, step, sub, sw, vec3, vec4 } from '../shaderBuilder'; 2 | import { glslSaturate } from './glslSaturate'; 3 | 4 | const LUMA = vec3( 0.2126, 0.7152, 0.0722 ); 5 | 6 | /** 7 | * DaVinci Resolve style color grading function 8 | */ 9 | export function liftGammaGain( 10 | rgb: GLSLExpression<'vec3'>, 11 | lift: GLSLExpression<'vec4'>, 12 | gamma: GLSLExpression<'vec4'>, 13 | gain: GLSLExpression<'vec4'>, 14 | ): GLSLExpression<'vec3'> { 15 | const liftt = def( 'vec4', ( 16 | sub( 1.0, pow( sub( 1.0, lift ), log2( add( gain, 1.0 ) ) ) ) 17 | ) ); 18 | 19 | const gammat = def( 'vec4', ( 20 | sub( gamma, vec4( 0.0, 0.0, 0.0, dot( vec4( LUMA, 0.0 ), gamma ) ) ) 21 | ) ); 22 | const gammatTemp = add( 1.0, mul( 4.0, abs( gammat ) ) ); 23 | assign( gammat, mix( gammatTemp, div( 1.0, gammatTemp ), step( 0.0, gammat ) ) ); 24 | 25 | const col = def( 'vec3', rgb ); 26 | const luma = def( 'float', dot( LUMA, col ) ); 27 | 28 | assign( col, pow( col, sw( gammat, 'rgb' ) ) ); 29 | mulAssign( col, pow( sw( gain, 'rgb' ), sw( gammat, 'rgb' ) ) ); 30 | assign( 31 | col, 32 | max( mix( mul( 2.0, sw( liftt, 'rgb' ) ), vec3( 1.0 ), col ), 0.0 ) 33 | ); 34 | 35 | assign( luma, pow( luma, sw( gammat, 'a' ) ) ); 36 | mulAssign( luma, pow( sw( gain, 'a' ), sw( gammat, 'a' ) ) ); 37 | assign( luma, max( mix( mul( 2.0, sw( liftt, 'a' ) ), 1.0, luma ), 0.0 ) ); 38 | 39 | addAssign( col, sub( luma, dot( LUMA, col ) ) ); 40 | 41 | return glslSaturate( col ); 42 | } 43 | -------------------------------------------------------------------------------- /src/utils/RandomTexture.ts: -------------------------------------------------------------------------------- 1 | import { GL_LINEAR, GL_REPEAT } from '../gl/constants'; 2 | import { Xorshift } from '@0b5vr/experimental'; 3 | import { gl } from '../globals/canvas'; 4 | import { glSetTexture } from '../gl/glSetTexture'; 5 | import { glTextureFilter } from '../gl/glTextureFilter'; 6 | import { glTextureWrap } from '../gl/glTextureWrap'; 7 | 8 | export class RandomTexture { 9 | private __texture: WebGLTexture; 10 | private __array: Uint8Array; 11 | private __rng: Xorshift; 12 | private __width: number; 13 | private __height: number; 14 | 15 | public constructor( 16 | width: number, 17 | height: number, 18 | ) { 19 | this.__width = width; 20 | this.__height = height; 21 | this.__rng = new Xorshift(); 22 | this.__array = new Uint8Array( width * height * 4 ); 23 | 24 | const texture = this.__texture = gl.createTexture()!; 25 | glTextureFilter( texture, GL_LINEAR ); 26 | glTextureWrap( texture, GL_REPEAT ); 27 | } 28 | 29 | public get texture(): WebGLTexture { 30 | return this.__texture; 31 | } 32 | 33 | public resize( width: number, height: number, seed?: number ): void { 34 | this.__width = width; 35 | this.__height = height; 36 | this.__array = new Uint8Array( width * height * 4 ); 37 | 38 | this.update( seed ); 39 | } 40 | 41 | public update( seed?: number ): void { 42 | if ( seed ) { this.__rng.seed = seed; } 43 | 44 | for ( let i = 0; i < this.__array.length; i ++ ) { 45 | this.__array[ i ] = this.__rng.gen() * 256.0; 46 | } 47 | 48 | glSetTexture( this.__texture, this.__width, this.__height, this.__array ); 49 | } 50 | } 51 | --------------------------------------------------------------------------------