Working always-on-top stencil outlines
This commit is contained in:
@@ -189,7 +189,8 @@ export default class SpeckleRenderer {
|
||||
this._renderer = new WebGLRenderer({
|
||||
antialias: true,
|
||||
alpha: true,
|
||||
preserveDrawingBuffer: true
|
||||
preserveDrawingBuffer: true,
|
||||
stencil: true
|
||||
})
|
||||
this._renderer.setClearColor(0xffffff, 0)
|
||||
this._renderer.setPixelRatio(window.devicePixelRatio)
|
||||
|
||||
@@ -159,6 +159,33 @@ export default class Batcher {
|
||||
return visibilityRanges
|
||||
}
|
||||
|
||||
public getStencil(): Record<string, BatchUpdateRange> {
|
||||
const visibilityRanges = {}
|
||||
for (const k in this.batches) {
|
||||
const batch: Batch = this.batches[k]
|
||||
if (batch.geometryType !== GeometryType.MESH) {
|
||||
visibilityRanges[k] = HideAllBatchUpdateRange
|
||||
continue
|
||||
}
|
||||
const batchMesh: Mesh = batch.renderObject as Mesh
|
||||
if (batchMesh.geometry.groups.length === 0) {
|
||||
if ((batchMesh.material as Material).stencilWrite === true)
|
||||
visibilityRanges[k] = AllBatchUpdateRange
|
||||
} else {
|
||||
const stencilGroup = batchMesh.geometry.groups.find((value) => {
|
||||
return batchMesh.material[value.materialIndex].stencilWrite === true
|
||||
})
|
||||
if (stencilGroup) {
|
||||
visibilityRanges[k] = {
|
||||
offset: stencilGroup.start,
|
||||
count: stencilGroup.count
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return visibilityRanges
|
||||
}
|
||||
|
||||
public getOpaque() {
|
||||
const visibilityRanges = {}
|
||||
for (const k in this.batches) {
|
||||
@@ -190,27 +217,6 @@ export default class Batcher {
|
||||
return visibilityRanges
|
||||
}
|
||||
|
||||
public enableTransparent(value: boolean) {
|
||||
for (const k in this.batches) {
|
||||
const batch: Batch = this.batches[k]
|
||||
if (batch.geometryType !== GeometryType.MESH) continue
|
||||
const batchMesh: Mesh = batch.renderObject as Mesh
|
||||
if (batchMesh.geometry.groups.length === 0) {
|
||||
batchMesh.visible = (batchMesh.material as Material).transparent
|
||||
? value
|
||||
: batchMesh.visible
|
||||
} else {
|
||||
const transparentGroup = batchMesh.geometry.groups.find((value) => {
|
||||
return batchMesh.material[value.materialIndex].transparent === true
|
||||
})
|
||||
batch.setVisibleRange({
|
||||
offset: 0,
|
||||
count: transparentGroup.start
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public purgeBatches(subtreeId: string) {
|
||||
for (const k in this.batches) {
|
||||
if (this.batches[k].subtreeId === subtreeId) {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import {
|
||||
AlwaysStencilFunc,
|
||||
Color,
|
||||
DoubleSide,
|
||||
FrontSide,
|
||||
Material,
|
||||
MathUtils,
|
||||
ReplaceStencilOp,
|
||||
Texture,
|
||||
Vector2
|
||||
} from 'three'
|
||||
@@ -19,7 +21,6 @@ import defaultGradient from '../../assets/gradient.png'
|
||||
import { Assets } from '../Assets'
|
||||
import { getConversionFactor } from '../converter/Units'
|
||||
import SpeckleGhostMaterial from './SpeckleGhostMaterial'
|
||||
import SpeckleBasicMaterial from './SpeckleBasicMaterial'
|
||||
|
||||
export interface MaterialOptions {
|
||||
rampIndex?: number
|
||||
@@ -98,32 +99,25 @@ export default class Materials {
|
||||
}
|
||||
|
||||
private async createDefaultMeshMaterials() {
|
||||
// this.meshHighlightMaterial = new SpeckleStandardMaterial(
|
||||
// {
|
||||
// color: 0x047efb,
|
||||
// emissive: 0x0,
|
||||
// roughness: 1,
|
||||
// metalness: 0,
|
||||
// side: DoubleSide
|
||||
// },
|
||||
// ['USE_RTE']
|
||||
// )
|
||||
// this.meshHighlightMaterial.clipShadows = true
|
||||
this.meshHighlightMaterial = new SpeckleBasicMaterial(
|
||||
this.meshHighlightMaterial = new SpeckleStandardMaterial(
|
||||
{
|
||||
color: 0x047efb,
|
||||
emissive: 0x0,
|
||||
roughness: 1,
|
||||
metalness: 0,
|
||||
side: DoubleSide
|
||||
},
|
||||
['USE_RTE']
|
||||
)
|
||||
this.meshHighlightMaterial.clipShadows = true
|
||||
// this.meshHighlightMaterial.depthWrite = false
|
||||
// this.meshHighlightMaterial.depthTest = false
|
||||
// this.meshHighlightMaterial.transparent = true
|
||||
// this.meshHighlightMaterial.blendSrc = OneFactor
|
||||
// this.meshHighlightMaterial.blendDst = ZeroFactor
|
||||
// this.meshHighlightMaterial.blendSrcAlpha = OneFactor
|
||||
// this.meshHighlightMaterial.blendDstAlpha = ZeroFactor
|
||||
this.meshHighlightMaterial.stencilWrite = true
|
||||
this.meshHighlightMaterial.stencilWriteMask = 0xff
|
||||
this.meshHighlightMaterial.stencilRef = 0x00
|
||||
this.meshHighlightMaterial.stencilFunc = AlwaysStencilFunc
|
||||
this.meshHighlightMaterial.stencilZFail = ReplaceStencilOp
|
||||
this.meshHighlightMaterial.stencilZPass = ReplaceStencilOp
|
||||
this.meshHighlightMaterial.stencilFail = ReplaceStencilOp
|
||||
|
||||
this.meshTransparentHighlightMaterial = new SpeckleStandardMaterial(
|
||||
{
|
||||
color: 0x047efb,
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable camelcase */
|
||||
import { speckleDisplaceVert } from './shaders/speckle-displace.vert'
|
||||
import { speckleDisplaceFrag } from './shaders/speckle-displace-frag'
|
||||
import { UniformsUtils, ShaderLib, Vector3, Vector2 } from 'three'
|
||||
import SpeckleBasicMaterial from './SpeckleBasicMaterial'
|
||||
|
||||
class SpeckleDisplaceMaterial extends SpeckleBasicMaterial {
|
||||
constructor(parameters, defines = []) {
|
||||
super(parameters)
|
||||
|
||||
this.userData.uViewer_high = {
|
||||
value: new Vector3()
|
||||
}
|
||||
this.userData.uViewer_low = {
|
||||
value: new Vector3()
|
||||
}
|
||||
this.userData.size = {
|
||||
value: new Vector2()
|
||||
}
|
||||
this.userData.displacement = {
|
||||
value: 0
|
||||
}
|
||||
;(this as any).vertProgram = speckleDisplaceVert
|
||||
;(this as any).fragProgram = speckleDisplaceFrag
|
||||
;(this as any).uniforms = UniformsUtils.merge([
|
||||
ShaderLib.standard.uniforms,
|
||||
{
|
||||
uViewer_high: {
|
||||
value: this.userData.uViewer_high.value
|
||||
},
|
||||
uViewer_low: {
|
||||
value: this.userData.uViewer_low.value
|
||||
},
|
||||
size: {
|
||||
value: this.userData.size.value
|
||||
},
|
||||
displacement: {
|
||||
value: this.userData.displacement.value
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
this.onBeforeCompile = function (shader) {
|
||||
shader.uniforms.uViewer_high = this.userData.uViewer_high
|
||||
shader.uniforms.uViewer_low = this.userData.uViewer_low
|
||||
shader.uniforms.size = this.userData.size
|
||||
shader.uniforms.displacement = this.userData.displacement
|
||||
shader.vertexShader = this.vertProgram
|
||||
shader.fragmentShader = this.fragProgram
|
||||
}
|
||||
|
||||
if (defines) {
|
||||
this.defines = {}
|
||||
}
|
||||
for (let k = 0; k < defines.length; k++) {
|
||||
this.defines[defines[k]] = ' '
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default SpeckleDisplaceMaterial
|
||||
@@ -94,13 +94,6 @@ void main() {
|
||||
mvPosition = modelViewMatrix * mvPosition;
|
||||
|
||||
gl_Position = projectionMatrix * mvPosition;
|
||||
|
||||
// Transform normal vector from object space to clip space.
|
||||
vec3 normalHCS = mat3(projectionMatrix) * normalMatrix * normal;
|
||||
|
||||
// Move vertex along normal vector in clip space.
|
||||
float width = 5.;
|
||||
gl_Position.xy += normalize(normalHCS.xy) / vec2(2034., 1896.) * gl_Position.w * width * 2.;
|
||||
#include <logdepthbuf_vertex>
|
||||
#include <clipping_planes_vertex>
|
||||
#include <worldpos_vertex>
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
export const speckleDisplaceFrag = /* glsl */ `
|
||||
uniform vec3 diffuse;
|
||||
uniform float opacity;
|
||||
#ifndef FLAT_SHADED
|
||||
varying vec3 vNormal;
|
||||
#endif
|
||||
#include <common>
|
||||
#include <dithering_pars_fragment>
|
||||
#include <color_pars_fragment>
|
||||
#include <uv_pars_fragment>
|
||||
#include <uv2_pars_fragment>
|
||||
#include <map_pars_fragment>
|
||||
#include <alphamap_pars_fragment>
|
||||
#include <alphatest_pars_fragment>
|
||||
#include <aomap_pars_fragment>
|
||||
#include <lightmap_pars_fragment>
|
||||
#include <envmap_common_pars_fragment>
|
||||
#include <envmap_pars_fragment>
|
||||
#include <cube_uv_reflection_fragment>
|
||||
#include <fog_pars_fragment>
|
||||
#include <specularmap_pars_fragment>
|
||||
#include <logdepthbuf_pars_fragment>
|
||||
#include <clipping_planes_pars_fragment>
|
||||
void main() {
|
||||
#include <clipping_planes_fragment>
|
||||
vec4 diffuseColor = vec4( diffuse, opacity );
|
||||
#include <logdepthbuf_fragment>
|
||||
#include <map_fragment>
|
||||
#include <color_fragment>
|
||||
#include <alphamap_fragment>
|
||||
#include <alphatest_fragment>
|
||||
#include <specularmap_fragment>
|
||||
ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );
|
||||
// accumulation (baked indirect lighting only)
|
||||
#ifdef USE_LIGHTMAP
|
||||
vec4 lightMapTexel = texture2D( lightMap, vUv2 );
|
||||
reflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity * RECIPROCAL_PI;
|
||||
#else
|
||||
reflectedLight.indirectDiffuse += vec3( 1.0 );
|
||||
#endif
|
||||
// modulation
|
||||
#include <aomap_fragment>
|
||||
reflectedLight.indirectDiffuse *= diffuseColor.rgb;
|
||||
vec3 outgoingLight = reflectedLight.indirectDiffuse;
|
||||
#include <envmap_fragment>
|
||||
#include <output_fragment>
|
||||
#include <tonemapping_fragment>
|
||||
#include <encodings_fragment>
|
||||
#include <fog_fragment>
|
||||
#include <premultiplied_alpha_fragment>
|
||||
#include <dithering_fragment>
|
||||
}
|
||||
`
|
||||
@@ -0,0 +1,111 @@
|
||||
export const speckleDisplaceVert = /* glsl */ `
|
||||
#include <common>
|
||||
#ifdef USE_RTE
|
||||
// The high component is stored as the default 'position' attribute buffer
|
||||
attribute vec3 position_low;
|
||||
uniform vec3 uViewer_high;
|
||||
uniform vec3 uViewer_low;
|
||||
#endif
|
||||
uniform vec2 size;
|
||||
uniform float displacement;
|
||||
#include <uv_pars_vertex>
|
||||
#include <uv2_pars_vertex>
|
||||
#include <envmap_pars_vertex>
|
||||
#include <color_pars_vertex>
|
||||
#include <fog_pars_vertex>
|
||||
#include <morphtarget_pars_vertex>
|
||||
#include <skinning_pars_vertex>
|
||||
#include <logdepthbuf_pars_vertex>
|
||||
#include <clipping_planes_pars_vertex>
|
||||
|
||||
vec4 computeRelativePositionSeparate(in vec3 position_low, in vec3 position_high, in vec3 relativeTo_low, in vec3 relativeTo_high){
|
||||
/*
|
||||
Vector calculation for the high and low differences works on everything
|
||||
*BESIDES* Apple Silicon (or whatever they call it) GPUs
|
||||
|
||||
It would seem that when this code gets compiled, vector types get a lower precision(?)
|
||||
which completely brakes the 2 float -> double reconstructio. Doing it separately for each
|
||||
vector component using floats works fine.
|
||||
*/
|
||||
vec3 highDifference;
|
||||
vec3 lowDifference;
|
||||
float t1 = position_low.x - relativeTo_low.x;
|
||||
float e = t1 - position_low.x;
|
||||
float t2 = ((-relativeTo_low.x - e) + (position_low.x - (t1 - e))) + position_high.x - relativeTo_high.x;
|
||||
highDifference.x = t1 + t2;
|
||||
lowDifference.x = t2 - (highDifference.x - t1);
|
||||
|
||||
t1 = position_low.y - relativeTo_low.y;
|
||||
e = t1 - position_low.y;
|
||||
t2 = ((-relativeTo_low.y - e) + (position_low.y - (t1 - e))) + position_high.y - relativeTo_high.y;
|
||||
highDifference.y = t1 + t2;
|
||||
lowDifference.y = t2 - (highDifference.y - t1);
|
||||
|
||||
t1 = position_low.z - relativeTo_low.z;
|
||||
e = t1 - position_low.z;
|
||||
t2 = ((-relativeTo_low.z - e) + (position_low.z - (t1 - e))) + position_high.z - relativeTo_high.z;
|
||||
highDifference.z = t1 + t2;
|
||||
lowDifference.z = t2 - (highDifference.z - t1);
|
||||
|
||||
vec3 position = highDifference.xyz + lowDifference.xyz;
|
||||
return vec4(position, 1.);
|
||||
}
|
||||
|
||||
vec4 computeRelativePosition(in vec3 position_low, in vec3 position_high, in vec3 relativeTo_low, in vec3 relativeTo_high){
|
||||
/*
|
||||
Source https://github.com/virtualglobebook/OpenGlobe/blob/master/Source/Examples/Chapter05/Jitter/GPURelativeToEyeDSFUN90/Shaders/VS.glsl
|
||||
Note here, we're storing the high part of the position encoding inside three's default 'position' attribute buffer so we avoid redundancy
|
||||
*/
|
||||
vec3 t1 = position_low.xyz - relativeTo_low;
|
||||
vec3 e = t1 - position_low.xyz;
|
||||
vec3 t2 = ((-relativeTo_low - e) + (position_low.xyz - (t1 - e))) + position_high.xyz - relativeTo_high;
|
||||
vec3 highDifference = t1 + t2;
|
||||
vec3 lowDifference = t2 - (highDifference - t1);
|
||||
|
||||
vec3 position = highDifference.xyz + lowDifference.xyz;
|
||||
return vec4(position, 1.);
|
||||
}
|
||||
|
||||
void main() {
|
||||
#include <uv_vertex>
|
||||
#include <uv2_vertex>
|
||||
#include <color_vertex>
|
||||
#include <morphcolor_vertex>
|
||||
#if defined ( USE_ENVMAP ) || defined ( USE_SKINNING )
|
||||
#include <beginnormal_vertex>
|
||||
#include <morphnormal_vertex>
|
||||
#include <skinbase_vertex>
|
||||
#include <skinnormal_vertex>
|
||||
#include <defaultnormal_vertex>
|
||||
#endif
|
||||
#include <begin_vertex>
|
||||
#include <morphtarget_vertex>
|
||||
#include <skinning_vertex>
|
||||
// #include <project_vertex> COMMENTED CHUNK
|
||||
#ifdef USE_RTE
|
||||
vec4 mvPosition = computeRelativePositionSeparate(position_low.xyz, position.xyz, uViewer_low, uViewer_high);
|
||||
#else
|
||||
vec4 mvPosition = vec4( transformed, 1.0 );
|
||||
#endif
|
||||
|
||||
#ifdef USE_INSTANCING
|
||||
|
||||
mvPosition = instanceMatrix * mvPosition;
|
||||
|
||||
#endif
|
||||
mvPosition = modelViewMatrix * mvPosition;
|
||||
|
||||
gl_Position = projectionMatrix * mvPosition;
|
||||
|
||||
// Transform normal vector from object space to clip space.
|
||||
vec3 normalHCS = mat3(projectionMatrix) * normalMatrix * normal;
|
||||
|
||||
// Move vertex along normal vector in clip space.
|
||||
gl_Position.xy += normalize(normalHCS.xy) / size * gl_Position.w * displacement * 2.;
|
||||
#include <logdepthbuf_vertex>
|
||||
#include <clipping_planes_vertex>
|
||||
#include <worldpos_vertex>
|
||||
#include <envmap_vertex>
|
||||
#include <fog_vertex>
|
||||
}
|
||||
`
|
||||
@@ -23,6 +23,8 @@ import {
|
||||
} from './StaticAOPass'
|
||||
import { SpecklePass } from './SpecklePass'
|
||||
import { ColorPass } from './ColorPass'
|
||||
import { StencilPass } from './StencilPass'
|
||||
import { StencilMaskPass } from './StencilMaskPass'
|
||||
|
||||
export enum RenderType {
|
||||
NORMAL,
|
||||
@@ -71,7 +73,9 @@ export class Pipeline {
|
||||
|
||||
private depthPass: DepthPass = null
|
||||
private normalsPass: NormalsPass = null
|
||||
private stencilPass: StencilPass = null
|
||||
private renderPass: ColorPass = null
|
||||
private stencilMaskPass: StencilMaskPass = null
|
||||
private dynamicAoPass: DynamicSAOPass = null
|
||||
private applySaoPass: ApplySAOPass = null
|
||||
private copyOutputPass: CopyOutputPass = null
|
||||
@@ -224,7 +228,9 @@ export class Pipeline {
|
||||
this.depthPass = new DepthPass()
|
||||
this.normalsPass = new NormalsPass()
|
||||
this.dynamicAoPass = new DynamicSAOPass()
|
||||
this.stencilPass = new StencilPass()
|
||||
this.renderPass = new ColorPass()
|
||||
this.stencilMaskPass = new StencilMaskPass()
|
||||
this.applySaoPass = new ApplySAOPass()
|
||||
this.staticAoPass = new StaticAOPass()
|
||||
|
||||
@@ -233,11 +239,13 @@ export class Pipeline {
|
||||
|
||||
this.depthPass.setLayers([ObjectLayers.STREAM_CONTENT])
|
||||
this.normalsPass.setLayers([ObjectLayers.STREAM_CONTENT])
|
||||
this.stencilPass.setLayers([ObjectLayers.STREAM_CONTENT])
|
||||
this.renderPass.setLayers([
|
||||
ObjectLayers.PROPS,
|
||||
ObjectLayers.STREAM_CONTENT,
|
||||
ObjectLayers.SHADOWCATCHER
|
||||
])
|
||||
this.stencilMaskPass.setLayers([ObjectLayers.STREAM_CONTENT])
|
||||
|
||||
let restoreVisibility
|
||||
this.depthPass.onBeforeRender = () => {
|
||||
@@ -258,6 +266,24 @@ export class Pipeline {
|
||||
this._batcher.applyVisibility(restoreVisibility)
|
||||
}
|
||||
|
||||
this.stencilPass.onBeforeRender = () => {
|
||||
restoreVisibility = this._batcher.saveVisiblity()
|
||||
const stencil = this._batcher.getStencil()
|
||||
this._batcher.applyVisibility(stencil)
|
||||
}
|
||||
this.stencilPass.onAfterRender = () => {
|
||||
this._batcher.applyVisibility(restoreVisibility)
|
||||
}
|
||||
|
||||
this.stencilMaskPass.onBeforeRender = () => {
|
||||
restoreVisibility = this._batcher.saveVisiblity()
|
||||
const stencil = this._batcher.getStencil()
|
||||
this._batcher.applyVisibility(stencil)
|
||||
}
|
||||
this.stencilMaskPass.onAfterRender = () => {
|
||||
this._batcher.applyVisibility(restoreVisibility)
|
||||
}
|
||||
|
||||
this.setPipeline(this.getDefaultPipeline())
|
||||
}
|
||||
|
||||
@@ -287,7 +313,9 @@ export class Pipeline {
|
||||
pipeline.push(this.normalsPass)
|
||||
pipeline.push(this.dynamicAoPass)
|
||||
pipeline.push(this.staticAoPass)
|
||||
pipeline.push(this.stencilPass)
|
||||
pipeline.push(this.renderPass)
|
||||
pipeline.push(this.stencilMaskPass)
|
||||
pipeline.push(this.applySaoPass)
|
||||
|
||||
this.needsProgressive = true
|
||||
@@ -316,7 +344,9 @@ export class Pipeline {
|
||||
}
|
||||
|
||||
public update(renderer: SpeckleRenderer) {
|
||||
this.stencilPass.update(renderer.scene, renderer.camera)
|
||||
this.renderPass.update(renderer.scene, renderer.camera)
|
||||
this.stencilMaskPass.update(renderer.scene, renderer.camera)
|
||||
this.depthPass.update(renderer.scene, renderer.camera)
|
||||
this.dynamicAoPass.update(renderer.scene, renderer.camera)
|
||||
this.normalsPass.update(renderer.scene, renderer.camera)
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
import {
|
||||
Camera,
|
||||
Color,
|
||||
DoubleSide,
|
||||
EqualStencilFunc,
|
||||
Material,
|
||||
Scene,
|
||||
Texture,
|
||||
Vector2
|
||||
} from 'three'
|
||||
import SpeckleDisplaceMaterial from '../materials/SpeckleDisplaceMaterial'
|
||||
import { BaseSpecklePass, SpecklePass } from './SpecklePass'
|
||||
|
||||
export class StencilMaskPass extends BaseSpecklePass implements SpecklePass {
|
||||
private camera: Camera
|
||||
private scene: Scene
|
||||
private overrideMaterial: Material = null
|
||||
private _oldClearColor: Color = new Color()
|
||||
private clearColor: Color = null
|
||||
private clearAlpha = 0
|
||||
private clearDepth = true
|
||||
private drawBufferSize: Vector2 = new Vector2()
|
||||
|
||||
public onBeforeRender: () => void = null
|
||||
public onAfterRender: () => void = null
|
||||
|
||||
public constructor() {
|
||||
super()
|
||||
this.overrideMaterial = new SpeckleDisplaceMaterial({ color: 0x04a5fb }, [
|
||||
'USE_RTE'
|
||||
])
|
||||
this.overrideMaterial.userData.displacement.value = 2
|
||||
this.overrideMaterial.colorWrite = true
|
||||
this.overrideMaterial.depthWrite = false
|
||||
this.overrideMaterial.stencilWrite = true
|
||||
this.overrideMaterial.stencilFunc = EqualStencilFunc
|
||||
this.overrideMaterial.stencilRef = 0xff
|
||||
this.overrideMaterial.side = DoubleSide
|
||||
}
|
||||
public get displayName(): string {
|
||||
return 'STENCIL'
|
||||
}
|
||||
public get outputTexture(): Texture {
|
||||
return null
|
||||
}
|
||||
|
||||
public update(scene: Scene, camera: Camera) {
|
||||
this.camera = camera
|
||||
this.scene = scene
|
||||
}
|
||||
|
||||
render(renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */) {
|
||||
if (this.onBeforeRender) this.onBeforeRender()
|
||||
const oldAutoClear = renderer.autoClear
|
||||
renderer.autoClear = false
|
||||
|
||||
let oldClearAlpha, oldOverrideMaterial
|
||||
|
||||
if (this.overrideMaterial !== undefined) {
|
||||
oldOverrideMaterial = this.scene.overrideMaterial
|
||||
|
||||
this.scene.overrideMaterial = this.overrideMaterial
|
||||
}
|
||||
|
||||
if (this.clearColor) {
|
||||
renderer.getClearColor(this._oldClearColor)
|
||||
oldClearAlpha = renderer.getClearAlpha()
|
||||
|
||||
renderer.setClearColor(this.clearColor, this.clearAlpha)
|
||||
}
|
||||
|
||||
if (this.clearDepth) {
|
||||
renderer.clearDepth()
|
||||
}
|
||||
|
||||
this.applyLayers(this.camera)
|
||||
|
||||
renderer.setRenderTarget(this.renderToScreen ? null : readBuffer)
|
||||
|
||||
// TODO: Avoid using autoClear properties, see https://github.com/mrdoob/three.js/pull/15571#issuecomment-465669600
|
||||
if (this.clear)
|
||||
renderer.clear(
|
||||
renderer.autoClearColor,
|
||||
renderer.autoClearDepth,
|
||||
renderer.autoClearStencil
|
||||
)
|
||||
renderer.getDrawingBufferSize(this.drawBufferSize)
|
||||
this.overrideMaterial.userData.size.value.copy(this.drawBufferSize)
|
||||
renderer.render(this.scene, this.camera)
|
||||
|
||||
if (this.clearColor) {
|
||||
renderer.setClearColor(this._oldClearColor, oldClearAlpha)
|
||||
}
|
||||
|
||||
if (this.overrideMaterial !== undefined) {
|
||||
this.scene.overrideMaterial = oldOverrideMaterial
|
||||
}
|
||||
renderer.autoClear = oldAutoClear
|
||||
if (this.onAfterRender) this.onAfterRender()
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,15 @@
|
||||
import { Camera, Color, Material, Scene, Texture } from 'three'
|
||||
import {
|
||||
AlwaysStencilFunc,
|
||||
Camera,
|
||||
Color,
|
||||
DoubleSide,
|
||||
Material,
|
||||
ReplaceStencilOp,
|
||||
Scene,
|
||||
Texture,
|
||||
Vector2
|
||||
} from 'three'
|
||||
import SpeckleDisplaceMaterial from '../materials/SpeckleDisplaceMaterial'
|
||||
import { BaseSpecklePass, SpecklePass } from './SpecklePass'
|
||||
|
||||
export class StencilPass extends BaseSpecklePass implements SpecklePass {
|
||||
@@ -9,12 +20,27 @@ export class StencilPass extends BaseSpecklePass implements SpecklePass {
|
||||
private clearColor: Color = null
|
||||
private clearAlpha = 0
|
||||
private clearDepth = true
|
||||
private drawBufferSize: Vector2 = new Vector2()
|
||||
|
||||
public onBeforeRender: () => void = null
|
||||
public onAfterRender: () => void = null
|
||||
|
||||
public constructor() {
|
||||
super()
|
||||
this.overrideMaterial = new SpeckleDisplaceMaterial({ color: 0xff0000 }, [
|
||||
'USE_RTE'
|
||||
])
|
||||
this.overrideMaterial.userData.displacement.value = 2
|
||||
this.overrideMaterial.colorWrite = false
|
||||
this.overrideMaterial.depthWrite = false
|
||||
this.overrideMaterial.stencilWrite = true
|
||||
this.overrideMaterial.stencilFunc = AlwaysStencilFunc
|
||||
this.overrideMaterial.stencilWriteMask = 0xff
|
||||
this.overrideMaterial.stencilRef = 0xff
|
||||
this.overrideMaterial.stencilZFail = ReplaceStencilOp
|
||||
this.overrideMaterial.stencilZPass = ReplaceStencilOp
|
||||
this.overrideMaterial.stencilFail = ReplaceStencilOp
|
||||
this.overrideMaterial.side = DoubleSide
|
||||
}
|
||||
public get displayName(): string {
|
||||
return 'STENCIL'
|
||||
@@ -29,7 +55,7 @@ export class StencilPass extends BaseSpecklePass implements SpecklePass {
|
||||
}
|
||||
|
||||
render(renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */) {
|
||||
this.onBeforeRender()
|
||||
if (this.onBeforeRender) this.onBeforeRender()
|
||||
const oldAutoClear = renderer.autoClear
|
||||
renderer.autoClear = false
|
||||
|
||||
@@ -63,6 +89,9 @@ export class StencilPass extends BaseSpecklePass implements SpecklePass {
|
||||
renderer.autoClearDepth,
|
||||
renderer.autoClearStencil
|
||||
)
|
||||
renderer.getDrawingBufferSize(this.drawBufferSize)
|
||||
this.overrideMaterial.userData.size.value.copy(this.drawBufferSize)
|
||||
renderer.clear(false, false, true)
|
||||
renderer.render(this.scene, this.camera)
|
||||
|
||||
if (this.clearColor) {
|
||||
@@ -73,6 +102,6 @@ export class StencilPass extends BaseSpecklePass implements SpecklePass {
|
||||
this.scene.overrideMaterial = oldOverrideMaterial
|
||||
}
|
||||
renderer.autoClear = oldAutoClear
|
||||
this.onAfterRender()
|
||||
if (this.onAfterRender) this.onAfterRender()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user