Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add reflector #136

Merged
merged 20 commits into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export default defineConfig({
{ text: 'Levioso (Float)', link: '/guide/abstractions/levioso' },
{ text: 'Contact Shadows', link: '/guide/abstractions/contact-shadows' },
{ text: 'Precipitation', link: '/guide/abstractions/precipitation' },
{ text: 'Reflector', link: '/guide/abstractions/reflector' }
],
},
{
Expand Down Expand Up @@ -64,7 +65,9 @@ export default defineConfig({
{
text: 'Materials',
collapsed: true,
items: [{ text: 'WobbleMaterial', link: '/guide/materials/wobble-material' }],
items: [
{ text: 'WobbleMaterial', link: '/guide/materials/wobble-material' },
],
},
{
text: 'Shapes',
Expand Down
131 changes: 131 additions & 0 deletions docs/guide/abstractions/reflector.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# Reflector

The `cientos` package provides an abstraction of the Reflector class, which creates a reflector material in real time of your scene `<Reflector >` component that makes a geometry as an argument to create a mirror. This Mesh extends from `Mesh` so all the default props can be passed as well:

## Usage

```html
<Reflector :rotation="[-Math.PI * 0.5, 0, 0]" :position-y="-2" color="#F7F7F7">
<TresCircleGeometry :args="[10, 10]" />
</Reflector>
```

## Custom mirror effect

For more complex effect you can provide your own shaders, you could do this creating an object and pass the uniforms, vertexShaders or fragmentShaders:

```vue{3}
<script setup lang="ts" >
import vertexShader from "MyCustomvertexShader.glsl"

const customShader = {
vertexShader
}
<script>
<template>
<TresCanvas shadows alpha>
<TresPerspectiveCamera :position="[0, 0, 3]" />
...
<Reflector :rotation="[-Math.PI * 0.5, 0, 0]"
:position-y="-2"
color="#fff"
:shader="customShader"
>
<TresCircleGeometry :args="[10, 10]" />
</Reflector>
...
</TresCanvas>
</template>
```

| Prop | Description | Default |
| :---------------- | :--------------------------------------------------- | ------------------------- |
| **color** | The base color that's combine with the mirror effect | '#000000' |
| **textureWidth** | the width of the texture to render on the mirror | 512 |
| **textureHeight** | the height of the texture to render on the mirror | 512 |
| **clipBias** | to use the clipBias property | 0 |
| **multisample** | how many samplers will be render | 4 |
| **shader** | The texture of the smoke. | Reflector.ReflectorShader |


## The Reflector shader use the following configuration by default:

You can extend, modify or just play with them

### name

```js
name:"ReflectorShader"
```

### Uniforms

```js
uniforms: {
color: {
value: null
},
tDiffuse: {
value: null
},
textureMatrix: {
value: null
}
},
```

### VertexShader

```glsl
vertexShader: /* glsl */`
uniform mat4 textureMatrix;
varying vec4 vUv;

#include <common>
#include <logdepthbuf_pars_vertex>

void main() {

vUv = textureMatrix * vec4( position, 1.0 );

gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );

#include <logdepthbuf_vertex>

}`
```

### FragmentShader

```glsl
fragmentShader: /* glsl */`
uniform vec3 color;
uniform sampler2D tDiffuse;
varying vec4 vUv;

#include <logdepthbuf_pars_fragment>

float blendOverlay( float base, float blend ) {

return( base < 0.5 ? ( 2.0 * base * blend ) : ( 1.0 - 2.0 * ( 1.0 - base ) * ( 1.0 - blend ) ) );

}

vec3 blendOverlay( vec3 base, vec3 blend ) {

return vec3( blendOverlay( base.r, blend.r ), blendOverlay( base.g, blend.g ), blendOverlay( base.b, blend.b ) );

}

void main() {

#include <logdepthbuf_fragment>

vec4 base = texture2DProj( tDiffuse, vUv );
gl_FragColor = vec4( blendOverlay( base.rgb, color ), 1.0 );

#include <tonemapping_fragment>
#include <colorspace_fragment>

}`
```
2 changes: 1 addition & 1 deletion playground/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ declare module 'vue' {
BackdropDemo: typeof import('./src/components/BackdropDemo.vue')['default']
ContactShadowsDemo: typeof import('./src/components/ContactShadowsDemo.vue')['default']
EnvironmentDemo: typeof import('./src/components/EnvironmentDemo.vue')['default']
GlassMaterialDemo: typeof import('./src/components/GlassMaterialDemo.vue')['default']
Gltf: typeof import('./src/components/gltf/index.vue')['default']
LeviosoDemo: typeof import('./src/components/LeviosoDemo.vue')['default']
MapControlsDemo: typeof import('./src/components/MapControlsDemo.vue')['default']
ModelsDemo: typeof import('./src/components/ModelsDemo.vue')['default']
ReflectorDemo: typeof import('./src/components/ReflectorDemo.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
ScrollDemo: typeof import('./src/components/ScrollDemo.vue')['default']
Expand Down
82 changes: 82 additions & 0 deletions playground/src/components/ReflectorDemo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<script setup lang="ts">
import { reactive } from 'vue'
import { TresCanvas } from '@tresjs/core'
import { OrbitControls, MeshWobbleMaterial, Reflector, Stars, useTweakPane } from '@tresjs/cientos'
import { BasicShadowMap, SRGBColorSpace, NoToneMapping } from 'three'

const gl = {
clearColor: '#111',
shadows: false,
alpha: false,
shadowMapType: BasicShadowMap,
outputColorSpace: SRGBColorSpace,
toneMapping: NoToneMapping,
}

const customShader = {
name: 'customShader',

fragmentShader: /* glsl */ `
uniform vec3 color;
uniform sampler2D tDiffuse;
varying vec4 vUv;

#include <logdepthbuf_pars_fragment>

float blendOverlay( float base, float blend ) {

return( base < 0.5 ? ( 2.0 * base * blend ) : ( 1.0 - 2.0 * ( 1.0 - base ) * ( 1.0 - blend ) ) );

}

vec3 blendOverlay( vec3 base, vec3 blend ) {

return vec3( blendOverlay( base.r, blend.r ), blendOverlay( base.g, blend.g ), blendOverlay( base.b, blend.b ) );

}

void main() {

#include <logdepthbuf_fragment>

vec4 base = texture2DProj( tDiffuse, vUv );
gl_FragColor = vec4( blendOverlay( base.rgb, color ), 1.0 );

#include <tonemapping_fragment>
#include <colorspace_fragment>

}`,
}

const options = reactive({
color: '#f7f7f7',
clipBias: 1,
textureWidth: 1024,
})

const { pane } = useTweakPane()

pane.addInput(options, 'color', { label: 'MirrorColor' })
pane.addInput(options, 'clipBias', { label: 'clipBias', min: 0, max:1, step: 0.001 })

</script>

<template>
<TresCanvas v-bind="gl" ref="context">
<TresPerspectiveCamera :position="[3, 3, 6]" :look-at="[0, 0, 0]" />
<Stars />
<TresMesh >
<TresTorusGeometry />
<MeshWobbleMaterial color="orange" :speed="1" :factor="2" />
</TresMesh>
<Reflector :rotation="[-Math.PI * 0.5, 0, 0]" :position-y="-2" :color="options.color" :shader="customShader"
:clip-bias="options.clipBias"
:texture-width="options.textureWidth"
>
<!-- <TresBoxGeometry :args="[10, 10]" /> -->
<TresCircleGeometry :args="[10, 10]" />
</Reflector>
<TresAmbientLight :intensity="1" />
<OrbitControls />
</TresCanvas>
</template>
4 changes: 1 addition & 3 deletions playground/src/pages/index.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
<script setup lang="ts"></script>
<template>
<Suspense>
<OrbitControlsDemo />
</Suspense>
<ReflectorDemo />
</template>
110 changes: 110 additions & 0 deletions src/core/abstractions/Reflector.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<script lang="ts" setup>
import { shallowRef, reactive, toRefs, watchEffect } from 'vue'
import { TresColor } from '@tresjs/core'
import { useTresContext } from '@tresjs/core'
import { Reflector } from 'three/addons/objects/Reflector'
import { PlaneGeometry } from 'three'

export interface ReflectorProps {
/**
* The color of the reflector.
*
* @default '#000000'
* @type {TresColor}
* @memberof ReflectorProps
*
*/
color?: TresColor
/**
* The textureWidth of the internal WebGLRenderTarget.
*
* @default window.innerWidth
* @type {number}
* @memberof ReflectorProps
*
*/
textureWidth?: number
/**
* The textureHeight of the internal WebGLRenderTarget.
*
* @default window.innerHeight
* @type {number}
* @memberof ReflectorProps
*
*/
textureHeight?: number
/**
* The clipBias.
*
* @default 0
* @type {number}
* @memberof ReflectorProps
*
*/
clipBias?: number
/**
* The number of samples to render.
*
* @default 4
* @type {number}
* @memberof ReflectorProps
*
*/
multisample?: number
/**
* The number of samples to render.
*
* @default Reflector.ReflectorShader
* @type {object}
* @memberof ReflectorProps
*
*/
shader?: object
}

const props = withDefaults(defineProps<ReflectorProps>(), {
color: '#333',
textureWidth: 512,
textureHeight: 512,
clipBias: 0,
multisample: 4,
shader: Reflector.ReflectorShader,
})

const reflectorRef = shallowRef<Reflector>()

const { extend } = useTresContext()

extend({ Reflector })

const { color, textureWidth, textureHeight, clipBias, multisample, shader } = toRefs(props)

const options = reactive({
color: color.value,
textureWidth: textureWidth.value,
textureHeight: textureHeight.value,
clipBias: clipBias.value,
multisample: multisample.value,
shader: {...Reflector.ReflectorShader,...shader.value },
})

watchEffect(() =>{
if(!reflectorRef?.value) return
if (clipBias.value) options.clipBias = clipBias.value
const currentGeo = reflectorRef.value.geometry
reflectorRef.value.dispose()
reflectorRef.value = new Reflector(currentGeo, options)
})

defineExpose({
value: reflectorRef,
})
</script>

<template>
<TresReflector ref="reflectorRef" :args="[new PlaneGeometry(), options]" :material-uniforms-color-value="color">
<slot>
<TresPlaneGeometry />
</slot>
</TresReflector>
</template>
2 changes: 2 additions & 0 deletions src/core/abstractions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Precipitation from './Precipitation.vue'
import Smoke from './Smoke.vue'
import Levioso from './Levioso.vue'
import ContactShadows from './ContactShadows.vue'
import Reflector from './Reflector.vue'
import MouseParallax from './MouseParallax.vue'
export * from './useEnvironment'
export {
Expand All @@ -18,4 +19,5 @@ export {
Levioso,
ContactShadows,
Precipitation,
Reflector
}