Giter Club home page Giter Club logo

kwokcb / materialx Goto Github PK

View Code? Open in Web Editor NEW

This project forked from academysoftwarefoundation/materialx

1.0 1.0 0.0 615.43 MB

MaterialX is an open standard for transfer of rich material and look-development content between applications and renderers.

Home Page: http://www.materialx.org/

License: Apache License 2.0

CMake 2.27% Python 4.38% C++ 77.11% C 1.56% Objective-C 0.99% GLSL 2.84% JavaScript 3.92% EJS 0.04% Batchfile 0.04% CSS 1.72% Metal 0.41% Objective-C++ 4.72%

materialx's Introduction

You've reached the home of Bernard Kwok

  • ๐Ÿ”ญ Iโ€™m currently open for work on open source projects. The Academy Software Foundation material standard: MaterialX is my primary focus along with it's interrelation with industry standards: Khronos glTF and Pixar USD. Also of focus is MaterialX's interlation with standards such as OCIO (colour management), and shading languages: OSL (Open Shading Language), MDL, and GLSL for both desktop and web rendering.

  • Related connections includes:

materialx's People

Contributors

anderslanglands avatar ashwinbhat avatar bernardkwok avatar briansharpe avatar code-monkey avatar crydalch avatar da-krunch avatar dbsmythe avatar derek-nvidia avatar dgovil avatar friedererdmann avatar ix-dcourtois avatar jstone-lucasfilm avatar krohmernv avatar kwokcb avatar laserallan avatar lfl-eholthouser avatar marsupial avatar mjyip-lucasfilm avatar morteeza avatar niklasharrysson avatar pablode avatar pmolodo avatar proog128 avatar rasmusbonnedal avatar scatteredray avatar tellusim avatar walbourn avatar willmuto-lucasfilm avatar yurivict avatar

Stargazers

 avatar

materialx's Issues

WIP Node Graph Introspection

Progress:

  • Export to Mermaid and dot (GraphViz) from arbitrary <output> or surfaceshader as roots.
  • Allow export using category names or instance names for nodes. Interface inputs and outputs use instance names for
    clarity
  • Extrapolate a new interface for input / output filtering Filter class (under discussion)
  • Determined ability to embed mermaid into parsed cpp files with additional html header.
  • Allow for merging together of graphs as every element created per graph is unique within a document

Functional NodeGraph

  • Supported and tested in unit test and mxdoc.py
  • Example from Lama generation via new version of mxdoc.py. Mermaid graph inside HTML output, with
    using DoxygenAwesome CSS file

duced in unit tests (GraphViz output)

GraphViz Results:

  • dot exporter uses the exact same logic (common) as the Mermaid one with a few methods to override
  • Example brick shader (category names)
    standard_surface_brick_procedural_ dot
  • Example cascading nodegraphs
    cascade_nodegraphs_ dot

Mermaid Results:

  • Example Brick shader (category names)
graph TD;
    NG_BrickPattern_node_clamp_0[clamp] --> NG_BrickPattern_base_color_output([base_color_output]) --.base_color--> N_StandardSurface[standard_surface]
    style NG_BrickPattern_base_color_output fill:#1b1,color:#111
    NG_BrickPattern_node_mix_8[mix] --.in--> NG_BrickPattern_node_clamp_0[clamp]
    NG_BrickPattern_node_multiply_5[multiply] --.fg--> NG_BrickPattern_node_mix_8[mix]
    NG_BrickPattern_node_mix_6[mix] --.in1--> NG_BrickPattern_node_multiply_5[multiply]
    NG_BrickPattern_dirt_color([dirt_color]) ==.fg==> NG_BrickPattern_node_mix_6[mix]
    style NG_BrickPattern_dirt_color fill:#0bb,color:#111
    NG_BrickPattern_node_hsvtorgb_17[hsvtorgb] --.bg--> NG_BrickPattern_node_mix_6[mix]
    NG_BrickPattern_node_add_16[add] --.in--> NG_BrickPattern_node_hsvtorgb_17[hsvtorgb]
    NG_BrickPattern_node_combine3_color3_13[combine3] --.in1--> NG_BrickPattern_node_add_16[add]
    NG_BrickPattern_node_multiply_14[multiply] --.in1--> NG_BrickPattern_node_combine3_color3_13[combine3]
    NG_BrickPattern_hue_variation([hue_variation]) ==.in2==> NG_BrickPattern_node_multiply_14[multiply]
    style NG_BrickPattern_hue_variation fill:#0bb,color:#111
    NG_BrickPattern_node_subtract_18[subtract] --.in1--> NG_BrickPattern_node_multiply_14[multiply]
    NG_BrickPattern_node_add_19[add] --.in1--> NG_BrickPattern_node_subtract_18[subtract]
    NG_BrickPattern_node_multiply_25[multiply] --.in1--> NG_BrickPattern_node_add_19[add]
    NG_BrickPattern_hue_variation([hue_variation]) ==.in1==> NG_BrickPattern_node_multiply_25[multiply]
    style NG_BrickPattern_hue_variation fill:#0bb,color:#111
    NG_BrickPattern_node_tiledimage_float_26[tiledimage] --.in2--> NG_BrickPattern_node_multiply_25[multiply]
    NG_BrickPattern_node_convert_1[convert] --.uvtiling--> NG_BrickPattern_node_tiledimage_float_26[tiledimage]
    NG_BrickPattern_uvtiling([uvtiling]) ==.in==> NG_BrickPattern_node_convert_1[convert]
    style NG_BrickPattern_uvtiling fill:#0bb,color:#111
    NG_BrickPattern_node_tiledimage_float_7[tiledimage] --.in2--> NG_BrickPattern_node_add_19[add]
    NG_BrickPattern_node_convert_1[convert] --.uvtiling--> NG_BrickPattern_node_tiledimage_float_7[tiledimage]
    NG_BrickPattern_node_multiply_15[multiply] --.in3--> NG_BrickPattern_node_combine3_color3_13[combine3]
    NG_BrickPattern_node_add_19[add] --.in1--> NG_BrickPattern_node_multiply_15[multiply]
    NG_BrickPattern_node_multiply_20[multiply] --.in2--> NG_BrickPattern_node_multiply_15[multiply]
    NG_BrickPattern_value_variation([value_variation]) ==.in1==> NG_BrickPattern_node_multiply_20[multiply]
    style NG_BrickPattern_value_variation fill:#0bb,color:#111
    NG_BrickPattern_node_tiledimage_float_26[tiledimage] --.in2--> NG_BrickPattern_node_multiply_20[multiply]
    NG_BrickPattern_node_rgbtohsv_12[rgbtohsv] --.in2--> NG_BrickPattern_node_add_16[add]
    NG_BrickPattern_brick_color([brick_color]) ==.in==> NG_BrickPattern_node_rgbtohsv_12[rgbtohsv]
    style NG_BrickPattern_brick_color fill:#0bb,color:#111
    NG_BrickPattern_node_multiply_23[multiply] --.mix--> NG_BrickPattern_node_mix_6[mix]
    NG_BrickPattern_dirt_amount([dirt_amount]) ==.in1==> NG_BrickPattern_node_multiply_23[multiply]
    style NG_BrickPattern_dirt_amount fill:#0bb,color:#111
    NG_BrickPattern_node_tiledimage_float_24[tiledimage] --.in2--> NG_BrickPattern_node_multiply_23[multiply]
    NG_BrickPattern_node_convert_1[convert] --.uvtiling--> NG_BrickPattern_node_tiledimage_float_24[tiledimage]
    NG_BrickPattern_node_tiledimage_float_7[tiledimage] --.in2--> NG_BrickPattern_node_multiply_5[multiply]
    NG_BrickPattern_node_multiply_9[multiply] --.bg--> NG_BrickPattern_node_mix_8[mix]
    NG_BrickPattern_node_color_11[constant] --.in1--> NG_BrickPattern_node_multiply_9[multiply]
    NG_BrickPattern_node_tiledimage_float_7[tiledimage] --.in2--> NG_BrickPattern_node_multiply_9[multiply]
    NG_BrickPattern_node_tiledimage_float_10[tiledimage] --.mix--> NG_BrickPattern_node_mix_8[mix]
    NG_BrickPattern_node_convert_1[convert] --.uvtiling--> NG_BrickPattern_node_tiledimage_float_10[tiledimage]
    NG_BrickPattern_node_multiply_1[multiply] --> NG_BrickPattern_specular_roughness_output([specular_roughness_output]) --.specular_roughness--> N_StandardSurface[standard_surface]
    style NG_BrickPattern_specular_roughness_output fill:#1b1,color:#111
    NG_BrickPattern_node_divide_21[divide] --.in1--> NG_BrickPattern_node_multiply_1[multiply]
    NG_BrickPattern_roughness_amount([roughness_amount]) ==.in1==> NG_BrickPattern_node_divide_21[divide]
    style NG_BrickPattern_roughness_amount fill:#0bb,color:#111
    NG_BrickPattern_node_max_1[max] --.in2--> NG_BrickPattern_node_divide_21[divide]
    NG_BrickPattern_node_tiledimage_float_10[tiledimage] --.in1--> NG_BrickPattern_node_max_1[max]
    NG_BrickPattern_node_tiledimage_float_22[tiledimage] --.in2--> NG_BrickPattern_node_multiply_1[multiply]
    NG_BrickPattern_node_convert_1[convert] --.uvtiling--> NG_BrickPattern_node_tiledimage_float_22[tiledimage]
    NG_BrickPattern_node_normalmap_3[normalmap] --> NG_BrickPattern_normal_output([normal_output]) --.normal--> N_StandardSurface[standard_surface]
    style NG_BrickPattern_normal_output fill:#1b1,color:#111
    NG_BrickPattern_node_tiledimage_vector3_27[tiledimage] --.in--> NG_BrickPattern_node_normalmap_3[normalmap]
    NG_BrickPattern_node_convert_1[convert] --.uvtiling--> NG_BrickPattern_node_tiledimage_vector3_27[tiledimage]
  subgraph NG_BrickPattern
    NG_BrickPattern_base_color_output
    NG_BrickPattern_brick_color
    NG_BrickPattern_dirt_amount
    NG_BrickPattern_dirt_color
    NG_BrickPattern_hue_variation
    NG_BrickPattern_node_add_16
    NG_BrickPattern_node_add_19
    NG_BrickPattern_node_clamp_0
    NG_BrickPattern_node_color_11
    NG_BrickPattern_node_combine3_color3_13
    NG_BrickPattern_node_convert_1
    NG_BrickPattern_node_divide_21
    NG_BrickPattern_node_hsvtorgb_17
    NG_BrickPattern_node_max_1
    NG_BrickPattern_node_mix_6
    NG_BrickPattern_node_mix_8
    NG_BrickPattern_node_multiply_1
    NG_BrickPattern_node_multiply_14
    NG_BrickPattern_node_multiply_15
    NG_BrickPattern_node_multiply_20
    NG_BrickPattern_node_multiply_23
    NG_BrickPattern_node_multiply_25
    NG_BrickPattern_node_multiply_5
    NG_BrickPattern_node_multiply_9
    NG_BrickPattern_node_normalmap_3
    NG_BrickPattern_node_rgbtohsv_12
    NG_BrickPattern_node_subtract_18
    NG_BrickPattern_node_tiledimage_float_10
    NG_BrickPattern_node_tiledimage_float_22
    NG_BrickPattern_node_tiledimage_float_24
    NG_BrickPattern_node_tiledimage_float_26
    NG_BrickPattern_node_tiledimage_float_7
    NG_BrickPattern_node_tiledimage_vector3_27
    NG_BrickPattern_normal_output
    NG_BrickPattern_roughness_amount
    NG_BrickPattern_specular_roughness_output
    NG_BrickPattern_uvtiling
    NG_BrickPattern_value_variation
  end
  • Example Brick shader (instance names)
graph TD;
    NG_BrickPattern_node_clamp_0[NG_BrickPattern_node_clamp_0] --> NG_BrickPattern_base_color_output([base_color_output]) --.base_color--> N_StandardSurface[N_StandardSurface]
    style NG_BrickPattern_base_color_output fill:#1b1,color:#111
    NG_BrickPattern_node_mix_8[NG_BrickPattern_node_mix_8] --.in--> NG_BrickPattern_node_clamp_0[node_clamp_0]
    NG_BrickPattern_node_multiply_5[NG_BrickPattern_node_multiply_5] --.fg--> NG_BrickPattern_node_mix_8[node_mix_8]
    NG_BrickPattern_node_mix_6[NG_BrickPattern_node_mix_6] --.in1--> NG_BrickPattern_node_multiply_5[node_multiply_5]
    NG_BrickPattern_dirt_color([dirt_color]) ==.fg==> NG_BrickPattern_node_mix_6[NG_BrickPattern/node_mix_6]
    style NG_BrickPattern_dirt_color fill:#0bb,color:#111
    NG_BrickPattern_node_hsvtorgb_17[NG_BrickPattern_node_hsvtorgb_17] --.bg--> NG_BrickPattern_node_mix_6[node_mix_6]
    NG_BrickPattern_node_add_16[NG_BrickPattern_node_add_16] --.in--> NG_BrickPattern_node_hsvtorgb_17[node_hsvtorgb_17]
    NG_BrickPattern_node_combine3_color3_13[NG_BrickPattern_node_combine3_color3_13] --.in1--> NG_BrickPattern_node_add_16[node_add_16]
    NG_BrickPattern_node_multiply_14[NG_BrickPattern_node_multiply_14] --.in1--> NG_BrickPattern_node_combine3_color3_13[node_combine3_color3_13]
    NG_BrickPattern_hue_variation([hue_variation]) ==.in2==> NG_BrickPattern_node_multiply_14[NG_BrickPattern/node_multiply_14]
    style NG_BrickPattern_hue_variation fill:#0bb,color:#111
    NG_BrickPattern_node_subtract_18[NG_BrickPattern_node_subtract_18] --.in1--> NG_BrickPattern_node_multiply_14[node_multiply_14]
    NG_BrickPattern_node_add_19[NG_BrickPattern_node_add_19] --.in1--> NG_BrickPattern_node_subtract_18[node_subtract_18]
    NG_BrickPattern_node_multiply_25[NG_BrickPattern_node_multiply_25] --.in1--> NG_BrickPattern_node_add_19[node_add_19]
    NG_BrickPattern_hue_variation([hue_variation]) ==.in1==> NG_BrickPattern_node_multiply_25[NG_BrickPattern/node_multiply_25]
    style NG_BrickPattern_hue_variation fill:#0bb,color:#111
    NG_BrickPattern_node_tiledimage_float_26[NG_BrickPattern_node_tiledimage_float_26] --.in2--> NG_BrickPattern_node_multiply_25[node_multiply_25]
    NG_BrickPattern_node_convert_1[NG_BrickPattern_node_convert_1] --.uvtiling--> NG_BrickPattern_node_tiledimage_float_26[node_tiledimage_float_26]
    NG_BrickPattern_uvtiling([uvtiling]) ==.in==> NG_BrickPattern_node_convert_1[NG_BrickPattern/node_convert_1]
    style NG_BrickPattern_uvtiling fill:#0bb,color:#111
    NG_BrickPattern_node_tiledimage_float_7[NG_BrickPattern_node_tiledimage_float_7] --.in2--> NG_BrickPattern_node_add_19[node_add_19]
    NG_BrickPattern_node_convert_1[NG_BrickPattern_node_convert_1] --.uvtiling--> NG_BrickPattern_node_tiledimage_float_7[node_tiledimage_float_7]
    NG_BrickPattern_node_multiply_15[NG_BrickPattern_node_multiply_15] --.in3--> NG_BrickPattern_node_combine3_color3_13[node_combine3_color3_13]
    NG_BrickPattern_node_add_19[NG_BrickPattern_node_add_19] --.in1--> NG_BrickPattern_node_multiply_15[node_multiply_15]
    NG_BrickPattern_node_multiply_20[NG_BrickPattern_node_multiply_20] --.in2--> NG_BrickPattern_node_multiply_15[node_multiply_15]
    NG_BrickPattern_value_variation([value_variation]) ==.in1==> NG_BrickPattern_node_multiply_20[NG_BrickPattern/node_multiply_20]
    style NG_BrickPattern_value_variation fill:#0bb,color:#111
    NG_BrickPattern_node_tiledimage_float_26[NG_BrickPattern_node_tiledimage_float_26] --.in2--> NG_BrickPattern_node_multiply_20[node_multiply_20]
    NG_BrickPattern_node_rgbtohsv_12[NG_BrickPattern_node_rgbtohsv_12] --.in2--> NG_BrickPattern_node_add_16[node_add_16]
    NG_BrickPattern_brick_color([brick_color]) ==.in==> NG_BrickPattern_node_rgbtohsv_12[NG_BrickPattern/node_rgbtohsv_12]
    style NG_BrickPattern_brick_color fill:#0bb,color:#111
    NG_BrickPattern_node_multiply_23[NG_BrickPattern_node_multiply_23] --.mix--> NG_BrickPattern_node_mix_6[node_mix_6]
    NG_BrickPattern_dirt_amount([dirt_amount]) ==.in1==> NG_BrickPattern_node_multiply_23[NG_BrickPattern/node_multiply_23]
    style NG_BrickPattern_dirt_amount fill:#0bb,color:#111
    NG_BrickPattern_node_tiledimage_float_24[NG_BrickPattern_node_tiledimage_float_24] --.in2--> NG_BrickPattern_node_multiply_23[node_multiply_23]
    NG_BrickPattern_node_convert_1[NG_BrickPattern_node_convert_1] --.uvtiling--> NG_BrickPattern_node_tiledimage_float_24[node_tiledimage_float_24]
    NG_BrickPattern_node_tiledimage_float_7[NG_BrickPattern_node_tiledimage_float_7] --.in2--> NG_BrickPattern_node_multiply_5[node_multiply_5]
    NG_BrickPattern_node_multiply_9[NG_BrickPattern_node_multiply_9] --.bg--> NG_BrickPattern_node_mix_8[node_mix_8]
    NG_BrickPattern_node_color_11[NG_BrickPattern_node_color_11] --.in1--> NG_BrickPattern_node_multiply_9[node_multiply_9]
    NG_BrickPattern_node_tiledimage_float_7[NG_BrickPattern_node_tiledimage_float_7] --.in2--> NG_BrickPattern_node_multiply_9[node_multiply_9]
    NG_BrickPattern_node_tiledimage_float_10[NG_BrickPattern_node_tiledimage_float_10] --.mix--> NG_BrickPattern_node_mix_8[node_mix_8]
    NG_BrickPattern_node_convert_1[NG_BrickPattern_node_convert_1] --.uvtiling--> NG_BrickPattern_node_tiledimage_float_10[node_tiledimage_float_10]
    NG_BrickPattern_node_multiply_1[NG_BrickPattern_node_multiply_1] --> NG_BrickPattern_specular_roughness_output([specular_roughness_output]) --.specular_roughness--> N_StandardSurface[N_StandardSurface]
    style NG_BrickPattern_specular_roughness_output fill:#1b1,color:#111
    NG_BrickPattern_node_divide_21[NG_BrickPattern_node_divide_21] --.in1--> NG_BrickPattern_node_multiply_1[node_multiply_1]
    NG_BrickPattern_roughness_amount([roughness_amount]) ==.in1==> NG_BrickPattern_node_divide_21[NG_BrickPattern/node_divide_21]
    style NG_BrickPattern_roughness_amount fill:#0bb,color:#111
    NG_BrickPattern_node_max_1[NG_BrickPattern_node_max_1] --.in2--> NG_BrickPattern_node_divide_21[node_divide_21]
    NG_BrickPattern_node_tiledimage_float_10[NG_BrickPattern_node_tiledimage_float_10] --.in1--> NG_BrickPattern_node_max_1[node_max_1]
    NG_BrickPattern_node_tiledimage_float_22[NG_BrickPattern_node_tiledimage_float_22] --.in2--> NG_BrickPattern_node_multiply_1[node_multiply_1]
    NG_BrickPattern_node_convert_1[NG_BrickPattern_node_convert_1] --.uvtiling--> NG_BrickPattern_node_tiledimage_float_22[node_tiledimage_float_22]
    NG_BrickPattern_node_normalmap_3[NG_BrickPattern_node_normalmap_3] --> NG_BrickPattern_normal_output([normal_output]) --.normal--> N_StandardSurface[N_StandardSurface]
    style NG_BrickPattern_normal_output fill:#1b1,color:#111
    NG_BrickPattern_node_tiledimage_vector3_27[NG_BrickPattern_node_tiledimage_vector3_27] --.in--> NG_BrickPattern_node_normalmap_3[node_normalmap_3]
    NG_BrickPattern_node_convert_1[NG_BrickPattern_node_convert_1] --.uvtiling--> NG_BrickPattern_node_tiledimage_vector3_27[node_tiledimage_vector3_27]
  subgraph NG_BrickPattern
    NG_BrickPattern_base_color_output
    NG_BrickPattern_brick_color
    NG_BrickPattern_dirt_amount
    NG_BrickPattern_dirt_color
    NG_BrickPattern_hue_variation
    NG_BrickPattern_node_add_16
    NG_BrickPattern_node_add_19
    NG_BrickPattern_node_clamp_0
    NG_BrickPattern_node_color_11
    NG_BrickPattern_node_combine3_color3_13
    NG_BrickPattern_node_convert_1
    NG_BrickPattern_node_divide_21
    NG_BrickPattern_node_hsvtorgb_17
    NG_BrickPattern_node_max_1
    NG_BrickPattern_node_mix_6
    NG_BrickPattern_node_mix_8
    NG_BrickPattern_node_multiply_1
    NG_BrickPattern_node_multiply_14
    NG_BrickPattern_node_multiply_15
    NG_BrickPattern_node_multiply_20
    NG_BrickPattern_node_multiply_23
    NG_BrickPattern_node_multiply_25
    NG_BrickPattern_node_multiply_5
    NG_BrickPattern_node_multiply_9
    NG_BrickPattern_node_normalmap_3
    NG_BrickPattern_node_rgbtohsv_12
    NG_BrickPattern_node_subtract_18
    NG_BrickPattern_node_tiledimage_float_10
    NG_BrickPattern_node_tiledimage_float_22
    NG_BrickPattern_node_tiledimage_float_24
    NG_BrickPattern_node_tiledimage_float_26
    NG_BrickPattern_node_tiledimage_float_7
    NG_BrickPattern_node_tiledimage_vector3_27
    NG_BrickPattern_normal_output
    NG_BrickPattern_roughness_amount
    NG_BrickPattern_specular_roughness_output
    NG_BrickPattern_uvtiling
    NG_BrickPattern_value_variation
  end
  • Example of cascading nodegraph output from 2 source materials "merge" (text copied) into same graph:
graph TD;
    upstream1_remove_red[multiply] --> upstream1_upstream1_out2([upstream1_out2]) --.base_color--> standard_surface1[standard_surface]
    style upstream1_upstream1_out2 fill:#1b1,color:#111
    upstream2_make_red[multiply] --.in1--> upstream1_remove_red[multiply]
    upstream3_upstream_image1[image] --.in1--> upstream2_make_red[multiply]
    upstream3_file1([file1]) ==.file==> upstream3_upstream_image1[image]
    style upstream3_file1 fill:#0bb,color:#111
  subgraph upstream1
    upstream1_remove_red
    upstream1_upstream1_out2
  end
  subgraph upstream2
    upstream2_make_red
  end
  subgraph upstream3
    upstream3_file1
    upstream3_upstream_image1
  end

    upstream1_make_yellow[multiply] --> upstream1_upstream1_out1([upstream1_out1]) --.base_color--> standard_surface[standard_surface]
    style upstream1_upstream1_out1 fill:#1b1,color:#111
    upstream2_multiply_by_image[multiply] --.in1--> upstream1_make_yellow[multiply]
    upstream3_upstream_image[image] --.in1--> upstream2_multiply_by_image[multiply]
    upstream3_file([file]) ==.file==> upstream3_upstream_image[image]
    style upstream3_file fill:#0bb,color:#111
    upstream2_image[image] --.in2--> upstream2_multiply_by_image[multiply]
  subgraph upstream1
    upstream1_make_yellow
    upstream1_upstream1_out1
  end
  subgraph upstream2
    upstream2_image
    upstream2_multiply_by_image
  end
  subgraph upstream3
    upstream3_file
    upstream3_upstream_image
  end
  • Same graphs with instance instead of category names:
graph TD;
    upstream1_remove_red[upstream1_remove_red] --> upstream1_upstream1_out2([upstream1_out2]) --.base_color--> standard_surface1[standard_surface1]
    style upstream1_upstream1_out2 fill:#1b1,color:#111
    upstream2_make_red[upstream2_make_red] --.in1--> upstream1_remove_red[remove_red]
    upstream3_upstream_image1[upstream3_upstream_image1] --.in1--> upstream2_make_red[make_red]
    upstream3_file1([file1]) ==.file==> upstream3_upstream_image1[upstream3/upstream_image1]
    style upstream3_file1 fill:#0bb,color:#111
  subgraph upstream1
    upstream1_remove_red
    upstream1_upstream1_out2
  end
  subgraph upstream2
    upstream2_make_red
  end
  subgraph upstream3
    upstream3_file1
    upstream3_upstream_image1
  end

    upstream1_make_yellow[upstream1_make_yellow] --> upstream1_upstream1_out1([upstream1_out1]) --.base_color--> standard_surface[standard_surface]
    style upstream1_upstream1_out1 fill:#1b1,color:#111
    upstream2_multiply_by_image[upstream2_multiply_by_image] --.in1--> upstream1_make_yellow[make_yellow]
    upstream3_upstream_image[upstream3_upstream_image] --.in1--> upstream2_multiply_by_image[multiply_by_image]
    upstream3_file([file]) ==.file==> upstream3_upstream_image[upstream3/upstream_image]
    style upstream3_file fill:#0bb,color:#111
    upstream2_image[upstream2_image] --.in2--> upstream2_multiply_by_image[multiply_by_image]
  subgraph upstream1
    upstream1_make_yellow
    upstream1_upstream1_out1
  end
  subgraph upstream2
    upstream2_image
    upstream2_multiply_by_image
  end
  subgraph upstream3
    upstream3_file
    upstream3_upstream_image
  end
  • Conditional node test. Note TBD if this should be an option as it
    is not cheap to find the corresponding NodeDef for a Node.
graph TD; 
  subgraph ifgreater_float
    ifgreater_float_ifgreater1
    ifgreater_float_out
  end
    ifgreater_float_ifgreater1{ifgreater} --> ifgreater_float_out([output])
    style ifgreater_float_out fill:#1b1, color:#111

WIP Connectivity Proposal

Node and Nodegraph Connectivity

PDF version

Introduction

This is a proposal to update the way that connections are
specified in MaterialX. To understand the proposal basic
background is provided first.

Background: Node Connection Combinations

  • A node can be connected to any other node with a nodegraph (node container)
  • If you consider a document to also be a node container then nodes can reside a the "top level" of a document as well.
  • Any output of a node can be connected to the input of a node or nodegraph if they are of the same type.
  • Any output of a nodegraph can be connected the input of a node or nodegraph if the inputs are of the same type.

*Note(): It is not valid to have both a value and a connection specified.

Examples

graph TD;
    node0-->node1;
    subgraph NodeGraph
    NodeGraph/node0-->NodeGraph/node1;
    end
    nodeGraph1-->node2;
    node3-->nodegraph2
    nodeGraph3-->nodeGraph4

Background: Nodegraph Input / Output Variations

  • A <nodegraph> can contain a set of nodes.
  • Though it is possible have no inputs nor outputs this would be of no practical use.
  • Any unconnected input on a nodegraph node can be connected to a nodegraph's input.
    This is currently via a interfacename reference on the node's input.
  • An output of a nodegraph node can can be connnected to a nodegraph <output>.
  • The unique interface "signature" of a nodegraph is defined by it's inputs and outputs.

Examples of Valid Configurations:

No inputs / Single output

graph LR;
    subgraph NG1
    NG1/node1-->NG1/output1
    end
    NG1/output1-->bxdf1

Single input / multiple outputs

graph LR;
    subgraph NG1
    NG1/node1-->NG1/output1
    NG1/node1-->NG1/output2
    end
    NG1/output1-->bxdf3
    NG1/output2-->bxdf3

Single input / single output

graph LR;
    subgraph NG1
    NG1/input1-->NG1/node1
    NG1/node1-->NG1/output1
    end
    NG1/output1-->bxdf1

Multiple inputs / single output

graph LR;
    subgraph NG1
    NG1/input1-->NG1/node1
    NG1/input2-->NG1/node1
    NG1/node1-->NG1/output1
    end
    NG1/output1-->bxdf1

Multiple inputs / multiple outputs

graph LR;
    subgraph NG1
    NG1/input1-->NG1/node1
    NG1/node1-->NG1/output1
    NG1/input2-->NG1/node1
    NG1/node1-->NG1/output2    
    end
    NG1/output1-->bxdf1
    NG1/output2-->bxdf3

Invalid Configurations

  • It is not allowed to connect an output of a node or nodegraph directly to an input of a node within a nodegraph. Similarly,
  • it is not allowed to connect input of a node inside a nodegraph directory to the output of another node or nodegraph outside the node's nodegraph
graph LR;
    nodeBad1-->NG1/node1
    subgraph NG1
    NG1/node1
    end
    NG1/node1-->badNode2
graph LR;
    subgraph NG1
    NG1/node1
    end
    subgraph NG0
    NG0/node1-->NG1/node1
    end
    subgraph NG2
    NG1/node1-->NG2/node1
    end

Proposed Changes

Connection Syntax

Currently connections are specified on an input using addition attributes:

  • node if connected to an upstream node output
  • nodegraph if connected to an upstream nodegraph output
  • interfacename if connected to the input interface of a nodegraph.
  • output This must be specified if the upstream node has one or more outputs to avoid ambiguity.
  • channel Based on the current 1.39 proposal a numeric channel can be specified for an given upstream output.

The proposal is to replace this with a MaterialX path and a single attribute name to representation a connection:

  • The attributes:node, nodegraph, interfacename and channel will be replaced with a single string attribute named connection.
    • The assigned value will be a MaterialX path which has been extended to support input interface and channel notation.
  • Paths are specified relative to the current scope. This could be within a nodegraph or directly under the root document.
  • Thus absolute paths are considered invalid. Syntactically a path starting with a / is not valid.
  • It is still possible to specify only the path to a upstream node without explicitly specifying it's output if and only if the node only has one output.
    • Otherwise the reference is considered to be ambiguous.
    • A fallback logic of using the first output can still be supported. )
  • Inputs which reference an interface input using interfacename will use a path notation of this form: .<input name>.
    • Note that this means that nodegraph inputs can be connected to node inputs. This makes it orthogonal to how node outputs can be connected to nodegraph outputs. These type of connections are still considered to be invalid if specified outside a nodegraph.
  • The 1.39 channel attribute (and the existing channels attribute are represented as part of the path notation using an array notation: [#]. # is the channel number 0..N. Where N+1 is the number of channels.
  • <namespace> can still be supported as part of the path name (as it currently is now). That is it is still allowed to connected between namespaces.

Connections Using A Common Parent

The following are some examples of connections where the connections occur within the parent.

  • Connection from node1 in the same parent:
   <input name="in1" type="color3" connection="node1" />
   <!-- or -->
   <input name="in1" type="color3" connection="node1.out" />
  • Connection from channel "1" on node1 in the same parent:
   <input name="in1" type="float" connection="node1.out[1]" />
  • Connection from the interface input "albedo" inside a nodegraph:
   <input name="in1" type="color3" connection=".albedo" />
  • Connection from channel "0" of the interface input "albedo" inside a nodegraph:
   <input name="in1" type="float" connection=".albedo[0]" />
  • Connection from node2 to the output interface "result" inside a nodegraph:
   <output name="result" type="color4" connection="node2" />
   <!-- or -->
   <output name="result" type="color4" connection="node2.out" />
  • Connection from channel "3" of node2 to the output interface "resultAlpha" inside a nodegraph:
   <output name="resultAlpha" type="float" connection="node2.out[3]" />

Connections Between Nodes and Nodegraphs

This example shows:

  • nodegraph N2's interface input is connected to an upstream nodegraph N1
  • nodegraph N2's multiply node input being connected to N2's interface input.
  • N1's output being connected to N1's add node's output
  • N2's output being connected to N2's multiply nod's output
  • node multiply_by_2's input being connected to upstream node N2's output
<nodegraph name="N1">
  <add name="add_color" type="color3">
    <input name="in1" type="color3" value="0.1, 0.1, 0.1" />
    <input name="in2" type="color3" value="0.3, 0.4, 0.5" />
  </add>
  <output name="outA" type="color3" connection="add_color" />
</nodegraph>

<nodegraph name="N2">
  <input name="in_color" connection="N1/outA" />
  <multiply name="multiply_color" type="color3">
    <input name="in1" type="color3" connection=".in_color" />
    <input name="in2" type="color3" value="0.5, 0.5, 0.5" />
  </multiply>
  <output name="out_color" type="color3" connection="multiply_color" />
</nodegraph>

<multiply name="multiply_by_2" type="color3">
  <input name="in1" type="color3" connection="N2/out_color" />
  <input name="in2" type="color3" value="2.0, 2.0, 2.0" />
</multiply>
graph TD;
    subgraph N1
    N1/add_color --connection=add_color--> N1/outA
    style N1/outA fill:#bfb,color:#000
    end
    subgraph N2
    N1/outA --connection=N1/outA --> N2/in_color
    N2/in_color --connection=.in_color--> N2/multiply_color.in1 
    style N2/in_color fill:#bfb,color:#000
    N2/multiply_color.in1 -.- N2/multiply_color
    style N2/multiply_color.in1 fill:#bfb,color:#000
    N2/multiply_color --connection=multiply_color--> N2/output_color
    style N2/output_color fill:#bfb,color:#000
    end
    N2/output_color --connection=N2/out_color--> multiply_by_2.in1
    style multiply_by_2.in1 fill:#bfb,color:#000

Restrictions

  • Changing scope using something like "../" is not allowed. That is it is not permitted to specify connection to an upstream input or output which is not under the same parent.

Notes

  • It is assumed that connection path parsing will occur during document input and output conversion from / to a document.
  • This scheme will work with nested nodegraphs assuming that the same connection rules are maintained.

WIP Shader Graph Introspection

MaterialX Graph Handling

Introduction

A shader graph is composed of various combinations of <nodes> and <nodegraphs> elements which can be connected together via child <inputs> and <outputs>.

This document first provides some background on the composition and semantics for shader graphs and then discuss usage in some user scenarios.

Basic Components

  • A <node> is atomic and is not represented by other nodes. Each node has a unique name. A valid contains only alphanumeric characters and cannot
    contain a path separator: /.
graph TD
    node1
    node2
    node3
  • Both <nodegraph>'s and documents are categorized as a graph elements.
    • Nodegraphs can contain 0 or more nodes or nodegraphs and 0 or more direct child <input>s or <output>s.
  • Nodes within a nodegraph or document are considered to be within the "scope" of the graph element. Nodegraph inputs and outputs are in the same scope as direct child nodes.
graph TD
   subgraph my_nodegraph
      input1(input)
      style input1 fill:#1b1,color:#fff 
      input2(input1) 
      style input2 fill:#1b1,color:#fff 
      output1(output1) 
      style output1 fill:#0bb,color:#fff
      node1 
      node2
  end
  • Though a document is considered to be a graph element direct child <input>s and <output>s are not allowed. A document node graph where no data flows in or out. At this time, documents cannot contain or
    reference other documents as children.
graph TD
   subgraph document
      my_node 
      my_nodegraph      
  end
  • <input>s and <output>s on <node>s or <nodegraph>s define what is connectable. There can be 0 or more inputs and 1 or more outputs on a node or nodegraph.
    • Having no outputs is "allowed" but these nodes /nodgraphs are generally of no use as there is no starting point / root for evaluation.
classDiagram
class node {
    +string name
    +float in1
    +color3 in2
    +color3 out1 
    +int out2
}
class nodegraph {
    +string name
    +float in1
    +color3 in2
    +color3 out1 
    +int out2
}

Connectivity

  • For subsequent diagrams the connections are shown with an
    upstream element connected to a downstream element by an arrow.
  • The child element of the downstream element is shown if required to
    avoid ambiguity.
  • Elements may be <input>s or <output>s depending on specification
    rules.

Rules

  1. Shader graphs are directed acyclic graphs.
  2. A <node> or <nodegraph> <output> may be connected one or more <input> on another node or nodegraph <input> within the same scope.
graph TB
    node2 --> node0.input1
    node2 --> nodegraph1.input2
    subgraph nodegraph3;
    nodegraph3.output1
    end
    nodegraph3.output1 --> node0.input2
    nodegraph3.output1 --> nodegraph1.input1
    subgraph node0;
    node0.output1
    node0.input2
    node0.input1
    end
    subgraph nodegraph1;
    nodegraph1.input1
    nodegraph1.input2
    nodegraph1.output1 
    end
    node1
    node0.output1 --.input1--> node1
    nodegraph1.output1 --.input2--> node1
  1. A <nodegraph> <input> may be connected to one or more interior node's <input> within the same scope.
graph TB
    subgraph nodegraph1
        .input1 --> node1.input1
        .input1 --> node2.input2
        .input2 --> node2.input1
        style .input1 fill:#1b1,color:#fff 
        style .input2 fill:#1b1,color:#fff 
    end
  1. An interior node's <output>s may be connected to one or more nodegraph outputs within the same scope.
graph TB
    subgraph nodegraph1
        node1.input1 --> .output1 
        node1.input1 --> .output2
        node1.input2 --> .output3
        style .output1 fill:#0bb,color:#fff
        style .output2 fill:#0bb,color:#fff
        style .output3 fill:#0bb,color:#fff
    end

Interface Building / Publishing Interfaces

The act of adding or removing nodegraph inputs and outputs can be thought of as publishing the public interface for the graph.

A node should never have inputs / outputs added or removed which are not part of their definition -- in fact this will be tagged a node instance which has no matching definition if a validation check is performed.

Compound and Functional Nodegraphs and "Flattening" and "Publishing"

If node is implemented by a nodegraph, then the nodegraph is called a functional nodegraph. Otherwise it is called a compound nodegraph.

Thus a more complete definition of a shader graph is that:

  1. It is composed of a series of connected nodes and compound nodegraphs.
  2. One or more of these nodes may be implemented as functional graphs.
  3. If the node instance is replaced with the functional graph implementation then the node essentially "becomes" a compound graph. This operation is called flattening a node instance.
  4. If all nodes are taken out of the scope of their parent nodegraphs then all that is left is a series of connected nodes. This operation is is called flattening a nodegraph.
  5. The reverse operation to add nodes to nodegraphs allows users to logically group nodes and/or publisih it's public interface.
    If a new definition <nodedef> is created and the nodegraph becomes a functional graph then can be thought of as publishing a new definition.

Flattening Example

graph LR
  subgraph document
    subgraph nodegraph1
        nodegraph1.input1 --> nodegraph1/node1.input1
        nodegraph1.input1 --> nodegraph1/node2.input2
        nodegraph1.input2 --> nodegraph1/node2.input1
        subgraph node1;
            nodegraph1/node1.input1
            nodegraph1/node1.input2
        end
        subgraph node2;
            nodegraph1/node2.input2
            nodegraph1/node2.input1
        end
        nodegraph1/node1.input1 --> nodegraph1/operator 
        nodegraph1/node1.input1 --> nodegraph1/operator 
        nodegraph1/operator --> nodegraph1.output2
        nodegraph1/node1.input2 --> nodegraph1/operator2
        nodegraph1/operator2 --> nodegraph1.output3
        nodegraph1/node2.input2 --> nodegraph1/operator2 
        nodegraph1/node2.input1 --> nodegraph1/operator2
        nodegraph1/node2.input1 -.-> nodegraph1/dot((dot)) -.-> nodegraph1.output1

        style nodegraph1.input1 fill:#1b1,color:#fff 
        style nodegraph1.input2 fill:#1b1,color:#fff 
        style nodegraph1.output1 fill:#0bb,color:#fff
        style nodegraph1.output2 fill:#0bb,color:#fff
        style nodegraph1.output3 fill:#0bb,color:#fff
    end
  end

if flattened would look something like this if the parent of the nodegraph was a document. The interface <input> and <output> elements are not present as this is disallowed within the document scope.

graph 
  subgraph document
    node1.input1 --> operator
    node1.input1 --> operator 
    node1.input2 --> operator2
    node2.input2 --> operator2 
    node2.input1 --> operator2
    node2.input1 -.-> dot((dot))
  end

The reverse process could create a nodegraph, with inputs and outputs added to create the public interface for the nodegraph.

Shader Generation Graphs

When dealing with shader generation shader graphs are simplified to having only nodes with inputs and outputs "ports".

The key components are:

  • Shader Node: Basically corresponds to a node.
  • Shader Port: A connectable attribute of a Shader Node. Can either be Input or Output Ports.
  • Public Ports: Are bindable as shader code inputs or exposed as the root for evaluation as an output.
  • Private Ports: Inputs and Outputs which are not exposed.

All original nodes are flattened to remove the notion of a graph hierarchy
and replace any nodes which are represented as functional graphs.

Upstream Traversal

Upstream traversal is fairly simple where the root to start from should be an <output> on a node or nodegraph. Traversal will naturally only follow direct connections.

This is straightforward when:

  1. There are no nodegraphs within the shader graph.
  2. Or all of the nodes reside within a single nodegraph.

In this case only node inputs connect to upstream outputs.

Examples

Interior of nodegraph to upstream nodegraphs and nodes

graph TD;
  subgraph Document;
  subgraph surf_graph_graph; 
    surf_graph_graph_default_shader[surf_graph_graph/default_shader] --> surf_graph_graph_surf_graph_graph_out[surf_graph_graph/surf_graph_graph_out]
    style surf_graph_graph_surf_graph_graph_out fill:#1b1,color:#fff
    surf_graph_graph_input([surf_graph_graph/input]) ==.base_color==> surf_graph_graph_default_shader[surf_graph_graph/default_shader]
    style surf_graph_graph_input fill:#0bb,color:#fff
    graph_graph_multiply[graph_graph/multiply] --.base_color--> surf_graph_graph_default_shader[surf_graph_graph/default_shader]
    graph_graph_input([graph_graph/input]) ==.in1==> graph_graph_multiply[graph_graph/multiply]
    style graph_graph_input fill:#0bb,color:#fff
    upstream_graph_image[upstream_graph/image] --.in1--> graph_graph_multiply[graph_graph/multiply]
    upstream_graph_file([upstream_graph/file]) ==.file==> upstream_graph_image[upstream_graph/image]
    style upstream_graph_file fill:#0bb,color:#fff
  subgraph graph_graph;
    graph_graph_multiply
    graph_graph_input
  end
  subgraph upstream_graph;
    upstream_graph_image
    upstream_graph_file
  end
  end
  end

Cascading nodegraph to nodegraph

graph TD;
  subgraph DocumentRoot; 
    standard_surface[standard_surface] --.surfaceshader--> surfacematerial[surfacematerial]
    upstream1_make_yellow[upstream1/make_yellow] --.base_color--> standard_surface[standard_surface]
    upstream1_upstream1_in1([upstream1/upstream1_in1]) ==.in1==> upstream1_make_yellow[upstream1/make_yellow]
    style upstream1_upstream1_in1 fill:#0bb,color:#111
    upstream2_multiply_by_image[upstream2/multiply_by_image] --.in1--> upstream1_make_yellow[upstream1/make_yellow]
    upstream2_upstream2_in1([upstream2/upstream2_in1]) ==.in1==> upstream2_multiply_by_image[upstream2/multiply_by_image]
    style upstream2_upstream2_in1 fill:#0bb,color:#111
    upstream3_upstream_image[upstream3/upstream_image] --.in1--> upstream2_multiply_by_image[upstream2/multiply_by_image]
    upstream3_file([upstream3/file]) ==.file==> upstream3_upstream_image[upstream3/upstream_image]
    style upstream3_file fill:#0bb,color:#111
    upstream2_image[upstream2/image] --.in2--> upstream2_multiply_by_image[upstream2/multiply_by_image]
  end

Sample AMD material

graph BT;
  subgraph DocumentRoot; 
    SR_MaterialX_Graph[SR_MaterialX_Graph] --.surfaceshader--> MaterialX_Graph[MaterialX_Graph]
    NG_MaterialX_Graph_node_image_color3_2[NG_MaterialX_Graph/node_image_color3_2] --.base_color--> SR_MaterialX_Graph[SR_MaterialX_Graph]
    NG_MaterialX_Graph_node_multiply_9[NG_MaterialX_Graph/node_multiply_9] --.texcoord--> NG_MaterialX_Graph_node_image_color3_2[NG_MaterialX_Graph/node_image_color3_2]
    NG_MaterialX_Graph_node_texcoord_vector2_8[NG_MaterialX_Graph/node_texcoord_vector2_8] --.in1--> NG_MaterialX_Graph_node_multiply_9[NG_MaterialX_Graph/node_multiply_9]
    NG_MaterialX_Graph_node_float_1[NG_MaterialX_Graph/node_float_1] --.in2--> NG_MaterialX_Graph_node_multiply_9[NG_MaterialX_Graph/node_multiply_9]
    NG_MaterialX_Graph_node_mix_3[NG_MaterialX_Graph/node_mix_3] --.specular_roughness--> SR_MaterialX_Graph[SR_MaterialX_Graph]
    NG_MaterialX_Graph_node_float_7[NG_MaterialX_Graph/node_float_7] --.fg--> NG_MaterialX_Graph_node_mix_3[NG_MaterialX_Graph/node_mix_3]
    NG_MaterialX_Graph_node_float_0[NG_MaterialX_Graph/node_float_0] --.bg--> NG_MaterialX_Graph_node_mix_3[NG_MaterialX_Graph/node_mix_3]
    NG_MaterialX_Graph_node_extract_11[NG_MaterialX_Graph/node_extract_11] --.mix--> NG_MaterialX_Graph_node_mix_3[NG_MaterialX_Graph/node_mix_3]
    NG_MaterialX_Graph_node_image_vector3_12[NG_MaterialX_Graph/node_image_vector3_12] --.in--> NG_MaterialX_Graph_node_extract_11[NG_MaterialX_Graph/node_extract_11]
    NG_MaterialX_Graph_node_multiply_9[NG_MaterialX_Graph/node_multiply_9] --.texcoord--> NG_MaterialX_Graph_node_image_vector3_12[NG_MaterialX_Graph/node_image_vector3_12]
    NG_MaterialX_Graph_onthefly_4[NG_MaterialX_Graph/onthefly_4] --.coat_normal--> SR_MaterialX_Graph[SR_MaterialX_Graph]
    NG_MaterialX_Graph_node_normalmap[NG_MaterialX_Graph/node_normalmap] --.normal--> SR_MaterialX_Graph[SR_MaterialX_Graph]
    NG_MaterialX_Graph_node_image_vector3_10[NG_MaterialX_Graph/node_image_vector3_10] --.in--> NG_MaterialX_Graph_node_normalmap[NG_MaterialX_Graph/node_normalmap]
    NG_MaterialX_Graph_node_multiply_9[NG_MaterialX_Graph/node_multiply_9] --.texcoord--> NG_MaterialX_Graph_node_image_vector3_10[NG_MaterialX_Graph/node_image_vector3_10]
    NG_MaterialX_Graph_onthefly_6[NG_MaterialX_Graph/onthefly_6] --.tangent--> SR_MaterialX_Graph[SR_MaterialX_Graph]
  end

Workflows

  • Logically a both a Document and a NodeGraph are considered to be containers of nodes or a "node graph".
  • However a Node which may have an implementation as a graph is not considered to be a container. This means
    traversal up and downstream from a given node requires special casing.
  • Another issue is that in order to keep a minimal size, only those inputs and which are explicit connected to or
    assigned non-default values will exist on the instance of a Node or Nodegraph, even though they are part of the
    interface definition.
  • Any connections which within Nodegraphs which connect interior Node inputs to Nodegraph inputs also currently have
    special syntax.
  • All connections are specified on a downstream input instead of as a structure which provides both the input and output. This makes downstream traversal much less straightforward to perform than upstream.
  • Materials as of 1.38 are nodes and traversal can find upstream shaders to allow a full material graph to be traversed.

Recommendations

  • In order to create a "complete" graph, when instances are created all inputs and outputs should be instantiated. This can be done via utilities which scan the associated NodeDef (definition) and add inputs and outputs with default values.
  • An NodeGraph itself should have all of it's inputs specified even if it's a functional graph for the same reason.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.