Interactive 3D Graphics

Chris Hill

Wolfram Research, Inc.

Overview

• Primitives

• Colors

• Lighting Model

• Viewing Parameters

• Incorporating interactive elements

Overview

■ Primitives

• Colors

• Lighting Model

• Viewing Parameters

• Incorporating interactive elements

Sphere

Sphere[center,radius]

• Implemented as polygonal approximation of sphere

• Automatic generation of vertex normals for smooth shading

Examples

Graphics3D[Sphere[{0,0,0},1]]

Manipulate[Graphics3D[Sphere[{cx,cy,cz},radius],PlotRange->1],{{cx,0},-1,1},{{cy,0},-1,1},{{cz,0},-1,1},{radius,0.1,1}]

Graphics3D[Table[Sphere[25 Table[Random[],{3}]],{1000}]]

Why have a specialized Sphere primitive?

Dramatically more compact than the specification of the equivalent polygons

• Reduces transmission time from kernel to FE

• Makes Notebook files smaller

• FE has special internal optimizations

SpherePoints

The SpherePoints Method option specifies number of polygons used to approximate sphere.

Manipulate[Graphics3D[Sphere[{0,0,0},r],PlotRange->1,Method->{"SpherePoints"->{long,lat}}],{lat,3,100,1},{long,3,100,1},{r,1,0}]

SpherePoints for Scalability

Cylinder

Cylinder[{{pt1,pt2},radius}]

• Same rationale and benefits as Sphere: efficiency and compactness of specification

• Respects EdgeForm like Cuboid

Examples

Graphics3D[Cylinder[{{0,0,0},{1,1,1}},.1]]

Graphics3D[{EdgeForm[{Orange,Thickness[0.025],Dashing[{0.1}]}],Cylinder[{{0,0,0},{1,1,1}},1]}]

Manipulate[Graphics3D[Cylinder[{{0,0,0},{cx,cy,cz}},radius],PlotRange->1],{{cx,0},-1,1},{{cy,0},-1,1},{{cz,0.5},-1,1},{radius,0.1,1}]

CylinderPoints

The CylinderPoints Method option controls number of polygons used to approximate

Manipulate[Graphics3D[Cylinder[{{0,0,0},{1,1,1}},1],Method->{"CylinderPoints"->{radius,length}}],{radius,3,100,1},{length,3,100,1}]

3D Line and Point rendering

• 3D vertices are used to control positioning and hidden surface removal

• Thickness/PointSize is specified in 2D (proportional to 2D width of graphic)

• Rendering is always perpendicular to viewer

• Rendering of edges (as specified with EdgeForm) is similar to Line.

• If this interpretation of Point and Line is not suitable for your needs, you may want to use Sphere and Cylinder instead

Point Example

pts=Table[Random[],{1000},{3}];
Manipulate[Graphics3D[{
PointSize[size],
Opacity[opacity],
Point[Take[pts,count]]
},SphericalRegion->True,
PlotRange->{{0,1},{0,1},{0,1}}],{{size,0.25},0,0.25},{opacity,1,0},{{count,5},1,1000}]

Line Example

Manipulate[Graphics3D[{Purple,Thickness[thickness],Dashing[{on,off}],Line[{{0,0,0},{1,0,0},{1,1,0},{1,1,1},{0.5,0.5,0.5}}]}],{{thickness,0.05},0.01,0.1},{{on,0.05},0.01,0.1},{off,0.01,0.1}]

Overview

• Primitives

■ Colors

• Lighting Model

• Viewing Parameters

• Incorporating interactive elements

Colors

The Old Way

• Two cases

1.  Lighting->True  use SurfaceColor to set material properties to be used in the lighting equation

2.  Lighting->False use normal color (RGBColor, GrayLevel, Hue) to directly specify final color of primitives

The New Way

• Lighting is always enabled

• Components may be independently specified

• Diffuse Color (RGBColor, etc.)

• Specular Color and Exponent (Specularity)

• Glow Color (Glow)

• SurfaceColor remains for compatibility

• LightSources and AmbientLight options were removed, light sources specification is now given using Lighting option

Where do colors come from?

Primitive level material specification with a directive

Graphics3D[{RGBColor[1,0,0],Polygon[{{0,0,0},{1,0,0},{1,1,0}}]},PlotRange->{-0.1,0.1}]

VertexColors

Graphics3D[Polygon[{{0,0,0},{1,0,0},{1,1,0}},VertexColors->{Red,Green,Blue}],PlotRange->{-0.1,0.1}]

Manipulate[Graphics3D[Polygon[{{0,0,0},{1,0,0},{1,1,0}},VertexColors->{c1,c2,c3}],PlotRange->{-0.1,0.1}],{c1,Red},{c2,Green},{c3,Blue}]

VertexColors

• The color associated with a vertex may be a list which can contain any of the material directives:

{Opacity,RGBColor,GrayLevel,Hue,CMYKColor,Specularity,Glow,SurfaceColor}

Overview

• Primitives

• Colors

■ Lighting Model

• Viewing Parameters

• Incorporating interactive elements

Lighting system overview

Vertex based

Lighting equation is evaluated at each vertex to produce a color.  The resulting color is interpolated between vertices.

Primitive Scoped

The light source specification is an option that can change for different objects in the scene

Basic components in lighting model

The final color at a vertex is the sum of the contributions from the following components

Glow

Color is used exactly as specified. Independent of light sources. Does not "light up" other objects in scene.

Diffuse

Intensity of reflection depends only on the angle between the normal and the direction of the light, the location of the viewer is irrelevant

Manipulate[Graphics[{PointSize[0.05],Point[{0,0}],Arrow[{{0,0},{0,.25}}],Arrow[{{Cos[a],Sin[a]},.75{Cos[a],Sin[a]}}],Red,Rectangle[{-0.05,-0.6},{0.05,-0.6+0.5Max[0,({Cos[a],Sin[a]}.{0,1})]}],FaceForm[None],EdgeForm[Black],Rectangle[{-0.05,-0.6},{0.05,-.1}]},PlotRange->{{-1,1},{-1,1}}],{{a,Pi/2},0,Pi}]

Ambient

Diffuse light that comes from every direction

Manipulate[Graphics[{{Red,Rectangle[{-0.05,-0.6},{0.05,-0.1}],FaceForm[None],EdgeForm[Black],Rectangle[{-0.05,-0.6},{0.05,-.1}]},PointSize[0.05],Point[{0,0}],Arrow[{{0,0},0.25{Cos[a],Sin[a]}}],Table[Arrow[{{Cos[a],Sin[a]},.75{Cos[a],Sin[a]}}],{a,0,2Pi,2Pi/30}]},PlotRange->{{-1,1},{-1,1}}],{{a,Pi/2},-Pi/2,3Pi/2}]

Specular

Shininess which depends both on the direction of the light and the viewer

Graphics3D[{Black,Specularity[White,128],Sphere[{0,0,0}]}]

Plot3D[Sin[x y],{x,0,3},{y,0,3},PlotStyle->{Black,Specularity[White,128]},PlotPoints->100]

Light Types

The Lighting option allows the specification of the following kinds of light sources

• Ambient

• Directional

• Positional

• Spotlight

Factors which affect final color

Surface

Material properties (colors, etc)

Normals

Light

Color

Direction or position

Spotlight cutoff angle and attenuation

Other

Position of viewer

Distance from light to vertex

Spotlights

• Light cone bounded by opening angle

• By default, there is a hard edge at the boundary of the light cone, so there is an exponent factor to smooth the transition

Manipulate[With[{lightpos={x,y,z},lightcenter={cx,cy,cz}},Graphics3D[{EdgeForm[None],{Yellow,PointSize[0.025],Point[lightpos]},{Red,PointSize[0.025],Point[lightcenter]},walls},ViewPoint->{2,1.6,1.9},Lighting->{{White,{{lightpos,lightcenter,{angle,spotexp}},0}}}]],{{x,.7},0.1,1},{{y,.85},0.1,1},{{z,.2},0.1,1},{cx,0.1,1},{cy,0.1,1},{cz,0.1,1},{{angle,π/4},0,π},{spotexp,0,128}]

Light Coordinate Systems

Camera Relative

Positive Z is out of screen. Positive X to the right. Positive Y is up.

Graphics3D[Sphere[{0,0,0}],Lighting->{{Red,ImageScaled[{1,0,0}]}}]

Scene Relative

Same as the coordinates of primitives.

Graphics3D[Sphere[{0,0,0}],Lighting->{{Red,{0,0,1}}}]

Scoped lighting

• Uses a "option directive" syntax to permit changing the light sources

Graphics3D[{White,
Sphere[{0,0,6}],
Lighting->{{Red,ImageScaled[{1,0,0}]}},Sphere[{0,0,4}],
Lighting->{Yellow},Sphere[{0,0,2}],
Lighting->{{Green,{{{0,-2,0},{0,0,0}},0}}},Sphere[{0,0,0}]
},Boxed->False]

• Scoped in the same way as directives

Graphics3D[{White,
Sphere[{0,0,4}],
{Lighting->{Orange},Sphere[{0,0,2}]},
Sphere[{0,0,0}]
},Lighting->{Purple}]

Example

Manipulate[With[{lightpos={x,y,z},lightpos1={x1,y1,z1},lightpos2={x2,y2,z2}},Graphics3D[{EdgeForm[None],{White,Line[{{0,-.1,0.01},{0,1.1,0.01}}],Line[{{1,-.1,0.01},{1,1.1,0.01}}]},{Lighting->{{Red,{{lightpos,{0,0,0}},0}}},{Yellow,PointSize[0.025],Point[lightpos]},floor1},{Lighting->{{Green,{{lightpos1,{0,0,0}},0}}},{Yellow,PointSize[0.025],Point[lightpos1]},floor2},{Lighting->{{Blue,{{lightpos2,{0,0,0}},0}}},{Yellow,PointSize[0.025],Point[lightpos2]},floor3},
{Lighting->{{Red,{{lightpos,{0,0,0}},0}},{Green,{{lightpos1,{0,0,0}},0}},{Blue,{{lightpos2,{0,0,0}},0}}},backsplash}},ViewPoint->{2,1.6,1.9},PlotRange->{{-1,2},{0,1},{0,1}}]],{{y,0.5},0,1},{{z,0.2},0.1,1},{{y1,0.5},0,1},{{z1,0.2},0.1,1},{{y2,0.5},0,1},{{z2,0.2},0.1,1},{{x,0.5},-1,2},{{x1,1.5},-1,2},{{x2,-.5},-1,2}]

Normals

Where do normals come from?

({{Polygon, Automatically generated (face normal) or user supplied (per vertex)}, {Cuboid, Automatically generated face normals}, {Sphere, Automatically generated vertex normals}, {Cylinder, Automatically generated vertex normals}})

• Automatically generated (Sphere, Cylinder, Cuboid, Polygon without VertexNormals specified)

• May be user specified per vertex for Polygon

VertexNormals

Plot3D[Sin[x] Cos[y],{x,-3,3},{y,-3,3},Mesh->False]

Face normals

If VertexNormals are not supplied for Polygon, face normals are computed

<<Graphics`Shapes`

Graphics3D[{EdgeForm[],Torus[]}]

Surfaces are two faced

• All 3D polygonal rendering in Mathematica is two sided

• Directive level face specifications may be different for front and back faces using FaceForm

Graphics3D[{FaceForm[Red,{Blue,Opacity[0.3]}],Polygon[{{0,0,0},{1,0,0},{1,1,0},{0,1,0}}],Green,Sphere[{0.5,0.5,-1},0.1],Sphere[{0.5,0.5,1},0.1]}]

Opacity

Based on simple two dimensional compositing logic, not any optical properties of light.

Manipulate[Graphics[{background,Rectangle[{0,0}],Blend[{foreground,background},opacity],Rectangle[{1,0}],foreground,Rectangle[{2,0}]}],{background,Red},{foreground,Blue},{opacity,0,1},ControlType->{Color,Color,Slider}]

Graphics3D[{Opacity[0.8],Red,Sphere[{0,0,0}],Green,Sphere[{1,0,0}],Blue,Sphere[{0.5,1,0}]}]

VertexColor opacity multiplies with primitive level opacity

Manipulate[Graphics3D[{Opacity[primitiveOpacity],Polygon[{{0,0,0},{1,0,0},{1,1,0},{0,1,0}},VertexColors->{Opacity[vertexOpacity],Black,Black,Black}]}],{{primitiveOpacity,1},0,1},{{vertexOpacity,1},0,1}]

Non-Convex Polygon Rendering

Non-convex

Graphics3D[Polygon[{{0,0,0},{1,0,0},{1,2,0},{3,2,0},{3,3,0},{1,3,0},{1,5,0},{0,5,0},{0,3,0},{-2,3,0},{-2,2,0},{0,2,0}}]]

Self-intersecting

Graphics3D[Polygon[p=Table[{Cos[a],Sin[a],0},{a,0,2Pi,2Pi/5}];p[[#]]&/@{1,3,5,2,4},VertexColors->Table[Hue[Random[]],{5}]]]

Overview

• Primitives

• Colors

• Lighting Model

■ Viewing Parameters

• Incorporating interactive elements

Symbolic ViewPoint

• Symbolic names for above, below, front, back, left, right

Manipulate[Show[ship,ViewPoint->viewpoint],{viewpoint,{Above,Below,Front,Back,Left,Right}}]

Orthographic Projection

• Removes foreshortening associated with the usual perspective projection

• For each of the symbolic viewpoints, there is a corresponding orthographic form for a parallel projection

({{Above, {0,0,Infinity}}, {Below, {0,0,-Infinity}}, {Front, {0,Infinity,0}}, {Back, {0,-Infinity,0}}, {Left, {Infinity,0,0}}, {Right, {-Infinity,0,0}}})

Manipulate[Graphics3D[{Polygon[{{0,-1,0},{1,-1,0},{1,2,0},{0,2,0}}],Polygon[{{0,-1,1},{1,-1,1},{1,2,1},{0,2,1}}]},PlotRange->{{-1,2},{-1,2},{-1,2}},ViewPoint->viewpoint],{viewpoint,{Front,{0,Infinity,0},{0,0,Infinity},{Infinity,0,0}}}]

• Orthographic projections which are from directions other than axis aligned directions are specified using ProjectionMatrix

ViewVector

• Overrides ViewPoint (and possibly ViewCenter)

• Specified in plot coordinates rather than a scaled coordinate system

ViewVector->fromPt or ViewVector->{fromPt, toPt}

• Convenient for flying past scenes since coordinates match the graphics data

ViewAngle

• Controls the field of view

• Narrowing the angle produces a zoom effect, widening the angle captures more of the surroundings

Manipulate[Graphics3D[{Sphere[{-3,-3,0}],Sphere[{0,0,0}],Sphere[{3,3,0}]},SphericalRegion->True,ViewAngle->viewangle],{{viewangle,0.5},0.1,Pi-0.1}]

ViewMatrix and ProjectionMatrix

• Rather than specifying various view parameters, users may specify two matrices

• Overrides ViewPoint, ViewCenter, ViewVector

ViewMatrix

Takes coordinates from the PlotRange coordinate system to an eye/camera relative coordinate system.  Various tasks such as lighting may be performed in this eye relative coordinate space.

ProjectionMatrix

Takes coordinates from the eye relative coordinate system to a 2D screen coordinate space (with Z coordinate)

Overview

• Primitives

• Colors

• Lighting Model

• Viewing Parameters

■ Incorporating interactive elements

Tooltip and Mouseover

Tooltip and Mouseover can be used in 3D

Graphics3D[{Red,Tooltip[Polygon[{{0,0,0},{1,1,0},{1,1,1}}],Row[{"Red",Graphics[{Red,Disk[{0,0}]},ImageSize->50]}]],Green,Tooltip[Polygon[{{0,0,0},{1,0,1},{1,0,0}}],Row[{"Green",Graphics[{Green,Disk[{0,0}]},ImageSize->50]}]],Blue,Tooltip[Polygon[{{0,0,0},{0,1,0},{0,1,1}}],Row[{"Blue",Graphics[{Blue,Disk[{0,0}]},ImageSize->50]}]],Mouseover[{Black,Polygon[{{0,0,0},{1,0,0},{1,1,0},{0,1,0}}]},{Yellow,Polygon[{{0,0,0},{1,0,0},{1,1,0},{0,1,0}}]}]}]

MousePosition

MousePosition["Graphics"] gives intersection points with near and far planes for Graphics3D objects

Column[{Dynamic[MousePosition["Graphics"]],Row[{Graphics3D[{Dynamic[Module[{pos=MousePosition["Graphics"]},{Thickness[0.1],Sphere[pos[[1]]+1pos[[2]],0.1],Sphere[pos[[1]]+2pos[[2]],0.3]}]]},PlotRange->1],Graphics3D[{Dynamic[Module[{pos=MousePosition["Graphics"]},{Thickness[0.1],Sphere[pos[[1]]+1pos[[2]],0.1],Sphere[pos[[1]]+2pos[[2]],0.3]}]]},PlotRange->1,ViewPoint->{1,1,1}]}]}]

Summary

• Primitives

• Colors

• Lighting Model

• Viewing Parameters

• Incorporating interactive elements

Related Talks

Implementation

FloorWall[div_,extent_]:=Module[{step=N[extent/(div-1)]},Polygon[Flatten[Table[{{i,j,0.},{i+step,j,0.},{i+step,j+step,0.},{i,j+step,0.}},{i,0.,extent-step/2,step},{j,0.,extent-step/2,step}],1]]];

Swap[e_,{a_,b_,c_}]:=(e/.v:{__Real}:>{v[[a]],v[[b]],v[[c]]});

TransX[e_,off_]:=(e/.{u_Real,v_Real,w_Real}:>{u+off,v,w});

Trans[e_,off_]:=(e/.{u_Real,v_Real,w_Real}:>{u,v,w}+off);

Scal[e_,s_]:=(e/.{u_Real,v_Real,w_Real}:>{u,v,w}*s);

makeFloor[div_,extent_]:=Module[{},
floor1=TransX[FloorWall[div,extent],0];
floor2=TransX[FloorWall[div,extent],extent];
floor3=TransX[FloorWall[div,extent],-extent];
backsplash=Trans[Scal[Swap[FloorWall[div,extent],{1,3,2}],{3,1,1}],{-1,0,0}]];

makeFloor[15,1];

ThreeWalls[div_,extent_]:=Swap[FloorWall[div,extent],#]&/@{{1,2,3},{2,3,1},{3,2,1}};

ThreeFloors[div_,extent_]:=TransX[FloorWall[div,extent],#]&/@{0,extent,-extent};

walls=ThreeWalls[50,1];

ship=Graphics3D[{EdgeForm[],Polygon[Identity@@#&/@Cases[,Polygon[___],Infinity]]},Boxed->False,Background->Black];