VisualShader: graphs, color and transparency
A working C# graph, material parameters, Alpha, persistence and troubleshooting.
VisualShader stores a typed graph and generates engine shading-language code from it. It is a Shader resource used by a ShaderMaterial, not an Entity hierarchy or an automatic performance optimization. Graph elements remain VisualShaderNode objects in the SDK.
Create the first material
- Create a ShaderMaterial on the object that should display the effect.
- Assign a new VisualShader resource to its Shader property.
- Select the shader mode for the target: CanvasItem for a 2D ColorRect/Sprite2D, Spatial for a 3D surface. Then select the stage you are editing, such as Fragment.
- Open the graph resource and add a ColorParameter named tint, with its default enabled and set to opaque red.
- Connect RGB to the Fragment Output Color input. Extract the fourth component separately and connect it to Alpha.
- Assign the material to a visible object and verify the rendered result, not only the graph preview.
In the current editor source the add button is labeled Add Entity.... In this panel it creates shader graph nodes; it does not create a scene-tree Entity. The generated-code view and material preview are separate controls. Do not identify them by an old toolbar position.
For the checked CanvasItem Fragment output, Color is input 0 and Alpha input 1. Port layouts vary with mode, stage and node configuration; these numbers are not universal for every output node.
Complete C# construction
Save this helper as VisualColorGraph.cs:
using System;
using Reckfell;
public static class VisualColorGraph
{
public static VisualShader Create()
{
var shader = new VisualShader();
shader.SetMode(Shader.Mode.CanvasItem);
var stage = VisualShader.Type.Fragment;
var color = new VisualShaderNodeColorParameter
{
ParameterName = "tint",
DefaultValueEnabled = true,
DefaultValue = Colors.Red,
};
int colorId = shader.GetValidNodeId(stage);
shader.AddNode(stage, color, new Vector2(0, 0), colorId);
var split = new VisualShaderNodeVectorDecompose
{
OpType = VisualShaderNodeVectorBase.OpTypeEnum.Vector4D,
};
int splitId = shader.GetValidNodeId(stage);
shader.AddNode(stage, split, new Vector2(250, 120), splitId);
Connect(shader, colorId, 0, 0, 0);
Connect(shader, colorId, 0, splitId, 0);
Connect(shader, splitId, 3, 0, 1);
return shader;
}
private static void Connect(VisualShader shader, int from, int fromPort, int to, int toPort)
{
var stage = VisualShader.Type.Fragment;
if (!shader.CanConnectNodes(stage, from, fromPort, to, toPort))
throw new InvalidOperationException("Incompatible graph connection.");
if (shader.ConnectNodes(stage, from, fromPort, to, toPort) != Error.Ok)
throw new InvalidOperationException("Graph connection failed.");
}
}Create a ShaderMaterial with Shader = VisualColorGraph.Create() and assign it to a white ColorRect. The native example uses 64×64 cards. The default card is red. Set material.SetShaderParameter("tint", new Color(0, 1, 0, 1)) to make that material green. Two separate materials can share the same VisualShader and keep independent tint values.
The graph owns references to its nodes. Do not put live nodes in using scopes or dispose a borrowed node wrapper while the graph still uses it, especially for C# custom-node behavior. Release an owned graph/material after consumers no longer use it.
Follow the types, including Alpha
ColorParameter has one vec4/RGBA output in this SDK. The example connects it to the vec3 Color input, and also to a VectorDecompose configured for Vector4D. Decompose output 3 is W/Alpha and connects to the scalar Alpha input.
Connecting RGBA only to Color drops the fourth component from that connection. Connecting the whole vector directly to a scalar does not extract alpha and does not average the components: the current numeric conversion uses X. The GPU check sets red with alpha 0; the explicit W path hides the card, whereas the vector→scalar X path makes it opaque red.
Read port types/dimensions rather than relying on wire colors. Scalar, integer scalar, vec2/3/4, boolean, transform and sampler are different contracts. Numeric conversions may be accepted but change meaning. Use explicit decomposition, composition, dot products or other intended operations when the algorithm needs them. Expanded ports and a changed node mode can alter the port layout.
Node IDs belong to one stage graph; GetValidNodeId chooses an available ID in that stage. ID 0 is the built-in Output. Use CanConnectNodes before ConnectNodes and check the Error result. Preflight rejects missing nodes, invalid ports, duplicate/self links and incompatible/cyclic wiring; it is not proof that every generated expression is valid or that an effect is fast.
Parameters, defaults and shared resources
A ColorConstant changes generated code. A ColorParameter exposes a shader uniform and can be updated on each ShaderMaterial. The graph parameter's default is distinct from a material override. Changing the graph default affects consumers that have no explicit override; passing Nil to the checked material parameter restores that default.
ParameterName is the uniform name, not the graph node ID or caption. Keep names unique and inspect the actual name after editing/adding nodes. Renaming a parameter requires updating material setters and saved consumers. A graph-stage selection is distinct from the shader mode, and both are distinct from the parameter's material/global/instance qualifier.
Use global/instance qualifiers only with their required registry/instance setup; they do not automatically behave like ordinary material parameters. See uniform scopes. Do not change a shader's mode after constructing a graph and assume all old connections still match.
Organize larger graphs deliberately
| Element | Use and boundary |
|---|---|
| Group, GroupInput, GroupOutput | Reusable subgraph resource with declared inputs/outputs. Keep its interface typed; a group is more than a visual frame. |
| Frame | Visual organization of related nodes; do not assume a new shader function or performance boundary. |
| Expression / GlobalExpression | Code inside the graph with the appropriate port/global context. A graph containing expressions still needs valid shader-language syntax and stage rules. |
| Reroute | Wire organization/type propagation, not an automatic mathematical conversion of arbitrary resources. |
| Boolean, If, Switch | Logical values and selection. Select compatible data types; a visual branch does not by itself guarantee fewer GPU instructions. |
| Fresnel | View/normal-dependent edge weighting in the relevant context, not a complete reflection or physical material system. |
| Particle MeshEmitter | Particle emission data from geometry in the appropriate particle graph/stage; not a gameplay Entity factory or a normal fragment-output effect. |
Build and verify a small output path before adding groups or expressions. Unconnected calculations do not necessarily enter generated code. For reusable C# custom nodes, use the custom-node guide; callback defaults and runtime behavior need their own checks.
Save graphs and convert intentionally
Save the VisualShader as a graph resource, such as ResourceSaver.Save(graph, "asset://ColorGraph.rdata"). The executed test reloads an independent VisualShader using CacheMode.Ignore, checks node IDs/connections and renders the saved default. Loading text code is not the same as loading the graph topology.
GetCode returns generated shader text for inspection or a deliberate text-shader copy. For this simple graph, new Shader { Code = graph.GetCode() } renders the same result, while the original graph remains available. It does not make the text shader editable as the original graph.
General conversion is not lossless: the current editor conversion rejects embedded subresources and warns that external resource references can require rebinding on the material. Keep the graph asset before conversion and inspect dependencies instead of assuming every graph can be converted with one click.
Diagnose a graph that looks wrong
| Symptom | Check |
|---|---|
| Graph changes but the object does not | Correct material/graph instance, mode/stage, connection reaching Output and visible object. |
| Color works but transparency does not | The Alpha input and explicit W extraction; vec4→scalar selects X here. |
| Two objects change together | They may share a material override, not merely a Shader resource. |
| Parameter change has no effect | Exact ParameterName, qualifier and whether its output reaches the active output path. |
| Default edits do not show | A material or instance override may still be active. |
| Shader fails after a port/type change | Inspect generated code and revalidate affected connections. |
| Save/reload loses the intended graph | Save the VisualShader resource, not only generated text; keep required external/custom-node dependencies. |
The installed Windows Forward+/Vulkan test covers actual color/alpha pixels, independent materials, default edits, graph persistence, simple text conversion and connection editing. Editor controls and specialized-node roles above are source-reviewed; no fresh editor screenshot, arbitrary group/expression/mesh-emitter effect, complete conversion matrix, other renderer/export or performance result is claimed.