@@ -74,10 +75,14 @@ getObjectToSerialize and the name of the arrays used in the GLSL code.
distanceFunctionName: string
The name of the function defined in the value of shader.
-Its signature should look like this:
-
float (in vec2 target, out float colorIndex)
+Its signature must be:
+
float distanceFunction(in vec2 target, out vec4 color)
+
Replace distanceFunction with the name given here. Return the signed
+distance to the closest drawable at target and assign its RGBA color
+to color on every code path. Both WebGL and WebGL2 pass a vec4 to
+this output parameter.
OptionalisInverted?: boolean
@@ -89,7 +94,7 @@ Its signature should look like this:
Your code should work with both GLSL version 100 and version 300 es.
+
Defined in drawables/drawable-descriptor.ts:29
shaderCombinationSteps
shaderCombinationSteps:number[]
@@ -99,7 +104,7 @@ shader is used to render a given part of the scene.
Must contain 0 as a value.
+
Defined in drawables/drawable-descriptor.ts:72
uniformCountMacroName
uniformCountMacroName:string
@@ -107,7 +112,7 @@ shader is used to render a given part of the scene.
number of drawables of this type.
+
Defined in drawables/drawable-descriptor.ts:24
diff --git a/documentation-readme.md b/documentation-readme.md
index 114a2b5..9b21061 100644
--- a/documentation-readme.md
+++ b/documentation-readme.md
@@ -31,6 +31,83 @@ See its [documentation](functions/run-animation.runAnimation.html) for more deta
- Add a static `descriptor` property of type [DrawableDescriptor](interfaces/drawables_drawable-descriptor.DrawableDescriptor.html) to your class
- Follow the instructions given in [Usage](#usage-1st-option)
+### Custom drawable example
+
+The function named by `sdf.distanceFunctionName` must have the signature
+`float distanceFunction(in vec2 target, out vec4 color)` in both GLSL 100 and GLSL 300 ES.
+It returns the signed distance (negative inside, zero on the boundary, positive outside)
+and writes the closest drawable's RGBA color to `color` on every code path.
+
+This complete example defines a custom orange circle, maps its serialized properties
+to shader uniforms, and compiles and renders it. Use it in a JavaScript module with
+`sdf-2d` and `gl-matrix` installed. Documentation CI runs this exact code with both
+WebGL 1 and WebGL 2.
+
+
+```js
+import { compile, Drawable } from 'sdf-2d';
+import { vec2 } from 'gl-matrix';
+
+class CustomCircle extends Drawable {
+ constructor(center, radius) {
+ super();
+ this.center = center;
+ this.radius = radius;
+ }
+
+ static descriptor = {
+ propertyUniformMapping: {
+ center: 'customCircleCenters',
+ radius: 'customCircleRadii',
+ },
+ uniformCountMacroName: 'CUSTOM_CIRCLE_COUNT',
+ shaderCombinationSteps: [0, 1, 4],
+ // Unused array entries are filled with this zero-radius circle and moved away.
+ empty: new CustomCircle([0, 0], 0),
+ sdf: {
+ distanceFunctionName: 'customCircleDistance',
+ shader: `
+ uniform vec2 customCircleCenters[CUSTOM_CIRCLE_COUNT];
+ uniform float customCircleRadii[CUSTOM_CIRCLE_COUNT];
+
+ float customCircleDistance(in vec2 target, out vec4 color) {
+ color = vec4(1.0, 0.25, 0.0, 1.0);
+ float minDistance = 1000.0;
+ for (int i = 0; i < CUSTOM_CIRCLE_COUNT; i++) {
+ float d = distance(target, customCircleCenters[i]) - customCircleRadii[i];
+ minDistance = min(minDistance, d);
+ }
+ return minDistance;
+ }
+ `,
+ },
+ };
+
+ minDistance(target) {
+ return vec2.distance(this.center, target) - this.radius;
+ }
+
+ getObjectToSerialize(transform2d, transform1d) {
+ return {
+ center: vec2.transformMat2d(vec2.create(), this.center, transform2d),
+ radius: this.radius * transform1d,
+ };
+ }
+}
+
+const canvas = document.createElement('canvas');
+canvas.width = 320;
+canvas.height = 240;
+document.body.appendChild(canvas);
+
+const renderer = await compile(canvas, [CustomCircle.descriptor]);
+renderer.setRuntimeSettings({ ambientLight: [1, 1, 1], motionBlur: 0 });
+renderer.addDrawable(new CustomCircle([160, 120], 50));
+renderer.renderDrawables();
+
+// Call renderer.destroy() when the renderer is no longer needed.
+```
+
## Useful to know
### Math
diff --git a/src/drawables/drawable-descriptor.ts b/src/drawables/drawable-descriptor.ts
index 1f98519..f188cd1 100644
--- a/src/drawables/drawable-descriptor.ts
+++ b/src/drawables/drawable-descriptor.ts
@@ -7,7 +7,8 @@ import { Drawable } from './drawable';
* Each [[Drawable]] must have a static property of this type, called descriptor.
*
* For more information on how to create your own DrawableDescriptors, look at the
- * code of [[CircleFactory]] or [[InvertedTunnelFactory]].
+ * [complete custom drawable example](https://sdf-2d-docs.schmelczer.dev/index.html#custom-drawable-example),
+ * or the code of [[CircleFactory]] or [[InvertedTunnelFactory]].
*/
export interface DrawableDescriptor {
/**
@@ -34,10 +35,14 @@ export interface DrawableDescriptor {
shader: string;
/**
* The name of the function defined in the value of `shader`.
- * Its signature should look like this:
+ * Its signature must be:
* ```glsl
- * float (in vec2 target, out float colorIndex)
+ * float distanceFunction(in vec2 target, out vec4 color)
* ```
+ * Replace `distanceFunction` with the name given here. Return the signed
+ * distance to the closest drawable at `target` and assign its RGBA color
+ * to `color` on every code path. Both WebGL and WebGL2 pass a `vec4` to
+ * this output parameter.
*/
distanceFunctionName: string;
The name of the function defined in the value of
-shader. -Its signature should look like this: