Skip to content

Commit 3c64ca4

Browse files
committed
Dynamic surface color rendering.
1 parent ffd626d commit 3c64ca4

9 files changed

Lines changed: 264 additions & 179 deletions

File tree

app/scripts/app.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,13 @@ class App {
3939

4040

4141
const random = new RandomFlowNodeController(this.surface);
42-
random.mode = RandomMode.NUMBER_ARRAY;
43-
const barchart = new BarChartFlowNodeController(this.surface);
44-
this.surface.connect(random.ports['Output'], barchart.ports['Input']);
45-
const spy = new SpyFlowNodeController(this.surface);
46-
this.surface.connect(random.ports['Output'], spy.ports['Input']);
42+
random.mode = RandomMode.VECTOR3;
43+
// const barchart = new BarChartFlowNodeController(this.surface);
44+
// this.surface.connect(random.ports['Output'], barchart.ports['Input']);
45+
// const spy = new SpyFlowNodeController(this.surface);
46+
// this.surface.connect(random.ports['Output'], spy.ports['Input']);
4747
const ray = new RaytraceFlowNodeController(this.surface);
48+
this.surface.connect(random.ports['Output'], ray.ports['SurfaceColor']);
4849
this.surface.layout();
4950
}
5051

app/scripts/core/Surface.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export class Surface implements ISurface {
6262
}
6363

6464
private startListeningToFlow(item) {
65-
if(!IEdge.isInstance(item)){
65+
if (!IEdge.isInstance(item)) {
6666
return;
6767
}
6868
const edge = item as IEdge;
@@ -140,7 +140,7 @@ export class Surface implements ISurface {
140140
if (_.isNumber(realValue)) {
141141
return value;
142142
} else if (_.isArray(realValue)) {
143-
const els = _.take(realValue, 2).join(', ');
143+
const els = _.take(realValue, 2).map(x => Math.round(x * 100) / 100).join(', ');
144144
return `Array: ${els}...`;
145145
} else {
146146
if (value.length <= 10) {
@@ -154,6 +154,7 @@ export class Surface implements ISurface {
154154
}
155155
}
156156
}
157+
157158
graph: IGraph;
158159
model: IFlowModel;
159160
graphComponent: GraphComponent;
@@ -213,7 +214,7 @@ export class Surface implements ISurface {
213214
fixPorts: true,
214215
});
215216

216-
executor.start().then( () => {
217+
executor.start().then(() => {
217218
this.graphComponent.fitContent();
218219
this.graphComponent.zoom = 1;
219220
});

app/scripts/elements/random/RandomFlowNodeViewModel.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import * as _ from 'lodash';
99

1010
export enum RandomMode {
1111
NUNBER,
12-
NUMBER_ARRAY
12+
NUMBER_ARRAY,
13+
VECTOR3
1314
}
1415

1516
export interface IRandomGenerator {
@@ -37,6 +38,17 @@ export class RandomNumberArrayGenerator implements IRandomGenerator {
3738
}
3839
}
3940

41+
export class Vector3Generator implements IRandomGenerator {
42+
43+
constructor() {
44+
45+
}
46+
47+
generate(amount = 10): string {
48+
return JSON.stringify([Math.random(), Math.random(), Math.random()]);
49+
}
50+
}
51+
4052
export class RandomFlowNodeViewModel extends FlowNodeViewModel {
4153
get mode(): RandomMode {
4254
return this._mode;
@@ -99,13 +111,17 @@ export class RandomFlowNodeViewModel extends FlowNodeViewModel {
99111
case RandomMode.NUMBER_ARRAY:
100112
this.generator = new RandomNumberArrayGenerator();
101113
break;
114+
case RandomMode.VECTOR3:
115+
this.generator = new Vector3Generator();
116+
break;
102117
case RandomMode.NUNBER:
103118
this.generator = new RandomNumberGenerator();
104119
break;
120+
105121
}
106122
this.ticker = setInterval(() => {
107123
this.value = this.generator.generate();
108-
}, 1000);
124+
}, 3000);
109125

110126

111127
} else {

app/scripts/elements/raytrace/RaytraceFlowNodeController.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ export class RaytraceFlowNodeController extends FlowNodeController {
1616
tag: this.viewModel
1717
});
1818

19-
const vmInput = this.viewModel.portViewModels['Input'];
20-
this.ports['Input'] = this.surface.graph.addPort({owner: this.node, locationParameter: FreeNodePortLocationModel.INSTANCE.createParameter( this.node, vmInput.position), style: this.inputStyle, tag: vmInput});
19+
const vmInput = this.viewModel.portViewModels['SurfaceColor'];
20+
this.ports['SurfaceColor'] = this.surface.graph.addPort({owner: this.node, locationParameter: FreeNodePortLocationModel.INSTANCE.createParameter( this.node, vmInput.position), style: this.inputStyle, tag: vmInput});
2121

2222
}
2323

app/scripts/elements/raytrace/RaytraceFlowNodeViewModel.ts

Lines changed: 65 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,35 +4,75 @@ import {PortType} from '../../core/PortType';
44
import {Point} from 'yfiles';
55
import {FlowNodeModel} from '../../core/FlowNodeModel';
66
import * as _ from 'lodash';
7+
import {Material, Vector3} from '../../style/raytracer';
78

89
export class RaytraceFlowNodeViewModel extends FlowNodeViewModel {
910

10-
/**
11-
* Property used by the stream to set the raw data given as string.
12-
* @param arrayAsString {string} Presumably an array of numbers in a string.
13-
*/
14-
public set rawValues(arrayAsString: string) {
15-
const parsed = this.parse(arrayAsString);
16-
if (!_.isNil(parsed)) {
17-
this._values = parsed;
18-
this.update();
19-
this.firePropertyChanged('values');
20-
this.setPropertyValue('values', parsed);
21-
}
11+
get material() {
12+
return new Material(this.surfaceColor, 0.1, 0.05, new Vector3(0.8, 0, 0));
13+
}
14+
15+
get emissionColor(): any {
16+
return this._emissionColor;
17+
}
18+
19+
set emissionColor(value: any) {
20+
value.forEach(this.ensureUnitSize);
21+
this._emissionColor = value;
2222
}
2323

24-
public get values(): number[] {
25-
return this._values;
24+
get reflection(): number {
25+
return this._reflection;
26+
}
2627

28+
set reflection(value: number) {
29+
this.ensureUnitSize(value);
30+
this._reflection = value;
2731
}
2832

33+
get transparency(): number {
34+
return this._transparency;
35+
}
2936

30-
private _values: number[];
37+
set transparency(value: number) {
38+
this.ensureUnitSize(value);
39+
this._transparency = value;
40+
}
41+
42+
get surfaceColor(): any {
43+
return this._surfaceColor;
44+
}
45+
46+
set surfaceColor(value: any) {
47+
if (_.isString(value)) {
48+
const found = this.parseVector3(value);
49+
this._surfaceColor = found;
50+
} else {
51+
value.forEach(this.ensureUnitSize);
52+
this._surfaceColor = new Vector3(value[0],value[1],value[2]);
53+
}
54+
this.firePropertyChanged('surfaceColor');
55+
this.setPropertyValue('surfaceColor', this._surfaceColor);
56+
}
57+
58+
private _surfaceColor: Vector3;
59+
private _transparency: number;
60+
private _reflection: number;
61+
private _emissionColor: Vector3;
62+
63+
private ensureUnitSize(x: number) {
64+
if (_.isNil(x)) {
65+
throw new Error('Nil material value.');
66+
}
67+
if (x < 0.0 || x > 1.0) {
68+
throw new Error('Material values should sit in the [0,1] interval.');
69+
}
70+
}
3171

3272
constructor(model) {
33-
super('Sum', model);
73+
super('Raytracer', model);
3474

35-
this.portViewModels['Input'] = new FlowPortViewModel('rawValues', PortType.INPUT, this, new Point(0.0, 30 - 2));
75+
this.portViewModels['SurfaceColor'] = new FlowPortViewModel('surfaceColor', PortType.INPUT, this, new Point(0.0, 30 - 2));
3676
this.model.nodes[this.id] = new FlowNodeModel(this.id, this.model);
3777

3878
}
@@ -42,14 +82,19 @@ export class RaytraceFlowNodeViewModel extends FlowNodeViewModel {
4282

4383
}
4484

45-
parse(x) {
85+
86+
parseVector3(x: string): Vector3 {
4687
if (_.isString(x)) {
4788
const found = JSON.parse(x);
4889
if (_.isArray(found)) {
49-
return found;
90+
if (found.length !== 3) {
91+
throw new Error('Given string is not a Vector3 type.');
92+
}
93+
found.forEach(this.ensureUnitSize);
94+
return new Vector3(found[0],found[1],found[2]);
5095
}
5196
}
52-
return null;
97+
throw new Error('Expected a Vector3 type.');
5398
}
5499

55100

app/scripts/style/RaytraceNodeStyle.ts

Lines changed: 29 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,36 @@
1-
import {HtmlCanvasVisual, IRenderContext, NodeStyleBase, Point, Rect, SvgVisual} from 'yfiles'
2-
import {} from '../elements/raytrace/RaytraceFlowNodeViewModel';
1+
import {HtmlCanvasVisual, IRenderContext, NodeStyleBase, Rect, SvgVisual} from 'yfiles'
32
import * as _ from 'lodash';
4-
import {Material, RayTracer, roundRect, Scene, Sphere, Vector3} from './raytracer.js'
5-
6-
const margin = {
7-
top: 30,
8-
right: 3,
9-
bottom: -20,
10-
left: 3
11-
};
3+
import {Material, RayTracer, roundRect, Scene, Sphere, Vector3} from './raytracer'
4+
import {RaytraceFlowNodeViewModel} from '../elements/raytrace/RaytraceFlowNodeViewModel';
125

136
export class RaytraceVisual extends HtmlCanvasVisual {
7+
get material(): Material {
8+
return this._material;
9+
}
10+
11+
set material(value: Material) {
12+
this._material = value;
13+
this.sphere.material = value;
14+
}
15+
16+
1417
private rayTracer: RayTracer;
1518

19+
private _material: Material;
20+
private sphere: Sphere;
21+
1622
private getRendering(scaling) {
17-
const buffer = this.rayTracer.render(Math.round(scaling*(105 - 2)), Math.round(scaling * (150 - 12)));
23+
const buffer = this.rayTracer.render(Math.round(scaling * (105 - 2)), Math.round(scaling * (150 - 12)));
1824
return new Uint8ClampedArray(buffer);
1925
}
2026

2127
public layout: Rect;
2228

2329
constructor() {
2430
super();
31+
this._material = new Material(new Vector3(0.100, 0.32, 0.936), 0.1, 0.05, new Vector3(0.8, 0, 0));
2532
const scene = new Scene();
26-
33+
this.sphere = new Sphere(new Vector3(0, -1, -20), 3, this._material);
2734
// add background sphere
2835
scene.add(
2936
new Sphere(new Vector3(10.0, -10004, -20), 10000,
@@ -32,8 +39,7 @@ export class RaytraceVisual extends HtmlCanvasVisual {
3239

3340
// add sphere
3441
scene.add(
35-
new Sphere(new Vector3(0, -1, -20), 3,
36-
new Material(new Vector3(0.100, 0.32, 0.936), 0.1, 0.05, new Vector3(0.8, 0, 0)))
42+
this.sphere
3743
);
3844

3945
// add lights
@@ -48,7 +54,7 @@ export class RaytraceVisual extends HtmlCanvasVisual {
4854

4955
const backgroundColor = new Vector3(0.7, 0.8, 0.9);
5056

51-
// create ray tracer
57+
// create the raytracer
5258
this.rayTracer = new RayTracer(backgroundColor, scene);
5359
}
5460

@@ -59,8 +65,6 @@ export class RaytraceVisual extends HtmlCanvasVisual {
5965
const l = this.layout;
6066
const canvas = renderContext.canvasComponent;
6167
const viewPoint = canvas.viewPoint;
62-
const viewPort = canvas.viewport;
63-
const scaling = 1 / canvas.zoom;
6468

6569

6670
ctx.save();
@@ -73,11 +77,13 @@ export class RaytraceVisual extends HtmlCanvasVisual {
7377

7478
ctx.restore();
7579
const factor = canvas.zoom;
76-
const imageData = ctx.getImageData(l.x, l.y, Math.round(factor*(105 - 2)), Math.round(factor * (150 - 12)));
77-
imageData.data.set(this.getRendering(factor));
78-
// const p = canvas.toViewCoordinates(l)
79-
ctx.putImageData(imageData, canvas.zoom * (-viewPoint.x + l.x), canvas.zoom * (-viewPoint.y + l.y));
80-
// ctx.putImageData(imageData, p.x, p.y);
80+
const im = this.getRendering(factor);
81+
if(!_.isNil(im)){
82+
const imageData = ctx.getImageData(l.x, l.y, Math.round(factor * (105 - 2)), Math.round(factor * (150 - 12)));
83+
imageData.data.set(im);
84+
ctx.putImageData(imageData, canvas.zoom * (-viewPoint.x + l.x + 1), canvas.zoom * (-viewPoint.y + l.y + 1));
85+
}
86+
8187

8288
ctx.save();
8389
roundRect(ctx, l.x, l.y, l.width, l.height, 6, false);
@@ -97,46 +103,6 @@ export class RaytraceVisual extends HtmlCanvasVisual {
97103
ctx.strokeStyle = '#636363';
98104
ctx.lineWidth = 2;
99105
ctx.stroke();
100-
return;
101-
102-
103-
// ctx.translate(this.position.x, this.position.y);
104-
105-
ctx.save()
106-
107-
ctx.translate(viewPoint.x, viewPoint.y);
108-
ctx.scale(scaling, scaling);
109-
// create scene
110-
111-
112-
// get canvas
113-
const canvasWidth = 105;
114-
const canvasHeight = 150;
115-
116-
// save start time
117-
const startTime = Date.now();
118-
// ctx.save();
119-
// ctx.rect(1, 1, 104, 147);
120-
// ctx.clip();
121-
// ctx.fillStyle = '#6A5656';
122-
// ctx.fillRect(0, 0, 105, 150);
123-
124-
125-
ctx.fillStyle = 'green';
126-
ctx.fillRect(0, 0, 110, 20);
127-
128-
ctx.font = '10px sans-serif';
129-
ctx.fillStyle = 'white';
130-
ctx.fillText('Raytrace', 7, 13);
131-
132-
// ctx.restore();
133-
roundRect(ctx, 0, 0, 105, 150, 6, false);
134-
ctx.strokeStyle = '#636363';
135-
ctx.lineWidth = 2;
136-
ctx.stroke();
137-
ctx.restore()
138-
const totalDuration = (Date.now() - startTime) / 1000;
139-
// console.log(`Raytraced in ${totalDuration}s.`)
140106
}
141107

142108
}
@@ -165,6 +131,7 @@ export default class RaytraceNodeStyle extends NodeStyleBase {
165131
updateVisual(renderContext, oldVisual, node) {
166132
const visual = oldVisual as RaytraceVisual;
167133
visual.layout = node.layout;
134+
visual.material = (node.tag as RaytraceFlowNodeViewModel).material;
168135

169136
return visual;
170137
}

0 commit comments

Comments
 (0)