-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #25 from YertleTurtleGit/nodes
Nodes
- Loading branch information
Showing
35 changed files
with
2,832 additions
and
2,063 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,10 @@ | ||
{ | ||
"compilerOptions": { | ||
"target": "es2020", | ||
"target": "es2021", | ||
"checkJs": true | ||
}, | ||
"ecmaFeatures": { | ||
"modules": false, | ||
"es2020": true | ||
"es2021": true | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/* global NodeGraph, ambientOcclusionMap, roughnessMap */ | ||
|
||
const nodeGraph = new NodeGraph(document.getElementById("nodeGraphDiv")); | ||
|
||
const ambientOcclusionMapNode = nodeGraph.registerNodeAsWorker( | ||
ambientOcclusionMap, | ||
"./src/glsl-shader.js", | ||
"./src/ambient-occlusion-map.js" | ||
); | ||
const roughnessMapNode = nodeGraph.registerNodeAsWorker( | ||
roughnessMap, | ||
"./src/glsl-shader.js", | ||
"./src/roughness-map.js" | ||
); | ||
|
||
const ambientOcclusionMapNodeA = nodeGraph.placeNode(ambientOcclusionMapNode, { | ||
x: 800, | ||
y: 100, | ||
}); | ||
const roughnessMapNodeA = nodeGraph.placeNode(roughnessMapNode, { | ||
x: 800, | ||
y: 500, | ||
}); | ||
|
||
const normalMapInputNode = nodeGraph.createInputNode("ImageBitmap", { | ||
x: 200, | ||
y: 100, | ||
}); | ||
const depthMapInputNode = nodeGraph.createInputNode("ImageBitmap", { | ||
x: 200, | ||
y: 500, | ||
}); | ||
|
||
nodeGraph.connect( | ||
normalMapInputNode.getOutput(), | ||
ambientOcclusionMapNodeA.getInput("normalMap") | ||
); | ||
nodeGraph.connect( | ||
depthMapInputNode.getOutput(), | ||
ambientOcclusionMapNodeA.getInput("depthMap") | ||
); | ||
|
||
nodeGraph.connect( | ||
normalMapInputNode.getOutput(), | ||
roughnessMapNodeA.getInput("normalMap") | ||
); | ||
nodeGraph.connect( | ||
depthMapInputNode.getOutput(), | ||
roughnessMapNodeA.getInput("depthMap") | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
/* global NodeGraph, ambientOcclusionMap, roughnessMap, photometricStereoNormalMap, depthMap, albedoMap, PhotometricStereoRenderer */ | ||
|
||
async function main() { | ||
const nodeGraph = new NodeGraph(document.getElementById("nodeGraphDiv")); | ||
|
||
const albedoMapNode = nodeGraph.registerNodeAsWorker( | ||
albedoMap, | ||
"./src/glsl-shader.js", | ||
"./src/albedo-map.js" | ||
); | ||
const normalMapNode = nodeGraph.registerNodeAsWorker( | ||
photometricStereoNormalMap, | ||
"./src/glsl-shader.js", | ||
"./src/normal-map.js" | ||
); | ||
const depthMapNode = nodeGraph.registerNodeAsWorker( | ||
depthMap, | ||
"./src/glsl-shader.js", | ||
"./src/depth-map.js" | ||
); | ||
const ambientOcclusionMapNode = nodeGraph.registerNodeAsWorker( | ||
ambientOcclusionMap, | ||
"./src/glsl-shader.js", | ||
"./src/ambient-occlusion-map.js" | ||
); | ||
const roughnessMapNode = nodeGraph.registerNodeAsWorker( | ||
roughnessMap, | ||
"./src/glsl-shader.js", | ||
"./src/roughness-map.js" | ||
); | ||
|
||
const albedoMapNodeA = nodeGraph.placeNode(albedoMapNode, { | ||
x: 750, | ||
y: 500, | ||
}); | ||
const normalMapNodeA = nodeGraph.placeNode(normalMapNode, { | ||
x: 750, | ||
y: 150, | ||
}); | ||
const depthMapNodeA = nodeGraph.placeNode(depthMapNode, { x: 1025, y: 600 }); | ||
const ambientOcclusionMapNodeA = nodeGraph.placeNode( | ||
ambientOcclusionMapNode, | ||
{ | ||
x: 1300, | ||
y: 150, | ||
} | ||
); | ||
const roughnessMapNodeA = nodeGraph.placeNode(roughnessMapNode, { | ||
x: 1300, | ||
y: 500, | ||
}); | ||
|
||
const testImageUrls = [ | ||
"./../test-datasets/photometric-stereo/test_000_036.jpg", | ||
"./../test-datasets/photometric-stereo/test_045_036.jpg", | ||
"./../test-datasets/photometric-stereo/test_090_036.jpg", | ||
"./../test-datasets/photometric-stereo/test_135_036.jpg", | ||
"./../test-datasets/photometric-stereo/test_180_036.jpg", | ||
"./../test-datasets/photometric-stereo/test_225_036.jpg", | ||
"./../test-datasets/photometric-stereo/test_270_036.jpg", | ||
"./../test-datasets/photometric-stereo/test_315_036.jpg", | ||
]; | ||
|
||
/** @type {ImageBitmap[]} */ | ||
const testImages = []; | ||
|
||
for (let i = 0; i < testImageUrls.length; i++) { | ||
await new Promise((resolve) => { | ||
const htmlImage = new Image(); | ||
htmlImage.addEventListener("load", async () => { | ||
const imageBitmap = await createImageBitmap(htmlImage); | ||
testImages.push(imageBitmap); | ||
resolve(); | ||
}); | ||
htmlImage.src = testImageUrls[i]; | ||
}); | ||
} | ||
|
||
const lightPolarAngleInputNode = nodeGraph.createInputNode( | ||
"number", | ||
{ | ||
x: 200, | ||
y: 300, | ||
}, | ||
45 | ||
); | ||
const cameraDistanceInputNode = nodeGraph.createInputNode( | ||
"number", | ||
{ | ||
x: 200, | ||
y: 500, | ||
}, | ||
18 | ||
); | ||
const lightDistanceInputNode = nodeGraph.createInputNode( | ||
"number", | ||
{ | ||
x: 200, | ||
y: 600, | ||
}, | ||
18 | ||
); | ||
/*const lightImagesInputNode = nodeGraph.createInputNode("ImageBitmap[]", { | ||
x: 200, | ||
y: 400, | ||
});*/ | ||
|
||
const uiCanvas = document.createElement("canvas"); | ||
uiCanvas.width = 250; | ||
uiCanvas.height = 250; | ||
uiCanvas.style.zIndex = "999"; | ||
document.body.appendChild(uiCanvas); | ||
|
||
new PhotometricStereoRenderer( | ||
uiCanvas, | ||
"./test-datasets/models/mesh_plane.glb", | ||
{ | ||
width: 250, | ||
height: 250, | ||
} | ||
); | ||
await PhotometricStereoRenderer.renderLightImages(45, 18, 18); | ||
|
||
const lightImagesRenderNode = nodeGraph.registerNode( | ||
PhotometricStereoRenderer.renderLightImages | ||
); | ||
const lightImagesRenderNodeA = nodeGraph.placeNode(lightImagesRenderNode, { | ||
x: 450, | ||
y: 400, | ||
}); | ||
|
||
const qualityPercentInputNode = nodeGraph.createInputNode( | ||
"number", | ||
{ | ||
x: 750, | ||
y: 800, | ||
}, | ||
1 | ||
); | ||
|
||
/*nodeGraph.connect( | ||
lightImagesInputNode.getOutput(), | ||
normalMapNodeA.getInput("lightImages") | ||
); | ||
nodeGraph.connect( | ||
lightImagesInputNode.getOutput(), | ||
albedoMapNodeA.getInput("lightImages") | ||
);*/ | ||
nodeGraph.connect( | ||
lightPolarAngleInputNode.getOutput(), | ||
normalMapNodeA.getInput("lightPolarAngleDeg") | ||
); | ||
nodeGraph.connect( | ||
lightPolarAngleInputNode.getOutput(), | ||
lightImagesRenderNodeA.getInput("lightPolarAngleDeg") | ||
); | ||
nodeGraph.connect( | ||
cameraDistanceInputNode.getOutput(), | ||
lightImagesRenderNodeA.getInput("cameraDistance") | ||
); | ||
nodeGraph.connect( | ||
lightDistanceInputNode.getOutput(), | ||
lightImagesRenderNodeA.getInput("lightDistance") | ||
); | ||
nodeGraph.connect( | ||
lightImagesRenderNodeA.getOutput(), | ||
normalMapNodeA.getInput("lightImages") | ||
); | ||
nodeGraph.connect( | ||
lightImagesRenderNodeA.getOutput(), | ||
albedoMapNodeA.getInput("lightImages") | ||
); | ||
nodeGraph.connect( | ||
normalMapNodeA.getOutput(), | ||
depthMapNodeA.getInput("normalMap") | ||
); | ||
nodeGraph.connect( | ||
qualityPercentInputNode.getOutput(), | ||
depthMapNodeA.getInput("qualityPercent") | ||
); | ||
nodeGraph.connect( | ||
normalMapNodeA.getOutput(), | ||
ambientOcclusionMapNodeA.getInput("normalMap") | ||
); | ||
nodeGraph.connect( | ||
depthMapNodeA.getOutput(), | ||
ambientOcclusionMapNodeA.getInput("depthMap") | ||
); | ||
nodeGraph.connect( | ||
normalMapNodeA.getOutput(), | ||
roughnessMapNodeA.getInput("normalMap") | ||
); | ||
nodeGraph.connect( | ||
depthMapNodeA.getOutput(), | ||
roughnessMapNodeA.getInput("depthMap") | ||
); | ||
} | ||
main(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/* global GLSL */ | ||
/* exported albedoMap */ | ||
|
||
/** | ||
* @public | ||
* @param {ImageBitmap[]} lightImages | ||
* @returns {Promise<ImageBitmap>} | ||
*/ | ||
async function albedoMap(lightImages) { | ||
const albedoShader = new GLSL.Shader({ | ||
width: lightImages[0].width, | ||
height: lightImages[0].height, | ||
}); | ||
albedoShader.bind(); | ||
|
||
/** @type {GLSL.Vector4[]} */ | ||
const glslLightImageColor = []; | ||
|
||
lightImages.forEach((lightImage) => { | ||
const glslLightImage = new GLSL.Image(lightImage); | ||
glslLightImageColor.push(glslLightImage.getPixelColor()); | ||
}); | ||
|
||
const albedoColor = glslLightImageColor[0].maximum(...glslLightImageColor); | ||
|
||
const albedoMap = GLSL.render(albedoColor).getImageBitmap(); | ||
|
||
albedoShader.purge(); | ||
|
||
return albedoMap; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
/* global GLSL */ | ||
/* exported ambientOcclusionMap */ | ||
|
||
/** | ||
* @public | ||
* @param {ImageBitmap} normalMap | ||
* @param {ImageBitmap} depthMap | ||
* @returns {Promise<ImageBitmap>} | ||
*/ | ||
async function ambientOcclusionMap(normalMap, depthMap) { | ||
const ambientOcclusionShader = new GLSL.Shader({ | ||
width: normalMap.width, | ||
height: normalMap.height, | ||
}); | ||
ambientOcclusionShader.bind(); | ||
|
||
const glslNormalMap = new GLSL.Image(normalMap); | ||
|
||
const r = glslNormalMap.getNeighborPixel(1, 0).normalize(); | ||
const rb = glslNormalMap.getNeighborPixel(1, 1).normalize(); | ||
const b = glslNormalMap.getNeighborPixel(0, 1).normalize(); | ||
const lb = glslNormalMap.getNeighborPixel(-1, 1).normalize(); | ||
const l = glslNormalMap.getNeighborPixel(-1, 0).normalize(); | ||
const lt = glslNormalMap.getNeighborPixel(-1, -1).normalize(); | ||
const t = glslNormalMap.getNeighborPixel(0, -1).normalize(); | ||
const rt = glslNormalMap.getNeighborPixel(1, -1).normalize(); | ||
|
||
let normalMapOcclusion = new GLSL.Float(1); | ||
|
||
normalMapOcclusion = normalMapOcclusion | ||
.subtractFloat(r.dot(l).acos().abs()) | ||
.minimum(new GLSL.Float(1)); | ||
normalMapOcclusion = normalMapOcclusion | ||
.subtractFloat(rb.dot(lt).acos().abs()) | ||
.minimum(new GLSL.Float(1)); | ||
normalMapOcclusion = normalMapOcclusion | ||
.subtractFloat(b.dot(t).acos().abs()) | ||
.minimum(new GLSL.Float(1)); | ||
normalMapOcclusion = normalMapOcclusion | ||
.subtractFloat(lb.dot(rt).acos().abs()) | ||
.minimum(new GLSL.Float(1)); | ||
|
||
const glslDepthMap = new GLSL.Image(depthMap); | ||
|
||
const kernelPadding = 5; | ||
const neighborhood = []; | ||
|
||
for (let xOffset = 0; xOffset < kernelPadding + 1; xOffset++) { | ||
for (let yOffset = 0; yOffset < kernelPadding + 1; yOffset++) { | ||
neighborhood.push( | ||
glslDepthMap.getNeighborPixel(xOffset, yOffset).channel(0) | ||
); | ||
} | ||
} | ||
|
||
const depth = glslDepthMap.getPixelColor().channel(0); | ||
let depthMapOcclusion = new GLSL.Float(0); | ||
|
||
neighborhood.forEach((neighbor) => { | ||
const neighborOcclusion = neighbor | ||
.subtractFloat(depth) | ||
.addFloat(new GLSL.Float(1)); | ||
depthMapOcclusion = depthMapOcclusion.addFloat(neighborOcclusion); | ||
}); | ||
|
||
depthMapOcclusion = depthMapOcclusion | ||
.divideFloat(new GLSL.Float(neighborhood.length * 0.25)) | ||
.subtractFloat(new GLSL.Float(3.05)); | ||
|
||
let result = normalMapOcclusion | ||
.addFloat(depthMapOcclusion) | ||
.subtractFloat(new GLSL.Float(0.6)); | ||
|
||
const c = new GLSL.Float(0.5); | ||
|
||
const ccf = new GLSL.Float(1) | ||
.multiplyFloat(c.addFloat(new GLSL.Float(1))) | ||
.divideFloat(new GLSL.Float(1)) | ||
.multiplyFloat(new GLSL.Float(1).subtractFloat(c)); | ||
|
||
result = ccf | ||
.multiplyFloat(result.subtractFloat(new GLSL.Float(0.5))) | ||
.addFloat(new GLSL.Float(0.5)); | ||
|
||
result = new GLSL.Float(1).subtractFloat(result); | ||
result = result.multiplyFloat(new GLSL.Float(1.2)); | ||
result = new GLSL.Float(1).subtractFloat(result); | ||
|
||
const ambientOcclusionMap = GLSL.render( | ||
new GLSL.Vector4([result, result, result, new GLSL.Float(1)]) | ||
).getImageBitmap(); | ||
|
||
ambientOcclusionShader.purge(); | ||
return ambientOcclusionMap; | ||
} |
Oops, something went wrong.