Pārlūkot izejas kodu

Export preprocessMaterial in GBufferRenderPass. Make target, texture public in DepthBufferPlugin. Add NormalBufferPlugin and example.

master
Palash Bansal pirms 3 gadiem
vecāks
revīzija
4533ae301b
Revīzijas autora e-pasta adrese nav piesaistīta nevienam kontam

+ 3
- 3
examples/depth-buffer-plugin/script.ts Parādīt failu

@@ -29,9 +29,9 @@ async function init() {
viewer.scene.mainCamera.userData.maxFarPlane = 10
viewer.scene.refreshScene()

const depthTarget = depthPlugin.getTarget()
const depthTarget = depthPlugin.target
if (!depthTarget) {
throw new Error('depthPlugin.getTarget() returned undefined')
throw new Error('depthPlugin.target returned undefined')
}

// to render depth buffer to screen, uncomment this line:
@@ -42,7 +42,7 @@ async function init() {
targetPreview.addTarget(()=>depthTarget, 'depth')

createSimpleButtons({
['Toggle depth rendering']: () => {
['Toggle Depth rendering']: () => {
viewer.renderManager.screenPass.overrideReadBuffer =
viewer.renderManager.screenPass.overrideReadBuffer ? null : depthTarget
viewer.setDirty()

+ 1
- 0
examples/index.html Parādīt failu

@@ -216,6 +216,7 @@
<h2 class="category">Plugins</h2>
<ul>
<li><a href="./depth-buffer-plugin/">Depth Buffer Plugin </a></li>
<li><a href="./normal-buffer-plugin/">Normal Buffer Plugin </a></li>
<li><a href="./render-target-preview/">Render Target Preview </a></li>
<li><a href="./dropzone-plugin/">Dropzone (Drag & Drop) </a></li>
</ul>

+ 34
- 0
examples/normal-buffer-plugin/index.html Parādīt failu

@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Depth Buffer Plugin</title>
<!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

<script type="importmap">
{
"imports": {
"threepipe": "./../../dist/index.mjs"
}
}

</script>
<style id="example-style">
html, body, #canvas-container, #mcanvas {
width: 100%;
height: 100%;
margin: 0;
overflow: hidden;
}
</style>
<script type="module" src="../examples-utils/simple-code-preview.mjs"></script>
<script id="example-script" type="module" src="./script.js" data-scripts="./script.ts;./script.js"></script>
</head>
<body>
<div id="canvas-container">
<canvas id="mcanvas"></canvas>
</div>

</body>

+ 57
- 0
examples/normal-buffer-plugin/script.ts Parādīt failu

@@ -0,0 +1,57 @@
import {
_testFinish,
downloadBlob,
HalfFloatType,
NoColorSpace,
NormalBufferPlugin,
RenderTargetPreviewPlugin,
SRGBColorSpace,
ThreeViewer,
} from 'threepipe'
import {createSimpleButtons} from '../examples-utils/simple-bottom-buttons.js'

const viewer = new ThreeViewer({
canvas: document.getElementById('mcanvas') as HTMLCanvasElement,
})

async function init() {

const normalPlugin = viewer.addPluginSync(new NormalBufferPlugin(HalfFloatType))

await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr')
await viewer.load('https://threejs.org/examples/models/gltf/kira.glb', {
autoCenter: true,
autoScale: true,
})

const normalTarget = normalPlugin.target
if (!normalTarget) {
throw new Error('normalPlugin.target returned undefined')
}

viewer.renderManager.screenPass.overrideReadBuffer = normalTarget
viewer.renderManager.screenPass.outputColorSpace = NoColorSpace // default is SRGBColorSpace


const targetPreview = await viewer.addPlugin(RenderTargetPreviewPlugin)
targetPreview.addTarget(()=>normalTarget, 'normal')

createSimpleButtons({
['Toggle Normal rendering']: () => {
const state = !!viewer.renderManager.screenPass.overrideReadBuffer
viewer.renderManager.screenPass.overrideReadBuffer = state ? null : normalTarget
viewer.renderManager.screenPass.outputColorSpace = state ? SRGBColorSpace : NoColorSpace
viewer.setDirty()
},
['Download snapshot']: async(btn: HTMLButtonElement) => {
btn.disabled = true
const blob = await viewer.getScreenshotBlob({mimeType: 'image/png'})
if (blob) downloadBlob(blob, 'file.png')
else console.error('Unable to get screenshot')
btn.disabled = false
},
})

}

init().then(_testFinish)

+ 12
- 2
examples/render-target-preview/script.ts Parādīt failu

@@ -1,4 +1,11 @@
import {_testFinish, DepthBufferPlugin, HalfFloatType, RenderTargetPreviewPlugin, ThreeViewer} from 'threepipe'
import {
_testFinish,
DepthBufferPlugin,
HalfFloatType,
NormalBufferPlugin,
RenderTargetPreviewPlugin,
ThreeViewer,
} from 'threepipe'

const viewer = new ThreeViewer({
canvas: document.getElementById('mcanvas') as HTMLCanvasElement,
@@ -10,6 +17,8 @@ const viewer = new ThreeViewer({
async function init() {

const depth = viewer.addPluginSync(new DepthBufferPlugin(HalfFloatType, true))
const normal = viewer.addPluginSync(new NormalBufferPlugin(HalfFloatType))

const targetPreview = viewer.addPluginSync(RenderTargetPreviewPlugin)

await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr')
@@ -21,7 +30,8 @@ async function init() {
viewer.renderManager.autoBuildPipeline = false
viewer.renderManager.pipeline = ['depth', 'render', 'screen']

targetPreview.addTarget(()=>depth.getTarget(), 'depth', false, true)
targetPreview.addTarget(()=>depth.target, 'depth', false, true)
targetPreview.addTarget(()=>normal.target, 'normal', false, true)
targetPreview.addTarget(()=>viewer.renderManager.composerTarget, 'composer-1', false, false)
targetPreview.addTarget(()=>viewer.renderManager.composerTarget2, 'composer-2', false, false)


+ 1
- 0
src/plugins/index.ts Parādīt failu

@@ -1,4 +1,5 @@
export {DepthBufferPlugin} from './pipeline/DepthBufferPlugin'
export {NormalBufferPlugin} from './pipeline/NormalBufferPlugin'
export type {DepthBufferPluginEventTypes, DepthBufferPluginPass, DepthBufferPluginTarget} from './pipeline/DepthBufferPlugin'
export {PipelinePassPlugin} from './base/PipelinePassPlugin'
export {RenderTargetPreviewPlugin} from './ui/RenderTargetPreviewPlugin'

+ 13
- 16
src/plugins/pipeline/DepthBufferPlugin.ts Parādīt failu

@@ -25,8 +25,8 @@ export class DepthBufferPlugin
readonly passId = 'depth'
public static readonly PluginType = 'DepthBufferPlugin'

private _depthTarget?: DepthBufferPluginTarget
private _depthTexture?: Texture
target?: DepthBufferPluginTarget
texture?: Texture
readonly material: MeshDepthMaterial = new MeshDepthMaterial({
depthPacking: BasicDepthPacking,
blending: NoBlending,
@@ -34,7 +34,7 @@ export class DepthBufferPlugin
// private _gbufferPass?: IFilter<GBufferRenderPass<WebGLMultipleRenderTargets>

createPass(v: ThreeViewer) {
const target = v.renderManager.createTarget<DepthBufferPluginTarget>(
if (!this.target) this.target = v.renderManager.createTarget<DepthBufferPluginTarget>(
{
depthBuffer: true,
samples: v.renderManager.composerTarget.samples || 0,
@@ -44,14 +44,15 @@ export class DepthBufferPlugin
// generateMipmaps: false,
// encoding: LinearEncoding,
})
target.texture.name = 'depthBuffer'
this._depthTexture = target.texture
this._depthTarget = target
this.texture = this.target.texture
this.texture.name = 'depthBuffer'

if (this.isPrimaryGBuffer) v.renderManager.gbufferTarget = target
if (this.isPrimaryGBuffer) v.renderManager.gbufferTarget = this.target

this.material.userData.isGBufferMaterial = true
const pass = new GBufferRenderPass('depth', target, this.material, new Color(0, 0, 0), 1)
const pass = new GBufferRenderPass('depth', this.target, this.material, new Color(0, 0, 0), 1)
const preprocessMaterial = pass.preprocessMaterial
pass.preprocessMaterial = (m) => preprocessMaterial(m, m.userData.renderToDepth)
pass.before = ['render']
pass.after = []
pass.required = ['render']
@@ -66,19 +67,15 @@ export class DepthBufferPlugin
}

onRemove(viewer: ThreeViewer): void {
if (this._depthTarget) {
viewer.renderManager.disposeTarget(this._depthTarget)
this._depthTarget = undefined
if (this.target) {
viewer.renderManager.disposeTarget(this.target)
this.target = undefined
}
return super.onRemove(viewer)
}

getTarget() {
return this._depthTarget
}

updateShaderProperties(material: {defines: Record<string, string | number | undefined>; uniforms: {[p: string]: IUniform}}): this {
if (material.uniforms.tDepth) material.uniforms.tDepth.value = this._depthTexture ?? undefined
if (material.uniforms.tDepth) material.uniforms.tDepth.value = this.texture ?? undefined
else this._viewer?.console.warn('BaseRenderer: no uniform: tDepth')
return this
}

+ 82
- 0
src/plugins/pipeline/NormalBufferPlugin.ts Parādīt failu

@@ -0,0 +1,82 @@
import {
Color,
HalfFloatType,
IUniform,
LinearSRGBColorSpace,
MeshNormalMaterial,
NearestFilter,
NoBlending,
Texture,
TextureDataType,
WebGLRenderTarget,
} from 'three'
import {GBufferRenderPass} from '../../postprocessing'
import {ThreeViewer} from '../../viewer'
import {IShaderPropertiesUpdater} from '../../materials'
import {PipelinePassPlugin} from '../base/PipelinePassPlugin'

export type NormalBufferPluginEventTypes = ''
// type NormalBufferPluginTarget = WebGLMultipleRenderTargets | WebGLRenderTarget
export type NormalBufferPluginTarget = WebGLRenderTarget
export type NormalBufferPluginPass = GBufferRenderPass<'normal', NormalBufferPluginTarget>
export class NormalBufferPlugin
extends PipelinePassPlugin<NormalBufferPluginPass, 'normal', NormalBufferPluginEventTypes>
implements IShaderPropertiesUpdater {

readonly passId = 'normal'
public static readonly PluginType = 'NormalBufferPlugin'

target?: NormalBufferPluginTarget
texture?: Texture
readonly material: MeshNormalMaterial = new MeshNormalMaterial({
blending: NoBlending,
})
// private _gbufferPass?: IFilter<GBufferRenderPass<WebGLMultipleRenderTargets>

createPass(v: ThreeViewer) {
if (!this.target) this.target = v.renderManager.createTarget<NormalBufferPluginTarget>(
{
depthBuffer: true,
// samples: v.renderManager.composerTarget.samples || 0,
samples: 0,
type: this.bufferType,
magFilter: NearestFilter,
minFilter: NearestFilter,
generateMipmaps: false,
colorSpace: LinearSRGBColorSpace,
})
this.texture = this.target.texture
this.texture.name = 'normalBuffer'

this.material.userData.isGBufferMaterial = true
const pass = new GBufferRenderPass('normal', this.target, this.material, new Color(0, 0, 0), 1)
const preprocessMaterial = pass.preprocessMaterial
pass.preprocessMaterial = (m) => preprocessMaterial(m, true)
pass.before = ['render']
pass.after = []
pass.required = ['render']
return pass
}

constructor(
public readonly bufferType: TextureDataType = HalfFloatType,
) {
super()
}

onRemove(viewer: ThreeViewer): void {
if (this.target) {
viewer.renderManager.disposeTarget(this.target)
this.target = undefined
}
return super.onRemove(viewer)
}

updateShaderProperties(material: {defines: Record<string, string | number | undefined>; uniforms: {[p: string]: IUniform}}): this {
if (material.uniforms.tNormal) material.uniforms.tNormal.value = this.texture ?? undefined
else this._viewer?.console.warn('BaseRenderer: no uniform: tNormal')
return this
}

}


+ 22
- 22
src/postprocessing/GBufferRenderPass.ts Parādīt failu

@@ -18,6 +18,26 @@ export class GBufferRenderPass<TP extends IPassID, T extends WebGLMultipleRender
private _transparentMats = new Set<IMaterial>()
private _transmissiveMats = new Set<[IMaterial, number]>()

preprocessMaterial = (material: IMaterial, renderToGBuffer?: boolean) => {
renderToGBuffer = renderToGBuffer ?? material.userData.renderToGBuffer
if (
material.transparent && renderToGBuffer || // transparent and render to gbuffer
!material.transparent && !material.transmission && renderToGBuffer === false // opaque and dont render to gbuffer
) {
this._transparentMats.add(material)
material.transparent = !material.transparent
// material.needsUpdate = true
}
if (
material.transmission &&
Math.abs(material.transmission || 0) > 0 && renderToGBuffer // transmission and render to gbuffer
) {
this._transmissiveMats.add([material, material.transmission])
material.transmission = 0
// material.needsUpdate = true
}
}

/**
* Renders to {@link target}
* @param renderer
@@ -33,30 +53,10 @@ export class GBufferRenderPass<TP extends IPassID, T extends WebGLMultipleRender
const activeCubeFace = renderer.getActiveCubeFace()
const activeMipLevel = renderer.getActiveMipmapLevel()

const preprocessMaterial = (material: IMaterial) => {
const renderToGBuffer = material.userData.renderToGBuffer === undefined ? material.userData.renderToDepth : material.userData.renderToGBuffer
if (
material.transparent && material.userData.renderToDepth || // transparent and render to gbuffer
!material.transparent && !material.transmission && renderToGBuffer === false // opaque and dont render to gbuffer
) {
this._transparentMats.add(material)
material.transparent = !material.transparent
// material.needsUpdate = true
}
if (
material.transmission &&
Math.abs(material.transmission || 0) > 0 && renderToGBuffer // transmission and render to gbuffer
) {
this._transmissiveMats.add([material, material.transmission])
material.transmission = 0
// material.needsUpdate = true
}
}

this.scene.traverse(({material}) => {
if (!material) return
if (Array.isArray(material)) material.forEach(preprocessMaterial)
else preprocessMaterial(material)
if (Array.isArray(material)) material.forEach((m)=>this.preprocessMaterial(m))
else this.preprocessMaterial(material)
})

// todo; copy double sided, check with post processing

Notiek ielāde…
Atcelt
Saglabāt