3D Graphics

Yuzhu Lu, Wolfram Research, Inc.

Join the Conversation #ArmeniaWTC2017

Something New in Experimental Stage:

Single Pass Depth Peeling

Stereoscopic

Non-Photorealistic Rendering

Surface Appearance

GLView

Single Pass Depth Peeling

Why 3D Transparency Rendering is So Expensive?

BSPTree---Split and Sort before Rendering

Multiple Pass Depth Peeling---Render One Layer Each Pass

Single Pass Depth Peeling---Rendering All Layers in One Pass

User can set it with SetOptions

SetOptions[$FrontEnd,RenderingOptions->{"3DRenderingMethod"->"HardwareSinglePassDepthSorting"}]

User can also set it with Option Inspector: Graphics Options / RenderingOptions / “3DRenderingMethod”

drg=Import["dragon.obj","GraphicsComplex"];

Graphics3D[{Blue,Opacity[0.5],EdgeForm[],drg},ImageSize->Large,Method->{"RotationOptimization"->False},BaseStyle->{RenderingOptions->{"3DRenderingMethod"->"BSPTree","3DRenderingEngine"->"OpenGL"}},PlotLabel->"BSPTree"]

Graphics3D[{Yellow,Opacity[0.5],EdgeForm[],drg},ImageSize->Large,Method->{"RotationOptimization"->False},BaseStyle->{RenderingOptions->{"3DRenderingMethod"->"HardwareDepthPeeling","3DRenderingEngine"->"OpenGL"}},PlotLabel->"HardwareDepthPeeling"]

Graphics3D[{Green,Opacity[0.5],EdgeForm[],drg},ImageSize->Large,Method->{"RotationOptimization"->False},BaseStyle->{RenderingOptions->{"3DRenderingMethod"->"HardwareSinglePassDepthSorting","3DRenderingEngine"->"OpenGL"}},PlotLabel->"HardwareSinglePassDepthSorting"]

Grid[{{,"BSPTree","Multiple Pass Depth Peeling","Single Pass Depth Peeling"},{,"Not Responding","2 fps","10 fps"}},Frame->All,ItemStyle->{Automatic,Automatic,{{{1,1},{1,4}}->{Bold,16,RGBColor[0,0,0.8]}}}]

Build-In Stereoscopic

Be Aware:

1. Work with all 3D Graphics
2. Windows Only
3. Direct3D 11.1 Support
4. Hardware Requirements

Graphics3D[{Specularity[White,30],Raster3D[RawArray["Byte",Import["ExampleData/CThead.tiff","Data"]],{{-1,-1,-1},{1,1,1}},{0,255},ColorFunction->(Blend[{{0, RGBColor[0.035,0.058,0,0]},{0.1, RGBColor[0.015,0,0.035,0]},{0.2, RGBColor[0,0,0,0.032]},{0.3, RGBColor[0.103,0.032,0,0]},{0.4, RGBColor[0,0,0,0]},{0.5, RGBColor[0.202,0.203,0.218,0.337]},{0.6, RGBColor[0.9,0.9,0.9,0.457]},{0.7, RGBColor[0.98,0.97,1,0.682]},{0.8, RGBColor[1,1,1,0.794]},{0.9, RGBColor[0.95,0.97,0.95,0.842]},{1, RGBColor[1,1,1,0.962]}}, #] &),Method->{ "VolumeLighting"->"EnhancedEdge","InterpolateValues"->True}]},ViewPoint->{-3.2,0.89,-0.34},Lighting->{{"Directional",White,ImageScaled[{0,0,2}]}}]

Non-Photorealistic Rendering

What is NPR Rendering

Ink Outlines

FE`Evaluate@Evaluate[FEPrivate`AddSurfaceAppearanceDefinition["NPRSilhouetteOutlines",{{"position","ATTRIB_VERTEX"},{"normal","ATTRIB_NORMAL"}},{{"WVPMatrix","worldViewProjectionMatrix",Automatic,"WORLDVIEWPROJECTIONMATRIX"},{"WVITMatrix","worldViewITMatrix",Automatic,"WORLDVIEWITMATRIX"},{"OutlineColor","outlineColor",RGBColor[{0.0,0.0,0.0,1}],"COLOR"},{"OutlineThickness","outlineThickness",0.3,"NUMBER"}},{"uniform vec4 outlineColor; uniform float outlineThickness; varying float intensity; void main() { float fading = 3*sin(intensity); if(intensity < outlineThickness) gl_FragColor = vec4(outlineColor.r*(1.0-fading)+fading, outlineColor.g*(1.0-fading)+fading, outlineColor.b*(1.0-fading)+fading, 1.0); else gl_FragColor = vec4(1.0,1.0,1.0,1.0);}","attribute vec4 position; attribute vec4 normal; uniform mat4 worldViewProjectionMatrix; uniform mat4 worldViewITMatrix; varying float intensity; void main() { gl_Position = worldViewProjectionMatrix * position; vec4 TransformedNormal = worldViewITMatrix * normal; vec3 lightDir = vec3(0.0, 0.0, -1.0); intensity = dot(normalize(TransformedNormal.xyz), lightDir); }"}]];

data2=First@ExampleData[{"Geometry3D","Cow"}];
Graphics3D[{System`SurfaceAppearance["NPRSilhouetteOutlines"],data2},Boxed->False]

Graphics3D[{SurfaceAppearance["NPRSilhouetteOutlines","OutlineColor"->Red],data2},Boxed->False]

Graphics3D[{SurfaceAppearance["NPRSilhouetteOutlines"],First@ExampleData[{"Geometry3D","Tugboat"}]},Boxed->False]

Toon

FE`Evaluate@Evaluate[FEPrivate`AddSurfaceAppearanceDefinition["NPRToon",{{"position", "ATTRIB_VERTEX"}, {"normal", "ATTRIB_NORMAL"}},{{"WVPMatrix","worldViewProjectionMatrix",Automatic,"WORLDVIEWPROJECTIONMATRIX"},
{"WVITMatrix","worldViewITMatrix",Automatic,"WORLDVIEWITMATRIX"},{"AmbientColor","uAmbientColor",RGBColor[{0.25,0.25,0.25,1}],"COLOR"},{"LightingDirection","uLightingDirection",{-1,-1,-1},"NUMBER3"},{"DirectionalColor","uDirectionalColor",RGBColor[{0.5,0.5,0.5,1}],"COLOR"},{"ToonColor1","toonColor1",RGBColor[{0.804,0.796,0.807,1.0}],"COLOR"},{"ToonColor2","toonColor2",RGBColor[{0.4,0.4,0.8,1.0}],"COLOR"},{"ToonColor3","toonColor3",RGBColor[{0.2,0.2,0.4,1.0}],"COLOR"},{"ToonColor4","toonColor4",RGBColor[{0.086,0.094,0.07,1.0}],"COLOR"}},{"varying float intensity; uniform vec4 toonColor1; uniform vec4 toonColor2; uniform vec4 toonColor3; uniform vec4 toonColor4; void main() {  if(intensity > 0.95) gl_FragColor = toonColor1;  else if(intensity > 0.35)  gl_FragColor = toonColor2; else if(intensity > 0.05)  gl_FragColor = toonColor3; else  gl_FragColor = toonColor4;}","attribute vec4 position; attribute vec4 normal; uniform mat4 worldViewProjectionMatrix; uniform mat4 worldViewITMatrix; uniform vec4 uAmbientColor; uniform vec3 uLightingDirection; uniform vec4 uDirectionalColor; varying float intensity; void main() { gl_Position = worldViewProjectionMatrix * position; vec4 TransformedNormal = worldViewITMatrix * normal; vec3 lightDir = normalize(uLightingDirection); intensity = dot(normalize(TransformedNormal.xyz), lightDir); }"}]];

Graphics3D[{SurfaceAppearance["NPRToon"],data2}]

Graphics3D[{System`SurfaceAppearance["NPRToon","ToonColor1"->RGBColor[1,1,1,1],"ToonColor2"->RGBColor[0.48,0.8,0.137,1],"ToonColor3"->RGBColor[0.247,0.7,0.188,1],"ToonColor4"->RGBColor[0.06,0.55,0.216,1],"LightingDirection"->{-1,1,-1.5}],Sphere[],System`SurfaceAppearance["NPRToon","ToonColor1"->RGBColor[1,1,1,1],"ToonColor2"->RGBColor[0.996078431372549`,1.`,0.3529411764705882`,1],"ToonColor3"->RGBColor[0.8941176470588235`,0.8980392156862745`,0.34901960784313724`,1],"ToonColor4"->RGBColor[0.7686274509803921`,0.7686274509803921`,0.4`,1],"LightingDirection"->{-1,1,-1.5}],Cone[{{-2,-2,-1},{-2,-2,1}}]}]

2D Sketch

Apply sketch to fonts:

pattern = Image@Rasterize@Graphics[Line[Table[{{0,a},{1,1+a}},{a,-1,2,0.1}]],PlotRange->{{0,1},{0.5,1.5}},ImageSize->200];
text=First[First[ImportString[ExportString[Style["Wolfram",Italic,FontSize->24,FontFamily->"Times"],"PDF"],"PDF","TextMode"->"Outlines"]]];
Graphics[{EdgeForm[Black],Texture[pattern],text}]/.FilledCurve[a_,b_]:>FilledCurve[a,b, VertexTextureCoordinates->b]

Apply sketch to any Graphics:

Graphics[{Texture[pattern],First@First@ImportString[ExportString[Graphics[[[1]], ImageSize->{20,20}],"PDF"],"PDF","TextMode"->"Outlines"]/.{JoinedCurve[{{{0,2,0},{0,1,0},{0,1,0}}},{{{0.,20.},{20.,20.},{20.,0.},{0.,0.}}},op_]->{}}}]/.JoinedCurve[a_,b_,c_]:>FilledCurve[a,b, VertexTextureCoordinates->b/5]

convertedGraphics=First@First@ImportString[ExportString[Graphics[{Red,Disk[{0,0},100],Green,Rectangle[{0,0},{200,200}],Blue,Disk[{200,200},100]},ImageSize->{20,20}],"PDF"],"PDF","TextMode"->"Outlines"]/.FilledCurve[{{{0,2,0},{0,1,0},{0,1,0}}},{{{0.`,0.`},{20.`,0.`},{20.`,20.`},{0.`,20.`}}}]->{};
Graphics[{EdgeForm[Black],Texture[pattern],convertedGraphics}]/.FilledCurve[a_,b_]:>FilledCurve[a,b, VertexTextureCoordinates->b]

3D Sketch

FE`Evaluate@Evaluate[FEPrivate`AddSurfaceAppearanceDefinition["NPR3DSktech",{{"position", "ATTRIB_VERTEX"}, {"normal", "ATTRIB_NORMAL"}, {"vertexTextureCoordIn", "ATTRIB_TEXTURECOORD"}},{{"WVPMatrix","worldViewProjectionMatrix",Automatic,"WORLDVIEWPROJECTIONMATRIX"},
{"WVITMatrix","worldViewITMatrix",Automatic,"WORLDVIEWITMATRIX"},{"Texture2D","texture",Automatic,"TEXTURE"},{"LightingDirection","uLightingDirection",{-1,1,-1},"NUMBER3"},{"SketchColor","uSketchColor",RGBColor[{0.5,0.5,0.5,1}],"COLOR"}},{"varying vec4 texCoordOut; varying float intensity; uniform vec4 uSketchColor; uniform sampler2D texture;  void main() {  vec2 uv = texCoordOut.xy; if(intensity > 0.7) {uv.y = uv.y/3.0+0.66; gl_FragColor = texture2D(texture,uv.xy)+vec4(intensity/1,intensity/1,intensity/1,1);}  else if(intensity > 0.45)  {uv.y = uv.y/3.0+0.66; gl_FragColor = texture2D(texture,uv.xy)+vec4(intensity/1.5,intensity/1.5,intensity/1.5,1);} else if(intensity > 0.05)  {uv.y = uv.y/3.0 + 0.33; gl_FragColor = texture2D(texture,uv.xy)+vec4(intensity/1.5,intensity/1.5,intensity/1.5,1);} else  {uv.y = uv.y/3.0; gl_FragColor = texture2D(texture,uv.xy);} }","attribute vec4 position; attribute vec4 normal; attribute vec4 vertexTextureCoordIn; uniform mat4 worldViewProjectionMatrix; uniform mat4 worldViewITMatrix; uniform vec3 uLightingDirection; varying vec4 texCoordOut; varying float intensity; void main() { gl_Position = worldViewProjectionMatrix * position; texCoordOut = vertexTextureCoordIn; vec4 TransformedNormal = worldViewITMatrix * normal; vec3 lightDir = normalize(uLightingDirection); intensity = dot(normalize(TransformedNormal.xyz), lightDir); }"}]];

Sketch3DRendering[g_,sketchStyle_]:=g/.Texture[a_]:>Directive[System`SurfaceAppearance["NPR3DSktech"],Texture[sketchStyle]]

Sketch3DRendering[Graphics3D[{Specularity[White,20],Texture[{}],EdgeForm[Opacity[1/10]],(Append[#1,{VertexTextureCoordinates->With[{n=Length[First[#1]]},Table[1/2 {Cos[2 π i/n],Sin[2 π i/n]}+{1/2,1/2},{i,0,n-1}]]}]&)/@Flatten[PolyhedronData["RhombicHexecontahedron","Faces","Polygon"]]},Boxed->False],]

Sketch3DRendering[ParametricPlot3D[{Cos[u] (3+Cos[v]),Sin[u] (3+Cos[v]),Sin[v]},{u,0,2 π},{v,0,2 π},TextureCoordinateFunction->({2*#4,#5}&),PlotStyle->Directive[Texture[{}]],Axes->False,Lighting->"Neutral",Mesh->None,Boxed->False,ImageSize->300],#]&/@{,}

Sketch3DRendering[SphericalPlot3D[1 ,{u,0,Pi},{v, 0,2Pi}, Mesh->None,TextureCoordinateFunction->({#5,(1-#4)}&),PlotStyle->Directive[Texture[{}]],Axes->False,Boxed->False,ViewPoint->{-1.76,-2.74,0.89},ViewVertical->{-0.798,-0.019,0.6},ImageSize->300],#]&/@{,}

SurfaceAppearance

1. Customize Your Own Rendering With Shaders

2. Work with both Graphics and Graphics3D

3. Supported everywhere on all platforms with all drivers including Mesa
4. GLSL 1.2 standard

2D Examples

Customized Image Processing with GPU

FE`Evaluate@Evaluate[FEPrivate`AddSurfaceAppearanceDefinition["My Edge3",{{"position", "ATTRIB_VERTEX"}, {"vertexTextureCoordIn", "ATTRIB_TEXTURECOORD"}},{{"TMatrix","tranformationMatrix",Automatic,"TRANSFORMMATRIX"},{"Color","color",Yellow,"COLOR"},{"Texture2D","texture",Automatic,"TEXTURE"},{"Size","size",360,"NUMBER"}},{"varying vec4 texCoordOut; uniform vec4 color; uniform sampler2D texture; uniform float size; void main() { float offset=1.0/size;vec4 c=texture2D(texture,texCoordOut.xy); vec4 edge=texture2D(texture,texCoordOut.xy+vec2(-offset,-offset))+texture2D(texture,texCoordOut.xy+vec2(-offset,0.0))+texture2D(texture,texCoordOut.xy+vec2(-offset,offset))+texture2D(texture,texCoordOut.xy+vec2(0.0,offset))+texture2D(texture,texCoordOut.xy+vec2(offset,offset))+texture2D(texture,texCoordOut.xy+vec2(offset,0.0))+texture2D(texture,texCoordOut.xy+vec2(offset,-offset))+texture2D(texture,texCoordOut.xy+vec2(0.0,-offset));gl_FragColor=8.0*(c - 0.125*edge);gl_FragColor.a = 1.0; gl_FragColor *= color;}","attribute vec4 position; attribute vec4 vertexTextureCoordIn; uniform mat4 tranformationMatrix; varying vec4 texCoordOut; void main() { gl_Position = tranformationMatrix * position; texCoordOut = vertexTextureCoordIn;}"}]];

img=ExampleData[{"TestImage","Lena"}];
Manipulate[Graphics[{System`SurfaceAppearance["My Edge3","Color"->Dynamic@c],Texture[img],Polygon[{{-1,-1},{1,-1},{1,1},{-1,1}},VertexTextureCoordinates->{{0,0},{1,0},{1,1},{0,1}}]},ImageSize->{360,360},Frame->True],{c,White},ControlPlacement->Top]

GPGPU and Visualization: Julia Factor

FE`Evaluate@Evaluate[FEPrivate`AddSurfaceAppearanceDefinition["My GPGPU3",{{"position", "ATTRIB_VERTEX"}, {"vertexColor", "ATTRIB_COLOR"}},{},{"varying vec2 vPosition;  varying vec2 vJuliaPosition;  void main()  { float cx=vJuliaPosition.x;  float cy=vJuliaPosition.y;  float x=vPosition.x;  float y=vPosition.y;  float hue;  const float saturation=0.6;  const float value=1.0;  float hueRound;  int hueIndex;  float f;  float p;  float q;  float t;  float vel;  float x2=x*x;  float y2=y*y;  float tempX=0.0;  int i=60;  int runaway=0; for (int iter = 0; iter < 60; iter++) { tempX = x2 - y2 + cx; y = 2.0 * x * y + cy; x = tempX; x2 = x * x; y2 = y * y; vel = x2 + y2; if(vel > 10000.0) { i = iter; runaway = 1; break;}} if(runaway == 1)  {hue=(float(i)-log(vel)/9.21)/70.0;  hueRound=hue*6.0; hueIndex=int(mod(float(int(hueRound)),6.0)); f=fract(hueRound); p=value*(1.0-saturation); q=value*(1.0-f*saturation); t=value*(1.0-(1.0-f)*saturation);if (hueIndex == 0) gl_FragColor=vec4(value,t,p,1.0);else if (hueIndex == 1) gl_FragColor=vec4(q,value,p,1.0);else if (hueIndex == 2) gl_FragColor=vec4(p,value,t,1.0);else if (hueIndex == 3) gl_FragColor=vec4(p,q,value,1.0);else if (hueIndex == 4) gl_FragColor=vec4(t,p,value,1.0);else if (hueIndex == 5) gl_FragColor=vec4(value,p,q,1.0);} else gl_FragColor=vec4(0.0,0.0,0.0,1.0);}","attribute vec4 position; attribute vec4 vertexColor; varying vec2 vPosition;  varying vec2 vJuliaPosition;   void main() { gl_Position = vec4(position.xy, 1, 1); vPosition = position.xy * vec2(1.7, 1.2); vJuliaPosition = (vertexColor.xy - 0.5)*2.0;}"}]];

Manipulate[Graphics[{System`SurfaceAppearance["My GPGPU3"],Polygon[{{1.01,1.01},{-1.01,1.01},{-1.01,-1.01},{1.01,-1.01}},VertexColors->{RGBColor[{0.5 +0.5*Sin[0.7*(Dynamic[t]+Sin[Dynamic[t]*0.27]*(Sin[Dynamic[t]*0.55]*0.4+0.4))],0.5 +0.5*Sin[Dynamic[t]+Sin[Dynamic[t]*0.27]*(Sin[Dynamic[t]*0.55]*0.4+0.4)],0,1} ],RGBColor[{0.5 +0.5*Sin[0.7*(Dynamic[t]+Sin[Dynamic[t]*0.27+1.57]*(Sin[Dynamic[t]*0.55]*0.4+0.4))],0.5 +0.5*Sin[Dynamic[t]+Sin[Dynamic[t]*0.27 +1.57]*(Sin[Dynamic[t]*0.55]*0.4+0.4)],0,0}],RGBColor[{0.5 +0.5*Sin[0.7*(Dynamic[t]+Sin[Dynamic[t]*0.27+3*1.57]*(Sin[Dynamic[t]*0.55]*0.4+0.4))],0.5 +0.5*Sin[Dynamic[t]+Sin[Dynamic[t]*0.27 +3*1.57]*(Sin[Dynamic[t]*0.55]*0.4+0.4)],0,1} ],RGBColor[{0.5 +0.5*Sin[0.7*(Dynamic[t]+Sin[Dynamic[t]*0.27+2*1.57]*(Sin[Dynamic[t]*0.55]*0.4+0.4))],0.5 +0.5*Sin[Dynamic[t]+Sin[Dynamic[t]*0.27 +2*1.57]*(Sin[Dynamic[t]*0.55]*0.4+0.4)],0,1}]}]},PlotRange->{{-1,1},{-1,1}},Background->Blue],{t,0,30},ControlPlacement->Top]

3D Examples

Toon Shader

FE`Evaluate@Evaluate[FEPrivate`AddSurfaceAppearanceDefinition["My Toon3",{{"position", "ATTRIB_VERTEX"}, {"normal", "ATTRIB_NORMAL"}},{{"WVPMatrix","worldViewProjectionMatrix",Automatic,"WORLDVIEWPROJECTIONMATRIX"},
{"WVITMatrix","worldViewITMatrix",Automatic,"WORLDVIEWITMATRIX"},{"AmbientColor","uAmbientColor",RGBColor[{0.25,0.25,0.25,1}],"COLOR"},{"LightingDirection","uLightingDirection",{1,1,1},"NUMBER3"},{"DirectionalColor","uDirectionalColor",RGBColor[{0.5,0.5,0.5,1}],"COLOR"},{"ToonColor1","toonColor1",RGBColor[{0.804,0.796,0.807,1.0}],"COLOR"},{"ToonColor2","toonColor2",RGBColor[{0.4,0.4,0.8,1.0}],"COLOR"},{"ToonColor3","toonColor3",RGBColor[{0.2,0.2,0.4,1.0}],"COLOR"},{"ToonColor4","toonColor4",RGBColor[{0.086,0.094,0.07,1.0}],"COLOR"}},{"varying float intensity; uniform vec4 toonColor1; uniform vec4 toonColor2; uniform vec4 toonColor3; uniform vec4 toonColor4; void main() {  if(intensity > 0.95) gl_FragColor = toonColor1;  else if(intensity > 0.35)  gl_FragColor = toonColor2; else if(intensity > 0.05)  gl_FragColor = toonColor3; else  gl_FragColor = toonColor4;}","attribute vec4 position; attribute vec4 normal; uniform mat4 worldViewProjectionMatrix; uniform mat4 worldViewITMatrix; uniform vec4 uAmbientColor; uniform vec3 uLightingDirection; uniform vec4 uDirectionalColor; varying float intensity; void main() { gl_Position = worldViewProjectionMatrix * position; vec4 TransformedNormal = worldViewITMatrix * normal; vec3 lightDir = normalize(uLightingDirection); intensity = dot(normalize(TransformedNormal.xyz), lightDir); }"}]];

data2=First@ExampleData[{"Geometry3D","Cow"}];
Manipulate[Graphics3D[{System`SurfaceAppearance["My Toon3","DirectionalColor"->Dynamic@LightColor,"ToonColor1"->Dynamic@ToonColor1,"ToonColor2"->Dynamic@ToonColor2,"ToonColor3"->Dynamic@ToonColor3,"ToonColor4"->Dynamic@ToonColor4, "LightingDirection"->{Dynamic@s[[1]], Dynamic@s[[2]],-1}],data2}],{LightColor,GrayLevel[0.5]},{ToonColor1,RGBColor[0.804,0.796,0.807,1.0]},{ToonColor2,RGBColor[0.4,0.4,0.8,1.0]},{ToonColor3,RGBColor[0.2,0.2,0.4,1.0]},{ToonColor4,RGBColor[0.086,0.094,0.07,1.0]},{{s,{-1,-1}},{0,0},{-2,-2}}]

Combining 2D and 3D Examples

Post Processing: Toon Shader + Edge Detection(Post-Processing)

FE`Evaluate@Evaluate[FEPrivate`AddSurfaceAppearanceDefinition["My Edge3",{{"position", "ATTRIB_VERTEX"}, {"vertexTextureCoordIn", "ATTRIB_TEXTURECOORD"}},{{"TMatrix","tranformationMatrix",Automatic,"TRANSFORMMATRIX"},{"Color","color",Yellow,"COLOR"},{"Texture2D","texture",Automatic,"TEXTURE"},{"Size","size",360,"NUMBER"}},{"varying vec4 texCoordOut; uniform vec4 color; uniform sampler2D texture; uniform float size; void main() { float offset=1.0/size;vec4 c=texture2D(texture,texCoordOut.xy); vec4 edge=texture2D(texture,texCoordOut.xy+vec2(-offset,-offset))+texture2D(texture,texCoordOut.xy+vec2(-offset,0.0))+texture2D(texture,texCoordOut.xy+vec2(-offset,offset))+texture2D(texture,texCoordOut.xy+vec2(0.0,offset))+texture2D(texture,texCoordOut.xy+vec2(offset,offset))+texture2D(texture,texCoordOut.xy+vec2(offset,0.0))+texture2D(texture,texCoordOut.xy+vec2(offset,-offset))+texture2D(texture,texCoordOut.xy+vec2(0.0,-offset));gl_FragColor=8.0*(c - 0.125*edge);gl_FragColor.a = 1.0; gl_FragColor *= color;}","attribute vec4 position; attribute vec4 vertexTextureCoordIn; uniform mat4 tranformationMatrix; varying vec4 texCoordOut; void main() { gl_Position = tranformationMatrix * position; texCoordOut = vertexTextureCoordIn;}"}]];

data2=First@ExampleData[{"Geometry3D","Cow"}];
Manipulate[With[{v=RotationTransform[θ,{0,0,1}][{3,0,3}],b=Box,lColor=LightColor,tColor1=ToonColor1,tColor2=ToonColor2,tColor3=ToonColor3,tColor4=ToonColor4},Graphics[{System`SurfaceAppearance["My Edge3","Color"->Dynamic@c],Texture[ImageData@Graphics3D[{System`SurfaceAppearance["My Toon3","DirectionalColor"->lColor,"ToonColor1"->tColor1,"ToonColor2"->tColor2,"ToonColor3"->tColor3,"ToonColor4"->tColor4, "LightingDirection"->{-1, -1,-1}],data2},ViewPoint->v,Boxed->b,SphericalRegion->True]],Polygon[{{-1,-1},{1,-1},{1,1},{-1,1}},VertexTextureCoordinates->{{0,0},{1,0},{1,1},{0,1}}],System`SurfaceAppearance[None],EdgeForm[White],Polygon[{{0.5,0.5},{0.98,0.5},{0.98,0.98},{0.5,0.98}},VertexTextureCoordinates->{{0,0},{1,0},{1,1},{0,1}}]},ImageSize->{360,360}]],{LightColor,GrayLevel[0.5]},{ToonColor1,RGBColor[0.804,0.796,0.807,1.0]},{ToonColor2,RGBColor[0.4,0.4,0.8,1.0]},{ToonColor3,RGBColor[0.2,0.2,0.4,1.0]},{ToonColor4,RGBColor[0.086,0.094,0.07,1.0]},{{θ,1},0,2Pi},{Box,{True,False}},{c,White}]

GLView

GLView = Power of Mathematica + Flexibility of OpenGL

A procedure language with implementation of  more than 140 OpenGL ES2.0 functions, and a bunch of utility functions

Use of Mathematica matrix operation functions and other Mathematica functions

OpenGL Compile/Link/Running time Error  messages for Debugging

Create a simple image

The flowing simple example creates a color buffer and a depth and stencil buffer with specified size.

RawBoxes[Experimental`GLViewBox[
Experimental`glViewport[0,0,300,300],
Experimental`glClearColor[0.8,0.8,0.8,1],
Experimental`glClear["GL_COLOR_BUFFER_BIT"],
ImageSize->{300,300}
]]

View in View and Dynamics

DynamicModule[{vs,fs,program, texture,viewMatrixLocation,modelMatrixLocation,temp,temp2,t=0,r=0.3,vp,vt,bv,bt,bi,cv={1,1,1,1,0,1,0,1,1,0,0,1,  1,1,0,1,0,0, 1,1,1,1,0,1,     1,1,1,0,1,1,1,1,0,0,1,0,      0,1,1,0,0,1,0,1,0,0,0,0,   0,0,0,0,0,1,1,0,0,1,0,1,    1,0,0,1,1,0,0,0,0,0,1,0},
ct={0,0,1.0,0,0.0,1,1,1, 0,0,1.0,0,0.0,1,1,1,  0,0,1.0,0,0.0,1,1,1,  0,0,1.0,0,0.0,1,1,1,  0,0,1.0,0,0.0,1,1,1,  0,0,1.0,0,0.0,1,1,1},ci={0,1,2,2,1,3,4,5,6,6,5,7,8,9,10, 10, 9,11,12,13,14,14,13,15,16,17,18,18,17,19,20,21,22,22, 21,23},texData=Join@@Join@@ImageData[,"Byte"] ,texW=256,texH=256,vShaderStr="attribute vec3 vPosition;  attribute vec2 aTextureCoord;  uniform mat4 vMatrix;  uniform mat4 mMatrix; varying vec2 vTextureCoord; void main()  {    gl_Position = vMatrix * mMatrix * vec4(vPosition, 1.0);  vTextureCoord = aTextureCoord; }",fShaderStr="varying vec2 vTextureCoord; uniform sampler2D uSampler; void main() {  gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));  }"},{Grid[{{Slider[Dynamic[t]]},{Slider[Dynamic[r]]}}],RawBoxes[Experimental`GLViewBox[
Experimental`glViewport[0,0,300,300],
Experimental`glClearColor[0.9,0.9,0.9,1],
Experimental`glClear["GL_COLOR_BUFFER_BIT"],
Experimental`Set[vs,Experimental`glCreateShader["GL_VERTEX_SHADER"]],
Experimental`glShaderSource[vs,1,vShaderStr,0],
Experimental`glCompileShader[vs],
Experimental`Set[fs,Experimental`glCreateShader["GL_FRAGMENT_SHADER"]],
Experimental`glShaderSource[fs,1,fShaderStr,0],
Experimental`glCompileShader[fs],
Experimental`Set[program,Experimental`glCreateProgram[]],
Experimental`glAttachShader[program,vs],
Experimental`glAttachShader[program,fs],
Experimental`glLinkProgram[program],
Experimental`glUseProgram[program],
Experimental`Set[vp,Experimental`glGetAttribLocation[program, "vPosition"]],
Experimental`Set[vt,Experimental`glGetAttribLocation[program, "aTextureCoord"]],
Experimental`glEnableVertexAttribArray[vp],
Experimental`glEnableVertexAttribArray[vt],
Experimental`glGenTextures[1, texture],
Experimental`glBindTexture["GL_TEXTURE_2D",texture],
Experimental`glTexImage2D["GL_TEXTURE_2D",0, "GL_RGB",texW,texH,0,"GL_RGB","GL_UNSIGNED_BYTE",texData],
Experimental`glTexParameteri["GL_TEXTURE_2D", "GL_TEXTURE_MAG_FILTER", "GL_LINEAR"],
Experimental`glTexParameteri["GL_TEXTURE_2D", "GL_TEXTURE_MIN_FILTER", "GL_LINEAR"],
Experimental`Set[temp2, Experimental`GLViewConvertToGLMatrix[TransformationMatrix[RotationTransform[Dynamic[r-0.5],{1,0,0}].RotationTransform[Dynamic[t*10],{0,1,0}].ScalingTransform[{0.5,0.5,0.5}].TranslationTransform[{-0.5,-0.5,-0.5}]]]],
Experimental`Set[viewMatrixLocation,Experimental`glGetUniformLocation[program, "vMatrix"]],
Experimental`glUniformMatrix4fv[viewMatrixLocation, 1, False, {1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1}],
Experimental`Set[modelMatrixLocation,Experimental`glGetUniformLocation[program, "mMatrix"]],
Experimental`glUniformMatrix4fv[modelMatrixLocation, 1, False, temp2],
Experimental`glEnable["GL_DEPTH_TEST"],
Experimental`glDepthFunc["GL_LEQUAL"],
Experimental`glVertexAttribPointer[vp,3, "GL_FLOAT", "GL_FALSE", 0, cv],
Experimental`glVertexAttribPointer[vt, 2, "GL_FLOAT", "GL_FALSE", 0, ct],
Experimental`glDrawElements["GL_TRIANGLES",  36,"GL_UNSIGNED_SHORT",ci],

Experimental`glFlush[],
Experimental`glViewport[260,260,90,90],
Experimental`glEnable["GL_SCISSOR_TEST"],
Experimental`glScissor[260,260,90,90],
Experimental`glClearColor[0.5,.5,.5,.5],
Experimental`glClear["GL_COLOR_BUFFER_BIT"],
Experimental`Set[temp, Experimental`GLViewConvertToGLMatrix[RotationMatrix[3.14159/2,{1,0,0}]]],
Experimental`glUniformMatrix4fv[viewMatrixLocation, 1, False, temp],

Experimental`glDrawElements["GL_TRIANGLES",  36,"GL_UNSIGNED_SHORT",ci],

Experimental`glFlush[],
Experimental`glDisable["GL_SCISSOR_TEST"],
Experimental`glDisableVertexAttribArray[vp],
Experimental`glDisableVertexAttribArray[vt],
Experimental`glBindTexture["GL_TEXTURE_2D",texture],
Experimental`glDeleteTextures[1,texture],
Experimental`glBindBuffer["GL_ARRAY_BUFFER",0],
Experimental`glBindBuffer["GL_ELEMENT_ARRAY_BUFFER",0],
Experimental`glDeleteBuffers[1,bv],
Experimental`glDeleteBuffers[1,bt],
Experimental`glDeleteBuffers[1,bi],
Experimental`glUseProgram[0],
Experimental`glDetachShader[program,vs],
Experimental`glDetachShader[program,fs],
Experimental`glDeleteShader[vs],
Experimental`glDeleteShader[fs],
Experimental`glDeleteProgram[program],ImageSize->360]]}]

Mouse Interaction and EventHandler

Render[exampleData_, scale_]:=DynamicModule[{vs,fs,program, viewMatrixLocation,modelMatrixLocation,normalMatrixLocation,ambientColorUniformLocation, directionLightLocation, directionLightColorLocation,temp,temp2,mouse={0,0},lastMouse={0,0},pos={0,0},cv=Join@@ExampleData[{"Geometry3D",exampleData}][[1,2,1]],cn=Join@@ExampleData[{"Geometry3D",exampleData}][[1,2,3,2]],ci=Join@@ExampleData[{"Geometry3D",exampleData}][[1,2,2,1,1]]-1,size=Length[Join@@ExampleData[{"Geometry3D",exampleData}][[1,2,2,1,1]]],vShaderStr="attribute vec3 vPosition; attribute vec3 vNormal; uniform mat4 vMatrix; uniform mat4 mMatrix; uniform mat4 nMatrix; uniform vec4 uAmbientColor; uniform vec3 uLightingDirection; uniform vec4 uDirectionalColor; void main()  { gl_Position = vMatrix * mMatrix * vec4(vPosition,1.0); vec4 transformedNormal = nMatrix * vec4(vNormal,1); float directionalLightWeighting = max(dot(vNormal.xyz, uLightingDirection),.01); gl_FrontColor = uAmbientColor + uDirectionalColor * (directionalLightWeighting);}",
fShaderStr="void main() {  gl_FragColor = gl_Color;  }" },EventHandler[RawBoxes[Experimental`GLViewBox[
Experimental`glViewport[0,0,300,300],
Experimental`glClearColor[0.,0.,0.,1],
Experimental`glClear["GL_COLOR_BUFFER_BIT"],
Experimental`Set[vs,Experimental`glCreateShader["GL_VERTEX_SHADER"]], 
Experimental`glShaderSource[vs,1,vShaderStr,0],
Experimental`glCompileShader[vs],
Experimental`Set[fs,Experimental`glCreateShader["GL_FRAGMENT_SHADER"]],
Experimental`glShaderSource[fs,1,fShaderStr,0],
Experimental`glCompileShader[fs],
Experimental`Set[program,Experimental`glCreateProgram[]],
Experimental`glAttachShader[program,vs],
Experimental`glAttachShader[program,fs],
Experimental`glBindAttribLocation[program,0,"vPosition"],
Experimental`glBindAttribLocation[program,1,"vNormal"],
Experimental`glLinkProgram[program],
Experimental`glUseProgram[program],
Experimental`Set[temp2, Experimental`GLViewConvertToGLMatrix[TransformationMatrix[RotationTransform[-Dynamic@pos[[1]]*10,{0,1,0}].RotationTransform[Dynamic@pos[[2]]*10-1.57,{1,0,0}].ScalingTransform[{scale,scale,scale}]]]],
Experimental`Set[viewMatrixLocation,Experimental`glGetUniformLocation[program, "vMatrix"]],
Experimental`glUniformMatrix4fv[viewMatrixLocation, 1, False, {1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1}],
Experimental`Set[modelMatrixLocation,Experimental`glGetUniformLocation[program, "mMatrix"]],
Experimental`glUniformMatrix4fv[modelMatrixLocation, 1, False, temp2],
Experimental`Set[temp2, Experimental`GLViewConvertToGLMatrix[Transpose[Inverse[TransformationMatrix[RotationTransform[-Dynamic@pos[[1]]*10,{0,1,0}].RotationTransform[Dynamic@pos[[2]]*10-1.57,{1,0,0}].ScalingTransform[{scale,scale,scale}]]]]]],
Experimental`Set[normalMatrixLocation,Experimental`glGetUniformLocation[program, "nMatrix"]],
Experimental`glUniformMatrix4fv[normalMatrixLocation, 1, False, temp2],
Experimental`Set[ambientColorUniformLocation,Experimental`glGetUniformLocation[program, "uAmbientColor"]],
Experimental`glUniform4fv[ambientColorUniformLocation, 1, {0.25,0.25,0.25,1}],
Experimental`Set[directionLightLocation,Experimental`glGetUniformLocation[program, "uLightingDirection"]],
Experimental`glUniform3fv[directionLightLocation, 1, {1,1,1}],
Experimental`Set[directionLightColorLocation,Experimental`glGetUniformLocation[program, "uDirectionalColor"]],
Experimental`glUniform4fv[directionLightColorLocation, 1, {.5,.5,.5,1}],
Experimental`glEnable["GL_DEPTH_TEST"],
Experimental`glDepthFunc["GL_LEQUAL"],
Experimental`glVertexAttribPointer[0, 3, "GL_FLOAT", "GL_FALSE", 0, cv],
Experimental`glVertexAttribPointer[1,3, "GL_FLOAT", "GL_FALSE", 0, cn],
Experimental`glEnableVertexAttribArray[0],
Experimental`glEnableVertexAttribArray[1],
Experimental`glDrawElements["GL_TRIANGLES",  size,"GL_UNSIGNED_SHORT",ci],
Experimental`glFlush[],
Experimental`glViewport[260,260,90,90],
Experimental`glEnable["GL_SCISSOR_TEST"],
Experimental`glScissor[260,260,90,90],
Experimental`glClearColor[.3,.3,.3,.2],
Experimental`glClear["GL_COLOR_BUFFER_BIT"],
Experimental`Set[temp, Experimental`GLViewConvertToGLMatrix[RotationMatrix[-3.14159/2,{1,0,0}]]],
Experimental`glUniformMatrix4fv[viewMatrixLocation, 1, False, temp],
Experimental`glDrawElements["GL_TRIANGLES",  size,"GL_UNSIGNED_SHORT",ci],
Experimental`glFlush[],
Experimental`glDisable["GL_SCISSOR_TEST"],
Experimental`glDisableVertexAttribArray[0],
Experimental`glDisableVertexAttribArray[1],
Experimental`glUseProgram[0],
Experimental`glDetachShader[program,vs],
Experimental`glDetachShader[program,fs],
Experimental`glDeleteShader[vs],
Experimental`glDeleteShader[fs],
Experimental`glDeleteProgram[program],ImageSize->360]],{"MouseDown":>(mouse=MousePosition[{"Graphics",Graphics},{0,0}]),"MouseDragged":>(lastMouse=mouse;mouse=MousePosition[{"Graphics",Graphics},{0,0}];pos=pos+mouse-lastMouse)}]]

Render["Cow",2]

Customized modern 3D Graphics: Ray Tracing

updateFunc[t_,cameraTo_,cameraFrom_,up_,cameraPersp_,ratio_]:=(cameraDir=Normalize[cameraTo-cameraFrom];
cameraLeft=Normalize[Cross[cameraDir,up]];
cameraUp=Normalize[Cross[cameraLeft,cameraDir]];
cameraCenter=cameraFrom+cameraPersp*cameraDir;
cameraTopLeft=cameraCenter+cameraUp+cameraLeft*ratio;
cameraBotLeft=cameraCenter-cameraUp+cameraLeft*ratio;
cameraTopRight=cameraCenter+cameraUp-cameraLeft*ratio;
cameraBotRight=cameraCenter-cameraUp-cameraLeft*ratio;corners={cameraTopRight[[1]],cameraTopRight[[2]],cameraTopRight[[3]],cameraTopLeft[[1]],cameraTopLeft[[2]],cameraTopLeft[[3]],cameraBotRight[[1]],cameraBotRight[[2]],cameraBotRight[[3]],cameraBotLeft[[1]],cameraBotLeft[[2]],cameraBotLeft[[3]]})

DynamicModule[{vs,fs,program,attr1,attr2,attr3,newVertices={1.0,1.0,-1.0,1.0,1.0,-1.0,-1.0,-1.0},t=0,cameraPos,sph1,sph2,sph3,x1,y1,z1,x2,y2,z2,x3,y3,z3,cameraFrom,cameraTo={0,0,0},cameraPersp=6,up={0,1,0},ratio=1,cameraDir,cameraLeft,cameraUp,cameraCenter,cameraTopLeft,cameraBotLeft,cameraTopRight,cameraBotRight,corners,vShaderStr="attribute vec2 aVertexPosition; attribute vec3 aPlotPosition;varying vec3 vPosition; void main(void){gl_Position=vec4(aVertexPosition,1.0,1.0);vPosition=aPlotPosition;}",
fShaderStr="const vec3 lightDir=vec3(0.577,0.577,-0.577); varying vec3 vPosition;uniform vec3 cameraPos;uniform vec3 sphere1Center; uniform vec3 sphere2Center;uniform vec3 sphere3Center;                 bool intersectSphere(vec3 center,vec3 lStart,vec3 lDir,out float dist) {vec3 c=center-lStart;float b=dot(lDir,c);float d=b*b-dot(c,c)+1.0;  if (d<0.0) {dist=10000.0;return false;} dist=b-sqrt(d); if (dist<0.0) {dist=10000.0;return false;} return true;}                             vec3 lightAt(vec3 N,vec3 V,vec3 color) {vec3 L=lightDir;vec3 R=reflect(-L,N);float c=0.3+0.4*pow(max(dot(R,V),0.0),30.0)+0.7*dot(L,N);if (c>1.0) {return mix(color,vec3(1.6,1.6,1.6),c-1.0);} return c*color;}                 bool intersectWorld(vec3 lStart,vec3 lDir,out vec3 pos,out vec3 normal,out vec3 color) {float d1,d2,d3;bool h1,h2,h3;h1=intersectSphere(sphere1Center,lStart,lDir,d1);h2=intersectSphere(sphere2Center,lStart,lDir,d2);h3=intersectSphere(sphere3Center,lStart,lDir,d3); if (h1&&d1<d2&&d1<d3) {pos=lStart+d1*lDir;normal=pos-sphere1Center;color=vec3(0.0,0.0,0.9);} else if (h2&&d2<d3) {pos=lStart+d2*lDir;normal=pos-sphere2Center;color=vec3(0.9,0.0,0.0);} else if(h3) {pos=lStart+d3*lDir;normal=pos-sphere3Center;color=vec3(0.0,0.9,0.0);} else if (lDir.y<-0.01){pos=lStart+((lStart.y+2.7)/-lDir.y)*lDir; if(pos.x*pos.x+pos.z*pos.z>30.0) {return false;} normal=vec3(0.0,1.0,0.0); if (fract(pos.x/5.0)>0.5 == fract(pos.z/5.0)>0.5) {color=vec3(1.0);} else {color=vec3(0.0);}}  else { return false; } return true; }                     void main(void) {vec3 cameraDir=normalize(vPosition-cameraPos);vec3 p1,norm,p2;vec3 col,colT,colM,col3; if (intersectWorld(cameraPos,cameraDir,p1,norm,colT)) {col=lightAt(norm,-cameraDir,colT);colM=(colT+vec3(0.7))/1.7;cameraDir=reflect(cameraDir,norm); if (intersectWorld(p1,cameraDir,p2,norm,colT)){col += lightAt(norm,-cameraDir,colT)*colM;colM*=(colT+vec3(0.7))/1.7;cameraDir=reflect(cameraDir,norm);if (intersectWorld(p2,cameraDir,p1,norm,colT)){col+=lightAt(norm,-cameraDir,colT)*colM;}} gl_FragColor=vec4(col,1.0);} else {gl_FragColor=vec4(0.0,0.0,0.0,1.0);}}"},
{Slider[Dynamic[t],{0,30,0.01}],
x1=Sin[Dynamic[t]*1.1]*1.5;
y1=Cos[Dynamic[t]*1.3]*1.5;
z1=Sin[Dynamic[t]+1.05]*1.5;
x2=Cos[Dynamic[t]*1.2]*1.5;
y2=Sin[Dynamic[t]*1.4]*1.5;
z2=Sin[Dynamic[t]*1.25-1.05]*1.5;
x3=Cos[Dynamic[t]*1.15]*1.5;
y3=Sin[Dynamic[t]*1.37]*1.5;
z3=Sin[Dynamic[t]*1.27]*1.5;
cameraFrom={Sin[Dynamic[t]*0.4]*18,Sin[Dynamic[t]*0.13]*5+5,Cos[Dynamic[t]*0.4]*18};
RawBoxes[Experimental`GLViewBox[
Experimental`glViewport[0,0,300,300],
Experimental`glClearColor[.8,.8,.8,1],
Experimental`glClear["GL_COLOR_BUFFER_BIT"],
Experimental`glClearDepth[1.0],
Experimental`glClear["GL_DEPTH_BUFFER_BIT"],
Experimental`Set[vs,Experimental`glCreateShader["GL_VERTEX_SHADER"]],
Experimental`glShaderSource[vs,1,vShaderStr,0],
Experimental`glCompileShader[vs],
Experimental`Set[fs,Experimental`glCreateShader["GL_FRAGMENT_SHADER"]],
Experimental`glShaderSource[fs,1,fShaderStr,0],
Experimental`glCompileShader[fs],
Experimental`Set[program,Experimental`glCreateProgram[]],
Experimental`glAttachShader[program,vs],
Experimental`glAttachShader[program,fs],
Experimental`glLinkProgram[program],
Experimental`glUseProgram[program],
Experimental`Set[attr1,Experimental`glGetAttribLocation[program, "aVertexPosition"]],
Experimental`glEnableVertexAttribArray[attr1],
Experimental`Set[attr2,Experimental`glGetAttribLocation[program, "aPlotPosition"]],
Experimental`glEnableVertexAttribArray[attr2],
Experimental`Set[cameraPos,Experimental`glGetUniformLocation[program, "cameraPos"]],
Experimental`Set[sph1,Experimental`glGetUniformLocation[program, "sphere1Center"]],
Experimental`Set[sph2,Experimental`glGetUniformLocation[program, "sphere2Center"]],
Experimental`Set[sph3,Experimental`glGetUniformLocation[program, "sphere3Center"]],
Experimental`glVertexAttribPointer[attr1, 2, "GL_FLOAT", "GL_FALSE", 0, newVertices],
Experimental`glVertexAttribPointer[attr2, 3, "GL_FLOAT", "GL_FALSE", 0, Dynamic@N@updateFunc[Dynamic[t],cameraTo,{Sin[t*0.4]*18,Sin[t*0.13]*5+5,Cos[t*0.4]*18},up,cameraPersp,ratio]],
Experimental`glUniform3f[cameraPos,Dynamic[ cameraFrom[[1]]],Dynamic[ cameraFrom[[2]]],Dynamic[ cameraFrom[[3]]]],
Experimental`glUniform3f[sph1,Dynamic[ x1],Dynamic[ y1],Dynamic[ z1]],
Experimental`glUniform3f[sph2,Dynamic[ x2],Dynamic[ y2],Dynamic[ z2]],
Experimental`glUniform3f[sph3,Dynamic[ x3],Dynamic[ y3],Dynamic[ z3]],
Experimental`glDrawArrays["GL_TRIANGLE_STRIP", 0, 4],
Experimental`glDisableVertexAttribArray[attr1],
Experimental`glDisableVertexAttribArray[attr2],
Experimental`glFlush[],
Experimental`glUseProgram[0],
Experimental`glDetachShader[program,vs],
Experimental`glDetachShader[program,fs],
Experimental`glDeleteShader[vs],
Experimental`glDeleteShader[fs],
Experimental`glDeleteProgram[program],ImageSize->300]]}]