diff --git a/example/dev/devSRGB.json b/example/dev/devSRGB.json new file mode 100644 index 0000000..855a6ec --- /dev/null +++ b/example/dev/devSRGB.json @@ -0,0 +1,1349 @@ +{ + "id": "", + "nodes": { + "1403": { + "id": 1403, + "data": { + "vertValue": 0, + "vertValueType": "vertex", + "expanded": true + }, + "inputs": { + "vert": { + "connections": [ + { + "node": 1404, + "output": "vert", + "data": { + "fixed": true + } + } + ] + } + }, + "outputs": {}, + "blocks": [ + { + "id": 1407, + "data": { + "baseColorValue": [ + 0, + 0, + 0 + ], + "baseColorValueType": "vec3", + "expanded": true, + "baseColorValueUsage": "color" + }, + "inputs": { + "baseColor": { + "connections": [] + } + }, + "outputs": {}, + "blocks": [], + "position": [ + 0, + 0 + ], + "name": "BaseColorBlock", + "contextId": 1403 + } + ], + "position": [ + 484.3908264807476, + 1004.4686476670662 + ], + "name": "Fragment" + }, + "1404": { + "id": 1404, + "data": { + "vertValue": 0, + "vertValueType": "vertex", + "expanded": true + }, + "inputs": {}, + "outputs": { + "vert": { + "connections": [ + { + "node": 1403, + "input": "vert", + "data": { + "fixed": true + } + } + ] + } + }, + "blocks": [ + { + "id": 1405, + "data": { + "positionValue": [ + 0, + 0, + 0 + ], + "positionValueType": "vec3", + "expanded": true + }, + "inputs": { + "position": { + "connections": [] + } + }, + "outputs": {}, + "blocks": [], + "position": [ + 0, + 0 + ], + "name": "PositionBlock", + "contextId": 1404 + }, + { + "id": 1406, + "data": { + "normalValue": [ + 0, + 0, + 0 + ], + "normalValueType": "vec3", + "expanded": true + }, + "inputs": { + "normal": { + "connections": [] + } + }, + "outputs": {}, + "blocks": [], + "position": [ + 0, + 0 + ], + "name": "NormalBlock", + "contextId": 1404 + } + ], + "position": [ + 484.3908264807476, + 804.4686476670662 + ], + "name": "Vertex" + }, + "1408": { + "id": 1408, + "data": { + "outValue": [ + 0.07058823529411765, + 0.20392156862745098, + 0.33725490196078434 + ], + "outValueType": "vec3", + "outValueUsage": "color", + "expanded": true + }, + "inputs": {}, + "outputs": { + "out": { + "connections": [ + { + "node": 1409, + "input": "in", + "data": {} + } + ] + } + }, + "blocks": [], + "position": [ + -1452.7479819543387, + 250.04983913554486 + ], + "name": "Color" + }, + "1409": { + "id": 1409, + "data": { + "inValue": [ + 0, + 0, + 0 + ], + "inValueType": "vec3", + "outValue": [ + 0, + 0, + 0 + ], + "outValueType": "vec3", + "expanded": true, + "preview": true + }, + "inputs": { + "in": { + "connections": [ + { + "node": 1408, + "output": "out", + "data": {} + } + ] + } + }, + "outputs": { + "out": { + "connections": [ + { + "node": 1419, + "input": "in", + "data": {} + }, + { + "node": 1478, + "input": "a", + "data": {} + } + ] + } + }, + "blocks": [], + "position": [ + -1227.8391689759542, + 248.89623530723816 + ], + "name": "Preview" + }, + "1419": { + "id": 1419, + "data": { + "inValue": [ + 0, + 0, + 0 + ], + "inValueType": "vec3", + "outValue": [ + 0, + 0, + 0 + ], + "outValueType": "vec3", + "fromValue": "sRGB", + "fromValueType": "string", + "toValue": "Linear", + "toValueType": "string", + "expanded": true, + "preview": true + }, + "inputs": { + "in": { + "connections": [ + { + "node": 1409, + "output": "out", + "data": {} + } + ] + } + }, + "outputs": { + "out": { + "connections": [ + { + "node": 1440, + "input": "a", + "data": {} + } + ] + } + }, + "blocks": [], + "position": [ + -916.062807280652, + 237.67277508247582 + ], + "name": "ColorSpaceConversion" + }, + "1440": { + "id": 1440, + "data": { + "aValue": [ + 0, + 0, + 0 + ], + "aValueType": "vec3", + "bValue": [ + 0, + 0, + 0 + ], + "bValueType": "vec3", + "outValue": [ + 0, + 0, + 0 + ], + "outValueType": "vec3", + "expanded": true, + "preview": true + }, + "inputs": { + "a": { + "connections": [ + { + "node": 1419, + "output": "out", + "data": {} + } + ] + }, + "b": { + "connections": [ + { + "node": 1459, + "output": "out", + "data": {} + } + ] + } + }, + "outputs": { + "out": { + "connections": [ + { + "node": 1527, + "input": "in", + "data": {} + } + ] + } + }, + "blocks": [], + "position": [ + -490.00742884249996, + 256.9153421959767 + ], + "name": "Add" + }, + "1459": { + "id": 1459, + "data": { + "xValue": "0.1", + "xValueType": "float", + "outValue": 0, + "outValueType": "float", + "expanded": true + }, + "inputs": { + "x": { + "connections": [] + } + }, + "outputs": { + "out": { + "connections": [ + { + "node": 1440, + "input": "b", + "data": {} + }, + { + "node": 1478, + "input": "b", + "data": {} + } + ] + } + }, + "blocks": [], + "position": [ + -850.1147992728971, + 588.7708758735437 + ], + "name": "Float" + }, + "1478": { + "id": 1478, + "data": { + "aValue": [ + 0, + 0, + 0 + ], + "aValueType": "vec3", + "bValue": [ + 0, + 0, + 0 + ], + "bValueType": "vec3", + "outValue": [ + 0, + 0, + 0 + ], + "outValueType": "vec3", + "expanded": true, + "preview": true + }, + "inputs": { + "a": { + "connections": [ + { + "node": 1409, + "output": "out", + "data": {} + } + ] + }, + "b": { + "connections": [ + { + "node": 1459, + "output": "out", + "data": {} + } + ] + } + }, + "outputs": { + "out": { + "connections": [] + } + }, + "blocks": [], + "position": [ + -490.4852277266939, + 604.0584975076154 + ], + "name": "Add" + }, + "1527": { + "id": 1527, + "data": { + "inValue": [ + 0, + 0, + 0 + ], + "inValueType": "vec3", + "outValue": [ + 0, + 0, + 0 + ], + "outValueType": "vec3", + "fromValue": "Linear", + "fromValueType": "string", + "toValue": "sRGB", + "toValueType": "string", + "expanded": true, + "preview": true + }, + "inputs": { + "in": { + "connections": [ + { + "node": 1440, + "output": "out", + "data": {} + } + ] + } + }, + "outputs": { + "out": { + "connections": [] + } + }, + "blocks": [], + "position": [ + -147.51851183915318, + 271.55755435743174 + ], + "name": "ColorSpaceConversion" + }, + "1550": { + "id": 1550, + "data": { + "outValue": [ + 0.07058823529411765, + 0.20392156862745098, + 0.33725490196078434 + ], + "outValueType": "vec3", + "outValueName": "Color", + "exposed": true, + "expanded": true, + "outValueUsage": "color" + }, + "inputs": {}, + "outputs": { + "out": { + "connections": [ + { + "node": 1561, + "input": "in", + "data": {} + } + ] + } + }, + "blocks": [], + "position": [ + -1552.148770519548, + 1064.15686922814 + ], + "name": "Parameter" + }, + "1561": { + "id": 1561, + "data": { + "inValue": [ + 0, + 0, + 0 + ], + "inValueType": "vec3", + "outValue": [ + 0, + 0, + 0 + ], + "outValueType": "vec3", + "expanded": true, + "preview": true + }, + "inputs": { + "in": { + "connections": [ + { + "node": 1550, + "output": "out", + "data": {} + } + ] + } + }, + "outputs": { + "out": { + "connections": [ + { + "node": 1987, + "input": "in", + "data": {} + }, + { + "node": 1990, + "input": "a", + "data": {} + } + ] + } + }, + "blocks": [], + "position": [ + -1263.1714799682054, + 1007.4924839038126 + ], + "name": "Preview" + }, + "1987": { + "id": 1987, + "data": { + "inValue": [ + 0, + 0, + 0 + ], + "inValueType": "vec3", + "outValue": [ + 0, + 0, + 0 + ], + "outValueType": "vec3", + "fromValue": "sRGB", + "fromValueType": "string", + "toValue": "Linear", + "toValueType": "string", + "expanded": true, + "preview": true + }, + "inputs": { + "in": { + "connections": [ + { + "node": 1561, + "output": "out", + "data": {} + } + ] + } + }, + "outputs": { + "out": { + "connections": [ + { + "node": 1988, + "input": "a", + "data": {} + } + ] + } + }, + "blocks": [], + "position": [ + -928.5276749524386, + 1002.6309123766316 + ], + "name": "ColorSpaceConversion" + }, + "1988": { + "id": 1988, + "data": { + "aValue": [ + 0, + 0, + 0 + ], + "aValueType": "vec3", + "bValue": [ + 0, + 0, + 0 + ], + "bValueType": "vec3", + "outValue": [ + 0, + 0, + 0 + ], + "outValueType": "vec3", + "expanded": true, + "preview": true + }, + "inputs": { + "a": { + "connections": [ + { + "node": 1987, + "output": "out", + "data": {} + } + ] + }, + "b": { + "connections": [ + { + "node": 1989, + "output": "out", + "data": {} + } + ] + } + }, + "outputs": { + "out": { + "connections": [ + { + "node": 1991, + "input": "in", + "data": {} + } + ] + } + }, + "blocks": [], + "position": [ + -502.47229651428654, + 1021.8734794901322 + ], + "name": "Add" + }, + "1989": { + "id": 1989, + "data": { + "xValue": "0.1", + "xValueType": "float", + "outValue": 0, + "outValueType": "float", + "expanded": true + }, + "inputs": { + "x": { + "connections": [] + } + }, + "outputs": { + "out": { + "connections": [ + { + "node": 1988, + "input": "b", + "data": {} + }, + { + "node": 1990, + "input": "b", + "data": {} + } + ] + } + }, + "blocks": [], + "position": [ + -862.5796669446837, + 1353.7290131676993 + ], + "name": "Float" + }, + "1990": { + "id": 1990, + "data": { + "aValue": [ + 0, + 0, + 0 + ], + "aValueType": "vec3", + "bValue": [ + 0, + 0, + 0 + ], + "bValueType": "vec3", + "outValue": [ + 0, + 0, + 0 + ], + "outValueType": "vec3", + "expanded": true, + "preview": true + }, + "inputs": { + "a": { + "connections": [ + { + "node": 1561, + "output": "out", + "data": {} + } + ] + }, + "b": { + "connections": [ + { + "node": 1989, + "output": "out", + "data": {} + } + ] + } + }, + "outputs": { + "out": { + "connections": [] + } + }, + "blocks": [], + "position": [ + -502.95009539848047, + 1369.0166348017708 + ], + "name": "Add" + }, + "1991": { + "id": 1991, + "data": { + "inValue": [ + 0, + 0, + 0 + ], + "inValueType": "vec3", + "outValue": [ + 0, + 0, + 0 + ], + "outValueType": "vec3", + "fromValue": "Linear", + "fromValueType": "string", + "toValue": "sRGB", + "toValueType": "string", + "expanded": true, + "preview": true + }, + "inputs": { + "in": { + "connections": [ + { + "node": 1988, + "output": "out", + "data": {} + } + ] + } + }, + "outputs": { + "out": { + "connections": [] + } + }, + "blocks": [], + "position": [ + -159.98337951093976, + 1036.5156916515873 + ], + "name": "ColorSpaceConversion" + }, + "2034": { + "id": 2034, + "data": { + "rgbaValue": [ + 0, + 0, + 0, + 0 + ], + "rgbaValueType": "vec4", + "rValue": 0, + "rValueType": "float", + "gValue": 0, + "gValueType": "float", + "bValue": 0, + "bValueType": "float", + "aValue": 0, + "aValueType": "float", + "textureValueType": "texture2d", + "uvValue": "UV0", + "uvValueType": "vec2", + "typeValue": "default", + "typeValueType": "string", + "spaceValue": "tangent", + "spaceValueType": "string", + "texColorSpaceValue": "sRGB", + "texColorSpaceValueType": "string", + "expanded": true, + "preview": true, + "textureValue": { + "id": "/example/dev/gLTF/Default_albedo.jpg", + "label": "Default_albedo.jpg" + } + }, + "inputs": { + "texture": { + "connections": [] + }, + "uv": { + "connections": [] + } + }, + "outputs": { + "rgba": { + "connections": [] + }, + "r": { + "connections": [] + }, + "g": { + "connections": [] + }, + "b": { + "connections": [] + }, + "a": { + "connections": [] + } + }, + "blocks": [], + "position": [ + -795.3166942596437, + 2042.6426982879639 + ], + "name": "SampleTexture2D" + }, + "2079": { + "id": 2079, + "data": { + "rgbaValue": [ + 0, + 0, + 0, + 0 + ], + "rgbaValueType": "vec4", + "rValue": 0, + "rValueType": "float", + "gValue": 0, + "gValueType": "float", + "bValue": 0, + "bValueType": "float", + "aValue": 0, + "aValueType": "float", + "textureValueType": "texture2d", + "uvValue": "UV0", + "uvValueType": "vec2", + "typeValue": "default", + "typeValueType": "string", + "spaceValue": "tangent", + "spaceValueType": "string", + "texColorSpaceValue": "sRGB", + "texColorSpaceValueType": "string", + "expanded": true, + "preview": true, + "textureValue": { + "id": "/example/dev/gLTF/Default_AO.jpg", + "label": "Default_AO.jpg" + } + }, + "inputs": { + "texture": { + "connections": [] + }, + "uv": { + "connections": [] + } + }, + "outputs": { + "rgba": { + "connections": [] + }, + "r": { + "connections": [] + }, + "g": { + "connections": [] + }, + "b": { + "connections": [] + }, + "a": { + "connections": [] + } + }, + "blocks": [], + "position": [ + -351.635831695723, + 2050.119493723508 + ], + "name": "SampleTexture2D" + }, + "2128": { + "id": 2128, + "data": { + "rgbaValue": [ + 0, + 0, + 0, + 0 + ], + "rgbaValueType": "vec4", + "rValue": 0, + "rValueType": "float", + "gValue": 0, + "gValueType": "float", + "bValue": 0, + "bValueType": "float", + "aValue": 0, + "aValueType": "float", + "textureValueType": "texture2d", + "uvValue": "UV0", + "uvValueType": "vec2", + "typeValue": "default", + "typeValueType": "string", + "spaceValue": "tangent", + "spaceValueType": "string", + "texColorSpaceValue": "sRGB", + "texColorSpaceValueType": "string", + "expanded": true, + "preview": true, + "textureValue": { + "id": "/example/dev/gLTF/Default_metalRoughness.jpg", + "label": "Default_metalRoughness.jpg" + } + }, + "inputs": { + "texture": { + "connections": [] + }, + "uv": { + "connections": [] + } + }, + "outputs": { + "rgba": { + "connections": [] + }, + "r": { + "connections": [] + }, + "g": { + "connections": [] + }, + "b": { + "connections": [] + }, + "a": { + "connections": [] + } + }, + "blocks": [], + "position": [ + -818.8072502900317, + 2663.2661232009687 + ], + "name": "SampleTexture2D" + }, + "2181": { + "id": 2181, + "data": { + "rgbaValue": [ + 0, + 0, + 0, + 0 + ], + "rgbaValueType": "vec4", + "rValue": 0, + "rValueType": "float", + "gValue": 0, + "gValueType": "float", + "bValue": 0, + "bValueType": "float", + "aValue": 0, + "aValueType": "float", + "textureValueType": "texture2d", + "uvValue": "UV0", + "uvValueType": "vec2", + "typeValue": "default", + "typeValueType": "string", + "spaceValue": "tangent", + "spaceValueType": "string", + "texColorSpaceValue": "sRGB", + "texColorSpaceValueType": "string", + "expanded": true, + "preview": true, + "textureValue": { + "id": "/example/dev/gLTF/Default_normal.jpg", + "label": "Default_normal.jpg" + } + }, + "inputs": { + "texture": { + "connections": [] + }, + "uv": { + "connections": [] + } + }, + "outputs": { + "rgba": { + "connections": [] + }, + "r": { + "connections": [] + }, + "g": { + "connections": [] + }, + "b": { + "connections": [] + }, + "a": { + "connections": [] + } + }, + "blocks": [], + "position": [ + 148.28336014674096, + 2719.133562595263 + ], + "name": "SampleTexture2D" + }, + "2238": { + "id": 2238, + "data": { + "rgbaValue": [ + 0, + 0, + 0, + 0 + ], + "rgbaValueType": "vec4", + "rValue": 0, + "rValueType": "float", + "gValue": 0, + "gValueType": "float", + "bValue": 0, + "bValueType": "float", + "aValue": 0, + "aValueType": "float", + "textureValueType": "texture2d", + "uvValue": "UV0", + "uvValueType": "vec2", + "typeValue": "default", + "typeValueType": "string", + "spaceValue": "tangent", + "spaceValueType": "string", + "texColorSpaceValue": "sRGB", + "texColorSpaceValueType": "string", + "expanded": true, + "preview": true, + "textureValue": { + "id": "/example/dev/gLTF/Default_emissive.jpg", + "label": "Default_emissive.jpg" + } + }, + "inputs": { + "texture": { + "connections": [] + }, + "uv": { + "connections": [] + } + }, + "outputs": { + "rgba": { + "connections": [] + }, + "r": { + "connections": [] + }, + "g": { + "connections": [] + }, + "b": { + "connections": [] + }, + "a": { + "connections": [] + } + }, + "blocks": [], + "position": [ + -335.58890443705235, + 2679.8346957062886 + ], + "name": "SampleTexture2D" + }, + "2954": { + "id": 2954, + "data": { + "rgbaValue": [ + 0, + 0, + 0, + 0 + ], + "rgbaValueType": "vec4", + "rValue": 0, + "rValueType": "float", + "gValue": 0, + "gValueType": "float", + "bValue": 0, + "bValueType": "float", + "aValue": 0, + "aValueType": "float", + "textureValueType": "texture2d", + "uvValue": "UV0", + "uvValueType": "vec2", + "typeValue": "default", + "typeValueType": "string", + "spaceValue": "tangent", + "spaceValueType": "string", + "texColorSpaceValue": "Linear", + "texColorSpaceValueType": "string", + "expanded": true, + "preview": true, + "textureValue": { + "id": "/example/dev/gLTF/Default_normal.jpg", + "label": "Default_normal.jpg" + } + }, + "inputs": { + "texture": { + "connections": [] + }, + "uv": { + "connections": [] + } + }, + "outputs": { + "rgba": { + "connections": [ + { + "node": 3019, + "input": "in", + "data": {} + } + ] + }, + "r": { + "connections": [] + }, + "g": { + "connections": [] + }, + "b": { + "connections": [] + }, + "a": { + "connections": [] + } + }, + "blocks": [], + "position": [ + 156.1770155100248, + 3326.714204189191 + ], + "name": "SampleTexture2D" + }, + "3019": { + "id": 3019, + "data": { + "inValue": [ + 0, + 0, + 0 + ], + "inValueType": "vec3", + "outValue": [ + 0, + 0, + 0 + ], + "outValueType": "vec3", + "fromValue": "sRGB", + "fromValueType": "string", + "toValue": "Linear", + "toValueType": "string", + "expanded": true, + "preview": true + }, + "inputs": { + "in": { + "connections": [ + { + "node": 2954, + "output": "rgba", + "data": {} + } + ] + } + }, + "outputs": { + "out": { + "connections": [] + } + }, + "blocks": [], + "position": [ + 490.2333650552211, + 3331.0834985525976 + ], + "name": "ColorSpaceConversion" + }, + "3509": { + "id": 3509, + "data": { + "uvValue": "UV0", + "uvValueType": "vec2", + "colorAValue": [ + 0.07058823529411765, + 0.20392156862745098, + 0.33725490196078434 + ], + "colorAValueType": "vec3", + "colorAValueUsage": "color", + "colorBValue": [ + 0.6980392156862745, + 0.6980392156862745, + 0.6980392156862745 + ], + "colorBValueType": "vec3", + "colorBValueUsage": "color", + "frequencyValue": [ + 1, + 1 + ], + "frequencyValueType": "vec2", + "outValue": [ + 0, + 0, + 0 + ], + "outValueType": "vec3", + "expanded": true, + "preview": true + }, + "inputs": { + "uv": { + "connections": [] + }, + "colorA": { + "connections": [] + }, + "colorB": { + "connections": [] + }, + "frequency": { + "connections": [] + } + }, + "outputs": { + "out": { + "connections": [] + } + }, + "blocks": [], + "position": [ + -1682.0945529622738, + 1807.8321293115537 + ], + "name": "Checkerboard" + } + }, + "UIState": { + "showMainPreview": true, + "showBlackBoard": true, + "showInspector": true + }, + "type": "ShaderGraph", + "version": "", + "setting": { + "template": "unlit", + "precision": "single", + "allowMaterialOverride": false, + "surfaceType": "opaque", + "blendingMode": "alpha", + "renderFace": "front", + "depthWrite": "auto", + "depthTest": "l equal", + "alphaClipping": false, + "castShadows": true, + "clearCoat": false, + "linearColorSpace": true + }, + "parameters": [ + { + "name": "Color", + "type": "vec3", + "defalutValue": [ + 0.07058823529411765, + 0.20392156862745098, + 0.33725490196078434 + ], + "exposed": true, + "typeEdit": "color" + } + ] +} \ No newline at end of file diff --git a/example/dev/gLTF/Default_AO.jpg b/example/dev/gLTF/Default_AO.jpg new file mode 100644 index 0000000..419f628 Binary files /dev/null and b/example/dev/gLTF/Default_AO.jpg differ diff --git a/example/dev/gLTF/Default_albedo.jpg b/example/dev/gLTF/Default_albedo.jpg new file mode 100644 index 0000000..15d6485 Binary files /dev/null and b/example/dev/gLTF/Default_albedo.jpg differ diff --git a/example/dev/gLTF/Default_emissive.jpg b/example/dev/gLTF/Default_emissive.jpg new file mode 100644 index 0000000..2de59e8 Binary files /dev/null and b/example/dev/gLTF/Default_emissive.jpg differ diff --git a/example/dev/gLTF/Default_metalRoughness.jpg b/example/dev/gLTF/Default_metalRoughness.jpg new file mode 100644 index 0000000..04874cb Binary files /dev/null and b/example/dev/gLTF/Default_metalRoughness.jpg differ diff --git a/example/dev/gLTF/Default_normal.jpg b/example/dev/gLTF/Default_normal.jpg new file mode 100644 index 0000000..94ca20a Binary files /dev/null and b/example/dev/gLTF/Default_normal.jpg differ diff --git a/example/dev/gLTF/index.ts b/example/dev/gLTF/index.ts new file mode 100644 index 0000000..59e5067 --- /dev/null +++ b/example/dev/gLTF/index.ts @@ -0,0 +1,7 @@ +import Default_albedo from './Default_albedo.jpg'; +import Default_AO from './Default_AO.jpg'; +import Default_emissive from './Default_emissive.jpg'; +import Default_normal from './Default_normal.jpg'; +import Default_metalRoughness from './Default_metalRoughness.jpg'; + +export { Default_albedo, Default_AO, Default_emissive, Default_normal, Default_metalRoughness }; diff --git a/example/graph.tsx b/example/graph.tsx index a872fa6..83ce736 100644 --- a/example/graph.tsx +++ b/example/graph.tsx @@ -1,12 +1,8 @@ import { useState, useEffect, useRef, MutableRefObject } from 'react'; import AreaPlugin from 'rete-area-plugin'; -import { - ShaderGraphEditor, - AssetSimplePlugin, - setResourceAdapter, - PreviewCustomMeshPlugin, -} from '../src'; +import { ShaderGraphEditor, AssetSimplePlugin, setResourceAdapter, PreviewCustomMeshPlugin } from '../src'; import { Presets } from './presets'; +import { printCompile } from '../src/view/utils'; setResourceAdapter(asset => asset?.id); @@ -42,10 +38,7 @@ export async function createEditor(container: HTMLElement) { return editor; } -export function useRete(): [ - ReturnType>['1'], - MutableRefObject, -] { +export function useRete(): [ReturnType>['1'], MutableRefObject] { const [container, setContainer] = useState(); const editorRef = useRef(); @@ -63,20 +56,3 @@ export function useRete(): [ return [setContainer, editorRef]; } - -export async function printCompile(editor?: ShaderGraphEditor) { - if (editor) { - let vertCode = ''; - let fragCode = ''; - if (editor.editing === 'ShaderGraph') { - ({ vertCode, fragCode } = await editor.compiler.compile(editor.toJSON())); - } - if (editor.editing === 'SubGraph') { - ({ vertCode, fragCode } = await editor.compiler.compileSubGraphPreview(editor.toJSON())); - } - console.log('===== vertCode ====='); - console.log('%c' + vertCode, 'font-size: 14px'); - console.log('===== fragCode ====='); - console.log('%c' + fragCode, 'font-size: 14px'); - } -} diff --git a/example/main.tsx b/example/main.tsx index 0b467da..e1d1c02 100644 --- a/example/main.tsx +++ b/example/main.tsx @@ -1,10 +1,11 @@ import './index.css'; import { createRoot } from 'react-dom/client'; import React, { FC, MutableRefObject, useEffect, useState } from 'react'; -import { printCompile, useRete } from './graph'; +import { useRete } from './graph'; import copy from 'copy-to-clipboard'; import { Select, ShaderGraphEditor } from '../src'; import { Presets } from './presets'; +import { printCompile } from '../src/view/utils'; let toasted = false; const GraphKey = 'graph'; diff --git a/example/presets.ts b/example/presets.ts index aa44c6b..6c1b9a7 100644 --- a/example/presets.ts +++ b/example/presets.ts @@ -23,6 +23,7 @@ import devSubGraphUsage from './dev/devSubGraphUsage.json'; import devArtistic from './dev/devArtistic.json'; import devUV from './dev/devUV.json'; import devInput from './dev/devInput.json'; +import devSRGB_ from './dev/devSRGB.json'; import demoGradient from './demo/demoGradient.json'; import demoDissolve from './demo/demoDissolve.json'; import demoFresnelOutline from './demo/demoFresnelOutline.json'; @@ -33,6 +34,22 @@ import demoImageFlip from './demo/demoImageFlip.json'; import demoCartoonWater from './demo/demoCartoonWater'; import demoSkybox from './demo/demoSkybox.json'; +import * as gLTF from './dev/gLTF'; + +const replaceGLTFTex = (json: T): T => { + const data = JSON.parse(JSON.stringify(json)) as any; + const gLTFKeys = Object.keys(gLTF); + Object.values(data.nodes).forEach((node: any) => { + if (node.name === 'SampleTexture2D' && node.data.textureValue) { + const { label } = node.data.textureValue; + // @ts-ignore + node.data.textureValue.id = gLTF[gLTFKeys.find(i => label.includes(i))]; + } + }); + return data as T; +}; +const devSRGB = replaceGLTFTex(devSRGB_); + export const Presets = { devCompile, devVarying, @@ -59,6 +76,7 @@ export const Presets = { devArtistic, devUV, devInput, + devSRGB, demoGradient, demoDissolve, demoFresnelOutline, diff --git a/src/compilers/ShaderGraphCompiler.ts b/src/compilers/ShaderGraphCompiler.ts index 0b9c704..d69e903 100644 --- a/src/compilers/ShaderGraphCompiler.ts +++ b/src/compilers/ShaderGraphCompiler.ts @@ -10,6 +10,7 @@ import { OutputRC, ReteParameterNode, TransformationMatrixRC, + ColorSpaceConversionRC, } from '../components'; import { RC } from '../components/ReteComponent'; import { ShaderGraphData, SGNodeData, SGNodes, SubGraphProvider } from '../editors'; @@ -24,8 +25,9 @@ import { isMatrixType, VectorValueType, SamplerValue, + ValueUsage, } from '../types'; -import { hash, lowerCaseFirstLetter, removeWhiteSpace } from '../utils'; +import { SRGBToLinear, hash, lowerCaseFirstLetter, removeWhiteSpace } from '../utils'; import { GraphCompiler } from './GraphCompiler'; import { Context, @@ -85,12 +87,17 @@ export class ShaderGraphCompiler extends GraphCompiler { if (node.data.outValueType === ValueType.texture2d) { return this.compileValue(node.data.outValue, node.data.outValueType); } - return this.setContext( - 'uniforms', - node, - node.data.outValueName, - varName => `${varName}: ${this.getTypeClass(node.data.outValueType)}`, - ); + const uniformVar = this.setContext('uniforms', node, node.data.outValueName, varName => `${varName}: ${this.getTypeClass(node.data.outValueType)}`); + if (node.data.outValueUsage === ValueUsage.Color) { + // 目前实际输入的是sRGB, 后面再同步接入最新three的颜色空间管理 + const SRGBToLinear = ColorSpaceConversionRC.initFnContext(this, 'sRGB', 'Linear'); + const codeFn = (varName: string) => /* wgsl */ `let ${varName} = ${SRGBToLinear}(${uniformVar});`; + const fragVar = this.setContext('fragShared', node, node.data.outValueName, codeFn); + const vertVar = this.setContext('vertShared', node, node.data.outValueName, codeFn); + return this.setVarNameMap(node, node.data.outValueName, vertVar, fragVar); + } + + return uniformVar } setVarNameMap(node: NodeName, key: string, vertName: string, fragName: string, varName?: string) { @@ -119,12 +126,7 @@ export class ShaderGraphCompiler extends GraphCompiler { setContext(type: ContextKeys, node: NodeName, key: string, item: ContextItem): string; setContext(type: ContextKeys, node: NodeName, key: string, codeFn: CodeFn): string; - setContext( - type: ContextKeys, - node: NodeName, - key: string, - itemOrCode: ContextItem | CodeFn, - ): string { + setContext(type: ContextKeys, node: NodeName, key: string, itemOrCode: ContextItem | CodeFn): string { const contextKey = this.getContextKey(node, key); if (!this.context[type as ContextKeys][contextKey]) { @@ -177,11 +179,7 @@ export class ShaderGraphCompiler extends GraphCompiler { } /** 读取分量 只支持vec1234 */ - getVarChannel( - varName: string, - inType: ValueType, - channel: 'r' | 'g' | 'b' | 'a' | 'x' | 'y' | 'z' | 'w', - ) { + getVarChannel(varName: string, inType: ValueType, channel: 'r' | 'g' | 'b' | 'a' | 'x' | 'y' | 'z' | 'w') { const len = ValueComponentMap[inType]; const channelLenNeeds = ChannelLenNeedsMap[channel]; if (channelLenNeeds > len) return '0.0'; @@ -208,10 +206,7 @@ export class ShaderGraphCompiler extends GraphCompiler { if (inType === ValueType.float) return `${this.getTypeClass(outType)}(${varName})`; // 升 vec2 > vec3 vec3 > vec4 // vec2 > vec4 - if ( - (inType === ValueType.vec2 && outType === ValueType.vec3) || - (inType === ValueType.vec3 && outType === ValueType.vec4) - ) { + if ((inType === ValueType.vec2 && outType === ValueType.vec3) || (inType === ValueType.vec3 && outType === ValueType.vec4)) { return `${this.getTypeClass(outType)}(${varName}, 0)`; } else if (inType === ValueType.vec2 && outType === ValueType.vec4) { return `${this.getTypeClass(outType)}(${varName}, 0, 0)`; @@ -240,25 +235,16 @@ export class ShaderGraphCompiler extends GraphCompiler { getInputType(node: SGNodeData, inputKey: string): ValueType { const inCon = node.inputs[inputKey]?.connections[0]; - if (inCon) - return this.graphData.nodes[inCon.node].data[inCon.output + 'ValueType'] as ValueType; + if (inCon) return this.graphData.nodes[inCon.node].data[inCon.output + 'ValueType'] as ValueType; return node.data[inputKey + 'ValueType']; } getInputVarConverted(node: SGNodeData, inputKey: string): string; - getInputVarConverted( - node: SGNodeData, - inputKey: string, - fallback: false, - ): string | undefined; + getInputVarConverted(node: SGNodeData, inputKey: string, fallback: false): string | undefined; getInputVarConverted(node: SGNodeData, inputKey: string, fallback = true) { const inType = this.getInputType(node, inputKey); if (fallback) { - return this.typeConvert( - this.getInputVar(node, inputKey), - inType, - node.data[inputKey + 'ValueType'], - ); + return this.typeConvert(this.getInputVar(node, inputKey), inType, node.data[inputKey + 'ValueType']); } else { const inVar = this.getInputVar(node, inputKey, false); if (inVar) return this.typeConvert(inVar, inType, node.data[inputKey + 'ValueType']); @@ -304,7 +290,7 @@ export class ShaderGraphCompiler extends GraphCompiler { return 'sg_' + this.getContextKey(node, key); } - compileValue(value: any, type: ValueType) { + compileValue(value: any, type: ValueType, usage?: ValueUsage) { if (Number.isNaN(value) || (Array.isArray(value) && value.some(i => Number.isNaN(i)))) { console.warn(`value contains NaN`, value, type); } @@ -312,11 +298,11 @@ export class ShaderGraphCompiler extends GraphCompiler { case ValueType.float: return stringifyFloat(value); case ValueType.vec2: - return `vec2(${value[0] || 0}, ${value[1] || 0})`; + return stringifyVector(value, 2); case ValueType.vec3: - return `vec3(${value[0] || 0}, ${value[1] || 0}, ${value[2] || 0})`; + return usage === ValueUsage.Color ? stringifyVector(value.map(SRGBToLinear), 3) : stringifyVector(value, 3); case ValueType.vec4: - return `vec4(${value[0] || 0}, ${value[1] || 0}, ${value[2] || 0}, ${value[3] || 0})`; + return usage === ValueUsage.Color ? stringifyVector(value.map(SRGBToLinear), 4) : stringifyVector(value, 4); case ValueType.mat2: case ValueType.mat3: case ValueType.mat4: @@ -326,12 +312,7 @@ export class ShaderGraphCompiler extends GraphCompiler { if (!asset) return ''; const key = hash(asset.id); const node = { data: {}, name: 'Texture2D' } as any; - const outVar = this.setContext( - 'bindings', - node, - key, - (varName, i) => `@group(0) @binding(${i}) var ${varName}: texture_2d;`, - ); + const outVar = this.setContext('bindings', node, key, (varName, i) => `@group(0) @binding(${i}) var ${varName}: texture_2d;`); this.setResource('texture', node, key, value); return outVar; } @@ -339,12 +320,7 @@ export class ShaderGraphCompiler extends GraphCompiler { const sampler = (value || { filter: 'point', warp: 'clamp' }) as SamplerValue; const key = sampler.filter + '_' + sampler.warp; const node = { data: {}, name: 'Sampler' } as any; - const outVar = this.setContext( - 'bindings', - node, - key, - (varName, i) => `@group(0) @binding(${i}) var ${varName}: sampler;`, - ); + const outVar = this.setContext('bindings', node, key, (varName, i) => `@group(0) @binding(${i}) var ${varName}: sampler;`); this.setResource('sampler', node, key, sampler); return outVar; } @@ -354,7 +330,7 @@ export class ShaderGraphCompiler extends GraphCompiler { } compileNodeValue(node: SGNodeData, key: string) { - return this.compileValue(node.data[key + 'Value'], node.data[key + 'ValueType']); + return this.compileValue(node.data[key + 'Value'], node.data[key + 'ValueType'], node.data[key + 'ValueUsage']); } compileHeadCode(body: string, scope: 'vert' | 'frag') { @@ -384,9 +360,7 @@ export class ShaderGraphCompiler extends GraphCompiler { code = [ 'struct Varying {', ' @builtin(position) position: vec4,', - ...items - .filter(i => testCode.includes(i.varName.replace('v.', ''))) - .map((i, k) => ` @location(${k}) ${i.code},`), + ...items.filter(i => testCode.includes(i.varName.replace('v.', ''))).map((i, k) => ` @location(${k}) ${i.code},`), '};', ].join('\n'); } else { @@ -404,17 +378,12 @@ ${code}`; return headCode ? headCode + '\n\n' : ''; } - getLinkedVaryingNodes( - nodeId: number, - output: Array> = [], - ): Array> { + getLinkedVaryingNodes(nodeId: number, output: Array> = []): Array> { const nodeData = this.graphData.nodes[nodeId]; if (!nodeData) return []; if (nodeData.name === VaryingRC.Name) output.push(nodeData as SGNodeData); - Object.values(nodeData.inputs).forEach(i => - i.connections.forEach(con => this.getLinkedVaryingNodes(con.node, output)), - ); + Object.values(nodeData.inputs).forEach(i => i.connections.forEach(con => this.getLinkedVaryingNodes(con.node, output))); return output; } @@ -449,10 +418,7 @@ ${code}`; doVarMap(body: string, scope: 'vert' | 'frag') { return Object.values(this.varNameMap).reduce((body, map) => { - return body.replace( - new RegExp(`(${map.varName})`, 'g'), - scope === 'frag' ? map.fragName : map.vertName, - ); + return body.replace(new RegExp(`(${map.varName})`, 'g'), scope === 'frag' ? map.fragName : map.vertName); }, body); } @@ -516,31 +482,21 @@ ${code}`; // if (!vert) throw new Error('missing Vertex Context'); const varyingNodes = this.getLinkedVaryingNodes(node.id); const varyingBlocks = (vert?.blocks || []).filter( - i => - i.name === CustomInterpolatorBlock.Name && - varyingNodes.some(node => node.data.outValueName === i.data.varyingValueName), + i => i.name === CustomInterpolatorBlock.Name && varyingNodes.some(node => node.data.outValueName === i.data.varyingValueName), ); let vertBody = this.linkBlocks(varyingBlocks); let fragCode = ''; let vertCode = ''; if (node.name === VaryingRC.Name) { - if (!varyingBlocks[0]) - throw new Error('compile varying preview failed: missing CustomInterpolatorBlock'); - const { varName } = this.getContext( - 'varyings', - varyingBlocks[0], - varyingBlocks[0].data.varyingValueName, - )!; - const bodyCode = SGTemplates.unlit.frag( - this.prependFragSharedCode(`*baseColor = ${varName}.xyz;`), - ); + if (!varyingBlocks[0]) throw new Error('compile varying preview failed: missing CustomInterpolatorBlock'); + const { varName } = this.getContext('varyings', varyingBlocks[0], varyingBlocks[0].data.varyingValueName)!; + const bodyCode = SGTemplates.unlit.frag(this.prependFragSharedCode(`*baseColor = ${varName}.xyz;`)); const headCode = this.compileHeadCode(bodyCode, 'frag'); fragCode = headCode + '\n' + bodyCode; vertBody += this.getAutoVaryingsCode(fragCode); vertBody = this.prependVertSharedCode(vertBody); - vertCode = - SG_VERT + this.compileHeadCode(vertBody, 'vert') + SGTemplates.unlit.vert(vertBody); + vertCode = SG_VERT + this.compileHeadCode(vertBody, 'vert') + SGTemplates.unlit.vert(vertBody); } else { const baseColorData = await ctx.getNodeData(ctx.baseColorBlock); const output = [...node.outputs.keys()][0]; @@ -557,8 +513,7 @@ ${code}`; fragCode = this.compileHeadCode(fragBody, 'frag') + SGTemplates.unlit.frag(fragBody); vertBody += this.getAutoVaryingsCode(fragCode); vertBody = this.prependVertSharedCode(vertBody); - vertCode = - SG_VERT + this.compileHeadCode(vertBody, 'vert') + SGTemplates.unlit.vert(vertBody); + vertCode = SG_VERT + this.compileHeadCode(vertBody, 'vert') + SGTemplates.unlit.vert(vertBody); } return { ...this.compilation, fragCode, vertCode }; @@ -650,12 +605,25 @@ ${code}`; } } -const stringifyFloat = (num: number): string => { +const stringifyFloat = (num: number | number[]): string => { + if (Array.isArray(num)) { + num = num[0] || 0; + } const str = String(num); - if (str.includes('.')) return str; + const dotIndex = str.indexOf('.'); + if (dotIndex > -1) { + return str; + } return str + '.0'; }; +const stringifyVector = (value: number[], len: 2 | 3 | 4): string => { + return `vec${len}(${new Array(len) + .fill(0) + .map((v, k) => stringifyFloat(value[k] || 0)) + .join(', ')})`; +}; + export class SubGraphCompiler extends ShaderGraphCompiler { constructor(public sgCompiler: ShaderGraphCompiler) { super(); diff --git a/src/compilers/ShaderGraphFns.ts b/src/compilers/ShaderGraphFns.ts index 418c4d9..4b42e8e 100644 --- a/src/compilers/ShaderGraphFns.ts +++ b/src/compilers/ShaderGraphFns.ts @@ -63,3 +63,32 @@ fn ${varName}(tangentToWorld: mat3x3f, matTBN_I_T: ptr, sgn: }; } }; + +export const initUnpackNormalContext = (compiler: ShaderGraphCompiler) => { + const node = { name: 'Unpack', data: {} } as any; + const codeFn = (varName: string) => /* wgsl */ ` +fn ${varName}NormalRGB(packednormal: vec4f, bumpScale: f32) -> vec3f { + vec3 normal; + normal.xyz = packednormal.rgb * 2.0 - 1.0; + normal.xy *= bumpScale; + return normal; +} +fn ${varName}ScaleNormalRGorAG(packednormal_: vec4f, bumpScale: f32) { + var packednormal = vec4f(packednormal_); + packednormal.x *= packednormal.w; + + var normal: vec3f; + normal.xy = (packednormal.xy * 2.0 - 1.0); + normal.z = sqrt(1.0 - clamp(dot(normal.xy, normal.xy), 0.0, 1.0)); + return normal; +} +fn ${varName}ScaleNormal(packednormal: vec4f, bumpScale: f32) -> vec3f { + return ${varName}ScaleNormalRGorAG(packednormal, bumpScale); +}`; + const varName = compiler.setContext('defines', node, 'fn', codeFn); + return { + UnpackNormalRGB: `${varName}NormalRGB`, + UnpackScaleNormalRGorAG: `${varName}ScaleNormalRGorAG`, + UnpackScaleNormal: `${varName}ScaleNormal`, + }; +}; diff --git a/src/components/artistic/ColorSpaceConversionRC.ts b/src/components/artistic/ColorSpaceConversionRC.ts index e6683bb..1735343 100644 --- a/src/components/artistic/ColorSpaceConversionRC.ts +++ b/src/components/artistic/ColorSpaceConversionRC.ts @@ -59,17 +59,8 @@ export class ColorSpaceConversionRC extends RC { ); } - compileSG( - compiler: ShaderGraphCompiler, - node: SGNodeData, - ): SGNodeOutput { - const outVar = compiler.getOutVarName(node, 'out', 'contrast'); - const inVar = compiler.getInputVarConverted(node, 'in'); - const from = node.data.fromValue; - const to = node.data.toValue; - - if (from === to) return { outputs: { out: inVar }, code: '' }; - + static initFnContext(compiler: ShaderGraphCompiler, from: ColorSpace, to: ColorSpace) { + const node = { name: ColorSpaceConversionRC.Name }; let codeFn: (n: string) => string; if (from === 'sRGB' && to === 'HSV') { codeFn = (varName: string) => /* wgsl */ ` @@ -86,9 +77,9 @@ fn ${varName}(In: vec3) -> vec3 { if (from === 'sRGB' && to === 'Linear') { codeFn = (varName: string) => /* wgsl */ ` fn ${varName}(In: vec3) -> vec3 { - vec3 linearRGBLo = In / 12.92; - vec3 linearRGBHi = pow(max(abs((In + 0.055) / 1.055), 1.192092896e-07), vec3(2.4, 2.4, 2.4)); - vec3 stepCheck = step(0.04045, In); + let linearRGBLo = In / 12.92; + let linearRGBHi = pow(max(abs((In + 0.055) / 1.055), vec3f(1.192092896e-07)), vec3(2.4, 2.4, 2.4)); + let stepCheck = step(vec3f(0.04045), In); return stepCheck * linearRGBHi + (1.0 - stepCheck) * linearRGBLo; }`; } @@ -118,8 +109,8 @@ fn ${varName}(In: vec3) -> vec3 { codeFn = (varName: string) => /* wgsl */ ` fn ${varName}(In: vec3) -> vec3 { let sRGBLo = In * 12.92; - let sRGBHi = (pow(max(abs(In), 1.192092896e-07), vec3(1.0 / 2.4, 1.0 / 2.4, 1.0 / 2.4)) * 1.055) - 0.055; - let stepCheck = step(0.0031308, In); + let sRGBHi = (pow(max(abs(In), vec3f(1.192092896e-07)), vec3(1.0 / 2.4, 1.0 / 2.4, 1.0 / 2.4)) * 1.055) - 0.055; + let stepCheck = step(vec3f(0.0031308), In); return stepCheck * sRGBHi + (1.0 - stepCheck) * sRGBLo; }`; } @@ -128,7 +119,7 @@ fn ${varName}(In: vec3) -> vec3 { fn ${varName}(In: vec3) -> vec3 { let sRGBLo = In * 12.92; let sRGBHi = (pow(max(abs(In), 1.192092896e-07), vec3(1.0 / 2.4, 1.0 / 2.4, 1.0 / 2.4)) * 1.055) - 0.055; - let stepCheck = step(0.0031308, In); + let stepCheck = step(vec3f(0.0031308), In); let Linear = stepCheck * sRGBHi + (1.0 - stepCheck) * sRGBLo; let K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); let P = mix(vec4(Linear.bg, K.wz), vec4(Linear.gb, K.xy), step(Linear.b, Linear.g)); @@ -140,7 +131,21 @@ fn ${varName}(In: vec3) -> vec3 { } const fnVar = compiler.setContext('defines', node, from + '_' + to, codeFn!); + return fnVar; + } + + compileSG( + compiler: ShaderGraphCompiler, + node: SGNodeData, + ): SGNodeOutput { + const outVar = compiler.getOutVarName(node, 'out', 'contrast'); + const inVar = compiler.getInputVarConverted(node, 'in'); + const from = node.data.fromValue; + const to = node.data.toValue; + + if (from === to) return { outputs: { out: inVar }, code: '' }; + const fnVar = ColorSpaceConversionRC.initFnContext(compiler, from, to); return { outputs: { out: outVar }, code: `let ${outVar} = ${fnVar}(${inVar});`, diff --git a/src/components/artistic/adjustment/ReplaceColorRC.ts b/src/components/artistic/adjustment/ReplaceColorRC.ts index ca60c43..d7340c3 100644 --- a/src/components/artistic/adjustment/ReplaceColorRC.ts +++ b/src/components/artistic/adjustment/ReplaceColorRC.ts @@ -1,6 +1,6 @@ import { NodeView, DynamicControl, ColorControl } from '../../../view'; import { Sockets } from '../../../sockets'; -import { ExtendReteNode, Rete, ValueType } from '../../../types'; +import { ExtendReteNode, Rete, ValueType, ValueUsage } from '../../../types'; import { RC } from '../../ReteComponent'; import { ShaderGraphCompiler, SGNodeOutput } from '../../../compilers'; import { SGNodeData } from '../../../editors'; @@ -18,8 +18,10 @@ export type ReteReplaceColorNode = ExtendReteNode< fuzzinessValueType: ValueType.float; fromValue: number[]; fromValueType: ValueType.vec3; + fromValueUsage: ValueUsage; toValue: number[]; toValueType: ValueType.vec3; + toValueUsage: ValueUsage; } >; @@ -36,8 +38,8 @@ export class ReplaceColorRC extends RC { node.initValueType('out', [0, 0, 0], ValueType.vec3); node.initValueType('range', 0, ValueType.float); node.initValueType('fuzziness', 0, ValueType.float); - node.initValueType('from', [0, 0, 0], ValueType.vec3); - node.initValueType('to', [0, 0, 0], ValueType.vec3); + node.initValueType('from', [0, 0, 0], ValueType.vec3, undefined, ValueUsage.Color); + node.initValueType('to', [0, 0, 0], ValueType.vec3, undefined, ValueUsage.Color); data.expanded ??= true; meta.previewDisabled = false; diff --git a/src/components/artistic/mask/ColorMaskRC.ts b/src/components/artistic/mask/ColorMaskRC.ts index feb19a5..d434924 100644 --- a/src/components/artistic/mask/ColorMaskRC.ts +++ b/src/components/artistic/mask/ColorMaskRC.ts @@ -1,6 +1,6 @@ import { NodeView, DynamicControl, ColorControl } from '../../../view'; import { Sockets } from '../../../sockets'; -import { ExtendReteNode, Rete, ValueType } from '../../../types'; +import { ExtendReteNode, Rete, ValueType, ValueUsage } from '../../../types'; import { RC } from '../../ReteComponent'; import { ShaderGraphCompiler, SGNodeOutput } from '../../../compilers'; import { SGNodeData } from '../../../editors'; @@ -12,6 +12,7 @@ export type ReteColorMaskNode = ExtendReteNode< inValueType: ValueType.vec3; maskColorValue: number; maskColorValueType: ValueType.vec3; + maskColorValueUsage: ValueUsage; rangeValue: number; rangeValueType: ValueType.float; fuzzinessValue: number; @@ -31,7 +32,7 @@ export class ColorMaskRC extends RC { initNode(node: ReteColorMaskNode) { const { data, meta } = node; node.initValueType('in', [0, 0, 0], ValueType.vec3); - node.initValueType('maskColor', [0, 0, 0], ValueType.vec3); + node.initValueType('maskColor', [0, 0, 0], ValueType.vec3, undefined, ValueUsage.Color); node.initValueType('range', 0, ValueType.float); node.initValueType('fuzziness', 0, ValueType.float); node.initValueType('out', 0, ValueType.float); diff --git a/src/components/blocks/fragment/BaseColorBlock.ts b/src/components/blocks/fragment/BaseColorBlock.ts index 12e9c25..b89f5da 100644 --- a/src/components/blocks/fragment/BaseColorBlock.ts +++ b/src/components/blocks/fragment/BaseColorBlock.ts @@ -1,6 +1,6 @@ import { ColorControl, BlockView } from '../../../view'; import { Sockets } from '../../../sockets'; -import { Rete, ValueType, ExtendReteNode } from '../../../types'; +import { Rete, ValueType, ExtendReteNode, ValueUsage } from '../../../types'; import { RCBlock } from '../../ReteComponent'; import { ShaderGraphCompiler, SGNodeOutput } from '../../../compilers'; import { SGNodeData } from '../../../editors'; @@ -10,6 +10,7 @@ export type ReteBaseColorBlock = ExtendReteNode< { baseColorValue: number[]; baseColorValueType: ValueType.vec3; + baseColorValueUsage: ValueUsage; } >; @@ -22,7 +23,7 @@ export class BaseColorBlock extends RCBlock { async initNode(node: ReteBaseColorBlock) { const { data, meta } = node; - node.initValueType('baseColor', [0, 0, 0], ValueType.vec3); + node.initValueType('baseColor', [0, 0, 0], ValueType.vec3, undefined, ValueUsage.Color); data.expanded ??= true; meta.category = ''; meta.isContext = false; diff --git a/src/components/blocks/fragment/EmissionBlock.ts b/src/components/blocks/fragment/EmissionBlock.ts index 3a780c8..29b9318 100644 --- a/src/components/blocks/fragment/EmissionBlock.ts +++ b/src/components/blocks/fragment/EmissionBlock.ts @@ -1,6 +1,6 @@ import { BlockView, ColorControl } from '../../../view'; import { Sockets } from '../../../sockets'; -import { Rete, ValueType, ExtendReteNode } from '../../../types'; +import { Rete, ValueType, ExtendReteNode, ValueUsage } from '../../../types'; import { RCBlock } from '../../ReteComponent'; import { ShaderGraphCompiler, SGNodeOutput } from '../../../compilers'; import { SGNodeData } from '../../../editors'; @@ -10,6 +10,7 @@ export type ReteEmissionBlock = ExtendReteNode< { emissionValue: number[]; emissionValueType: ValueType.vec3; + emissionValueUsage: ValueUsage; } >; @@ -22,7 +23,7 @@ export class EmissionBlock extends RCBlock { async initNode(node: ReteEmissionBlock) { const { data, meta } = node; - node.initValueType('emission', [0, 0, 0], ValueType.vec3); + node.initValueType('emission', [0, 0, 0], ValueType.vec3, undefined, ValueUsage.Color); data.expanded ??= true; meta.category = ''; meta.isContext = false; diff --git a/src/components/input/ParameterRC.ts b/src/components/input/ParameterRC.ts index 71c2622..01f0802 100644 --- a/src/components/input/ParameterRC.ts +++ b/src/components/input/ParameterRC.ts @@ -1,6 +1,6 @@ import { ParameterView } from '../../view'; import { Sockets } from '../../sockets'; -import { ValueType, Rete, ValueTypeSocketMap, ExtendReteNode } from '../../types'; +import { ValueType, Rete, ValueTypeSocketMap, ExtendReteNode, ValueUsage } from '../../types'; import { RC } from '../ReteComponent'; import { ShaderGraphCompiler, SGNodeOutput } from '../../compilers'; import { SGNodeData } from '../../editors'; @@ -11,6 +11,7 @@ declare module '../../rete/core/events' { name: string; outValue: any; outValueType: ValueType; + outValueUsage?: ValueUsage; outValueName: string; exposed: boolean; }; @@ -23,6 +24,7 @@ export type ReteParameterNode = ExtendReteNode< { outValue: any; outValueType: ValueType; + outValueUsage?: ValueUsage; outValueName: string; } >; @@ -37,12 +39,13 @@ export class ParameterRC extends RC { onRegister(editor: Rete.NodeEditor): void { editor.bind('parameterchange'); editor.bind('parameterdelete'); - editor.on('parameterchange', ({ name, outValue, outValueName, outValueType, exposed }) => { + editor.on('parameterchange', ({ name, outValue, outValueName, outValueType, exposed, outValueUsage }) => { const nodes = editor.nodes.filter(node => node.name === ParameterRC.Name && node.data.outValueName === name); nodes.forEach(node => { node.data.outValue = outValue; node.data.outValueName = outValueName; node.data.outValueType = outValueType; + node.data.outValueUsage = outValueUsage; node.data.exposed = exposed; node.dataChanged = true; node.update(); diff --git a/src/components/input/basic/ColorRC.ts b/src/components/input/basic/ColorRC.ts index 95d0747..2fea85d 100644 --- a/src/components/input/basic/ColorRC.ts +++ b/src/components/input/basic/ColorRC.ts @@ -1,6 +1,6 @@ import { ColorControl, NodeView } from '../../../view'; import { Sockets } from '../../../sockets'; -import { ValueType, Rete, ExtendReteNode } from '../../../types'; +import { ValueType, Rete, ExtendReteNode, ValueUsage } from '../../../types'; import { RC } from '../../ReteComponent'; import { ShaderGraphCompiler, SGNodeOutput } from '../../../compilers'; import { SGNodeData } from '../../../editors'; @@ -10,6 +10,7 @@ export type ReteColorNode = ExtendReteNode< { outValue: number[]; outValueType: ValueType.vec3; + outValueUsage: ValueUsage.Color; } >; @@ -21,7 +22,7 @@ export class ColorRC extends RC { initNode(node: ReteColorNode) { const { data, meta } = node; - node.initValueType('out', [0, 0, 0], ValueType.vec3); + node.initValueType('out', [0, 0, 0], ValueType.vec3, undefined, ValueUsage.Color); data.expanded ??= true; meta.previewDisabled = true; @@ -39,7 +40,7 @@ export class ColorRC extends RC { const outVar = compiler.getOutVarName(node, 'out', 'color'); return { outputs: { out: outVar }, - code: `let ${outVar} = ${compiler.compileNodeValue(node, 'out')};\n`, + code: `let ${outVar} = ${compiler.compileNodeValue(node, 'out')};`, }; } } diff --git a/src/components/input/texture/SampleTexture2DRC.ts b/src/components/input/texture/SampleTexture2DRC.ts index e292c0a..9cff47a 100644 --- a/src/components/input/texture/SampleTexture2DRC.ts +++ b/src/components/input/texture/SampleTexture2DRC.ts @@ -1,10 +1,11 @@ import { AssetControl, NodeView, SelectControl } from '../../../view'; import { Sockets } from '../../../sockets'; -import { ValueType, Rete, ExtendReteNode, AssetValue } from '../../../types'; +import { ValueType, Rete, ExtendReteNode, AssetValue, COLOR_SPACE_OPTIONS, UV_OPTIONS, TYPE_OPTIONS, SPACE_OPTIONS } from '../../../types'; import { RC } from '../../ReteComponent'; -import { ShaderGraphCompiler, SGNodeOutput } from '../../../compilers'; +import { ShaderGraphCompiler, SGNodeOutput, initUnpackNormalContext } from '../../../compilers'; import { SGNodeData } from '../../../editors'; import { UVRC } from '../geometry'; +import { ColorSpaceConversionRC } from '../../artistic'; export type ReteSampleTexture2DNode = ExtendReteNode< 'SampleTexture2D', @@ -27,6 +28,8 @@ export type ReteSampleTexture2DNode = ExtendReteNode< typeValue: 'default' | 'normal'; spaceValue: 'object' | 'tangent'; + texColorSpaceValue: 'sRGB' | 'Linear'; + texColorSpaceValueType: ValueType.string; } >; @@ -47,7 +50,8 @@ export class SampleTexture2DRC extends RC { node.initValueType('uv', 'UV0', ValueType.vec2); node.initValueType('sampler', undefined, ValueType.sampler); node.initValueType('type', 'default', ValueType.string); - node.initValueType('space', 'object', ValueType.string); + node.initValueType('space', 'tangent', ValueType.string); + node.initValueType('texColorSpace', 'sRGB', ValueType.string); data.expanded ??= true; data.preview ??= true; @@ -69,16 +73,14 @@ export class SampleTexture2DRC extends RC { const uv = new Rete.Input('uv', 'UV', Sockets.vec2); const sampler = new Rete.Input('sampler', 'Sampler', Sockets.sampler); [texture, uv, sampler].forEach(i => node.addInput(i)); - uv.addControl(new SelectControl('uv', node, '', ['UV0', 'UV1', 'UV2', 'UV3'], true)); + uv.addControl(new SelectControl('uv', node, '', UV_OPTIONS, true)); texture.addControl(new AssetControl('texture', node, this.editor!, true)); - node.addControl(new SelectControl('type', node, 'Type', ['default', 'normal'], false)); - node.addControl(new SelectControl('space', node, 'Space', ['object', 'tangent'], false)); + node.addControl(new SelectControl('type', node, 'Type', TYPE_OPTIONS, false)); + node.addControl(new SelectControl('space', node, 'Space', SPACE_OPTIONS, false)); + node.addControl(new SelectControl('texColorSpace', node, 'TexColorSpace', COLOR_SPACE_OPTIONS, false)); } - compileSG( - compiler: ShaderGraphCompiler, - node: SGNodeData, - ): SGNodeOutput { + compileSG(compiler: ShaderGraphCompiler, node: SGNodeData): SGNodeOutput { const outVar = compiler.getOutVarName(node, 'rgba', 'texColor'); const textureVar = compiler.getInputVar(node, 'texture'); const samplerVar = textureVar ? compiler.getInputVar(node, 'sampler') : ''; @@ -86,18 +88,21 @@ export class SampleTexture2DRC extends RC { if (!uvVar) uvVar = UVRC.initUVContext(compiler); - // TODO type space + const { typeValue, spaceValue, texColorSpaceValue } = node.data; + let normalizeCode = ''; + if (typeValue === 'normal') { + const { UnpackScaleNormal, UnpackNormalRGB } = initUnpackNormalContext(compiler); + normalizeCode = `\n ${outVar}.rgb = normalize(${spaceValue === 'tangent' ? UnpackScaleNormal : UnpackNormalRGB}(vec4(${outVar}.rgb, 1.), 1.0));\n`; + } + // 后面将由纹理确定 GPUTexture format rgbaXXXX-srgb + let toLinearCode = ''; + if (typeValue === 'default' && texColorSpaceValue === 'sRGB') { + const sRGBToLinear = ColorSpaceConversionRC.initFnContext(compiler, 'sRGB', 'Linear'); + toLinearCode = `\n ${outVar} = vec4f(${sRGBToLinear}(${outVar}.rgb), ${outVar}.a);`; + } return { - outputs: { - rgba: outVar, - r: `${outVar}.r`, - g: `${outVar}.g`, - b: `${outVar}.b`, - a: `${outVar}.a`, - }, - code: `let ${outVar} = ${ - textureVar ? `textureSample(${textureVar}, ${samplerVar}, ${uvVar})` : 'vec4(0)' - };`, + outputs: { rgba: outVar, r: `${outVar}.r`, g: `${outVar}.g`, b: `${outVar}.b`, a: `${outVar}.a` }, + code: `var ${outVar} = ${textureVar ? `textureSample(${textureVar}, ${samplerVar}, ${uvVar})` : 'vec4(0)'};${normalizeCode}${toLinearCode}`, }; } } diff --git a/src/components/procedural/Checkerboard.ts b/src/components/procedural/Checkerboard.ts index d5e5941..5a00861 100644 --- a/src/components/procedural/Checkerboard.ts +++ b/src/components/procedural/Checkerboard.ts @@ -1,7 +1,7 @@ import { ShaderGraphCompiler, SGNodeOutput } from '../../compilers'; import { SGNodeData } from '../../editors'; import { Sockets } from '../../sockets'; -import { ExtendReteNode, ValueType, Rete, UV_OPTIONS } from '../../types'; +import { ExtendReteNode, ValueType, Rete, UV_OPTIONS, ValueUsage } from '../../types'; import { NodeView, SelectControl, ColorControl, DynamicControl } from '../../view'; import { UVRC } from '../input'; import { RC } from '../ReteComponent'; @@ -13,8 +13,10 @@ export type ReteCheckerboardNode = ExtendReteNode< uvValueType: ValueType.vec2; colorAValue: number[]; colorAValueType: ValueType.vec3; + colorAValueUsage: ValueUsage.Color; colorBValue: number[]; colorBValueType: ValueType.vec3; + colorBValueUsage: ValueUsage.Color; frequencyValue: number[]; frequencyValueType: ValueType.vec2; outValue: number[]; @@ -31,8 +33,8 @@ export class CheckerboardRC extends RC { initNode(node: ReteCheckerboardNode) { const { data, meta } = node; node.initValueType('uv', 'UV0', ValueType.vec2); - node.initValueType('colorA', [0, 0.98, 1], ValueType.vec3); - node.initValueType('colorB', [0.62, 0.58, 1], ValueType.vec3); + node.initValueType('colorA', [0, 0.98, 1], ValueType.vec3, undefined, ValueUsage.Color); + node.initValueType('colorB', [0.62, 0.58, 1], ValueType.vec3, undefined, ValueUsage.Color); node.initValueType('frequency', [1, 1], ValueType.vec2); node.initValueType('out', [0, 0, 0], ValueType.vec3); data.expanded ??= true; diff --git a/src/rete/node.ts b/src/rete/node.ts index db241e7..f11d468 100644 --- a/src/rete/node.ts +++ b/src/rete/node.ts @@ -145,17 +145,30 @@ export class Node { this.data[prefix + 'ValueName'] = name; } + getValueUsage(prefix: string): string { + return this.data[prefix + 'ValueUsage'] as string; + } + + setValueUsage(prefix: string, name: string) { + this.data[prefix + 'ValueUsage'] = name; + } + removeValue(prefix: string) { delete this.data[prefix + 'Value']; delete this.data[prefix + 'ValueType']; delete this.data[prefix + 'ValueName']; } - initValueType(prefix: string, value: any, type?: string, name?: string) { - if (this.data[prefix + 'ValueType'] === undefined) { + initValueType(prefix: string, value: any, type?: string, name?: string, usage?: string) { + const currType = this.data[prefix + 'ValueType']; + const currUsage = this.data[prefix + 'ValueUsage']; + if (currType === undefined) { this.setValue(prefix, value); type && this.setValueType(prefix, type); name && this.setValueName(prefix, name); + usage && this.setValueUsage(prefix, usage); + } else if (usage && currUsage !== usage) { + this.setValueUsage(prefix, usage); } } diff --git a/src/templates/Lit.ts b/src/templates/Lit.ts index 862f1b6..c087157 100644 --- a/src/templates/Lit.ts +++ b/src/templates/Lit.ts @@ -42,13 +42,17 @@ fn main( @group(0) @binding(0) var u: Uniform; +fn LinearToGammaSpace(linRGB: vec3f) -> vec3f { + return max(vec3f(1.055) * pow(max(linRGB, vec3f(0.0)), vec3f(0.416666667)) - 0.055, vec3f(0.0)); +} + @fragment fn main(v: Varying) -> @location(0) vec4 { var sg_baseColor = vec3(); var sg_alpha = 1.0; sg_frag(&sg_baseColor, &sg_alpha, v); - return vec4(sg_baseColor, sg_alpha); + return vec4(LinearToGammaSpace(sg_baseColor), sg_alpha); // return vec4(0.0, 1.0, 0.0, 1.0); }`, }; diff --git a/src/templates/Unlit.ts b/src/templates/Unlit.ts index bc54f18..1510fb9 100644 --- a/src/templates/Unlit.ts +++ b/src/templates/Unlit.ts @@ -44,13 +44,17 @@ fn main( @group(0) @binding(0) var u: Uniform; +fn LinearToGammaSpace(linRGB: vec3f) -> vec3f { + return max(vec3f(1.055) * pow(max(linRGB, vec3f(0.0)), vec3f(0.416666667)) - 0.055, vec3f(0.0)); +} + @fragment fn main(v: Varying) -> @location(0) vec4 { var sg_baseColor = vec3(); var sg_alpha = 1.0; sg_frag(&sg_baseColor, &sg_alpha, v); - return vec4(sg_baseColor, sg_alpha); + return vec4(LinearToGammaSpace(sg_baseColor), sg_alpha); // return vec4(0.0, 1.0, 0.0, 1.0); }`, }; diff --git a/src/types.ts b/src/types.ts index 9ccd752..7e20ac3 100644 --- a/src/types.ts +++ b/src/types.ts @@ -20,6 +20,9 @@ export enum ValueType { string = 'string', bool = 'bool', } +export enum ValueUsage { + Color = 'color', +} export const VectorTypes = [ValueType.float, ValueType.vec2, ValueType.vec3, ValueType.vec4]; export type VectorValueType = ValueType.float | ValueType.vec2 | ValueType.vec3 | ValueType.vec4; export const MatrixTypes = [ValueType.mat2, ValueType.mat3, ValueType.mat4]; @@ -172,7 +175,7 @@ export interface ExtendReteContext meta: ReteContextNode['meta'] & Meta; } -export type ValueTypeEdit = undefined | 'color'; +export type ValueTypeEdit = undefined | ValueUsage.Color; export interface ParameterData { type: ValueType; name: string; @@ -203,6 +206,9 @@ export const SpaceSuffixMap = Object.freeze({ } as const); export const UV_OPTIONS = ['UV0', 'UV1', 'UV2', 'UV3']; +export const TYPE_OPTIONS = ['default', 'normal']; +export const SPACE_OPTIONS = ['tangent', 'object']; +export const COLOR_SPACE_OPTIONS = ['sRGB', 'Linear']; export type ValueOf = T[keyof T]; export type MaybePromise = T | Promise; diff --git a/src/utils.ts b/src/utils.ts index e7e2660..27c278e 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -26,3 +26,11 @@ export function hash(str: string) { } return hash.toString(16).replace('-', 'n'); } + +export function SRGBToLinear(c: number): number { + return c < 0.04045 ? c * 0.0773993808 : Math.pow(c * 0.9478672986 + 0.0521327014, 2.4); +} + +export function LinearToSRGB(c: number): number { + return c < 0.0031308 ? c * 12.92 : 1.055 * Math.pow(c, 0.41666) - 0.055; +} \ No newline at end of file diff --git a/src/view/popups/BlackBoard.tsx b/src/view/popups/BlackBoard.tsx index dc6a23c..fa8acce 100644 --- a/src/view/popups/BlackBoard.tsx +++ b/src/view/popups/BlackBoard.tsx @@ -7,6 +7,7 @@ import { ValueTypeEdit, ValueTypeNameMap, ValueTypeNameReverseMap, + ValueUsage, VectorTypes, } from '../../types'; import React, { FC, MouseEventHandler, useContext, useEffect, useRef, useState } from 'react'; @@ -82,7 +83,7 @@ const ParameterItem: FC = ({ editor, view, item }) => { { name: '重命名', onclick: close(() => setEdit(true)) }, { name: '删除', onclick: close(() => view.delParameter(name)) }, ], - [{ name: '克隆', onclick: close(() => view.cloneParamter(name)) }], + [{ name: '克隆', onclick: close(() => view.cloneParameter(name)) }], ]}>
@@ -174,10 +175,10 @@ export const BlackBoard: FC = ({ visiable, view, editor, subtit let customName: string | undefined; if (name === 'Color') { type = ValueType.vec3; - typeEdit = 'color'; + typeEdit = ValueUsage.Color; customName = 'Color'; } - view.addParamter(type, true, typeEdit, customName); + view.addParameter(type, true, typeEdit, customName); }; return ( @@ -231,7 +232,7 @@ export class BlackBoardView extends PopupView { return this.data.map(i => ({ name: i.name, type: i.type, defalutValue: i.defalutValue, exposed: i.exposed, typeEdit: i.typeEdit })); } - addParamter(type: ValueType, editing = false, typeEdit?: ValueTypeEdit, customName?: string) { + addParameter(type: ValueType, editing = false, typeEdit?: ValueTypeEdit, customName?: string) { const nextIndex = this.data.filter(i => i.type == type).length; let name = customName || ValueTypeNameMap[type]; if (nextIndex) name += `(${nextIndex})`; @@ -243,14 +244,14 @@ export class BlackBoardView extends PopupView { setParameter(name: string, data: Partial): boolean { const item = this.data.find(i => i.name === name); if (data.name !== undefined && !data.name) { - this.editor.trigger('warn', `Paramter name invalid ${data.name}`); + this.editor.trigger('warn', `Parameter name invalid ${data.name}`); return false; } if (data.name) { if (data.name === name) return true; const nameUsedItem = this.data.find(i => i.name === data.name); if (nameUsedItem) { - this.editor.trigger('warn', `Paramter name used ${data.name}`); + this.editor.trigger('warn', `Parameter name used ${data.name}`); return false; } } @@ -264,6 +265,7 @@ export class BlackBoardView extends PopupView { outValue: item.defalutValue, outValueName: item.name, outValueType: item.type, + outValueUsage: item.typeEdit, exposed: item.exposed, }); this.update(); @@ -281,7 +283,7 @@ export class BlackBoardView extends PopupView { } } - cloneParamter(name: string) { + cloneParameter(name: string) { const item = this.data.find(i => i.name === name); if (item) { diff --git a/src/view/popups/EditorMenu.tsx b/src/view/popups/EditorMenu.tsx index 85ecbeb..7a6773a 100644 --- a/src/view/popups/EditorMenu.tsx +++ b/src/view/popups/EditorMenu.tsx @@ -9,6 +9,7 @@ import copy from 'copy-to-clipboard'; import { Input, Node, Output } from '../../rete'; import { NodeData } from '../../rete/core/data'; import { getIOLinkToContextType } from '../../plugins'; +import { printCollapsed } from '../utils'; interface MenuProps extends PopupViewProps { popupAdd: PopupNodeAddView; @@ -41,8 +42,8 @@ const EditorContextMenu: FC = ({ editor, connection, node, popupAdd, editor.trigger('previewcopyshader', { node, callback: data => { - console.log('VertCode:\n', data?.vertCode); - console.log('FragCode:\n', data?.fragCode); + printCollapsed(`${node.name} ${node.id} Vert`, data?.vertCode); + printCollapsed(`${node.name} ${node.id} Frag`, data?.fragCode); data && copy(JSON.stringify(data, null, 2)); view.hide(); }, diff --git a/src/view/utils.ts b/src/view/utils.ts index f86f1f2..ed0173d 100644 --- a/src/view/utils.ts +++ b/src/view/utils.ts @@ -1,3 +1,6 @@ +import { ShaderGraphEditor } from "../editors"; +import { MaterialTemplates } from "../templates"; + export const preventDefault = (e: any) => e.preventDefault(); export const stopPropagation = (e: any) => e.stopPropagation(); export const isChildOf = (child: HTMLElement | null, parent?: HTMLElement, maxSearch = 20) => { @@ -11,3 +14,31 @@ export const isChildOf = (child: HTMLElement | null, parent?: HTMLElement, maxSe return false; }; + +export function printCollapsed(title: string, content?: string) { + console.groupCollapsed(`===== ${title} =====`); + console.log('%c' + content, 'font-size: 14px'); + console.groupEnd(); +} + +export async function printCompile(editor?: ShaderGraphEditor) { + if (editor) { + let vertCode = ''; + let fragCode = ''; + const data = editor.toJSON(); + if (editor.editing === 'ShaderGraph') { + ({ vertCode, fragCode } = await editor.compiler.compile(data)); + } + if (editor.editing === 'SubGraph') { + ({ vertCode, fragCode } = await editor.compiler.compileSubGraphPreview(data)); + } + printCollapsed('SG VertCode', vertCode); + printCollapsed('SG FragCode', fragCode); + + const tpl = MaterialTemplates[data.setting.template]; + if (tpl) { + printCollapsed('Material VertCode', tpl.vert(vertCode)); + printCollapsed('Material FragCode', tpl.frag(fragCode)); + } + } +}