Assignment 11
Transfer Functions
Due: Apr. 27, 2020 03:29:59 PM
Graded: May. 04, 2020
Percentage of Grade: 5%
Assignment Description: Finalized
- Objectives
- Description
- Part 1: Implementing Color Transfer Functions
- Part 2: Implementing Opacity Transfer Functions
- Submission
- Grading
- Extra Credit
In this assignment, you will write code to visualize three-dimensional scalar fields through the use of volume rendering. We will rely on a volume renderer from the VTK library.
Please click here to create your repository
Objectives
This assignment is designed to teach more advanced scalar field visualization through understanding how transfer functions work, utilizing a mapping from data values to optical properties. Specific objectives include:
- Utilizing transfer functions to specify the input to a volume renderer.
- Implementing an interface to specify transfer functions using d3.js.
- Understanding how interacting with a transfer function can be used to investigate volumetric data
- Experimenting with your designed transfer functions to investigate three-dimensional scalar fields.
Description
In this assignment, we will be utilizing volumetric scalar fields. Your template repo includes four example scalar fields in the datasets
directory. These are encoded as a .vti
(VTK ImageData) format, which will be parsed for you using the vtk.js library. This library will also do the heavy lifting of computing the volume rendered image. Your main task is to build an interface in d3.js to design the transfer functions that vtk.js will adjust how the final image looks.
We have provided a significant amount of skeleton code for you in volren.js
as well as a11.js
. volren.js
should not need to be edited. It includes two functions initializeVR()
and updateVR()
that will be create a volume rendering canvas as well as update it with modified transfer functions.
The template html file, index.html
, is set up so that it has two different div
’s, one for the volume renderer, with id volren
, and one for the transfer function editor, with id tfunc
. tfunc
will ultimately contain and SVG that you specify using d3.js.
Your transfer function editor should be designed to modify and visualize the contents of two variables: colorTF
and opacityTF
, both declared in a11.js
. To accomplish this, you will use d3.js to populate the contents of an SVG objects stored in the div tfunc
.
Both transfer functions will be encoded as a simple list of pairs of the format [t, val]
where t
is a particular scalar value and val
is either an opacity (between \([0,1]\)) or a color (specified as a d3.rgb()
object). These pairs are control points that VTK will linearly interpolate for you to define the appropriate color (emission) and opacity (absorption) values for any scalar value.
Part 1: Implementing Color Transfer Functions
First, you will implement three different color transfer functions. These can be selected by the user by pressing a button in index.html
(we’ve provided an example of one such button for you, you should add two more).
For each button press, you should update the variable colorTF
and populate it with a color transfer function that you specify in a11.js
. There should be three types, based on a sequential color map of your choice, a diverging color map of your choice, and a categorical color map of your choice. You are welcome to specify these as a manual list, but you may also want to use many of the predefined color maps that d3 constructors for you. See d3-scale-chromatic for many examples here.
Specifying a color transfer function requires two pieces. You must: (1) specify the variable colorScale
that will be used to interpolate color for your interface and (2) specify the variable colorTF
that will be a list of colors you pass to VTK.
Your specification should cover the full range of data values. When the input dataset is loaded by the function initializeVR
, it will populate a global variable dataRange
with the minimum (dataRange[0]
) and maximum (dataRange[1]
) of the dataset. You should use this to specify a list of color values in colorTF
.
For the sequential scale, the colorTF
you specify must correspond to a sequential color map. I recommend using at least a few control points for this (d3.schemeXXX allows you to design a variety of scales this way, typically using 3 to 9 control points). One way to do this is use the function makeSequential()
to both update colorScale
and then use the updated colorScale
to specify a list of points for colorTF
.
The diverging scale should be constructed similarly, except using a diverging color map.
The categorical scale can be used to provide a coarse set of labels to different ranges of scalar values. To do this, instead of using a d3.scaleLinear
, I used a d3.scaleQuantize
with an appropriate categorical color scheme.
Once a new color transfer function is specified, you should update the visualization of the interface by calling updateTFunc()
and update the transfer function with the volume renderer by calling updateTF
. Note that, when using a categorical color map, you should set the optional third parameter of updateTF()
to true
. When set to false
, it forces VTK to linearly interpolate the color map, when set to true
, it will use nearest neighbor interpolation, and when undefined, it will keep the current state.
Finally, after implementing these three variants for color maps, you should generate a visualization that shows them in the tfunc
view. I did this using a simple color bar (a list of rectangles) which was sampled across the dataRange
and populating their fill color with colorScale
. I also provided a horizontal axis that indicated the domain of the transfer function and aligned with the color bar (this made use of the xScale
variable described below).
Part 2: Implementing Opacity Transfer Functions
Your opacity transfer function should be specified by a list of control points in the variable opacityTF
. Like the color transfer functions, this list will be based to VTK to control the volume rendering process. However, your interface for editing it should be more sophisticated than simple pre-defined transfer functions that are loaded by buttons.
Specifically, you will implement an editable curve interface for this. You should initialize opacityTF
with at least five control points. Each of these will be visualized by drawing a polyline where you can drag the corners of the polyline to update the control points of opacityTF
. This will require two scales, xScale
and yScale
that will map from data attributes to screen space. Specifically, xScale
should map from the range of data values and yScale
should map from the space of possible opacities (\([0,1]\)).
To draw an editable curve, we will draw both a polyline as well as a set of discrete circles. The circles will be hooked to a d3 drag interface, specified by 3 functions for the start, movement, and end of a drag event. The start event will set a variable selected
for which control point is selected, which we do using a variable index
. The drag event should access the position of the mouse and update opacityTF
as the mouse moves. When this happens, you should then update both the visualization of the polylne by calling updateTFunc()
and update the volume renderer by calling updateVR
. You might find this example of a line chart with draggable circles particularly helpful.
When editing the curve, you must handle two special cases. First, if the point being dragged is one of the endpoints of the curve, you should only allow it to move up or down. This will ensure that all possible scalar values have a defined opacity. Second, when moving an interior point to the polyline, you not allow it to move so far left or right so as to cross the point before or after it in the curve. Both of these constraints can be checked by looking at the value pos
defined in the function dragged()
. All points must only be allowed to be moved within the range of valid control points. All \(x\)-coordinates must lie within dataRange
and all \(y\)-coordinates must lie within \([0,1]\).
When moving points, I also changed their fill color to represent the color specified by colorScale
. This isn’t required, but I found it added some context to which opacity values were mapped to which colors.
Submission
You should use git to submit all source code files. The expectation is that your code will be graded by cloning your repo and then executing it within a modern browser (Chrome, Firefox, etc.)
Please provide a README.md
file that provides a text description of how to run your program and any parameters that you used. Also document any idiosyncrasies, behaviors, or bugs of note that you want us to be aware of.
To summarize, my expectation is that your repo will contain:
- A
README.md
file - A
index.html
file - An
a11.js
file - All other Javascript files necessary to run the code (including
volren.js
,vtk.js
, andd3.v5.js
plus any others you require) - Any
.css
files containing style information
Grading
Deductions
Reason | Value |
Bugs or syntax errors | -10 each bug at grader's discretion to fix |
Point Breakdown of Features
Requirement | Value | ||||||||||||||||
Consistent modular coding style | 5 | ||||||||||||||||
External documentation (README.md) following the template provided in the base repository | 5 | ||||||||||||||||
Header documentation, Internal documentation (Block for functions and Inline descriptive comments). Wherever applicable / for all files | 10 | ||||||||||||||||
Expected output / behavior for your chart based on the assignment specification, including
| 80 | ||||||||||||||||
Total | 100/100 |
Cumulative Relationship to Final Grade
Worth 5% of your final grade
Extra Credit
Implementing features above and beyond the specification may result in additional extra credit, please document these in your README.md. Particularly, you may want to consider additional user interface features that allow you to inspect and/or edit the transfer fucntion.
Instead of using buttons to specify the color transfer function, you are welcome to consider a more sophisticated interface when the user can design a color transfer function. Depending on the sophistication level, this is worth as much as 50% extra credit. If you choose to implement such an interface, you need not support the button-based selection, provided they support designing colorTF
’s which are equally or more sophisticated.