1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
|
\name{setUserShaders}
\alias{setUserShaders}
\alias{getShaders}
\title{
Set user-defined shaders for RGL objects, or get
shaders.
}
\description{
\code{setUserShaders} sets user-defined shaders (programs written in GLSL)
for customized display of RGL objects. Currently
only supported in WebGL displays, as the regular
displays do not support GLSL. \code{getShaders} gets
the user defined shader, or if it is not present, the
automatically generated one.
}
\usage{
setUserShaders(ids, vertexShader = NULL, fragmentShader = NULL,
attributes = NULL, uniforms = NULL, textures = NULL,
scene = scene3d(minimal), minimal = TRUE)
getShaders(id, scene = scene3d(minimal), minimal = TRUE)
}
\arguments{
\item{ids, id}{
Which objects should receive the shaders, or which object
should be queried?
}
\item{vertexShader, fragmentShader}{
The vertex and fragment shader source code. If \code{NULL}, the
automatically generated shader will be used instead.
}
\item{attributes}{
A named list of \dQuote{attributes} to attach to each vertex.
}
\item{uniforms}{
A named list of \dQuote{uniforms}.
}
\item{textures}{
A named list of textures.
}
\item{scene}{
A \code{\link{scene3d}} object to work with.
}
\item{minimal}{
See \code{\link{scene3d}}.
}
}
\details{
Modern versions of OpenGL work with \dQuote{shaders},
programs written to run on the graphics processor. The
vertex shader does the calculations to move vertices and
set their intrinsic colours. The fragment shader
computes how each pixel in the display will be shown,
taking into account lighting, material properties, etc.
(More precisely, it does the computation for each \dQuote{fragment}; a fragment is a pixel within an object to display.
There may be many objects at a particular location, and
each will result in a fragment calculation unless culled
by z-buffering or being discarded in some other way.)
Normally the WebGL Javascript code uses the default
shaders stored in
\code{system.file("htmlwidgets/lib/rglClass/shaders",
package = "rgl")}. This function allows them to be written
by hand, for testing new features, hand optimization, etc.
The defines used by the default shaders will also be prepended
to user shaders, which can use them for customization on
an object-by-object basis.
The names used for the \code{attributes}, \code{uniforms}
and \code{textures} should match names in the shaders
for corresponding variables. (The texture names should be
names of \code{uniform sampler2D} variables.)
}
\note{
The \code{getShaders} function requires the \pkg{V8} package
to extract auto-generated shaders, since the defines
are generated by Javascript code.
}
\value{
A modified version of the \code{scene}.
}
\author{
Duncan Murdoch
}
\seealso{
\code{\link{rglwidget}} for display of the scene in WebGL.
}
\examples{
open3d()
id <- shade3d(octahedron3d(), col = "red")
# For each triangle, set weights on the 3 vertices.
# This will be replicated to the appropriate size in Javascript.
wts <- diag(3)
# This leaves out the centres of each face
vs <- "
attribute vec3 aPos;
attribute vec4 aCol;
uniform mat4 mvMatrix;
uniform mat4 prMatrix;
varying vec4 vCol;
varying vec4 vPosition;
attribute vec3 aNorm;
uniform mat4 normMatrix;
varying vec3 vNormal;
attribute vec3 wts;
varying vec3 vwts;
void main(void) {
vPosition = mvMatrix * vec4(aPos, 1.);
gl_Position = prMatrix * vPosition;
vCol = aCol;
vNormal = normalize((normMatrix * vec4(aNorm, 1.)).xyz);
vwts = wts;
}
"
fs <- "
#ifdef GL_ES
precision highp float;
#endif
varying vec4 vCol; // carries alpha
varying vec4 vPosition;
varying vec3 vNormal;
uniform mat4 mvMatrix;
uniform vec3 emission;
uniform float shininess;
uniform vec3 ambient[NLIGHTS];
uniform vec3 specular[NLIGHTS]; // light*material
uniform vec3 diffuse[NLIGHTS];
uniform vec3 lightDir[NLIGHTS];
uniform bool viewpoint[NLIGHTS];
uniform bool finite[NLIGHTS];
varying vec3 vwts;
uniform vec2 wtrange;
void main(void) {
float minwt = min(vwts.x, min(vwts.y, vwts.z));
if (minwt < wtrange.x || minwt > wtrange.y) discard;
vec3 eye = normalize(-vPosition.xyz);
vec3 lightdir;
vec4 colDiff;
vec3 halfVec;
vec4 lighteffect = vec4(emission, 0.);
vec3 col;
float nDotL;
vec3 n = normalize(vNormal);
n = -faceforward(n, n, eye);
colDiff = vec4(vCol.rgb * diffuse[0], vCol.a);
lightdir = lightDir[0];
if (!viewpoint[0])
lightdir = (mvMatrix * vec4(lightdir, 1.)).xyz;
if (!finite[0]) {
halfVec = normalize(lightdir + eye);
} else {
lightdir = normalize(lightdir - vPosition.xyz);
halfVec = normalize(lightdir + eye);
}
col = ambient[0];
nDotL = dot(n, lightdir);
col = col + max(nDotL, 0.) * colDiff.rgb;
col = col + pow(max(dot(halfVec, n), 0.), shininess) * specular[0];
lighteffect = lighteffect + vec4(col, colDiff.a);
gl_FragColor = lighteffect;
}
"
x <- setUserShaders(id, vs, fs, attributes = list(wts=wts),
uniforms = list(wtrange = c(-0.01, 0.15)))
if (interactive() || in_pkgdown_example())
rglwidget(x)
}
|