Archive for the ‘shader graph’ tag
Shader Builder
The shader builder from a while ago has been resurrected/rewritten and integrated into LxEngine. I prioritized this as I wanted LxEngine Tutorial 3 to have use procedural materials to produce a somewhat advanced look – given the naive objectives of Tutorial 1 (i.e. get a window up) and Tutorial 2 (i.e. draw something as basic as possible).
The shader builder is not complete yet, but the core architecture is done. With the core architecture in place, advancing the code is largely a matter of adding support for more parameters and adding convenience via simple bits of intelligence in the builder. Eventually, I’d like the shader builder to be a stand-alone component that any GLSL application can use, that is to say make it usable outside LxEngine. Of course, the application using it will inevitably have to adapt to some of the variable naming, but that’s more or less an unavoidable part of interface with any code that has named arguments.
What?
Below is the demonstration screen shot of a cube with an unlit, nested spherical checker map. And immediately following is the XML + JSON code that’s the input to the shader generator.
<Material id="checker_nested"> { graph : { _type : "solid", color : { _type : "checker", color0 : { _type : "checker", color0 : [ 1, 0, 0 ], color1 : [ 0, 0, 0 ], uv : { _type : "spherical", scale : [ 8, 8 ], }, }, color1 : [ 1, 1, .8 ], uv : { _type : "spherical", scale : [ 2, 2 ], }, }, } } </Material>
Update:
Below is a slightly more interesting looking example: a weave pattern nested with a checker pattern. The code for the weave pattern comes from the LxEngine wiki (with the Javascript translated to GLSL):
How?
I’ll just fly through the how…
The graph is essentially a collection of functions, each with one output and N inputs. The functions in the above are “solid”, “checker”, and “spherical”. Each of these functions is packaged a snippet of GLSL code (i.e. the actual function code) and a chunk of JSON annotation that describes the functions data types and default values. (These function + annotation pairs are not shown above.)
The builder then merely walks the JSON graph collects the set of functions being used, creates a tree of calls where each parameter is either (a) the default because it was unspecified in the material description, (b) a hard-coded value in the shader because a hard-coded value was used in the material description, or (c) the result of another function call – i.e. which has it’s value generated by recursively repeating the process.
Now, part (b) is inefficient at the moment as two identical shaders with different parameterizations will generate two different shaders because of the hard-coding; however, that’s easily fixable and on the todo list. (The fix basically is to generate uniforms for all hard-coded values and modify the builder to output a shader + a set of uniform values. This would then be used along with a simple cache mechanism so the same shader gets returned in case of identical graphs.)
Lithosphere Terrain Generator
From the author of the blog over at CodeFlow, here’s a video of a fantastic shader-graph based procedural terrain generator. It’s GPU driven via OpenGL fragment shaders – and while it’s a resource hog, the terrains can be imported and exported in static form:
Thanks to FreeGamer for the link.
The project description on CodeFlow is located here, which includes the source code, documentation, additional screenshots, etc. The author, Florian Bösch, appears to do some high-quality work. He provides his LinkedIn page, if you want to know more about the author himself.
This impressive work really sets a new standard after my recent, low-expertise experiments with heightmaps in Blender. Wow. I’ve always been interested in the idea of having LxEngine content be driven by procedurally generated content as much as possible; the above video is a good reminder of the potential behind that idea.
Effects Sub-Project Complete
One more shader fragment for the tile procedural and an updated data file later:
Definition of “Complete”
According to the objectives of this sub-project, it’s fair to say the rasterized versus raytraced images results match sufficiently to call this sub-project done. The remaining mismatches are primarily: (1) lack of shadows, (2) light position mismatch, (3) color tweaking. Regarding lack of rasterized, soft, area light shadows, that is a sizable sub-project in itself; I’d like to pursue some other areas of the code before embarking on that one. Regarding the light position mismatch, that’s a defect in the ray-tracer code: there’s no real learning value in attempting to compensate for that defect. Regarding color tweaking, it’s close enough that I’m satisfied with the results.
There are plenty of areas for further improvement (there always are!) such as bitmap texture support, light shaders, nested uv spaces, shared variables, etc. However, in the interest of exploring different areas of graphics code and based on the aims of this particular effort, I’m labeling this sub-project complete.
A complicated, nested procedural example
I’m fairly happy with the system’s capabilities. For example, the foremost sphere in below image demonstrates a fairly complicated setup. The diffuse channel contains a nested procedural: there is outer checker pattern which defines an inner checker pattern for one tile and a spot pattern for the other tiles. Furthermore, the UV scaling on each level varies (the inner checker is 2×2, the inner spot is 3×4). Lastly, the specular channel is completely independent as it defines a checker pattern of it’s own with a completely different UV mapping.
Here’s what the corresponding data file for the nested procedural sphere looks like (in the JSON scene format):
{
description : "Nested checker",
type : "plyfile",
content : "sphere.ply",
style : {
scale : 0.00392156863,
translate : [ 0.0, -1.25, 0.5 ],
exponent : 128,
material : {
phong : {
diffuse : {
checker : {
primary : {
checker : {
uv : { spherical : { scale : [ 24,9 ]}},
primary : [ .4, 0, 1],
secondary : [ .2, .6, .3],
},
},
secondary : {
spot : {
uv : { spherical : { scale : [ 36,24 ]}},
radius : .45,
primary : [ .5, 1, 1 ],
secondary : [ 0, 0, .1],
},
},
},
},
specular : {
checker : {
uv : { spherical : { scale : [ 32,16 ]}},
primary : [ 1, 1, 1],
secondary : [ 0, 0, 1],
},
},
}
},
}
}
Effect System Support
A quick look some of what the system currently supports:
- Pluggable shader fragments
- Current Mappers cube, spherical, spherical-xy
- Current Procedurals: checker, spot, tile
- Current Base Shaders: phong
- Fully dynamic material shader generation
- Shaders can be nested arbitrarily (to the limit of what the video card can support for a single shader)
- Objects can share the same procedural and mapping for diffuse and specular, or have unique definitions. The correct shader will be generated automatically.
- If two materials have the same structure but different parameters, the system automatically reuses the existing shader and simply changes the uniform variables.
- Inherited Stylization in Scene Graph
- Child nodes automatically inherit any parent attribute, unless the child overrides it. Example: the three stacked cubes share a parent that defines the stylization; the children only define the transform and geometry.
- Shader fragment definitions can automatically pick up these style parameters. Example: the checker procedural automatically grabs the current primary and secondary colors defined by the parent if it is not given explicit values to use.





