diff --git a/_projects/bathroom_shelf.md b/_projects/bathroom_shelf.md index c050501..067756f 100644 --- a/_projects/bathroom_shelf.md +++ b/_projects/bathroom_shelf.md @@ -15,7 +15,7 @@ model: /assets/projects/bathroom_shelf/models/ikea.glb --- {% include mastodon_post.html post_id = "111822564173512216" %} - +

Loading model...

diff --git a/_projects/ceramics.md b/_projects/ceramics.md index c865fd7..6c6741d 100644 --- a/_projects/ceramics.md +++ b/_projects/ceramics.md @@ -17,7 +17,7 @@ model: /assets/projects/ceramics/scan.glb

Loading model...

--> - +

Loading model...

\ No newline at end of file diff --git a/assets/js/outline-model-viewer/CustomOutlinePass.js b/assets/js/outline-model-viewer/CustomOutlinePass.js index dbfef5a..dfa551a 100644 --- a/assets/js/outline-model-viewer/CustomOutlinePass.js +++ b/assets/js/outline-model-viewer/CustomOutlinePass.js @@ -1,9 +1,7 @@ import * as THREE from "three"; import { Pass } from "three/addons/postprocessing/Pass.js"; import { FullScreenQuad } from "three/addons/postprocessing/Pass.js"; -import { - getSurfaceIdMaterial, -} from "./FindSurfaces.js"; +import { getSurfaceIdMaterial } from "./FindSurfaces.js"; // Follows the structure of // https://github.com/mrdoob/three.js/blob/master/examples/jsm/postprocessing/OutlinePass.js @@ -19,8 +17,7 @@ class CustomOutlinePass extends Pass { this.fsQuad = new FullScreenQuad(null); this.fsQuad.material = this.createOutlinePostProcessMaterial(); - // Create a buffer to store the normals of the scene onto - // or store the "surface IDs" + // Create a buffer to surface ids const surfaceBuffer = new THREE.WebGLRenderTarget( this.resolution.x, this.resolution.y @@ -117,7 +114,7 @@ class CustomOutlinePass extends Pass { uniform float cameraFar; uniform vec4 screenSize; uniform vec3 outlineColor; - uniform vec2 multiplierParameters; + uniform vec3 multiplierParameters; uniform int debugVisualize; varying vec2 vUv; @@ -152,19 +149,36 @@ class CustomOutlinePass extends Pass { return clamp(num, 0.0, 1.0); } - float getSufaceIdDiff(vec3 surfaceValue) { - float surfaceIdDiff = 0.0; - surfaceIdDiff += distance(surfaceValue, getSurfaceValue(1, 0)); - surfaceIdDiff += distance(surfaceValue, getSurfaceValue(0, 1)); - surfaceIdDiff += distance(surfaceValue, getSurfaceValue(0, 1)); - surfaceIdDiff += distance(surfaceValue, getSurfaceValue(0, -1)); - surfaceIdDiff += distance(surfaceValue, getSurfaceValue(1, 1)); - surfaceIdDiff += distance(surfaceValue, getSurfaceValue(1, -1)); - surfaceIdDiff += distance(surfaceValue, getSurfaceValue(-1, 1)); - surfaceIdDiff += distance(surfaceValue, getSurfaceValue(-1, -1)); - return surfaceIdDiff; - } + float getSurfaceIdDiff(vec3 surfaceValue) { + float surfaceIdDiff = 0.0; + + surfaceIdDiff += any(notEqual(surfaceValue, getSurfaceValue(1, 0))) ? 1.0 : 0.0; + surfaceIdDiff += any(notEqual(surfaceValue, getSurfaceValue(0, 1))) ? 1.0 : 0.0; + surfaceIdDiff += any(notEqual(surfaceValue, getSurfaceValue(-1, 0))) ? 1.0 : 0.0; + surfaceIdDiff += any(notEqual(surfaceValue, getSurfaceValue(0, -1))) ? 1.0 : 0.0; + + surfaceIdDiff += any(notEqual(surfaceValue, getSurfaceValue(1, 1))) ? 1.0 : 0.0; + surfaceIdDiff += any(notEqual(surfaceValue, getSurfaceValue(1, -1))) ? 1.0 : 0.0; + surfaceIdDiff += any(notEqual(surfaceValue, getSurfaceValue(-1, 1))) ? 1.0 : 0.0; + surfaceIdDiff += any(notEqual(surfaceValue, getSurfaceValue(-1, -1))) ? 1.0 : 0.0; + + return surfaceIdDiff; + } + + float getDepthDiff(float depth) { + float depthDiff = 0.0; + depthDiff += abs(depth - getPixelDepth(1, 0)); + depthDiff += abs(depth - getPixelDepth(-1, 0)); + depthDiff += abs(depth - getPixelDepth(0, 1)); + depthDiff += abs(depth - getPixelDepth(0, -1)); + + depthDiff += abs(depth - getPixelDepth(1, 1)); + depthDiff += abs(depth - getPixelDepth(1, -1)); + depthDiff += abs(depth - getPixelDepth(-1, 1)); + depthDiff += abs(depth - getPixelDepth(-1, -1)); + return depthDiff; + } const uint k = 1103515245U; // GLIB C @@ -184,34 +198,44 @@ class CustomOutlinePass extends Pass { vec3 surfaceValue = getSurfaceValue(0, 0); // Get the difference between depth of neighboring pixels and current. - float depthDiff = 0.0; - depthDiff += abs(depth - getPixelDepth(1, 0)); - depthDiff += abs(depth - getPixelDepth(-1, 0)); - depthDiff += abs(depth - getPixelDepth(0, 1)); - depthDiff += abs(depth - getPixelDepth(0, -1)); + float depthDiff = getDepthDiff(depth); // Get the difference between surface values of neighboring pixels // and current - float surfaceValueDiff = getSufaceIdDiff(surfaceValue); + float surfaceValueDiff = getSurfaceIdDiff(surfaceValue); // Apply multiplier & bias to each float depthBias = multiplierParameters.x; float depthMultiplier = multiplierParameters.y; + float lerp = multiplierParameters.z; - depthDiff = depthDiff * depthMultiplier; - depthDiff = saturateValue(depthDiff); + depthDiff = saturateValue(depthDiff * depthMultiplier); depthDiff = pow(depthDiff, depthBias); + if (debugVisualize == 7) { + // Surface ID difference + gl_FragColor = vec4(vec3(surfaceValueDiff), 1.0); + } + if (surfaceValueDiff != 0.0) surfaceValueDiff = 1.0; + + float outline; + vec4 outlineColor = vec4(outlineColor, 1.0);; - float outline = saturateValue(surfaceValueDiff + depthDiff); - - // Combine outline with scene color. - vec4 outlineColor = vec4(outlineColor, 1.0); - gl_FragColor = vec4(mix(sceneColor, outlineColor, outline)); + // Normal mode, use the surface ids to draw outlines and add the shaded scene in too + if (debugVisualize == 0) { + outline = saturateValue(surfaceValueDiff); + gl_FragColor = vec4(mix(sceneColor, outlineColor, outline)); + } - //// For debug visualization of the different inputs to this shader. - if (debugVisualize == 2) { + // Depth mode, use the depth to draw outlines only at the outside + if (debugVisualize == 1) { + outline = saturateValue(depthDiff); + gl_FragColor = vec4(mix(sceneColor, outlineColor, outline)); + } + + //Scene color no outline + if (debugVisualize == 2) { gl_FragColor = sceneColor; } if (debugVisualize == 3) { @@ -223,8 +247,14 @@ class CustomOutlinePass extends Pass { } if (debugVisualize == 5) { // Outlines only + outline = mix(surfaceValueDiff, depthDiff, lerp); + outline = saturateValue(outline); gl_FragColor = mix(vec4(0,0,0,0), outlineColor, outline); } + if (debugVisualize == 6) { + // Depth difference + gl_FragColor = vec4(vec3(depthDiff), 1.0); + } } `; } @@ -237,10 +267,8 @@ class CustomOutlinePass extends Pass { depthBuffer: {}, surfaceBuffer: {}, outlineColor: { value: new THREE.Color(this.outlineColor) }, - //4 scalar values packed in one uniform: - // depth multiplier, depth bias multiplierParameters: { - value: new THREE.Vector2(0.9, 20), + value: new THREE.Vector3(0.9, 20, 0.5), }, cameraNear: { value: this.renderCamera.near }, cameraFar: { value: this.renderCamera.far }, diff --git a/assets/js/outline-model-viewer/FindSurfaces.js b/assets/js/outline-model-viewer/FindSurfaces.js index dc343a0..b4dcbc1 100644 --- a/assets/js/outline-model-viewer/FindSurfaces.js +++ b/assets/js/outline-model-viewer/FindSurfaces.js @@ -12,6 +12,7 @@ class FindSurfaces { constructor() { // This identifier, must be globally unique for each surface // across all geometry rendered on screen + // reserve 10 special ids for various purposes this.surfaceId = 10; } diff --git a/assets/js/outline-model-viewer/index.js b/assets/js/outline-model-viewer/index.js index df228ee..e326285 100644 --- a/assets/js/outline-model-viewer/index.js +++ b/assets/js/outline-model-viewer/index.js @@ -106,7 +106,6 @@ export class OutlineModelViewer extends HTMLElement { const canvas = this.shadow.querySelector("canvas"); let canvas_rect = canvas.getBoundingClientRect(); - console.log(canvas_rect); // determine the outline and bg colors const body = document.getElementsByTagName("body")[0]; @@ -138,11 +137,18 @@ export class OutlineModelViewer extends HTMLElement { renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(canvas_rect.width, canvas_rect.height, false); - const light = new THREE.DirectionalLight(0xffffff, 2); - scene.add(light); - light.position.set(1.7, 1, -1); + const directionalLight = new THREE.DirectionalLight( + 0xffffff, + this.getAttribute("directional-light") || 2 + ); + scene.add(directionalLight); + directionalLight.position.set(1.7, 1, -1); - scene.add(new THREE.AmbientLight(0xffffff, 5)); + const ambientLight = new THREE.AmbientLight( + 0xffffff, + this.getAttribute("ambient-light") || 0.5 + ); + scene.add(ambientLight); // Set up post processing // Create a render target that holds a depthTexture so we can use it in the outline pass @@ -180,6 +186,7 @@ export class OutlineModelViewer extends HTMLElement { composer.addPass(effectFXAA); const surfaceFinder = new FindSurfaces(); + // Load model const loader = new GLTFLoader(); const dracoLoader = new DRACOLoader(); @@ -189,7 +196,6 @@ export class OutlineModelViewer extends HTMLElement { loader.load(model_path, (gltf) => { scene.add(gltf.scene); - surfaceFinder.surfaceId = 0; // Compute bounding box let box = new THREE.Box3().setFromObject(gltf.scene); @@ -212,6 +218,7 @@ export class OutlineModelViewer extends HTMLElement { if (node.type == "Mesh") { // Add surface ID attribute to the geometry const colorsTypedArray = surfaceFinder.getSurfaceIdAttribute(node); + node.surfaceId = colorsTypedArray; node.geometry.setAttribute( "color", new THREE.BufferAttribute(colorsTypedArray, 4) @@ -293,7 +300,9 @@ export class OutlineModelViewer extends HTMLElement { ); } - shadow.querySelector("#clicked-item").innerText = object.name; + shadow.querySelector( + "#clicked-item" + ).innerText = `${object.name} - ${object.type}`; } } else if (this.intersectedObject) { this.intersectedObject = null; @@ -359,22 +368,23 @@ export class OutlineModelViewer extends HTMLElement { injectStyles: false, closeFolders: true, }); - gui.close(); + + if ((this.getAttribute("model") || "closed") === "closed") gui.close(); const uniforms = customOutline.fsQuad.material.uniforms; - uniforms.debugVisualize.value = - this.getAttribute("outlines") === "false" ? 2 : 0; + uniforms.debugVisualize.value = parseInt(this.getAttribute("mode")) || 0; const params = { - selectedObject: "None", spin: controls.autoRotate, - mode: uniforms.debugVisualize.value, - // depthBias: uniforms.multiplierParameters.value.x, - // depthMult: uniforms.multiplierParameters.value.y, + ambientLight: parseFloat(ambientLight.intensity), + directionalLight: parseFloat(directionalLight.intensity), + mode: { Mode: uniforms.debugVisualize.value }, + depthBias: uniforms.multiplierParameters.value.x, + depthMult: uniforms.multiplierParameters.value.y, + lerp: uniforms.multiplierParameters.value.z, printCamera: () => console.log(serialiseCamera(camera, controls)), }; - gui.add(params, "selectedObject").listen(); gui.add(params, "spin").onChange((value) => { controls.autoRotate = value; }); @@ -383,21 +393,34 @@ export class OutlineModelViewer extends HTMLElement { gui .add(params.mode, "Mode", { "Outlines + Shaded (default)": 0, + "Only outer outlines + shading": 1, Shaded: 2, "Depth buffer": 3, "SurfaceID buffer": 4, Outlines: 5, + "Depth Difference": 6, + "SurfaceID Difference": 7, }) .onChange(function (value) { uniforms.debugVisualize.value = value; }); - // gui.add(params, "depthBias", 0.0, 5).onChange(function (value) { - // uniforms.multiplierParameters.value.x = value; - // }); - // gui.add(params, "depthMult", 0.0, 20).onChange(function (value) { - // uniforms.multiplierParameters.value.y = value; - // }); + gui.add(params, "ambientLight", 0.0, 10.0).onChange(function (value) { + ambientLight.intensity = value; + }); + gui.add(params, "directionalLight", 0.0, 10.0).onChange(function (value) { + directionalLight.intensity = value; + }); + + gui.add(params, "depthBias", 0.0, 5).onChange(function (value) { + uniforms.multiplierParameters.value.x = value; + }); + gui.add(params, "depthMult", 0.0, 40.0).onChange(function (value) { + uniforms.multiplierParameters.value.y = value; + }); + gui.add(params, "lerp", 0.0, 1.0).onChange(function (value) { + uniforms.multiplierParameters.value.z = value; + }); // Toggle fullscreen mode const shadow = this.shadow;