瀏覽代碼

Add camera shader helpers, support for custom shader snippet in ExtendedCopyPass and RenderTargetPreviewPlugin, some doc comments in IPass.

master
Palash Bansal 2 年之前
父節點
當前提交
5e8faf2be3
沒有連結到貢獻者的電子郵件帳戶。

+ 5
- 0
src/core/camera/PerspectiveCamera2.ts 查看文件



// for shader prop updater // for shader prop updater
private _positionWorld = new Vector3() private _positionWorld = new Vector3()

/**
* See also cameraHelpers.glsl
* @param material
*/
updateShaderProperties(material: {defines: Record<string, string | number | undefined>; uniforms: {[p: string]: IUniform}}): this { updateShaderProperties(material: {defines: Record<string, string | number | undefined>; uniforms: {[p: string]: IUniform}}): this {
material.uniforms.cameraPositionWorld?.value?.copy(this._positionWorld) material.uniforms.cameraPositionWorld?.value?.copy(this._positionWorld)
material.uniforms.cameraNearFar?.value?.set(this.near, this.far) material.uniforms.cameraNearFar?.value?.set(this.near, this.far)

+ 18
- 3
src/plugins/ui/RenderTargetPreviewPlugin.ts 查看文件

import {AViewerPluginSync, ThreeViewer} from '../../viewer' import {AViewerPluginSync, ThreeViewer} from '../../viewer'
import {IRenderTarget} from '../../rendering' import {IRenderTarget} from '../../rendering'
import {createDiv, createStyles, getOrCall, onChange, ValOrArr, ValOrFunc} from 'ts-browser-helpers' import {createDiv, createStyles, getOrCall, onChange, ValOrArr, ValOrFunc} from 'ts-browser-helpers'
import {SRGBColorSpace, Vector4, WebGLRenderTarget} from 'three'
import {ShaderMaterial, SRGBColorSpace, Vector4, WebGLRenderTarget} from 'three'
import styles from './RenderTargetPreviewPlugin.css?inline' import styles from './RenderTargetPreviewPlugin.css?inline'
import {CustomContextMenu} from '../../utils' import {CustomContextMenu} from '../../utils'
import {uiFolderContainer, uiToggle} from 'uiconfig.js' import {uiFolderContainer, uiToggle} from 'uiconfig.js'
import {ITexture} from '../../core' import {ITexture} from '../../core'
import {ExtendedCopyPass} from '../../postprocessing'


export interface RenderTargetBlock { export interface RenderTargetBlock {
target: ValOrFunc<IRenderTarget|{texture?: ValOrArr<ITexture>}|undefined> target: ValOrFunc<IRenderTarget|{texture?: ValOrArr<ITexture>}|undefined>
transparent: boolean transparent: boolean
originalColorSpace: boolean originalColorSpace: boolean
div: HTMLDivElement div: HTMLDivElement
material?: ShaderMaterial // see ExtendedCopyPass
} }
@uiFolderContainer('Render Target Preview Plugin') @uiFolderContainer('Render Target Preview Plugin')
export class RenderTargetPreviewPlugin<TEvent extends string> extends AViewerPluginSync<TEvent> { export class RenderTargetPreviewPlugin<TEvent extends string> extends AViewerPluginSync<TEvent> {
clear: !targetBlock.transparent, clear: !targetBlock.transparent,
respectColorSpace: !targetBlock.originalColorSpace, respectColorSpace: !targetBlock.originalColorSpace,
viewport: new Vector4(rect.x, rect.y, rect.width, rect.height), viewport: new Vector4(rect.x, rect.y, rect.width, rect.height),
material: targetBlock.material,
}) })
this._viewer.renderManager.webglRenderer.outputColorSpace = outputColorSpace this._viewer.renderManager.webglRenderer.outputColorSpace = outputColorSpace
} }
} }


addTarget(target: RenderTargetBlock['target'], name: string, transparent = false, originalColorSpace = false, visible = true): this {
/**
*
* @param target - render target or a function that returns a render target
* @param name - name of the target
* @param transparent - if true, the target will be rendered with transparency
* @param originalColorSpace - if true, the target will be rendered in its original color space
* @param visible - initial visibility
* @param material - snippet for {@link ExtendedCopyPass} or a custom {@link ExtendedShaderMaterial} or three.js ShaderMaterial. Example to read just the red channel `(s)=>s + ' = vec4(' + s + '.r);'`
*/
addTarget(target: RenderTargetBlock['target'], name: string, transparent = false, originalColorSpace = false, visible = true, material?: ValOrFunc<string, [string]> | ShaderMaterial): this {
if (!target) return this if (!target) return this
const div = document.createElement('div') const div = document.createElement('div')
const targetDef = {target, name, transparent, div, originalColorSpace, visible}
const targetDef: RenderTargetBlock = {target, name, transparent, div, originalColorSpace, visible}
if (material) targetDef.material = (material as ShaderMaterial)?.isMaterial ? material as ShaderMaterial : new ExtendedCopyPass(material as any).material

div.classList.add('RenderTargetPreviewPluginTarget') div.classList.add('RenderTargetPreviewPluginTarget')
if (!targetDef.visible) div.classList.add('RenderTargetPreviewPluginCollapsed') if (!targetDef.visible) div.classList.add('RenderTargetPreviewPluginCollapsed')
const header = document.createElement('div') const header = document.createElement('div')
if (!canvas) return this if (!canvas) return this
const blob = this._viewer.renderManager.exportRenderTarget(target as WebGLRenderTarget) const blob = this._viewer.renderManager.exportRenderTarget(target as WebGLRenderTarget)
const url = URL.createObjectURL(blob) const url = URL.createObjectURL(blob)
// todo use file transfer or viewer downloadBlob
const link = document.createElement('a') const link = document.createElement('a')
document.body.appendChild(link) document.body.appendChild(link)
link.style.display = 'none' link.style.display = 'none'

+ 7
- 4
src/postprocessing/ExtendedCopyPass.ts 查看文件

import {UniformsUtils} from 'three' import {UniformsUtils} from 'three'
import {CopyShader} from 'three/examples/jsm/shaders/CopyShader.js' import {CopyShader} from 'three/examples/jsm/shaders/CopyShader.js'
import {glsl} from 'ts-browser-helpers'
import {getOrCall, glsl, ValOrFunc} from 'ts-browser-helpers'
import {ExtendedShaderPass} from './ExtendedShaderPass' import {ExtendedShaderPass} from './ExtendedShaderPass'


export class ExtendedCopyPass extends ExtendedShaderPass { export class ExtendedCopyPass extends ExtendedShaderPass {
constructor() {
constructor(snippet?: ValOrFunc<string, [string]>, respectColorSpace = true) {
super({ super({
uniforms: UniformsUtils.clone(CopyShader.uniforms), uniforms: UniformsUtils.clone(CopyShader.uniforms),
vertexShader: CopyShader.vertexShader, vertexShader: CopyShader.vertexShader,
#include <alphatest_pars_fragment> #include <alphatest_pars_fragment>
varying vec2 vUv; varying vec2 vUv;
void main() { void main() {
vec4 diffuseColor = tDiffuseTexelToLinear(texture2D(tDiffuse, vUv)) * opacity;
${respectColorSpace ?
'vec4 diffuseColor = tDiffuseTexelToLinear(texture2D(tDiffuse, vUv)) * opacity;' :
'vec4 diffuseColor = texture2D(tDiffuse, vUv) * opacity;'}
#include <alphatest_fragment> #include <alphatest_fragment>
${snippet ? getOrCall(snippet, 'diffuseColor') : ''}
#ifdef OPAQUE #ifdef OPAQUE
diffuseColor.a = 1.0; diffuseColor.a = 1.0;
#endif #endif
gl_FragColor = diffuseColor; gl_FragColor = diffuseColor;
#include <encodings_fragment>
${respectColorSpace ? '#include <encodings_fragment>' : ''}
} }
`, `,
}, 'tDiffuse') }, 'tDiffuse')

+ 5
- 0
src/postprocessing/ExtendedShaderPass.ts 查看文件

}) })
} }


/**
* to be called from beforeRender or onObjectRender or similar.
* @param updater
*/
updateShaderProperties(updater?: (IShaderPropertiesUpdater|undefined) | (IShaderPropertiesUpdater|undefined)[]) { updateShaderProperties(updater?: (IShaderPropertiesUpdater|undefined) | (IShaderPropertiesUpdater|undefined)[]) {
if (!updater) return if (!updater) return
if (!Array.isArray(updater)) updater = [updater] if (!Array.isArray(updater)) updater = [updater]
} }


setDirty() { setDirty() {
this.material.needsUpdate = true // do this when material defines etc are changed
this.onDirty.forEach(v=>v()) this.onDirty.forEach(v=>v())
} }



+ 16
- 2
src/postprocessing/Pass.ts 查看文件

import {IDisposable, ValOrFunc} from 'ts-browser-helpers' import {IDisposable, ValOrFunc} from 'ts-browser-helpers'
import {IUniform} from 'three' import {IUniform} from 'three'
import {Pass} from 'three/examples/jsm/postprocessing/Pass.js' import {Pass} from 'three/examples/jsm/postprocessing/Pass.js'
import {IShaderPropertiesUpdater, MaterialExtension} from '../materials'
import {MaterialExtension} from '../materials'
import {ICamera, IRenderManager, IScene} from '../core' import {ICamera, IRenderManager, IScene} from '../core'


export type IPassID = 'render' | 'screen' | string export type IPassID = 'render' | 'screen' | string
export interface IPass<Tid extends IPassID = IPassID> extends Pass, IDisposable { export interface IPass<Tid extends IPassID = IPassID> extends Pass, IDisposable {
uniforms?: {[name: string]: IUniform} uniforms?: {[name: string]: IUniform}


updateShaderProperties?: (updater?: (IShaderPropertiesUpdater|undefined) | (IShaderPropertiesUpdater|undefined)[])=>void
// todo?
// updateShaderProperties?: (updater?: (IShaderPropertiesUpdater|undefined) | (IShaderPropertiesUpdater|undefined)[])=>void

materialExtension?: MaterialExtension materialExtension?: MaterialExtension


/**
* Checked by {@link RenderManager} to determine whether to render this frame. A frame is rendered if any pass is dirty.
* This can be set by the plugin/pass to indicate when to continue rendering. See {@link ProgressivePlugin}.
* This is different from {@link setDirty} which is implementation specific to the pass/plugin. It generally calls onDirty and set the viewer dirty.
*/
dirty?: ValOrFunc<boolean> // isDirty (optional) dirty?: ValOrFunc<boolean> // isDirty (optional)

/**
* Set the pass as dirty. This is implementation specific to the pass/plugin. It generally calls all {@link onDirty} and set the viewer dirty.
*/
setDirty?(): void setDirty?(): void
onDirty?: (()=>void)[]; onDirty?: (()=>void)[];


/**
* Unique id for the pass. Used to determine the order of passes in the pipeline.
*/
passId?: Tid; passId?: Tid;
} }



+ 3
- 1
src/utils/shaders.ts 查看文件

import simpleCameraHelpers from './shaders/simpleCameraHelpers.glsl' import simpleCameraHelpers from './shaders/simpleCameraHelpers.glsl'
import cameraHelpers from './shaders/cameraHelpers.glsl'
import randomHelpers from './shaders/randomHelpers.glsl' import randomHelpers from './shaders/randomHelpers.glsl'
import defaultVertex from './shaders/defaultVertex.glsl'
import voronoiNoise from './shaders/voronoiNoise.glsl' import voronoiNoise from './shaders/voronoiNoise.glsl'


export const shaderUtils = { export const shaderUtils = {
simpleCameraHelpers, randomHelpers, voronoiNoise,
simpleCameraHelpers, cameraHelpers, randomHelpers, defaultVertex, voronoiNoise,
} }

+ 51
- 0
src/utils/shaders/cameraHelpers.glsl 查看文件

#ifndef BASIC_CAMERA_HELPERS
#define BASIC_CAMERA_HELPERS

// See also PerspectiveCamera2
uniform mat4 projection;
uniform vec2 cameraNearFar;
uniform vec3 cameraPositionWorld;

#ifndef THREE_PACKING_INCLUDED
#define THREE_PACKING_INCLUDED
#include <packing>
#endif

float linstep(float edge0, float edge1, float value) {
return clamp((value-edge0)/(edge1-edge0), 0.0, 1.0);
}

float depthToViewZ(const in float depth){
return (depth > 0.999) ? -cameraNearFar.y * 1000.0 : -mix(cameraNearFar.x, cameraNearFar.y, depth);
}
float viewZToDepth(const in float viewZ){
return linstep(-cameraNearFar.x, -cameraNearFar.y, viewZ);
}

vec4 viewToScreen3(const in vec3 pos) {
vec4 projected = projection * vec4(pos, 1.0);
projected.z = pos.z;
// w is -viewZ
projected.w = 1./projected.w;
projected.xyz *= projected.w;
projected.xy = 0.5 + 0.5 * projected.xy;
return projected;
}

vec3 screenToView(const in vec2 uv, const in float viewZ) {
vec2 uv_ = 2. * uv - 1.;
float xe = -(uv_.x + projection[2][0]) * viewZ / projection[0][0];
float ye = -(uv_.y + projection[2][1]) * viewZ / projection[1][1];
return vec3(xe, ye, viewZ);
}

float viewZFromNDCZ(const in float depth) {
#if PERSPECTIVE_CAMERA == 1
return perspectiveDepthToViewZ(depth, cameraNearFar.x, cameraNearFar.y);
#else
return orthographicDepthToViewZ(depth, cameraNearFar.x, cameraNearFar.y);
#endif
}


#endif

+ 6
- 0
src/utils/shaders/simpleCameraHelpers.glsl 查看文件

vec4 projected = projectionMatrix * vec4(pos, 1.0); vec4 projected = projectionMatrix * vec4(pos, 1.0);
return vec3(0.5 + 0.5 * projected.xy / projected.w, projected.w); return vec3(0.5 + 0.5 * projected.xy / projected.w, projected.w);
} }
vec3 screenToView(const in vec2 uv, const in float viewZ) {
vec2 uv_ = 2. * uv - 1.;
float xe = -(uv_.x + projectionMatrix[2][0]) * viewZ / projectionMatrix[0][0];
float ye = -(uv_.y + projectionMatrix[2][1]) * viewZ / projectionMatrix[1][1];
return vec3(xe, ye, viewZ);
}
#endif #endif

Loading…
取消
儲存