lamina
Version:
🍰 An extensable, layer based shader material for ThreeJS.
1 lines • 73.4 kB
Source Map (JSON)
{"version":3,"file":"vanilla-t_CDvKEO.cjs","sources":["../src/types.ts","../src/utils/Functions.ts","../src/core/Abstract.ts","../src/core/Color.ts","../src/core/Depth.ts","../src/core/Displace.ts","../src/core/Fresnel.ts","../src/core/Gradient.ts","../src/core/Matcap.ts","../src/core/Noise.ts","../src/core/Normal.ts","../src/core/Texture.ts","../src/chunks/BlendModes.ts","../src/chunks/Helpers.ts","../src/chunks/Noise.ts","../src/vanilla.ts"],"sourcesContent":["import * as THREE from 'three'\r\nimport { Abstract } from './vanilla'\r\n\r\nexport const BlendModes: {\r\n [key: string]: string\r\n} = {\r\n normal: 'normal',\r\n add: 'add',\r\n subtract: 'subtract',\r\n multiply: 'multiply',\r\n lighten: 'lighten',\r\n darken: 'darken',\r\n divide: 'divide',\r\n overlay: 'overlay',\r\n screen: 'screen',\r\n softlight: 'softlight',\r\n negation: 'negation',\r\n reflect: 'reflect',\r\n}\r\n\r\nexport type BlendMode =\r\n | 'normal'\r\n | 'add'\r\n | 'subtract'\r\n | 'multiply'\r\n | 'lighten'\r\n | 'darken'\r\n | 'divide'\r\n | 'overlay'\r\n | 'screen'\r\n | 'softlight'\r\n | 'reflect'\r\n | 'negation'\r\n\r\nexport const NoiseTypes: {\r\n [key: string]: string\r\n} = {\r\n perlin: 'perlin',\r\n simplex: 'simplex',\r\n cell: 'cell',\r\n curl: 'curl',\r\n white: 'white',\r\n}\r\n\r\nexport type NoiseType = 'perlin' | 'simplex' | 'cell' | 'curl' | 'white'\r\n\r\nexport const MappingTypes: {\r\n [key: string]: string\r\n} = {\r\n local: 'local',\r\n world: 'world',\r\n uv: 'uv',\r\n}\r\n\r\nexport type MappingType = 'local' | 'world' | 'uv'\r\n\r\nexport const ShadingTypes: {\r\n [key: string]: new () => THREE.Material\r\n} = {\r\n phong: THREE.MeshPhongMaterial,\r\n physical: THREE.MeshPhysicalMaterial,\r\n toon: THREE.MeshToonMaterial,\r\n basic: THREE.MeshBasicMaterial,\r\n lambert: THREE.MeshLambertMaterial,\r\n standard: THREE.MeshStandardMaterial,\r\n}\r\n\r\nexport type ShadingType = 'phong' | 'physical' | 'toon' | 'basic' | 'lambert' | 'standard'\r\n\r\nexport interface BaseProps {\r\n color?: THREE.ColorRepresentation | THREE.Color\r\n alpha?: number\r\n name?: string\r\n}\r\n\r\nexport interface LayerMaterialParameters {\r\n layers?: Abstract[]\r\n color?: THREE.ColorRepresentation | THREE.Color\r\n alpha?: number\r\n lighting?: ShadingType\r\n name?: string\r\n}\r\nexport type LayerMaterialProps = Omit<LayerMaterialParameters, 'layers'>\r\n\r\nexport interface LayerProps {\r\n mode?: BlendMode\r\n name?: string\r\n visible?: boolean\r\n [key: string]: any\r\n}\r\n\r\nexport interface ColorProps extends LayerProps {\r\n color?: THREE.ColorRepresentation | THREE.Color\r\n alpha?: number\r\n}\r\nexport interface NormalProps extends LayerProps {\r\n direction?: THREE.Vector3 | [number, number, number]\r\n alpha?: number\r\n}\r\n\r\nexport interface DepthProps extends LayerProps {\r\n colorA?: THREE.ColorRepresentation | THREE.Color\r\n colorB?: THREE.ColorRepresentation | THREE.Color\r\n alpha?: number\r\n near?: number\r\n far?: number\r\n origin?: THREE.Vector3 | [number, number, number]\r\n mapping?: 'vector' | 'world' | 'camera'\r\n}\r\n\r\nexport interface NoiseProps extends LayerProps {\r\n colorA?: THREE.ColorRepresentation | THREE.Color\r\n colorB?: THREE.ColorRepresentation | THREE.Color\r\n colorC?: THREE.ColorRepresentation | THREE.Color\r\n colorD?: THREE.ColorRepresentation | THREE.Color\r\n alpha?: number\r\n mapping?: MappingType\r\n type?: NoiseType\r\n scale?: number\r\n offset?: THREE.Vector3 | [number, number, number]\r\n}\r\nexport interface DisplaceProps extends LayerProps {\r\n strength?: number\r\n scale?: number\r\n mapping?: MappingType\r\n type?: NoiseType\r\n offset?: THREE.Vector3 | [number, number, number]\r\n}\r\n\r\nexport interface FresnelProps extends LayerProps {\r\n color?: THREE.ColorRepresentation | THREE.Color\r\n alpha?: number\r\n power?: number\r\n intensity?: number\r\n bias?: number\r\n}\r\nexport interface GradientProps extends LayerProps {\r\n colorA?: THREE.ColorRepresentation | THREE.Color\r\n colorB?: THREE.ColorRepresentation | THREE.Color\r\n axes?: 'x' | 'y' | 'z'\r\n alpha?: number\r\n contrast?: number\r\n start?: number\r\n end?: number\r\n mapping?: MappingType\r\n}\r\n\r\nexport interface MatcapProps extends LayerProps {\r\n map?: THREE.Texture\r\n alpha?: number\r\n}\r\nexport interface TextureProps extends LayerProps {\r\n map?: THREE.Texture\r\n alpha?: number\r\n}\r\n\r\nexport interface SerializedLayer {\r\n constructor: string\r\n properties: {\r\n [name: string]: any\r\n }\r\n}\r\n","import { Color, Matrix3, Matrix4, Texture, Vector2, Vector3, Vector4 } from 'three'\r\nimport { LayerMaterialProps } from '../types'\r\n\r\nexport function getUniform(value: any) {\r\n if (typeof value === 'string') {\r\n return new Color(value).convertLinearToSRGB()\r\n }\r\n\r\n return value\r\n}\r\n\r\nexport function getSpecialParameters(label: string) {\r\n switch (label) {\r\n case 'alpha':\r\n return {\r\n min: 0,\r\n max: 1,\r\n }\r\n case 'scale':\r\n return {\r\n min: 0,\r\n }\r\n\r\n case 'map':\r\n return {\r\n image: undefined,\r\n }\r\n\r\n default:\r\n return {}\r\n }\r\n}\r\n\r\nexport function getLayerMaterialArgs({ color, alpha, lighting, name, ...rest }: LayerMaterialProps & any = {}) {\r\n return [\r\n {\r\n color,\r\n alpha,\r\n lighting,\r\n name,\r\n },\r\n rest,\r\n ] as any\r\n}\r\n\r\nexport function isSerializableType(prop: any) {\r\n return (\r\n prop instanceof Vector3 ||\r\n prop instanceof Vector2 ||\r\n prop instanceof Vector4 ||\r\n prop instanceof Matrix3 ||\r\n prop instanceof Matrix4\r\n )\r\n}\r\n\r\nexport function serializeProp(prop: any) {\r\n if (isSerializableType(prop)) {\r\n return prop.toArray()\r\n } else if (prop instanceof Color) {\r\n return '#' + prop.clone().convertLinearToSRGB().getHexString()\r\n } else if (prop instanceof Texture) {\r\n return prop.image.src\r\n }\r\n\r\n return prop\r\n}\r\n","import { Color, IUniform, MathUtils } from 'three'\r\nimport { BlendMode, BlendModes, LayerProps, SerializedLayer } from '../types'\r\nimport { getSpecialParameters, getUniform, isSerializableType, serializeProp } from '../utils/Functions'\r\n\r\n// @ts-ignore\r\nimport tokenize from 'glsl-tokenizer'\r\n// @ts-ignore\r\nimport descope from 'glsl-token-descope'\r\n// @ts-ignore\r\nimport stringify from 'glsl-token-string'\r\n// @ts-ignore\r\nimport tokenFunctions from 'glsl-token-functions'\r\n\r\nexport default class Abstract {\r\n uuid: string = MathUtils.generateUUID().replace(/-/g, '_')\r\n name: string = 'LayerMaterial'\r\n mode: BlendMode = 'normal'\r\n visible: boolean = true\r\n uniforms: {\r\n [key: string]: IUniform<any>\r\n }\r\n\r\n onParse?: (self: Abstract & any) => void\r\n\r\n fragmentShader: string\r\n vertexShader: string\r\n vertexVariables: string\r\n fragmentVariables: string\r\n\r\n schema: {\r\n value: any\r\n label: any\r\n options?: any[]\r\n }[]\r\n\r\n constructor(c: new () => Abstract, props?: LayerProps | null, onParse?: (self: Abstract & any) => void) {\r\n const defaults = Object.getOwnPropertyNames(c).filter((e) => e.startsWith('u_'))\r\n const uniforms: { [key: string]: any } = defaults.reduce((a, v) => {\r\n let value = Object.getOwnPropertyDescriptor(c, v)?.value\r\n\r\n if (isSerializableType(value) || value instanceof Color) value = value.clone()\r\n\r\n return {\r\n ...a,\r\n [v.slice(1)]: value,\r\n }\r\n }, {})\r\n\r\n for (const key in uniforms) {\r\n const propName = key.split('_')[1]\r\n if (props?.[propName] !== undefined) uniforms[key] = props[propName]\r\n }\r\n\r\n if (props) {\r\n Object.keys(props).map((key) => {\r\n if (props[key] !== undefined) {\r\n // @ts-ignore\r\n this[key] = props[key]\r\n }\r\n })\r\n }\r\n\r\n this.uniforms = {}\r\n this.schema = []\r\n const properties: PropertyDescriptorMap & ThisType<any> = {}\r\n Object.keys(uniforms).map((key) => {\r\n const propName = key.split('_')[1]\r\n\r\n this.uniforms[`u_${this.uuid}_${propName}`] = {\r\n value: getUniform(uniforms[key]),\r\n }\r\n\r\n this.schema.push({\r\n value: uniforms[key],\r\n label: propName,\r\n })\r\n\r\n properties[propName] = {\r\n set: (v: any) => {\r\n this.uniforms[`u_${this.uuid}_${propName}`].value = getUniform(v)\r\n },\r\n get: () => {\r\n return this.uniforms[`u_${this.uuid}_${propName}`].value\r\n },\r\n }\r\n })\r\n\r\n if (props?.name) this.name = props.name\r\n if (props?.mode) this.mode = props.mode\r\n if (props?.visible) this.visible = props.visible\r\n\r\n Object.defineProperties(this, properties)\r\n\r\n this.vertexShader = ''\r\n this.fragmentShader = ''\r\n this.vertexVariables = ''\r\n this.fragmentVariables = ''\r\n this.onParse = onParse\r\n\r\n this.buildShaders(c)\r\n\r\n // Remove Name field from Debugger until a way to\r\n // rename Leva folders is found\r\n // this.schema.push({\r\n // value: this.name,\r\n // label: 'name',\r\n // })\r\n this.schema.push({\r\n value: this.mode,\r\n label: 'mode',\r\n options: Object.values(BlendModes),\r\n })\r\n this.schema.push({\r\n value: this.visible,\r\n label: 'visible',\r\n })\r\n }\r\n\r\n buildShaders(constructor: any) {\r\n const shaders = Object.getOwnPropertyNames(constructor)\r\n .filter((e) => e === 'fragmentShader' || e === 'vertexShader')\r\n .reduce(\r\n (a, v) => ({\r\n ...a,\r\n [v]: Object.getOwnPropertyDescriptor(constructor, v)?.value,\r\n }),\r\n {}\r\n ) as {\r\n fragmentShader: string\r\n vertexShader: string\r\n }\r\n\r\n const tokens = {\r\n vert: tokenize(shaders.vertexShader || ''),\r\n frag: tokenize(shaders.fragmentShader || ''),\r\n }\r\n\r\n const descoped = {\r\n vert: descope(tokens.vert, this.renameTokens.bind(this)),\r\n frag: descope(tokens.frag, this.renameTokens.bind(this)),\r\n }\r\n\r\n const funcs = {\r\n vert: tokenFunctions(descoped.vert),\r\n frag: tokenFunctions(descoped.frag),\r\n }\r\n\r\n const mainIndex = {\r\n vert: funcs.vert\r\n .map((e: any) => {\r\n return e.name\r\n })\r\n .indexOf('main'),\r\n frag: funcs.frag\r\n .map((e: any) => {\r\n return e.name\r\n })\r\n .indexOf('main'),\r\n }\r\n\r\n const variables = {\r\n vert: mainIndex.vert >= 0 ? stringify(descoped.vert.slice(0, funcs.vert[mainIndex.vert].outer[0])) : '',\r\n frag: mainIndex.frag >= 0 ? stringify(descoped.frag.slice(0, funcs.frag[mainIndex.frag].outer[0])) : '',\r\n }\r\n\r\n const funcBodies = {\r\n vert: mainIndex.vert >= 0 ? this.getShaderFromIndex(descoped.vert, funcs.vert[mainIndex.vert].body) : '',\r\n frag: mainIndex.frag >= 0 ? this.getShaderFromIndex(descoped.frag, funcs.frag[mainIndex.frag].body) : '',\r\n }\r\n\r\n this.vertexShader = this.processFinal(funcBodies.vert, true)\r\n this.fragmentShader = this.processFinal(funcBodies.frag)\r\n this.vertexVariables = variables.vert\r\n this.fragmentVariables = variables.frag\r\n\r\n this.onParse?.(this)\r\n this.schema = this.schema.filter((value, index) => {\r\n const _value = value.label\r\n return (\r\n index ===\r\n this.schema.findIndex((obj) => {\r\n return obj.label === _value\r\n })\r\n )\r\n })\r\n }\r\n\r\n renameTokens(name: string) {\r\n if (name.startsWith('u_')) {\r\n const slice = name.slice(2)\r\n return `u_${this.uuid}_${slice}`\r\n } else if (name.startsWith('v_')) {\r\n const slice = name.slice(2)\r\n return `v_${this.uuid}_${slice}`\r\n } else if (name.startsWith('f_')) {\r\n const slice = name.slice(2)\r\n return `f_${this.uuid}_${slice}`\r\n } else {\r\n return name\r\n }\r\n }\r\n\r\n processFinal(shader: string, isVertex?: boolean) {\r\n const s: string = shader.replace(/\\sf_/gm, ` f_${this.uuid}_`).replace(/\\(f_/gm, `(f_${this.uuid}_`)\r\n\r\n const returnValue = s.match(/^.*return.*$/gm)\r\n let sReplaced = s.replace(/^.*return.*$/gm, '')\r\n\r\n if (returnValue?.[0]) {\r\n const returnVariable = returnValue[0].replace('return', '').trim().replace(';', '')\r\n\r\n const blendMode = this.getBlendMode(returnVariable, 'lamina_finalColor')\r\n sReplaced += isVertex ? `lamina_finalPosition = ${returnVariable};` : `lamina_finalColor = ${blendMode};`\r\n }\r\n\r\n return sReplaced\r\n }\r\n\r\n getShaderFromIndex(tokens: any, index: number[]) {\r\n return stringify(tokens.slice(index[0], index[1]))\r\n }\r\n\r\n getBlendMode(b: string, a: string) {\r\n switch (this.mode) {\r\n default:\r\n case 'normal':\r\n return `lamina_blend_alpha(${a}, ${b}, ${b}.a)`\r\n case 'add':\r\n return `lamina_blend_add(${a}, ${b}, ${b}.a)`\r\n case 'subtract':\r\n return `lamina_blend_subtract(${a}, ${b}, ${b}.a)`\r\n case 'multiply':\r\n return `lamina_blend_multiply(${a}, ${b}, ${b}.a)`\r\n case 'lighten':\r\n return `lamina_blend_lighten(${a}, ${b}, ${b}.a)`\r\n case 'darken':\r\n return `lamina_blend_darken(${a}, ${b}, ${b}.a)`\r\n case 'divide':\r\n return `lamina_blend_divide(${a}, ${b}, ${b}.a)`\r\n case 'overlay':\r\n return `lamina_blend_overlay(${a}, ${b}, ${b}.a)`\r\n case 'screen':\r\n return `lamina_blend_screen(${a}, ${b}, ${b}.a)`\r\n case 'softlight':\r\n return `lamina_blend_softlight(${a}, ${b}, ${b}.a)`\r\n case 'reflect':\r\n return `lamina_blend_reflect(${a}, ${b}, ${b}.a)`\r\n case 'negation':\r\n return `lamina_blend_negation(${a}, ${b}, ${b}.a)`\r\n }\r\n }\r\n\r\n getSchema() {\r\n const latestSchema = this.schema.map(({ label, options, ...rest }) => {\r\n return {\r\n label,\r\n options,\r\n ...getSpecialParameters(label),\r\n ...rest,\r\n // @ts-ignore\r\n value: serializeProp(this[label]),\r\n }\r\n })\r\n\r\n return latestSchema\r\n }\r\n\r\n serialize(): SerializedLayer {\r\n const name = this.constructor.name.split('$')[0]\r\n let nonUniformPropKeys = Object.keys(this)\r\n nonUniformPropKeys = nonUniformPropKeys.filter(\r\n (e) =>\r\n ![\r\n 'uuid',\r\n 'uniforms',\r\n 'schema',\r\n 'fragmentShader',\r\n 'vertexShader',\r\n 'fragmentVariables',\r\n 'vertexVariables',\r\n 'attribs',\r\n 'events',\r\n '__r3f',\r\n 'onParse',\r\n ].includes(e)\r\n )\r\n const nonUniformProps = {}\r\n nonUniformPropKeys.forEach((k) => {\r\n // @ts-ignore\r\n nonUniformProps[k] = this[k]\r\n })\r\n\r\n const props: { [key: string]: any } = {}\r\n for (const key in this.uniforms) {\r\n const name = key.replace(`u_${this.uuid}_`, '')\r\n props[name] = serializeProp(this.uniforms[key].value)\r\n }\r\n\r\n return {\r\n constructor: name,\r\n properties: {\r\n ...props,\r\n ...nonUniformProps,\r\n },\r\n }\r\n }\r\n}\r\n","import { ColorProps } from '../types'\r\nimport Abstract from './Abstract'\r\n\r\nexport default class Color extends Abstract {\r\n static u_color = 'red'\r\n static u_alpha = 1\r\n\r\n static fragmentShader = ` \r\n uniform vec3 u_color;\r\n uniform float u_alpha;\r\n\r\n void main() {\r\n return vec4(u_color, u_alpha);\r\n }\r\n `\r\n\r\n constructor(props?: ColorProps) {\r\n super(Color, {\r\n name: 'Color',\r\n ...props,\r\n })\r\n }\r\n}\r\n","import { Vector3 } from 'three'\r\nimport { DepthProps } from '../types'\r\nimport Abstract from './Abstract'\r\n\r\ntype AbstractExtended = Abstract & {\r\n mapping: DepthProps['mapping']\r\n}\r\n\r\nexport default class Depth extends Abstract {\r\n static u_near = 2\r\n static u_far = 10\r\n static u_origin = new Vector3(0, 0, 0)\r\n static u_colorA = 'white'\r\n static u_colorB = 'black'\r\n static u_alpha = 1\r\n\r\n static vertexShader = `\r\n varying vec3 v_worldPosition;\r\n varying vec3 v_position;\r\n\r\n void main() {\r\n v_worldPosition = (vec4(position, 1.0) * modelMatrix).xyz;\r\n v_position = position;\r\n }\r\n `\r\n\r\n static fragmentShader = ` \r\n uniform float u_alpha;\r\n uniform float u_near;\r\n uniform float u_far;\r\n uniform float u_isVector;\r\n uniform vec3 u_origin;\r\n uniform vec3 u_colorA;\r\n uniform vec3 u_colorB;\r\n\r\n varying vec3 v_worldPosition;\r\n varying vec3 v_position;\r\n\r\n void main() {\r\n float f_dist = lamina_mapping_template;\r\n float f_depth = (f_dist - u_near) / (u_far - u_near);\r\n\t\t\tvec3 f_depthColor = mix(u_colorB, u_colorA, 1.0 - clamp(f_depth, 0., 1.));\r\n \r\n \r\n return vec4(f_depthColor, u_alpha);\r\n }\r\n `\r\n\r\n mapping: 'vector' | 'world' | 'camera' = 'vector'\r\n\r\n constructor(props?: DepthProps) {\r\n super(\r\n Depth,\r\n {\r\n name: 'Depth',\r\n ...props,\r\n },\r\n (self: Depth) => {\r\n self.schema.push({\r\n value: self.mapping,\r\n label: 'mapping',\r\n options: ['vector', 'world', 'camera'],\r\n })\r\n\r\n const mapping = Depth.getMapping(self.uuid, self.mapping)\r\n\r\n self.fragmentShader = self.fragmentShader.replace('lamina_mapping_template', mapping)\r\n }\r\n )\r\n }\r\n\r\n private static getMapping(uuid: string, type?: string) {\r\n switch (type) {\r\n default:\r\n case 'vector':\r\n return `length(v_${uuid}_worldPosition - u_${uuid}_origin)`\r\n case 'world':\r\n return `length(v_${uuid}_position - vec3(0.))`\r\n case 'camera':\r\n return `length(v_${uuid}_worldPosition - cameraPosition)`\r\n }\r\n }\r\n}\r\n","import { Vector3 } from 'three'\r\nimport { ColorProps, DisplaceProps, MappingType, MappingTypes, NoiseProps, NoiseType, NoiseTypes } from '../types'\r\nimport Abstract from './Abstract'\r\n\r\ntype AbstractExtended = Abstract & {\r\n type: NoiseType\r\n mapping: MappingType\r\n}\r\n\r\nexport default class Displace extends Abstract {\r\n static u_strength = 1\r\n static u_scale = 1\r\n static u_offset = new Vector3(0, 0, 0)\r\n\r\n static vertexShader = `\r\n \r\n uniform float u_strength;\r\n uniform float u_scale;\r\n uniform vec3 u_offset;\r\n\r\n vec3 displace(vec3 p) {\r\n\t\t\t\tvec3 f_position = lamina_mapping_template;\r\n float f_n = lamina_noise_template((f_position + u_offset) * u_scale) * u_strength;\r\n vec3 f_newPosition = p + (f_n * normal);\r\n\r\n\t\t\t\treturn f_newPosition;\r\n }\r\n\r\n \r\n\t\t\tvec3 orthogonal(vec3 v) {\r\n \t\t return normalize(abs(v.x) > abs(v.z) ? vec3(-v.y, v.x, 0.0)\r\n \t\t : vec3(0.0, -v.z, v.y));\r\n \t\t}\r\n \t\tvec3 recalcNormals(vec3 newPos) {\r\n \t\t float offset = 0.001;\r\n \t\t vec3 tangent = orthogonal(normal);\r\n \t\t vec3 bitangent = normalize(cross(normal, tangent));\r\n \t\t vec3 neighbour1 = position + tangent * offset;\r\n \t\t vec3 neighbour2 = position + bitangent * offset;\r\n \t\t vec3 displacedNeighbour1 = displace(neighbour1);\r\n \t\t vec3 displacedNeighbour2 = displace(neighbour2);\r\n \t\t vec3 displacedTangent = displacedNeighbour1 - newPos;\r\n \t\t vec3 displacedBitangent = displacedNeighbour2 - newPos;\r\n \t\t return normalize(cross(displacedTangent, displacedBitangent));\r\n \t\t}\r\n \r\n \r\n void main() {\r\n \r\n\t\t\t\tvec3 f_newPosition = displace(position);\r\n lamina_finalNormal = recalcNormals(f_newPosition);\r\n\r\n return f_newPosition;\r\n }\r\n `\r\n\r\n type: NoiseType = 'perlin'\r\n mapping: MappingType = 'local'\r\n\r\n constructor(props?: DisplaceProps) {\r\n super(\r\n Displace,\r\n {\r\n name: 'Displace',\r\n ...props,\r\n },\r\n (self: Displace) => {\r\n self.schema.push({\r\n value: self.type,\r\n label: 'type',\r\n options: Object.values(NoiseTypes),\r\n })\r\n\r\n self.schema.push({\r\n value: self.mapping,\r\n label: 'mapping',\r\n options: Object.values(MappingTypes),\r\n })\r\n\r\n const noiseFunc = Displace.getNoiseFunction(self.type)\r\n const mapping = Displace.getMapping(self.mapping)\r\n\r\n self.vertexVariables = self.vertexVariables.replace('lamina_mapping_template', mapping)\r\n self.vertexVariables = self.vertexVariables.replace('lamina_noise_template', noiseFunc)\r\n }\r\n )\r\n }\r\n\r\n private static getNoiseFunction(type?: string) {\r\n switch (type) {\r\n default:\r\n case 'perlin':\r\n return `lamina_noise_perlin`\r\n case 'simplex':\r\n return `lamina_noise_simplex`\r\n case 'cell':\r\n return `lamina_noise_worley`\r\n case 'white':\r\n return `lamina_noise_white`\r\n case 'curl':\r\n return `lamina_noise_swirl`\r\n }\r\n }\r\n\r\n private static getMapping(type?: string) {\r\n switch (type) {\r\n default:\r\n case 'local':\r\n return `p`\r\n case 'world':\r\n return `(modelMatrix * vec4(p,1.0)).xyz`\r\n case 'uv':\r\n return `vec3(uv, 0.)`\r\n }\r\n }\r\n}\r\n","import { FresnelProps } from '../types'\r\nimport Abstract from './Abstract'\r\n\r\nexport default class Fresnel extends Abstract {\r\n static u_color = 'white'\r\n static u_alpha = 1\r\n static u_bias = 0\r\n static u_intensity = 1\r\n static u_power = 2\r\n static u_factor = 1\r\n\r\n static vertexShader = `\r\n varying vec3 v_worldPosition;\r\n varying vec3 v_worldNormal;\r\n\r\n void main() {\r\n v_worldPosition = vec3(-viewMatrix[0][2], -viewMatrix[1][2], -viewMatrix[2][2]);\r\n v_worldNormal = normalize( mat3( modelMatrix[0].xyz, modelMatrix[1].xyz, modelMatrix[2].xyz ) * normal );\r\n \r\n }\r\n `\r\n\r\n static fragmentShader = ` \r\n uniform vec3 u_color;\r\n uniform float u_alpha;\r\n uniform float u_bias;\r\n uniform float u_intensity;\r\n uniform float u_power;\r\n uniform float u_factor;\r\n\r\n varying vec3 v_worldPosition;\r\n varying vec3 v_worldNormal;\r\n\r\n void main() {\r\n float f_a = (u_factor + dot(v_worldPosition, v_worldNormal));\r\n float f_fresnel = u_bias + u_intensity * pow(abs(f_a), u_power);\r\n\r\n f_fresnel = clamp(f_fresnel, 0.0, 1.0);\r\n return vec4(f_fresnel * u_color, u_alpha);\r\n }\r\n `\r\n\r\n constructor(props?: FresnelProps) {\r\n super(Fresnel, {\r\n name: 'Fresnel',\r\n ...props,\r\n })\r\n }\r\n}\r\n","import { Vector3 } from 'three'\r\nimport { GradientProps, MappingType, MappingTypes } from '../types'\r\nimport Abstract from './Abstract'\r\n\r\nexport default class Gradient extends Abstract {\r\n static u_colorA = 'white'\r\n static u_colorB = 'black'\r\n static u_alpha = 1\r\n\r\n static u_start = 1\r\n static u_end = -1\r\n static u_contrast = 1\r\n\r\n static vertexShader = `\r\n\t\tvarying vec3 v_position;\r\n\r\n\t\tvod main() {\r\n v_position = lamina_mapping_template;\r\n\t\t}\r\n `\r\n\r\n static fragmentShader = ` \r\n uniform vec3 u_colorA;\r\n uniform vec3 u_colorB;\r\n uniform vec3 u_axis;\r\n uniform float u_alpha;\r\n uniform float u_start;\r\n uniform float u_end;\r\n uniform float u_contrast;\r\n\r\n\t\tvarying vec3 v_position;\r\n\r\n void main() {\r\n\r\n float f_step = smoothstep(u_start, u_end, v_position.axes_template * u_contrast);\r\n vec3 f_color = mix(u_colorA, u_colorB, f_step);\r\n\r\n return vec4(f_color, u_alpha);\r\n }\r\n `\r\n\r\n axes: 'x' | 'y' | 'z' = 'x'\r\n mapping: MappingType = 'local'\r\n\r\n constructor(props?: GradientProps) {\r\n super(\r\n Gradient,\r\n {\r\n name: 'Gradient',\r\n ...props,\r\n },\r\n (self: Gradient) => {\r\n self.schema.push({\r\n value: self.axes,\r\n label: 'axes',\r\n options: ['x', 'y', 'z'],\r\n })\r\n\r\n self.schema.push({\r\n value: self.mapping,\r\n label: 'mapping',\r\n options: Object.values(MappingTypes),\r\n })\r\n\r\n const mapping = Gradient.getMapping(self.mapping)\r\n\r\n self.vertexShader = self.vertexShader.replace('lamina_mapping_template', mapping || 'local')\r\n self.fragmentShader = self.fragmentShader.replace('axes_template', self.axes || 'x')\r\n }\r\n )\r\n }\r\n\r\n private static getMapping(type?: string) {\r\n switch (type) {\r\n default:\r\n case 'local':\r\n return `position`\r\n case 'world':\r\n return `(modelMatrix * vec4(position,1.0)).xyz`\r\n case 'uv':\r\n return `vec3(uv, 0.)`\r\n }\r\n }\r\n}\r\n","import { MatcapProps } from \"../types\";\r\nimport Abstract from \"./Abstract\";\r\n\r\n// Credits: https://www.clicktorelease.com/blog/creating-spherical-environment-mapping-shader/\r\n\r\nexport default class Matcap extends Abstract {\r\n static u_alpha = 1;\r\n static u_map = undefined;\r\n\r\n static vertexShader = `\r\n varying vec3 v_position;\r\n varying vec3 v_normal;\r\n \r\n void main() {\r\n v_position = normalize( vec3( modelViewMatrix * vec4( position, 1.0 ) ) );\r\n v_normal = normalize( normalMatrix * normal );\r\n }\r\n `;\r\n\r\n static fragmentShader = ` \r\n\t\tuniform sampler2D u_map; \r\n\t\tuniform float u_alpha; \r\n\t\tvarying vec3 v_position;\r\n\t\tvarying vec3 v_normal;\r\n\r\n\t\t\r\n void main() {\r\n\t\t\tvec3 f_r = reflect( v_position, v_normal );\r\n\t\t\tfloat f_m = 2. * sqrt( pow( f_r.x, 2. ) + pow( f_r.y, 2. ) + pow( f_r.z + 1., 2. ) );\r\n\t\t\tvec2 f_vN = f_r.xy / f_m + .5;\r\n\r\n\t\t\tvec3 f_base = texture2D(u_map, f_vN).rgb;\r\n\r\n return vec4(f_base, u_alpha);\r\n }\r\n `;\r\n\r\n constructor(props?: MatcapProps) {\r\n super(Matcap, {\r\n name: \"Matcap\",\r\n ...props,\r\n });\r\n }\r\n}\r\n","import { Vector3 } from 'three'\r\nimport { ColorProps, MappingType, MappingTypes, NoiseProps, NoiseType, NoiseTypes } from '../types'\r\nimport Abstract from './Abstract'\r\n\r\ntype AbstractExtended = Abstract & {\r\n type: NoiseType\r\n mapping: MappingType\r\n}\r\n\r\nexport default class Noise extends Abstract {\r\n static u_colorA = '#666666'\r\n static u_colorB = '#666666'\r\n static u_colorC = '#FFFFFF'\r\n static u_colorD = '#FFFFFF'\r\n\r\n static u_alpha = 1\r\n static u_scale = 1\r\n static u_offset = new Vector3(0, 0, 0)\r\n\r\n static vertexShader = `\r\n varying vec3 v_position;\r\n\r\n void main() {\r\n v_position = lamina_mapping_template;\r\n }\r\n `\r\n\r\n static fragmentShader = ` \r\n uniform vec3 u_colorA;\r\n uniform vec3 u_colorB;\r\n uniform vec3 u_colorC;\r\n uniform vec3 u_colorD;\r\n uniform vec3 u_offset;\r\n\r\n uniform float u_alpha;\r\n uniform float u_scale;\r\n\r\n varying vec3 v_position;\r\n\r\n\r\n void main() {\r\n float f_n = lamina_noise_template((v_position + u_offset) * u_scale);\r\n\r\n float f_step1 = 0.;\r\n float f_step2 = 0.2;\r\n float f_step3 = 0.6;\r\n float f_step4 = 1.;\r\n\r\n vec3 f_color = mix(u_colorA, u_colorB, smoothstep(f_step1, f_step2, f_n));\r\n f_color = mix(f_color, u_colorC, smoothstep(f_step2, f_step3, f_n));\r\n f_color = mix(f_color, u_colorD, smoothstep(f_step3, f_step4, f_n));\r\n\r\n return vec4(f_color, u_alpha);\r\n }\r\n `\r\n\r\n type: NoiseType = 'perlin'\r\n mapping: MappingType = 'local'\r\n\r\n constructor(props?: NoiseProps) {\r\n super(\r\n Noise,\r\n {\r\n name: 'noise',\r\n ...props,\r\n },\r\n (self: Noise) => {\r\n self.schema.push({\r\n value: self.type,\r\n label: 'type',\r\n options: Object.values(NoiseTypes),\r\n })\r\n\r\n self.schema.push({\r\n value: self.mapping,\r\n label: 'mapping',\r\n options: Object.values(MappingTypes),\r\n })\r\n\r\n const noiseFunc = Noise.getNoiseFunction(self.type)\r\n const mapping = Noise.getMapping(self.mapping)\r\n\r\n self.vertexShader = self.vertexShader.replace('lamina_mapping_template', mapping)\r\n self.fragmentShader = self.fragmentShader.replace('lamina_noise_template', noiseFunc)\r\n }\r\n )\r\n }\r\n\r\n private static getNoiseFunction(type?: string) {\r\n switch (type) {\r\n default:\r\n case 'perlin':\r\n return `lamina_noise_perlin`\r\n case 'simplex':\r\n return `lamina_noise_simplex`\r\n case 'cell':\r\n return `lamina_noise_worley`\r\n case 'white':\r\n return `lamina_noise_white`\r\n case 'curl':\r\n return `lamina_noise_swirl`\r\n }\r\n }\r\n\r\n private static getMapping(type?: string) {\r\n switch (type) {\r\n default:\r\n case 'local':\r\n return `position`\r\n case 'world':\r\n return `(modelMatrix * vec4(position,1.0)).xyz`\r\n case 'uv':\r\n return `vec3(uv, 0.)`\r\n }\r\n }\r\n}\r\n","import { Vector3 } from 'three'\r\nimport { NormalProps } from '../types'\r\nimport Abstract from './Abstract'\r\n\r\nexport default class Normal extends Abstract {\r\n static u_alpha = 1\r\n static u_direction = new Vector3(1, 1, 1)\r\n\r\n static vertexShader = ` \r\n varying vec3 v_normals; \r\n\r\n void main() {\r\n v_normals = normal;\r\n }\r\n`\r\n\r\n static fragmentShader = ` \r\n \tuniform float u_alpha;\r\n \tuniform vec3 u_color;\r\n \tuniform vec3 u_direction;\r\n\r\n\t\tvarying vec3 v_normals;\r\n\r\n void main() {\r\n\t\t\tvec3 f_normalColor = vec3(1.);\r\n f_normalColor.x = v_normals.x * u_direction.x;\r\n f_normalColor.y = v_normals.y * u_direction.y;\r\n f_normalColor.z = v_normals.z * u_direction.z;\r\n\r\n return vec4(f_normalColor, u_alpha);\r\n }\r\n `\r\n\r\n constructor(props?: NormalProps) {\r\n super(Normal, {\r\n name: 'Normal',\r\n ...props,\r\n })\r\n }\r\n}\r\n","import { TextureProps } from '../types'\r\nimport Abstract from './Abstract'\r\n\r\nexport default class Texture extends Abstract {\r\n static u_alpha = 1\r\n static u_map = undefined\r\n\r\n static vertexShader = `\r\n varying vec2 v_uv;\r\n \r\n void main() {\r\n v_uv = uv;\r\n }\r\n `\r\n\r\n static fragmentShader = ` \r\n\t\tuniform sampler2D u_map; \r\n\t\tuniform float u_alpha; \r\n\t\tvarying vec2 v_uv;\r\n\r\n void main() {\r\n\t\t\tvec4 f_color = texture2D(u_map, v_uv);\r\n return vec4(f_color.rgb, f_color.a * u_alpha);\r\n }\r\n `\r\n\r\n constructor(props?: TextureProps) {\r\n super(Texture, {\r\n name: 'Texture',\r\n ...props,\r\n })\r\n }\r\n}\r\n","export default /* glsl */ `\r\nvec4 lamina_blend_add(const in vec4 x, const in vec4 y, const in float opacity) {\r\n\r\n\treturn vec4(min(x.xyz + y.xyz, 1.0) * opacity + x.xyz * (1.0 - opacity), x.a);\r\n\r\n}\r\nvec3 lamina_blend_alpha(const in vec3 x, const in vec3 y, const in float opacity) {\r\n\r\n\treturn y * opacity + x * (1.0 - opacity);\r\n\r\n}\r\n\r\nvec4 lamina_blend_alpha(const in vec4 x, const in vec4 y, const in float opacity) {\r\n\r\n\tfloat a = min(y.a, opacity);\r\n\r\n\treturn vec4(lamina_blend_alpha(x.rgb, y.rgb, a), x.a);\r\n\r\n}\r\nvec4 lamina_blend_average(const in vec4 x, const in vec4 y, const in float opacity) {\r\n\r\n\treturn vec4((x.xyz + y.xyz) * 0.5 * opacity + x.xyz * (1.0 - opacity), x.a);\r\n\r\n}\r\nfloat lamina_blend_color_burn(const in float x, const in float y) {\r\n\r\n\treturn (y == 0.0) ? y : max(1.0 - (1.0 - x) / y, 0.0);\r\n\r\n}\r\n\r\nvec4 lamina_blend_color_burn(const in vec4 x, const in vec4 y, const in float opacity) {\r\n\r\n\tvec4 z = vec4(\r\n\t\tlamina_blend_color_burn(x.r, y.r),\r\n\t\tlamina_blend_color_burn(x.g, y.g),\r\n\t\tlamina_blend_color_burn(x.b, y.b),\r\n\t\tlamina_blend_color_burn(x.a, y.a)\r\n\t);\r\n\r\n\treturn vec4(z.xyz * opacity + x.xyz * (1.0 - opacity), x.a);\r\n\r\n}\r\nfloat lamina_blend_color_dodge(const in float x, const in float y) {\r\n\r\n\treturn (y == 1.0) ? y : min(x / (1.0 - y), 1.0);\r\n\r\n}\r\n\r\nvec4 lamina_blend_color_dodge(const in vec4 x, const in vec4 y, const in float opacity) {\r\n\r\n\tvec4 z = vec4(\r\n\t\tlamina_blend_color_dodge(x.r, y.r),\r\n\t\tlamina_blend_color_dodge(x.g, y.g),\r\n\t\tlamina_blend_color_dodge(x.b, y.b),\r\n\t\tlamina_blend_color_dodge(x.a, y.a)\r\n\t);\r\n\r\n\treturn vec4(z.xyz * opacity + x.xyz * (1.0 - opacity), x.a);\r\n\r\n}\r\nvec4 lamina_blend_darken(const in vec4 x, const in vec4 y, const in float opacity) {\r\n\r\n\treturn vec4(min(x.xyz, y.xyz) * opacity + x.xyz * (1.0 - opacity), x.a);\r\n\r\n}\r\nvec4 lamina_blend_difference(const in vec4 x, const in vec4 y, const in float opacity) {\r\n\r\n\treturn vec4(abs(x.xyz - y.xyz) * opacity + x.xyz * (1.0 - opacity), x.a);\r\n\r\n}\r\nfloat lamina_blend_divide(const in float x, const in float y) {\r\n\r\n\treturn (y > 0.0) ? min(x / y, 1.0) : 1.0;\r\n\r\n}\r\n\r\nvec4 lamina_blend_divide(const in vec4 x, const in vec4 y, const in float opacity) {\r\n\r\n\tvec4 z = vec4(\r\n\t\tlamina_blend_divide(x.r, y.r),\r\n\t\tlamina_blend_divide(x.g, y.g),\r\n\t\tlamina_blend_divide(x.b, y.b),\r\n\t\tlamina_blend_divide(x.a, y.a)\r\n\t);\r\n\r\n\treturn vec4(z.xyz * opacity + x.xyz * (1.0 - opacity), x.a);\r\n\r\n}\r\nvec4 lamina_blend_exclusion(const in vec4 x, const in vec4 y, const in float opacity) {\r\n\r\n\treturn vec4((x.xyz + y.xyz - 2.0 * x.xyz * y.xyz) * opacity + x.xyz * (1.0 - opacity), x.a);\r\n\r\n}\r\nvec4 lamina_blend_lighten(const in vec4 x, const in vec4 y, const in float opacity) {\r\n\r\n\treturn vec4(max(x.xyz, y.xyz) * opacity + x.xyz * (1.0 - opacity), x.a);\r\n\r\n}\r\nvec4 lamina_blend_multiply(const in vec4 x, const in vec4 y, const in float opacity) {\r\n\r\n\treturn vec4( x.xyz * y.xyz * opacity + x.xyz * (1.0 - opacity), x.a);\r\n\r\n}\r\nvec4 lamina_blend_negation(const in vec4 x, const in vec4 y, const in float opacity) {\r\n\r\n\treturn vec4((1.0 - abs(1.0 - x.xyz - y.xyz)) * opacity + x.xyz * (1.0 - opacity), x.a);\r\n\r\n}\r\nvec4 lamina_blend_normal(const in vec4 x, const in vec4 y, const in float opacity) {\r\n\r\n\treturn vec4(y.xyz * opacity + x.xyz * (1.0 - opacity), x.a);\r\n\r\n}\r\nfloat lamina_blend_overlay(const in float x, const in float y) {\r\n\r\n\treturn (x < 0.5) ? (2.0 * x * y) : (1.0 - 2.0 * (1.0 - x) * (1.0 - y));\r\n\r\n}\r\n\r\nvec4 lamina_blend_overlay(const in vec4 x, const in vec4 y, const in float opacity) {\r\n\r\n\tvec4 z = vec4(\r\n\t\tlamina_blend_overlay(x.r, y.r),\r\n\t\tlamina_blend_overlay(x.g, y.g),\r\n\t\tlamina_blend_overlay(x.b, y.b),\r\n\t\tlamina_blend_overlay(x.a, y.a)\r\n\t);\r\n\r\n\treturn vec4(z.xyz * opacity + x.xyz * (1.0 - opacity), x.a);\r\n\r\n}\r\nfloat lamina_blend_reflect(const in float x, const in float y) {\r\n\r\n\treturn (y == 1.0) ? y : min(x * x / (1.0 - y), 1.0);\r\n\r\n}\r\n\r\nvec4 lamina_blend_reflect(const in vec4 x, const in vec4 y, const in float opacity) {\r\n\r\n\tvec4 z = vec4(\r\n\t\tlamina_blend_reflect(x.r, y.r),\r\n\t\tlamina_blend_reflect(x.g, y.g),\r\n\t\tlamina_blend_reflect(x.b, y.b),\r\n\t\tlamina_blend_reflect(x.a, y.a)\r\n\t);\r\n\r\n\treturn vec4(z.xyz * opacity + x.xyz * (1.0 - opacity), x.a);\r\n\r\n}\r\nvec4 lamina_blend_screen(const in vec4 x, const in vec4 y, const in float opacity) {\r\n\r\n\treturn vec4((1.0 - (1.0 - x.xyz) * (1.0 - y.xyz)) * opacity + x.xyz * (1.0 - opacity), x.a);\r\n\r\n}\r\nfloat lamina_blend_softlight(const in float x, const in float y) {\r\n\r\n\treturn (y < 0.5) ?\r\n\t\t(2.0 * x * y + x * x * (1.0 - 2.0 * y)) :\r\n\t\t(sqrt(x) * (2.0 * y - 1.0) + 2.0 * x * (1.0 - y));\r\n\r\n}\r\n\r\nvec4 lamina_blend_softlight(const in vec4 x, const in vec4 y, const in float opacity) {\r\n\r\n\tvec4 z = vec4(\r\n\t\tlamina_blend_softlight(x.r, y.r),\r\n\t\tlamina_blend_softlight(x.g, y.g),\r\n\t\tlamina_blend_softlight(x.b, y.b),\r\n\t\tlamina_blend_softlight(x.a, y.a)\r\n\t);\r\n\r\n\treturn vec4(z.xyz * opacity + x.xyz * (1.0 - opacity), x.a);\r\n\r\n}\r\nvec4 lamina_blend_subtract(const in vec4 x, const in vec4 y, const in float opacity) {\r\n\r\n\treturn vec4(max(x.xyz + y.xyz - 1.0, 0.0) * opacity + x.xyz * (1.0 - opacity), x.a);\r\n\r\n}\r\n\r\n`\r\n","export default /* glsl */ `\r\n\r\nfloat lamina_map(float value, float min1, float max1, float min2, float max2) {\r\n return min2 + (value - min1) * (max2 - min2) / (max1 - min1);\r\n}\r\n\r\nfloat lamina_normalize(float v) { return lamina_map(v, -1.0, 1.0, 0.0, 1.0); }\r\n`;\r\n","export default /* glsl */ `\r\n\r\n// From: https://gist.github.com/patriciogonzalezvivo/670c22f3966e662d2f83\r\n// Huge thanks to the creators of these algorithms\r\n\r\nfloat lamina_noise_mod289(float x){return x - floor(x * (1.0 / 289.0)) * 289.0;}\r\nvec4 lamina_noise_mod289(vec4 x){return x - floor(x * (1.0 / 289.0)) * 289.0;}\r\nvec4 lamina_noise_perm(vec4 x){return lamina_noise_mod289(((x * 34.0) + 1.0) * x);}\r\nvec4 lamina_noise_permute(vec4 x) { return mod(((x * 34.0) + 1.0) * x, 289.0); }\r\nvec4 lamina_noise_taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; }\r\n\r\n\r\nfloat lamina_noise_white(vec2 p) {\r\n return fract(1e4 * sin(17.0 * p.x + p.y * 0.1) *\r\n (0.1 + abs(sin(p.y * 13.0 + p.x))));\r\n}\r\n\r\nfloat lamina_noise_white(vec3 p) {\r\n return lamina_noise_white(p.xy);\r\n}\r\n\r\n\r\nvec3 lamina_noise_fade(vec3 t) { return t * t * t * (t * (t * 6.0 - 15.0) + 10.0); }\r\n\r\nfloat lamina_noise_perlin(vec3 P) {\r\n vec3 Pi0 = floor(P); // Integer part for indexing\r\n vec3 Pi1 = Pi0 + vec3(1.0); // Integer part + 1\r\n Pi0 = mod(Pi0, 289.0);\r\n Pi1 = mod(Pi1, 289.0);\r\n vec3 Pf0 = fract(P); // Fractional part for interpolation\r\n vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0\r\n vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x);\r\n vec4 iy = vec4(Pi0.yy, Pi1.yy);\r\n vec4 iz0 = Pi0.zzzz;\r\n vec4 iz1 = Pi1.zzzz;\r\n\r\n vec4 ixy = lamina_noise_permute(lamina_noise_permute(ix) + iy);\r\n vec4 ixy0 = lamina_noise_permute(ixy + iz0);\r\n vec4 ixy1 = lamina_noise_permute(ixy + iz1);\r\n\r\n vec4 gx0 = ixy0 / 7.0;\r\n vec4 gy0 = fract(floor(gx0) / 7.0) - 0.5;\r\n gx0 = fract(gx0);\r\n vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0);\r\n vec4 sz0 = step(gz0, vec4(0.0));\r\n gx0 -= sz0 * (step(0.0, gx0) - 0.5);\r\n gy0 -= sz0 * (step(0.0, gy0) - 0.5);\r\n\r\n vec4 gx1 = ixy1 / 7.0;\r\n vec4 gy1 = fract(floor(gx1) / 7.0) - 0.5;\r\n gx1 = fract(gx1);\r\n vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1);\r\n vec4 sz1 = step(gz1, vec4(0.0));\r\n gx1 -= sz1 * (step(0.0, gx1) - 0.5);\r\n gy1 -= sz1 * (step(0.0, gy1) - 0.5);\r\n\r\n vec3 g000 = vec3(gx0.x, gy0.x, gz0.x);\r\n vec3 g100 = vec3(gx0.y, gy0.y, gz0.y);\r\n vec3 g010 = vec3(gx0.z, gy0.z, gz0.z);\r\n vec3 g110 = vec3(gx0.w, gy0.w, gz0.w);\r\n vec3 g001 = vec3(gx1.x, gy1.x, gz1.x);\r\n vec3 g101 = vec3(gx1.y, gy1.y, gz1.y);\r\n vec3 g011 = vec3(gx1.z, gy1.z, gz1.z);\r\n vec3 g111 = vec3(gx1.w, gy1.w, gz1.w);\r\n\r\n vec4 norm0 = lamina_noise_taylorInvSqrt(\r\n vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)));\r\n g000 *= norm0.x;\r\n g010 *= norm0.y;\r\n g100 *= norm0.z;\r\n g110 *= norm0.w;\r\n vec4 norm1 = lamina_noise_taylorInvSqrt(\r\n vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)));\r\n g001 *= norm1.x;\r\n g011 *= norm1.y;\r\n g101 *= norm1.z;\r\n g111 *= norm1.w;\r\n\r\n float n000 = dot(g000, Pf0);\r\n float n100 = dot(g100, vec3(Pf1.x, Pf0.yz));\r\n float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z));\r\n float n110 = dot(g110, vec3(Pf1.xy, Pf0.z));\r\n float n001 = dot(g001, vec3(Pf0.xy, Pf1.z));\r\n float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z));\r\n float n011 = dot(g011, vec3(Pf0.x, Pf1.yz));\r\n float n111 = dot(g111, Pf1);\r\n\r\n vec3 fade_xyz = lamina_noise_fade(Pf0);\r\n vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111),\r\n fade_xyz.z);\r\n vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y);\r\n float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x);\r\n return lamina_normalize(2.2 * n_xyz);\r\n}\r\n\r\nfloat lamina_noise_simplex(vec3 v) {\r\n const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0);\r\n const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);\r\n\r\n // First corner\r\n vec3 i = floor(v + dot(v, C.yyy));\r\n vec3 x0 = v - i + dot(i, C.xxx);\r\n\r\n // Other corners\r\n vec3 g = step(x0.yzx, x0.xyz);\r\n vec3 l = 1.0 - g;\r\n vec3 i1 = min(g.xyz, l.zxy);\r\n vec3 i2 = max(g.xyz, l.zxy);\r\n\r\n // x0 = x0 - 0. + 0.0 * C\r\n vec3 x1 = x0 - i1 + 1.0 * C.xxx;\r\n vec3 x2 = x0 - i2 + 2.0 * C.xxx;\r\n vec3 x3 = x0 - 1. + 3.0 * C.xxx;\r\n\r\n // Permutations\r\n i = mod(i, 289.0);\r\n vec4 p = lamina_noise_permute(lamina_noise_permute(lamina_noise_permute(i.z + vec4(0.0, i1.z, i2.z, 1.0)) + i.y +\r\n vec4(0.0, i1.y, i2.y, 1.0)) +\r\n i.x + vec4(0.0, i1.x, i2.x, 1.0));\r\n\r\n // Gradients\r\n // ( N*N points uniformly over a square, mapped onto an octahedron.)\r\n float n_ = 1.0 / 7.0; // N=7\r\n vec3 ns = n_ * D.wyz - D.xzx;\r\n\r\n vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,N*N)\r\n\r\n vec4 x_ = floor(j * ns.z);\r\n vec4 y_ = floor(j - 7.0 * x_); // mod(j,N)\r\n\r\n vec4 x = x_ * ns.x + ns.yyyy;\r\n vec4 y = y_ * ns.x + ns.yyyy;\r\n vec4 h = 1.0 - abs(x) - abs(y);\r\n\r\n vec4 b0 = vec4(x.xy, y.xy);\r\n vec4 b1 = vec4(x.zw, y.zw);\r\n\r\n vec4 s0 = floor(b0) * 2.0 + 1.0;\r\n vec4 s1 = floor(b1) * 2.0 + 1.0;\r\n vec4 sh = -step(h, vec4(0.0));\r\n\r\n vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;\r\n vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww;\r\n\r\n vec3 p0 = vec3(a0.xy, h.x);\r\n vec3 p1 = vec3(a0.zw, h.y);\r\n vec3 p2 = vec3(a1.xy, h.z);\r\n vec3 p3 = vec3(a1.zw, h.w);\r\n\r\n // Normalise gradients\r\n vec4 norm =\r\n lamina_noise_taylorInvSqrt(vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));\r\n p0 *= norm.x;\r\n p1 *= norm.y;\r\n p2 *= norm.z;\r\n p3 *= norm.w;\r\n\r\n // Mix final noise value\r\n vec4 m =\r\n max(0.6 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0);\r\n m = m * m;\r\n return lamina_normalize(42.0 *\r\n dot(m * m, vec4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3))));\r\n}\r\n\r\nvec3 lamina_noise_simplex3(vec3 x) {\r\n float s = lamina_noise_simplex(vec3(x));\r\n float s1 = lamina_noise_simplex(vec3(x.y - 19.1, x.z + 33.4, x.x + 47.2));\r\n float s2 = lamina_noise_simplex(vec3(x.z + 74.2, x.x - 124.5, x.y + 99.4));\r\n vec3 c = vec3(s, s1, s2);\r\n return c;\r\n}\r\n\r\nvec3 lamina_noise_curl(vec3 p) {\r\n const float e = .1;\r\n vec3 dx = vec3(e, 0.0, 0.0);\r\n vec3 dy = vec3(0.0, e, 0.0);\r\n vec3 dz = vec3(0.0, 0.0, e);\r\n\r\n vec3 p_x0 = lamina_noise_simplex3(p - dx);\r\n vec3 p_x1 = lamina_noise_simplex3(p + dx);\r\n vec3 p_y0 = lamina_noise_simplex3(p - dy);\r\n vec3 p_y1 = lamina_noise_simplex3(p + dy);\r\n vec3 p_z0 = lamina_noise_simplex3(p - dz);\r\n vec3 p_z1 = lamina_noise_simplex3(p + dz);\r\n\r\n float x = p_y1.z - p_y0.z - p_z1.y + p_z0.y;\r\n float y = p_z1.x - p_z0.x - p_x1.z + p_x0.z;\r\n float z = p_x1.y - p_x0.y - p_y1.x + p_y0.x;\r\n\r\n const float divisor = 1.0 / (2.0 * e);\r\n return normalize(vec3(x, y, z) * divisor);\r\n}\r\n\r\nvec3 lamina_permute(vec3 x) {\r\n return mod((34.0 * x + 1.0) * x, 289.0);\r\n}\r\n\r\nvec3 lamina_dist(vec3 x, vec3 y, vec3 z, bool manhattanDistance) {\r\n return manhattanDistance ? abs(x) + abs(y) + abs(z) : (x * x + y * y + z * z);\r\n}\r\n\r\n// From: https://github.com/Erkaman/glsl-worley\r\nfloat lamina_noise_worley(vec3 P) {\r\n float jitter = 1.;\r\n bool manhattanDistance = false; \r\n\r\n float K = 0.142857142857; // 1/7\r\n float Ko = 0.428571428571; // 1/2-K/2\r\n float K2 = 0.020408163265306; // 1/(7*7)\r\n float Kz = 0.166666666667; // 1/6\r\n float Kzo = 0.416666666667; // 1/2-1/6*2\r\n\r\n\tvec3 Pi = mod(floor(P), 289.0);\r\n \tvec3 Pf = fract(P) - 0.5;\r\n\r\n\tvec3 Pfx = Pf.x + vec3(1.0, 0.0, -1.0);\r\n\tvec3 Pfy = Pf.y + vec3(1.0, 0.0, -1.0);\r\n\tvec3 Pfz = Pf.z + vec3(1.0, 0.0, -1.0);\r\n\r\n\tvec3 p = lamina_permute(Pi.x + vec3(-1.0, 0.0, 1.0));\r\n\tvec3 p1 = lamina_permute(p + Pi.y - 1.0);\r\n\tvec3 p2 = lamina_permute(p + Pi.y);\r\n\tvec3 p3 = lamina_permute(p + Pi.y + 1.0);\r\n\r\n\tvec3 p11 = lamina_permute(p1 + Pi.z - 1.0);\r\n\tvec3 p12 = lamina_permute(p1 + Pi.z);\r\n\tvec3 p13 = lamina_permute(p1 + Pi.z + 1.0);\r\n\r\n\tvec3 p21 = lamina_permute(p2 + Pi.z - 1.0);\r\n\tvec3 p22 = lamina_permute(p2 + Pi.z);\r\n\tvec3 p23 = lamina_permute(p2 + Pi.z + 1.0);\r\n\r\n\tvec3 p31 = lamina_permute(p3 + Pi.z - 1.0);\r\n\tvec3 p32 = lamina_permute(p3 + Pi.z);\r\n\tvec3 p33 = lamina_permute(p3 + Pi.z + 1.0);\r\n\r\n\tvec3 ox11 = fract(p11*K) - Ko;\r\n\tvec3 oy11 = mod(floor(p11*K), 7.0)*K - Ko;\r\n\tvec3 oz11 = floor(p11*K2)*Kz - Kzo; // p11 < 289 guaranteed\r\n\r\n\tvec3 ox12 = fract(p12*K) - Ko;\r\n\tvec3 oy12 = mod(floor(p12*K), 7.0)*K - Ko;\r\n\tvec3 oz12 = floor(p12*K2)*Kz - Kzo;\r\n\r\n\tvec3 ox13 = fract(p13*K) - Ko;\r\n\tvec3 oy13 = mod(floor(p13*K), 7.0)*K - Ko;\r\n\tvec3 oz13 = floor(p13*K2)*Kz - Kzo;\r\n\r\n\tvec3 ox21 = fract(p21*K) - Ko;\r\n\tvec3 oy21 = mod(floor(p21*K), 7.0)*K - Ko;\r\n\tvec3 oz21 = floor(p21*K2)*Kz - Kzo;\r\n\r\n\tvec3 ox22 = fract(p22*K) - Ko;\r\n\tvec3 oy22 = mod(floor(p22*K), 7.0)*K - Ko;\r\n\tvec3 oz22 = floor(p22*K2)*Kz - Kzo;\r\n\r\n\tvec3 ox23 = fract(p23*K) - Ko;\r\n\tvec3 oy23 = mod(floor(p23*K), 7.0)*K - Ko;\r\n\tvec3 oz23 = floor(p23*K2)*Kz - Kzo;\r\n\r\n\tvec3 ox31 = fract(p31*K) - Ko;\r\n\tvec3 oy31 = mod(floor(p31*K), 7.0)*K - Ko;\r\n\tvec3 oz31 = floor(p31*K2)*Kz - Kzo;\r\n\r\n\tvec3 ox32 = fract(p32*K) - Ko;\r\n\tvec3 oy32 = mod(floor(p32*K), 7.0)*K - Ko;\r\n\tvec3 oz32 = floor(p32*K2)*Kz - Kzo;\r\n\r\n\tvec3 ox33 = fract(p33*K) - Ko;\r\n\tvec3 oy33 = mod(floor(p33*K), 7.0)*K - Ko;\r\n\tvec3 oz33 = floor(p33*K2)*Kz - Kzo;\r\n\r\n\tvec3 dx11 = Pfx + jitter*ox11;\r\n\tvec3 dy11 = Pfy.x + jitter*oy11;\r\n\tvec3 dz11 = Pfz.x + jitter*oz11;\r\n\r\n\tvec3 dx12 = Pfx + jitter*ox12;\r\n\tvec3 dy12 = Pfy.x + jitter*oy12;\r\n\tvec3 dz12 = Pfz.y + jitter*oz12;\r\n\r\n\tvec3 dx13 = Pfx + jitter*ox13;\r\n\tvec3 dy13 = Pfy.x + jitter*oy13;\r\n\tvec3 dz13 = Pfz.z + jitter*oz13;\r\n\r\n\tvec3 dx21 = Pfx + jitter*ox21;\r\n\tvec3 dy21 = Pfy.y + jitter*oy21;\r\n\tvec3 dz21 = Pfz.x + jitter*oz21;\r\n\r\n\tvec3 dx22 = Pfx + jitter*ox22;\r\n\tvec3 dy22 = Pfy.y + jitter*oy22;\r\n\tvec3 dz22 = Pfz.y + jitter*oz22;\r\n\r\n\tvec3 dx23 = Pfx + jitter*ox23;\r\n\tvec3 dy23 = Pfy.y + jitter*oy23;\r\n\tvec3 dz23 = Pfz.z + jitter*oz23;\r\n\r\n\tvec3 dx31 = Pfx + jitter*ox31;\r\n\tvec3 dy31 = Pfy.z + jitter*oy31;\r\n\tvec3 dz31 = Pfz.x + jitter*oz31;\r\n\r\n\tvec3 dx32 = Pfx + jitter*ox32;\r\n\tvec3 dy32 = Pfy.z + jitter*oy32;\r\n\tvec3 dz32 = Pfz.y + jitter*oz32;\r\n\r\n\tvec3 dx33 = Pfx + jitter*ox33;\r\n\tvec3 dy33 = Pfy.z + jitter*oy33;\r\n\tvec3 dz33 = Pfz.z + jitter*oz33;\r\n\r\n\tvec3 d11 = lamina_dist(dx11, dy11, dz11, manhattanDistance);\r\n\tvec3 d12 = lamina_dist(dx12, dy12, dz12, manhattanDistance);\r\n\tvec3 d13 = lamina_dist(dx13, dy13, dz13, manhattanDistance);\r\n\tvec3 d21 = lamina_dist(dx21, dy21, dz21, manhattanDistance);\r\n\tvec3 d22 = lamina_dist(dx22, dy22, dz22, manhattanDistance);\r\n\tvec3 d23 = lamina_dist(dx23, dy23, dz23, manhattanDistance);\r\n\tvec3 d31 = lamina_dist(dx31, dy31, dz31, manhattanDistance);\r\n\tvec3 d32 = lamina_dist(dx32, dy32, dz32, manhattanDistance);\r\n\tvec3 d33 = lamina_dist(dx33, dy33, dz33, manhattanDistance);\r\n\r\n\tvec3 d1a = min(d11, d12);\r\n\td12 = max(d11, d12);\r\n\td11 = min(d1a, d13); // Smallest now not in d12 or d13\r\n\td13 = max(d1a, d13);\r\n\td12 = min(d12, d13); // 2nd smallest now not in d13\r\n\tvec3 d2a = min(d21, d22);\r\n\td22 = max(d21, d22);\r\n\td21 = min(d2a, d23); // Smallest now not in d22 or d23\r\n\td23 = max(d2a, d23);\r\n\td22 = min(d22, d23); // 2nd smallest now not in d23\r\n\tvec3 d3a = min(d31, d32);\r\n\td32 = max(d31, d32);\r\n\td31 = min(d3a, d33); // Smallest now not in d32 or d33\r\n\td33 = max(d3a, d33);\r\n\td32 = min(d32, d33); // 2nd smallest now not in d33\r\n\tvec3 da = min(d11, d21);\r\n\td21 = max(d11, d21);\r\n\td11 = min(da, d31); // Smallest now in d11\r\n\td31 = max(da, d31); // 2nd smallest now not in d31\r\n\td11.xy = (d11.x < d11.y) ? d11.xy : d11.yx;\r\n\td11.xz = (d11.x < d11.z) ? d11.xz : d11.zx; // d11.x now smallest\r\n\td12 = min(d12, d21); // 2nd smallest now not in d21\r\n\td12 = min(d12, d22); // nor in d22\r\n\td12 = min(d12, d31); // nor in d31\r\n\td12 = min(d12, d32); // nor in d32\r\n\td11.yz = min(d11.yz,d12.xy); // nor in d12.yz\r\n\td11.y = min(d11.y,d12.z); // Only two more to go\r\n\td11.y = min(d11.y,d11.z); // Done! (Phew!)\r\n\r\n vec2 F = sqrt(d11.xy);\r\n\treturn F.x; // F1, F2\r\n\r\n}\r\n\r\nfloat lamina_noise_swirl(vec3 position) {\r\n float scale = 0.1;\r\n float freq = 4. * scale;\r\n float t = 1.;\r