diff --git a/.changeset/nine-tables-heal.md b/.changeset/nine-tables-heal.md new file mode 100644 index 000000000..9877da96e --- /dev/null +++ b/.changeset/nine-tables-heal.md @@ -0,0 +1,5 @@ +--- +"shader-composer": patch +--- + +Added new `Luminance` unit, wrapping Three's `luminance` function. diff --git a/.changeset/yellow-fishes-notice.md b/.changeset/yellow-fishes-notice.md new file mode 100644 index 000000000..472841fcb --- /dev/null +++ b/.changeset/yellow-fishes-notice.md @@ -0,0 +1,5 @@ +--- +"render-composer": patch +--- + +Added new `LensDirt` effect. diff --git a/apps/render-composer-examples/package.json b/apps/render-composer-examples/package.json index 416c566be..a421ba27e 100644 --- a/apps/render-composer-examples/package.json +++ b/apps/render-composer-examples/package.json @@ -12,6 +12,7 @@ "@hmans/r3f-animate": "^0.0.4", "@react-three/drei": "^9.29.1", "@react-three/fiber": "^8.7.0", + "postprocessing": "^6.28.7", "react": "^18.2.0", "react-dom": "^18.2.0", "render-composer": "^0.2.1", diff --git a/apps/render-composer-examples/public/textures/lensdirt.jpg b/apps/render-composer-examples/public/textures/lensdirt.jpg new file mode 100644 index 000000000..78217deeb Binary files /dev/null and b/apps/render-composer-examples/public/textures/lensdirt.jpg differ diff --git a/apps/render-composer-examples/src/App.tsx b/apps/render-composer-examples/src/App.tsx index 0bfc36844..26cf025df 100644 --- a/apps/render-composer-examples/src/App.tsx +++ b/apps/render-composer-examples/src/App.tsx @@ -1,8 +1,13 @@ import { Animate } from "@hmans/r3f-animate" -import { Environment, Loader, OrbitControls } from "@react-three/drei" +import { + Environment, + Loader, + OrbitControls, + useTexture +} from "@react-three/drei" +import * as PP from "postprocessing" import { Suspense, useState } from "react" import * as RC from "render-composer" -import * as PP from "postprocessing" import { bitmask } from "render-composer" import { Mesh, Object3D } from "three" @@ -20,20 +25,8 @@ function App() { - - - - {sun && } - - - - + @@ -96,3 +89,17 @@ function App() { } export default App + +const PostProcessing = ({ sun }: { sun?: Mesh | null }) => { + const texture = useTexture("/textures/lensdirt.jpg") + + return ( + + + + {sun && } + + + + ) +} diff --git a/packages/render-composer/package.json b/packages/render-composer/package.json index 3ef971c7c..1020ac243 100644 --- a/packages/render-composer/package.json +++ b/packages/render-composer/package.json @@ -34,6 +34,8 @@ "@hmans/use-const": "^0.0.1", "@hmans/use-mutable-list": "workspace:^0.0.2", "@hmans/use-nullable-state": "workspace:^0.0.1", + "shader-composer": "workspace:^0.4.3", + "shader-composer-postprocessing": "workspace:^0.0.1", "test": "^3.2.1" } } diff --git a/packages/render-composer/src/effects/LensDirtEffect.tsx b/packages/render-composer/src/effects/LensDirtEffect.tsx new file mode 100644 index 000000000..b59a820b5 --- /dev/null +++ b/packages/render-composer/src/effects/LensDirtEffect.tsx @@ -0,0 +1,47 @@ +import * as PP from "postprocessing" +import { + Luminance, + Mul, + Smoothstep, + Texture2D, + UniformUnit +} from "shader-composer" +import { + InputColor, + PostProcessingEffectMaster, + ShaderComposerEffect, + UV +} from "shader-composer-postprocessing" +import { Texture } from "three" +import { usePostProcessingEffect } from "../lib/usePostProcessingEffect" + +export type LensDirtEffectProps = ConstructorParameters< + typeof LensDirtEffectImpl +>[0] + +export const LensDirtEffect = (props: LensDirtEffectProps) => { + usePostProcessingEffect(() => new LensDirtEffectImpl(props), props) + return null +} + +export class LensDirtEffectImpl extends ShaderComposerEffect { + constructor({ + texture, + blendFunction = PP.BlendFunction.ADD + }: { + texture: Texture + blendFunction?: PP.BlendFunction + }) { + const u_texture = UniformUnit("sampler2D", texture) + + super({ + blendFunction, + root: PostProcessingEffectMaster({ + color: Mul( + Texture2D(u_texture, UV).color, + Smoothstep(0.1, 0.3, Luminance(InputColor)) + ) + }) + }) + } +} diff --git a/packages/render-composer/src/effects/index.ts b/packages/render-composer/src/effects/index.ts index 3ca1f2872..2d43216df 100644 --- a/packages/render-composer/src/effects/index.ts +++ b/packages/render-composer/src/effects/index.ts @@ -1,4 +1,5 @@ export * from "./GodRaysEffect" +export * from "./LensDirtEffect" export * from "./NoiseEffect" export * from "./SelectiveBloomEffect" export * from "./SMAAEffect" diff --git a/packages/shader-composer-postprocessing/LICENSE.md b/packages/shader-composer-postprocessing/LICENSE.md new file mode 100644 index 000000000..614e75493 --- /dev/null +++ b/packages/shader-composer-postprocessing/LICENSE.md @@ -0,0 +1,20 @@ +Copyright (c) 2022 Hendrik Mans + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/shader-composer-postprocessing/README.md b/packages/shader-composer-postprocessing/README.md new file mode 100644 index 000000000..7c2a4395a --- /dev/null +++ b/packages/shader-composer-postprocessing/README.md @@ -0,0 +1,32 @@ +# shader-composer-postprocessing + +## Introduction + +Build [postprocessing] effect passes using Shader Composer. + +## License + +``` +Copyright (c) 2022 Hendrik Mans + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +``` + +[postprocessing]: https://github.com/pmndrs/postprocessing diff --git a/packages/shader-composer-postprocessing/package.json b/packages/shader-composer-postprocessing/package.json new file mode 100644 index 000000000..4c19fce0a --- /dev/null +++ b/packages/shader-composer-postprocessing/package.json @@ -0,0 +1,29 @@ +{ + "name": "shader-composer-postprocessing", + "author": { + "name": "Hendrik Mans", + "email": "hendrik@mans.de", + "url": "https://hmans.co" + }, + "description": "Build postprocessing effects using Shader Composer.", + "version": "0.0.1", + "main": "dist/shader-composer-postprocessing.cjs.js", + "module": "dist/shader-composer-postprocessing.esm.js", + "files": [ + "dist/**", + "LICENSE", + "README.md" + ], + "license": "MIT", + "sideEffects": false, + "devDependencies": { + "postprocessing": "^6.28.7", + "shader-composer": "workspace:^0.4.3", + "three": "^0.143.0" + }, + "peerDependencies": { + "postprocessing": "^6.28.7", + "shader-composer": "workspace:^0.4.3", + "three": ">=0.141.0" + } +} diff --git a/packages/shader-composer-postprocessing/src/PostProcessingEffectMaster.ts b/packages/shader-composer-postprocessing/src/PostProcessingEffectMaster.ts new file mode 100644 index 000000000..b217a48c1 --- /dev/null +++ b/packages/shader-composer-postprocessing/src/PostProcessingEffectMaster.ts @@ -0,0 +1,19 @@ +import { $, Input, Master } from "shader-composer" +import { InputAlpha, InputColor } from "./units" + +export type PostProcessingEffectMasterProps = { + color?: Input<"vec3"> + alpha?: Input<"float"> +} + +export const PostProcessingEffectMaster = ({ + color = InputColor, + alpha = InputAlpha +}: PostProcessingEffectMasterProps) => + Master({ + fragment: { + body: $` + outputColor = vec4(${color}.rgb, ${alpha}); + ` + } + }) diff --git a/packages/shader-composer-postprocessing/src/ShaderComposerEffect.ts b/packages/shader-composer-postprocessing/src/ShaderComposerEffect.ts new file mode 100644 index 000000000..bf150d426 --- /dev/null +++ b/packages/shader-composer-postprocessing/src/ShaderComposerEffect.ts @@ -0,0 +1,28 @@ +import * as PP from "postprocessing" +import { compileShader } from "shader-composer" +import { PostProcessingEffectMaster } from "./PostProcessingEffectMaster" + +export type ShaderComposerEffectProps = { + root: ReturnType + blendFunction?: PP.BlendFunction +} + +export class ShaderComposerEffect extends PP.Effect { + constructor({ + root, + blendFunction = PP.BlendFunction.NORMAL + }: ShaderComposerEffectProps) { + const [shader] = compileShader(root) + + /* TODO: replace this hack with something nicer. Maybe we can teach `compileShader` the signature of the function it should emit? */ + const fragment = shader.fragmentShader.replace( + "void main()", + "void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor)" + ) + + super("LensDirt", fragment, { + blendFunction, + uniforms: new Map(Object.entries(shader.uniforms)) + }) + } +} diff --git a/packages/shader-composer-postprocessing/src/index.ts b/packages/shader-composer-postprocessing/src/index.ts new file mode 100644 index 000000000..74e203582 --- /dev/null +++ b/packages/shader-composer-postprocessing/src/index.ts @@ -0,0 +1,3 @@ +export * from "./PostProcessingEffectMaster" +export * from "./ShaderComposerEffect" +export * from "./units" diff --git a/packages/shader-composer-postprocessing/src/units.ts b/packages/shader-composer-postprocessing/src/units.ts new file mode 100644 index 000000000..5e68b99e5 --- /dev/null +++ b/packages/shader-composer-postprocessing/src/units.ts @@ -0,0 +1,5 @@ +import { $, Float, Vec2, Vec3 } from "shader-composer" + +export const InputColor = Vec3($`inputColor.rgb`) +export const InputAlpha = Float($`inputColor.a`) +export const UV = Vec2($`uv`) diff --git a/packages/shader-composer-postprocessing/tsconfig.json b/packages/shader-composer-postprocessing/tsconfig.json new file mode 100644 index 000000000..52d43eaaa --- /dev/null +++ b/packages/shader-composer-postprocessing/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src/**/*"] +} diff --git a/packages/shader-composer/src/stdlib/artistic.ts b/packages/shader-composer/src/stdlib/artistic.ts index 46bda441f..3207af76c 100644 --- a/packages/shader-composer/src/stdlib/artistic.ts +++ b/packages/shader-composer/src/stdlib/artistic.ts @@ -1,4 +1,5 @@ import { pipe } from "fp-ts/function" +import { $ } from "../expressions" import { GLSLType, Input, Unit } from "../units" import { Abs, Add, Lerp, Mul, Pow, Saturate, Smoothstep } from "./math" import { Float } from "./values" @@ -74,3 +75,5 @@ export const Gradient = ( return color as Unit } + +export const Luminance = (color: Input<"vec3">) => Float($`luminance(${color})`) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3472ccc44..4a2d1cd08 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -292,6 +292,7 @@ importers: '@types/react-dom': ^18.0.6 '@types/three': ^0.143.1 '@vitejs/plugin-react': ^2.0.1 + postprocessing: ^6.28.7 react: ^18.2.0 react-dom: ^18.2.0 render-composer: ^0.2.1 @@ -302,6 +303,7 @@ importers: '@hmans/r3f-animate': 0.0.4_y3omt5lvwtl6lo6hnfcawzz7ea '@react-three/drei': 9.29.1_dqbvravr3s5buz3zuoms5ekkmq '@react-three/fiber': 8.7.0_f72olm6mn3unzgg4exeiaoxanm + postprocessing: 6.28.7_three@0.143.0 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 render-composer: link:../../packages/render-composer @@ -662,12 +664,16 @@ importers: postprocessing: ^6.28.7 react: ^18.2.0 react-dom: ^18.2.0 + shader-composer: workspace:^0.4.3 + shader-composer-postprocessing: workspace:^0.0.1 test: ^3.2.1 three: ^0.143.0 dependencies: '@hmans/use-const': 0.0.1_react@18.2.0 '@hmans/use-mutable-list': link:../hmans-use-mutable-list '@hmans/use-nullable-state': link:../hmans-use-nullable-state + shader-composer: link:../shader-composer + shader-composer-postprocessing: link:../shader-composer-postprocessing test: 3.2.1 devDependencies: '@react-three/fiber': 8.7.0_f72olm6mn3unzgg4exeiaoxanm @@ -685,6 +691,16 @@ importers: devDependencies: three: 0.143.0 + packages/shader-composer-postprocessing: + specifiers: + postprocessing: ^6.28.7 + shader-composer: workspace:^0.4.3 + three: ^0.143.0 + devDependencies: + postprocessing: 6.28.7_three@0.143.0 + shader-composer: link:../shader-composer + three: 0.143.0 + packages/shader-composer-r3f: specifiers: '@react-three/fiber': ^8.7.0