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

Make it compatible with pmndrs/postprocessing #21

Open
samevision opened this issue Oct 30, 2024 · 0 comments
Open

Make it compatible with pmndrs/postprocessing #21

samevision opened this issue Oct 30, 2024 · 0 comments

Comments

@samevision
Copy link

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));
    }

`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant