Skip to content

Commit

Permalink
feat: Adds normal & distortion maps support to Reflector (#301)
Browse files Browse the repository at this point in the history
  • Loading branch information
emmelleppi authored Feb 12, 2021
1 parent 8d027a4 commit ea89c75
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 14 deletions.
Binary file added .storybook/public/NORM.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .storybook/public/dist_map.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 39 additions & 5 deletions .storybook/stories/Reflector.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react'
import { useFrame } from 'react-three-fiber'
import { Vector3, Mesh } from 'three'
import { Vector3, Mesh, RepeatWrapping, Vector2 } from 'three'

import { Setup } from '../Setup'
import { Reflector, useTexture, TorusKnot, Box } from '../../src'
Expand All @@ -18,11 +18,28 @@ export default {
],
}

function ReflectorScene({ blur, depthScale }: { blur?: [number, number]; depthScale?: number }) {
function ReflectorScene({
blur,
depthScale,
distortion,
normalScale,
}: {
blur?: [number, number]
depthScale?: number
distortion?: number
normalScale?: number
}) {
const roughness = useTexture('roughness_floor.jpeg')
const normal = useTexture('normal_floor.jpeg')

const normal = useTexture('NORM.jpg')
const distortionMap = useTexture('dist_map.jpeg')
const $box = React.useRef<Mesh>(null!)
const _normalScale = React.useMemo(() => new Vector2(normalScale || 0), [normalScale])

React.useEffect(() => {
distortionMap.wrapS = distortionMap.wrapT = RepeatWrapping
distortionMap.repeat.set(4, 4)
}, [distortionMap])

useFrame(({ clock }) => {
$box.current.position.y += Math.sin(clock.getElapsedTime()) / 25
$box.current.rotation.y = clock.getElapsedTime() / 2
Expand All @@ -43,6 +60,8 @@ function ReflectorScene({ blur, depthScale }: { blur?: [number, number]; depthSc
depthScale={depthScale || 0}
depthToBlurRatioBias={0.2}
debug={0}
distortion={distortion || 0}
distortionMap={distortionMap}
>
{(Material, props) => (
<Material
Expand All @@ -51,6 +70,7 @@ function ReflectorScene({ blur, depthScale }: { blur?: [number, number]; depthSc
roughnessMap={roughness}
roughness={1}
normalMap={normal}
normalScale={_normalScale}
{...props}
/>
)}
Expand All @@ -69,7 +89,7 @@ function ReflectorScene({ blur, depthScale }: { blur?: [number, number]; depthSc

export const ReflectorSt = () => (
<React.Suspense fallback={null}>
<ReflectorScene blur={[500, 500]} depthScale={2} />
<ReflectorScene blur={[500, 500]} depthScale={2} distortion={0.3} normalScale={0.5} />
</React.Suspense>
)
ReflectorSt.storyName = 'Default'
Expand All @@ -94,3 +114,17 @@ export const ReflectorDepth = () => (
</React.Suspense>
)
ReflectorDepth.storyName = 'Depth'

export const ReflectorDistortion = () => (
<React.Suspense fallback={null}>
<ReflectorScene distortion={1} />
</React.Suspense>
)
ReflectorDistortion.storyName = 'Distortion'

export const ReflectorNormalMap = () => (
<React.Suspense fallback={null}>
<ReflectorScene normalScale={0.5} />
</React.Suspense>
)
ReflectorNormalMap.storyName = 'NormalMap'
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,9 @@ Easily add reflections and/or blur to a planar surface. This reflector can also
minDepthThreshold={0.9} // Lower edge for the depthTexture interpolation (default = 0)
maxDepthThreshold={1} // Upper edge for the depthTexture interpolation (default = 0)
depthScale={1} // Scale the depth factor (0 = no depth, default = 0)
depthToBlurRatioBias={0.25} // Adds a bias factor to the depthTexture before calculating the blur amount [blurFactor = blurTexture * (depthTexture + bias)]. It accepts values between 0 and 1, default is 0.25. An amount > 0 of bias makes sure that the blurTexture is not too sharp because of the multiplication with the depthTexture
depthToBlurRatioBias={0.25} // Adds a bias factor to the depthTexture before calculating the blur amount [blurFactor = blurTexture * (depthTexture + bias)]. It accepts values between 0 and 1, default is 0.25. An amount > 0 of bias makes sure that the blurTexture is not too sharp because of the multiplication with the depthTexture
distortionMap={distortionTexture} // The texture to create a distortion map. The black and white values map to the perceived distortion
distortion={1} // How much the distortion map affects the material (default = 0)
debug={0} /* Depending on the assigned value, one of the following channels is shown:
0 = no debug
1 = depth channel
Expand Down
14 changes: 12 additions & 2 deletions src/core/Reflector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
DepthTexture,
DepthFormat,
UnsignedShortType,
Texture,
} from 'three'
import { useFrame, useThree, extend } from 'react-three-fiber'
import { BlurPass } from '../materials/BlurPass'
Expand All @@ -31,6 +32,8 @@ export type ReflectorProps = Omit<JSX.IntrinsicElements['mesh'], 'args' | 'child
depthScale?: number
depthToBlurRatioBias?: number
debug?: number
distortionMap?: Texture
distortion?: number
children: {
(
Component: React.ElementType<JSX.IntrinsicElements['meshReflectorMaterial']>,
Expand Down Expand Up @@ -62,6 +65,8 @@ export function Reflector({
mirror,
children,
debug = 0,
distortion = 1,
distortionMap,
...props
}: ReflectorProps) {
blur = Array.isArray(blur) ? blur : [blur, blur]
Expand Down Expand Up @@ -170,8 +175,11 @@ export function Reflector({
depthToBlurRatioBias,
transparent: true,
debug,
'defines-USE_BLUR': hasBlur,
'defines-USE_DEPTH': depthScale > 0,
distortion,
distortionMap,
'defines-USE_BLUR': hasBlur ? '' : undefined,
'defines-USE_DEPTH': depthScale > 0 ? '' : undefined,
'defines-USE_DISTORTION': !!distortionMap ? '' : undefined,
}
return [fbo1, fbo2, blurpass, reflectorProps]
}, [
Expand All @@ -188,6 +196,8 @@ export function Reflector({
depthScale,
depthToBlurRatioBias,
debug,
distortion,
distortionMap,
])

useFrame(() => {
Expand Down
57 changes: 51 additions & 6 deletions src/materials/MeshReflectorMaterial.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ type UninitializedUniform<Value> = { value: Value | null }
export class MeshReflectorMaterial extends MeshStandardMaterial {
private _debug: { value: number } = { value: 0 }
private _tDepth: UninitializedUniform<Texture> = { value: null }
private _distortionMap: UninitializedUniform<Texture> = { value: null }
private _tDiffuse: UninitializedUniform<Texture> = { value: null }
private _tDiffuseBlur: UninitializedUniform<Texture> = { value: null }
private _textureMatrix: UninitializedUniform<Matrix4> = { value: null }
Expand All @@ -16,16 +17,21 @@ export class MeshReflectorMaterial extends MeshStandardMaterial {
private _maxDepthThreshold: { value: number } = { value: 1 }
private _depthScale: { value: number } = { value: 0 }
private _depthToBlurRatioBias: { value: number } = { value: 0.25 }
private _distortion: { value: number } = { value: 1 }

constructor(parameters = {}) {
super(parameters)
this.setValues(parameters)
}
onBeforeCompile(shader) {
if (!shader.defines?.USE_UV) {
shader.defines.USE_UV = ''
}
shader.uniforms.debug = this._debug
shader.uniforms.hasBlur = this._hasBlur
shader.uniforms.tDiffuse = this._tDiffuse
shader.uniforms.tDepth = this._tDepth
shader.uniforms.distortionMap = this._distortionMap
shader.uniforms.tDiffuseBlur = this._tDiffuseBlur
shader.uniforms.textureMatrix = this._textureMatrix
shader.uniforms.mirror = this._mirror
Expand All @@ -35,6 +41,7 @@ export class MeshReflectorMaterial extends MeshStandardMaterial {
shader.uniforms.maxDepthThreshold = this._maxDepthThreshold
shader.uniforms.depthScale = this._depthScale
shader.uniforms.depthToBlurRatioBias = this._depthToBlurRatioBias
shader.uniforms.distortion = this._distortion
shader.vertexShader = `
uniform mat4 textureMatrix;
varying vec4 my_vUv;
Expand All @@ -50,6 +57,8 @@ export class MeshReflectorMaterial extends MeshStandardMaterial {
uniform sampler2D tDiffuse;
uniform sampler2D tDiffuseBlur;
uniform sampler2D tDepth;
uniform sampler2D distortionMap;
uniform float distortion;
uniform float cameraNear;
uniform float cameraFar;
uniform bool hasBlur;
Expand All @@ -65,16 +74,38 @@ export class MeshReflectorMaterial extends MeshStandardMaterial {
shader.fragmentShader = shader.fragmentShader.replace(
'#include <emissivemap_fragment>',
`#include <emissivemap_fragment>
vec4 base = texture2DProj(tDiffuse, my_vUv);
vec4 blur = texture2DProj(tDiffuseBlur, my_vUv);
float distortionFactor = 0.0;
#ifdef USE_DISTORTION
distortionFactor = texture2D(distortionMap, vUv).r * distortion;
#endif
vec4 new_vUv = my_vUv;
new_vUv.x += distortionFactor;
new_vUv.y += distortionFactor;
vec4 base = texture2DProj(tDiffuse, new_vUv);
vec4 blur = texture2DProj(tDiffuseBlur, new_vUv);
vec4 merge = base;
#ifdef USE_NORMALMAP
vec2 normal_uv = vec2(0.0);
vec4 normalColor = texture2D(normalMap, vUv * normalScale);
vec3 my_normal = normalize( vec3( normalColor.r * 2.0 - 1.0, normalColor.b, normalColor.g * 2.0 - 1.0 ) );
vec3 coord = new_vUv.xyz / new_vUv.w;
normal_uv = coord.xy + coord.z * my_normal.xz * 0.05;
vec4 base_normal = texture2D(tDiffuse, normal_uv);
vec4 blur_normal = texture2D(tDiffuseBlur, normal_uv);
merge = base_normal;
blur = blur_normal;
#endif
float depthFactor = 0.0001;
float blurFactor = 0.0;
#ifdef USE_DEPTH
vec4 depth = texture2DProj(tDepth, my_vUv);
vec4 depth = texture2DProj(tDepth, new_vUv);
depthFactor = smoothstep(minDepthThreshold, maxDepthThreshold, 1.0-(depth.r * depth.a));
depthFactor *= depthScale;
depthFactor = max(0.0001, min(1.0, depthFactor));
Expand Down Expand Up @@ -109,10 +140,10 @@ export class MeshReflectorMaterial extends MeshStandardMaterial {
diffuseColor = sRGBToLinear(vec4(vec3(blurFactor), 1.0));
}
if (debug == 3) {
diffuseColor = sRGBToLinear(texture2DProj(tDiffuse, my_vUv));
diffuseColor = sRGBToLinear(texture2DProj(tDiffuse, new_vUv));
}
if (debug == 4) {
diffuseColor = sRGBToLinear(texture2DProj(tDiffuseBlur, my_vUv));
diffuseColor = sRGBToLinear(texture2DProj(tDiffuseBlur, new_vUv));
}
`
)
Expand All @@ -129,6 +160,12 @@ export class MeshReflectorMaterial extends MeshStandardMaterial {
set tDepth(v: Texture | null) {
this._tDepth.value = v
}
get distortionMap(): Texture | null {
return this._distortionMap.value
}
set distortionMap(v: Texture | null) {
this._distortionMap.value = v
}
get tDiffuseBlur(): Texture | null {
return this._tDiffuseBlur.value
}
Expand Down Expand Up @@ -195,6 +232,12 @@ export class MeshReflectorMaterial extends MeshStandardMaterial {
set depthToBlurRatioBias(v: number) {
this._depthToBlurRatioBias.value = v
}
get distortion(): number {
return this._distortion.value
}
set distortion(v: number) {
this._distortion.value = v
}
}

export type MeshReflectorMaterialImpl = {
Expand All @@ -203,10 +246,12 @@ export type MeshReflectorMaterialImpl = {
mirror: number
textureMatrix: Matrix4
tDiffuse: Texture
distortionMap?: Texture
tDiffuseBlur: Texture
hasBlur: boolean
minDepthThreshold: number
maxDepthThreshold: number
depthScale: number
depthToBlurRatioBias: number
distortion: number
} & JSX.IntrinsicElements['meshStandardMaterial']

1 comment on commit ea89c75

@vercel
Copy link

@vercel vercel bot commented on ea89c75 Feb 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.