Skip to content

Make it compatible with pmndrs/postprocessing #21

@samevision

Description

@samevision

Hi,

currently I try to migrate this post process to work with pmdrs/postprocessing. Unfortunately I failed.

I would really appreciate if someone could help me with this.

import { Color, HalfFloatType, NearestFilter, RGBAFormat, Uniform, Vector2, Vector4, WebGLRenderTarget } from "three"
import { Effect } from 'postprocessing'

import { getSurfaceIdMaterial } from "./FindSurfaces"

export default class OutlineEffect extends Effect {

    constructor(resolution, scene, camera) {
        super('OutlineEffect', fragmentShader, {
            uniforms: new Map([
                ["surfaceBuffer", new Uniform(null)],
                ['outlineColor', new Uniform(new Color(1, 0, 0))],
                ['multiplierParameters', new Uniform(new Vector2(.9, 20))],
                ['screenSize', new Uniform(new Vector4(resolution.x, resolution.y, 1 / resolution.x, 1 / resolution.y))]
            ])
        })

        this.resolution = new Vector2(resolution.x, resolution.y)
        this.scene = scene
        this.camera = camera

        this.surfaceBuffer = new WebGLRenderTarget(this.resolution.x, this.resolution.y)
        this.surfaceBuffer.texture.format = RGBAFormat
        this.surfaceBuffer.texture.type = HalfFloatType
        this.surfaceBuffer.texture.minFilter = NearestFilter
        this.surfaceBuffer.texture.magFilter = NearestFilter
        this.surfaceBuffer.texture.generateMipmaps = false
        this.surfaceBuffer.stencilBuffer = false
        this.uniforms.get("surfaceBuffer").value = this.surfaceBuffer.texture

        this.surfaceIdOverrideMaterial = getSurfaceIdMaterial()
    }

    update(renderer, inputBuffer, deltaTime) {
        // Turn off writing to the depth buffer because we need to read from it in the subsequent passes.
        const depthBufferValue = writeBuffer.depthBuffer
        writeBuffer.depthBuffer = false

        // 1. Re-render the scene to capture all suface IDs in a texture.
        renderer.setRenderTarget(this.surfaceBuffer)
        const overrideMaterialValue = this.scene.overrideMaterial

        this.scene.overrideMaterial = this.surfaceIdOverrideMaterial
        renderer.render(this.scene, this.camera)
        this.scene.overrideMaterial = overrideMaterialValue

        // 2. Draw the outlines using the depth texture and normal texture and combine it with the scene color
        if (this.renderToScreen) {
            // If this is the last effect, then renderToScreen is true.
            // So we should render to the screen by setting target null
            // Otherwise, just render into the writeBuffer that the next effect will use as its read buffer.
            renderer.setRenderTarget(null)
            this.fsQuad.render(renderer)
        } else {
            renderer.setRenderTarget(writeBuffer)
            this.fsQuad.render(renderer)
        }

        // Reset the depthBuffer value so we continue writing to it in the next render.
        writeBuffer.depthBuffer = depthBufferValue
    }

    updateMaxSurfaceId(maxSurfaceId) {
        this.surfaceIdOverrideMaterial.uniforms.maxSurfaceId.value = maxSurfaceId
    }

    setSize(width, height) {
        this.resolution.set(width, height)
        this.surfaceBuffer.setSize(width, height)
        this.uniforms.get('screenSize').value.set(this.resolution.x, this.resolution.y, 1 / this.resolution.x, 1 / this.resolution.y)
    }

}

const fragmentShader = `
    uniform sampler2D surfaceBuffer;
    uniform vec4 screenSize;
    uniform vec3 outlineColor;
    uniform vec2 multiplierParameters;

    float readDepth (sampler2D depthSampler, vec2 coord) {
        float fragCoordZ = texture2D(depthSampler, coord).x;
        float viewZ = perspectiveDepthToViewZ(fragCoordZ, cameraNear, cameraFar);
        return viewZToOrthographicDepth(viewZ, cameraNear, cameraFar);
    }

    float getLinearDepth(vec3 pos) {
        return -(viewMatrix * vec4(pos, 1.0)).z;
    }

    float getLinearScreenDepth(sampler2D map) {
        vec2 vUv = gl_FragCoord.xy * screenSize.zw;
        return readDepth(map, vUv);
    }

    float getPixelDepth(int x, int y, vec2 uv) {
        return readDepth(depthBuffer, uv + screenSize.zw * vec2(x, y));
    }

    vec3 getSurfaceValue(int x, int y, vec2 uv) {
        vec3 val = texture2D(surfaceBuffer, uv + screenSize.zw * vec2(x, y)).rgb;
        return val;
    }

    float saturateValue(float num) {
        return clamp(num, 0.0, 1.0);
    }

    float getSufaceIdDiff(vec3 surfaceValue, vec2 uv) {
        float surfaceIdDiff = 0.0;

        surfaceIdDiff += distance(surfaceValue, getSurfaceValue(1, 0, uv));
        surfaceIdDiff += distance(surfaceValue, getSurfaceValue(0, 1, uv));
        surfaceIdDiff += distance(surfaceValue, getSurfaceValue(0, 1, uv));
        surfaceIdDiff += distance(surfaceValue, getSurfaceValue(0, -1, uv));

        surfaceIdDiff += distance(surfaceValue, getSurfaceValue(1, 1, uv));
        surfaceIdDiff += distance(surfaceValue, getSurfaceValue(1, -1, uv));
        surfaceIdDiff += distance(surfaceValue, getSurfaceValue(-1, 1, uv));
        surfaceIdDiff += distance(surfaceValue, getSurfaceValue(-1, -1, uv));

        return surfaceIdDiff;
    }

    void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) {
        float depth = getPixelDepth(0, 0, uv);
        vec3 surfaceValue = getSurfaceValue(0, 0, uv);

        // Get the difference between depth of neighboring pixels and current
        float depthDiff = 0.0;
        depthDiff += abs(depth - getPixelDepth(1, 0, uv));
        depthDiff += abs(depth - getPixelDepth(-1, 0, uv));
        depthDiff += abs(depth - getPixelDepth(0, 1, uv));
        depthDiff += abs(depth - getPixelDepth(0, -1, uv));

        // Get the difference between surface values of neighboring pixels and current
        float surfaceValueDiff = getSufaceIdDiff(surfaceValue, uv);
        
        // Apply multiplier & bias to each
        float depthBias = multiplierParameters.x;
        float depthMultiplier = multiplierParameters.y;

        depthDiff = depthDiff * depthMultiplier;
        depthDiff = saturateValue(depthDiff);
        depthDiff = pow(depthDiff, depthBias);

        if (surfaceValueDiff != 0.0) surfaceValueDiff = 1.0;

        float outline = saturateValue(surfaceValueDiff + depthDiff);
    
        // Combine outline with scene color
        vec4 outlineColor = vec4(outlineColor, 1.0);
        outputColor = vec4(mix(inputColor, outlineColor, outline));
    }

`

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions