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

Transition to a graph-based API #2332

Draft
wants to merge 44 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
f40335f
feat: add Graph and basic nodes
HoloTheDrunk May 6, 2024
a1d62e1
build: make ts work
HoloTheDrunk May 7, 2024
f4a9ce1
feat: alter post-processing example to use graph
HoloTheDrunk May 7, 2024
ea03206
build: configure eslint for typescript interop
HoloTheDrunk May 13, 2024
e463057
feat: add type-checking, update usage example
HoloTheDrunk May 13, 2024
32722fb
feat: add basic type inference for input nodes
HoloTheDrunk May 14, 2024
bc39d04
feat: add type inference and improve dot graph
HoloTheDrunk May 14, 2024
b81de50
feat: minor dumpDot style fix
HoloTheDrunk May 15, 2024
1978759
feat: add junction node
HoloTheDrunk May 15, 2024
275abe5
feat: add working subgraphs, dotDump is WIP
HoloTheDrunk May 15, 2024
6358753
fix: improve subgraph dotDump, avoid collisions
HoloTheDrunk May 16, 2024
8832ed1
fix: render subgraph deps outside of subgraph
HoloTheDrunk May 16, 2024
3a28fd0
fix: check for graphinput when creating subgraph
HoloTheDrunk May 16, 2024
7ec6ed8
fix: correct render target mistake in example
HoloTheDrunk May 16, 2024
e5311d5
feat!: add View nodes
HoloTheDrunk May 22, 2024
45c8b51
feat: improve ScreenShaderNode API
HoloTheDrunk May 23, 2024
d53f3c7
wip: allow multiple outputs per node
HoloTheDrunk May 27, 2024
0a76654
wip(feat): allow multiple outputs for subgraphs
HoloTheDrunk May 30, 2024
d835d23
feat: add working multiple outputs for subgraphs
HoloTheDrunk Jun 3, 2024
8421556
refacto: improve API terseness
HoloTheDrunk Jun 3, 2024
ed1423d
feat: add dumpdot for subgraph outputs
HoloTheDrunk Jun 3, 2024
3f1d823
feat: move mappings to class
HoloTheDrunk Jun 3, 2024
a8f6f39
refacto: rename Common.ts to Prelude.ts
HoloTheDrunk Jun 3, 2024
5e4dafa
feat: add graph optimizer
HoloTheDrunk Jun 5, 2024
4eb77ad
feat: improve graph optimizer
HoloTheDrunk Jun 5, 2024
60beac5
fix: enforce dot edge compass portPos
HoloTheDrunk Jun 6, 2024
583bb99
feat: add node ids and mangle names when merging
HoloTheDrunk Jun 10, 2024
5245402
fix: remove dead html code in example
HoloTheDrunk Jun 10, 2024
3208a6a
style: added inline glsl hints for editors
HoloTheDrunk Jun 11, 2024
448a175
build: fix babel/webpack inconsistencies on bundle
HoloTheDrunk Jun 12, 2024
51e809d
feat: improve screen shader handling
HoloTheDrunk Jun 18, 2024
0584085
fix: invalid arg type in ScreenShaderNode callback
HoloTheDrunk Jun 18, 2024
062a950
feat: improve post-processing graph example
HoloTheDrunk Jun 19, 2024
059c7eb
feat: add depth buffer to RenderViewNode
HoloTheDrunk Jun 20, 2024
67c678d
refactor: add an internal method to update outputs
HoloTheDrunk Jun 24, 2024
30ea8d5
feat(wip): make outputs objects, add dependants
HoloTheDrunk Jun 24, 2024
78253e6
feat: add auto-managed forward links
HoloTheDrunk Jun 26, 2024
935ada3
fix: remove console debug logging
HoloTheDrunk Jun 26, 2024
4b75645
feat: replace lazystaticnode with property
HoloTheDrunk Jun 26, 2024
14a2431
feat: adapt InputNode to the new static mode
HoloTheDrunk Jun 26, 2024
8fe966c
feat: add graph-wide state, minor renaming
HoloTheDrunk Jul 2, 2024
fab8b3f
wip(feat): sources
HoloTheDrunk Jul 23, 2024
9cc58ce
wip(feat): base design choices for source nodes
HoloTheDrunk Aug 11, 2024
378bf40
feat: improve side-effect-only ergonomics
HoloTheDrunk Oct 1, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
{
"presets": [
["@babel/preset-env", {
"targets": {
"browsers": "defaults and supports webgl2"
},
"modules": false
}]
["@babel/preset-typescript"]
],
"plugins": [
["module-resolver", { "root": ["./src"] } ],
Expand All @@ -17,9 +12,11 @@
".css"
]
}],
["module-extension-resolver"],
["@babel/plugin-transform-runtime", {
"regenerator": false
["module-extension-resolver", {
"srcExtensions": [
".ts",
".js"
]
}],
["minify-replace", {
"replacements": [{
Expand Down
38 changes: 34 additions & 4 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
module.exports = {
root: true,
plugins: [
'@typescript-eslint',
],
parser: '@typescript-eslint/parser',
extends: [
'eslint-config-airbnb-base',
'eslint-config-airbnb-base/rules/strict',
'plugin:@typescript-eslint/recommended',
],
parserOptions: {
ecmaVersion: 13,
ecmaVersion: 2023,
sourceType: 'module',
ecmaFeatures: {
impliedStrict: true,
},
},
settings: {
'import/resolver': {
webpack: {
config: './webpack.config.cjs',
'babel-module': {
extensions: ['.js', '.ts'],
},
},
},
Expand All @@ -25,9 +30,22 @@ module.exports = {
commonjs: true,
},
rules: {
'import/extensions': [
'off',
],
'no-trailing-spaces': 'warn',
'padded-blocks': 'warn',
'no-unused-vars': 'warn',
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': [
'warn',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^_',
},
],
'@typescript-eslint/no-this-alias': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'no-plusplus': 'off',
// this option sets a specific tab width for your code
// http://eslint.org/docs/rules/indent
Expand Down Expand Up @@ -108,6 +126,18 @@ module.exports = {
// change default-param-last to on, but there are several breaking changes or default params to add.
'default-param-last': 'off',
},
overrides: [
{
files: ['*.ts'],
rules: {
'valid-jsdoc': 'off',
'@typescript-eslint/explicit-function-return-type': [
'error',
{ allowExpressions: true },
],
},
},
],
globals: {
__DEBUG__: false,
},
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ potree
coverage
.nyc_output/
/src/ThreeExtended/
types/
5 changes: 5 additions & 0 deletions babel.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"babelrcRoots": [
"."
]
}
261 changes: 154 additions & 107 deletions examples/effects_postprocessing.html
Original file line number Diff line number Diff line change
@@ -1,113 +1,160 @@
<!DOCTYPE html>
<html>
<head>
<title>Itowns - postprocessing</title>

<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="css/example.css">
<link rel="stylesheet" type="text/css" href="css/LoadingScreen.css">

<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div id="viewerDiv"></div>
<script src="../dist/itowns.js"></script>
<script src="js/GUI/LoadingScreen.js"></script>
<!-- from https://github.com/mrdoob/three.js/blob/master/examples/js/shaders/DotScreenShader.js -->
<script type="x-shader/x-vertex" id="vertexshader">
varying vec2 vUv;

void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
</script>

<script type="x-shader/x-fragment" id="fragmentshader">
uniform vec2 center;
uniform float angle;
uniform float scale;
uniform vec2 tSize;

uniform sampler2D tDiffuse;

varying vec2 vUv;

float pattern() {

float s = sin( angle ), c = cos( angle );

vec2 tex = vUv * tSize - center;
vec2 point = vec2( c * tex.x - s * tex.y, s * tex.x + c * tex.y ) * scale;

return ( sin( point.x ) * sin( point.y ) ) * 4.0;
}
void main() {
vec4 color = texture2D( tDiffuse, vUv );
float average = ( color.r + color.g + color.b ) / 3.0;
gl_FragColor = vec4( vec3( average * 10.0 - 5.0 + pattern() ), color.a );
<head>
<title>Itowns - postprocessing</title>

<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="css/example.css">
<link rel="stylesheet" type="text/css" href="css/LoadingScreen.css">

<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>

<body>
<div id="viewerDiv"></div>
<script src="../dist/itowns.js"></script>
<script src="js/GUI/LoadingScreen.js"></script>

<script type="text/javascript">
const graph = itowns.graph;

// Graph showcase
const outerGraph = new graph.Graph();

// iTowns namespace defined here
const placement = new graph.InputNode({
coord: new itowns.Coordinates('EPSG:4326', 2.351323, 48.856712),
range: 25_000_000,
}, graph.BuiltinType.Placement);

const viewerDiv = new graph.InputNode(document.getElementById('viewerDiv'));
const viewNode = new graph.GlobeViewNode(viewerDiv, placement);
outerGraph.set({placement, viewerDiv, viewNode});

const div = viewerDiv.getOutput();
const view = viewNode.getOutput('view', outerGraph);
setupLoadingScreen(div, view);

const renderer = {node: viewNode, output: 'renderer'};
const render = new graph.RenderViewNode({node: viewNode, output: 'view'});
outerGraph.set({render});

// Post-processing subgraph
const postProcessingGraph = new graph.Graph();

// Coast highlight uniforms
const sharpenWeight = new graph.InputNode(5);
const sharpenOffset = new graph.InputNode(new itowns.THREE.Vector2(3., 0.));
postProcessingGraph.set({sharpenWeight, sharpenOffset});

// Screen shaders
const warp = new graph.ScreenShaderNode(render, renderer, {
fragmentShaderParts: {
auxCode: /* glsl */`
uniform vec2 resolution;
`,
main: /* glsl */`
float frequency = 50.;
float strength = 5.;

vec2 uv = sqrt(2. * abs(vUv - 0.5));
if (resolution.x > resolution.y) {
uv.x *= resolution.x / resolution.y;
}
vec2 squv = uv * uv;
vec2 uvOffset = vec2(
sin(floor(frequency * squv.x)),
cos(floor(frequency * squv.y))
);
return texture2D(tDiffuse, vUv + uvOffset * vec2(strength, strength) / resolution);
`
},
});

const coastHighlight = new graph.ScreenShaderNode(warp, renderer, {
fragmentShaderParts: {
uniforms: {uWeight: sharpenWeight, uOffset: sharpenOffset},
auxCode: /* glsl */`
uniform vec2 resolution;

float getAvg(vec4 color) {
return (color.r + color.g + color.b) / 3.0;
}
`,
main: /* glsl */`
float mid = getAvg(color);
float left = getAvg(texture2D(tDiffuse, vUv - uOffset / resolution));

float diff = uWeight * (mid - left);
float avg = (mid + left) / 2.0;

float smoothed = max(0., diff - avg);
float blueness = color.b / (color.r + color.g + color.b);

return color + blueness * vec4(smoothed, smoothed, smoothed, 1.0);
`
},
});

const greyscale = new graph.ScreenShaderNode(coastHighlight, renderer, {
fragmentShaderParts: {
main: /* glsl */`
float avg = (color.r + color.g + color.b) / 3.;
return vec4(avg, avg, avg, 1.0);`
},
});

const uvcolor = new graph.ScreenShaderNode(greyscale, renderer, {
fragmentShaderParts: {
main: /* glsl */`
float r = min(color.r * vUv.x, 1.);
float g = min(color.g * vUv.y, 1.);
return vec4(r, g, color.b, 1.0);
`,
},
});

postProcessingGraph.set({warp, coastHighlight, greyscale, uvcolor});

const postProcessingSubGraph = graph.SubGraph.from(postProcessingGraph, 'Post-processing');
const postProcessingGraphNode = new graph.SubGraphNode(outerGraph, postProcessingSubGraph, {
uvcolor: {
node: uvcolor,
output: 'value',
},
});

const renderFBO = new graph.ScreenShaderNode({node: postProcessingGraphNode, output: 'uvcolor'}, renderer, {toScreen: true});
outerGraph.set({postProcessingGraphNode, renderFBO});

// We expect coastHighlight, greyscale and uvcolor to be merged
// warp will not be merged as the merged node from the previous merges violates the no-offset access invariant
postProcessingSubGraph.optimize(uvcolor);

const graphNodeIds = graph => Array.from(graph.nodes.entries()).map(([name, n]) => `${name}: ${n.id}`).join('\n');

let frame = 0;
view.render = function render() {
outerGraph.run(frame++, renderFBO);
// Reach cruising speed before dumping so timing information is accurate
if (frame == 10) {
window.open(outerGraph.dumpDotGraphvizLink(), '_blank', 'popup');
}
</script>

<script type="text/javascript">
var placement = {
coord: new itowns.Coordinates('EPSG:4326', 2.351323, 48.856712),
range: 25000000,
}

};

itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) {
config.source = new itowns.WMTSSource(config.source);
var layer = new itowns.ColorLayer('Ortho', config);
view.addLayer(layer);
});
itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT.json').then(function _(config) {
config.source = new itowns.WMTSSource(config.source);
console.dir(config.source);
var layer = new itowns.ElevationLayer(config.id, config);
view.addLayer(layer);
});
</script>
</body>

// iTowns namespace defined here
var viewerDiv = document.getElementById('viewerDiv');
var view = new itowns.GlobeView(viewerDiv, placement);

// Simple postprocessing setup
//
var postprocessScene = new itowns.THREE.Scene();
var quad = new itowns.THREE.Mesh(new itowns.THREE.PlaneGeometry(2, 2), null);
var cam = new itowns.THREE.OrthographicCamera(-1, 1, 1, -1, 0, 10);

setupLoadingScreen(viewerDiv, view);

quad.frustumCulled = false;
quad.material = new itowns.THREE.ShaderMaterial({
uniforms: {
tDiffuse: { value: null },
tSize: { value: new itowns.THREE.Vector2(256, 256) },
center: { value: new itowns.THREE.Vector2(0.5, 0.5) },
angle: { value: 1.57 },
scale: { value: 1.0 },
},
vertexShader: document.getElementById('vertexshader').textContent,
fragmentShader: document.getElementById('fragmentshader').textContent,
});
postprocessScene.add(quad);

view.render = function render() {
var g = view.mainLoop.gfxEngine;
var r = g.renderer;
r.setRenderTarget(g.fullSizeRenderTarget);
r.clear();
r.render(view.scene, view.camera3D);

quad.material.uniforms.tDiffuse.value = g.fullSizeRenderTarget.texture;
quad.material.uniforms.tSize.value.set(
g.fullSizeRenderTarget.width, g.fullSizeRenderTarget.height);

r.setRenderTarget(null);
r.clear();
r.render(postprocessScene, cam);
};

itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) {
config.source = new itowns.WMTSSource(config.source);
var layer = new itowns.ColorLayer('Ortho', config);
view.addLayer(layer);
});
itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT.json').then(function _(config) {
config.source = new itowns.WMTSSource(config.source);
var layer = new itowns.ElevationLayer(config.id, config);
view.addLayer(layer);
});
</script>
</body>
</html>
Loading