16. - Colors, like the
screen dimensions,
are based on
percentages rather
than absolute
values.
- If you come from
a graphic design
background, you
need to convert
your 255 scale to
percentages.
18. Rosetta Stone
- Had the same text in
Greek, demotic, and
hieroglyphics. Was
used to translate
hieroglyphics
- Going to do similar
thing, but with math
algorithms, plain
English, and code
20. Algoritm
Σ5
i = 1
4i
I have a starting value of one.
I have an end value of five.
I want to multiply each value
by four and add them together.
21. Plain English
I have a starting value of one.
I have an end value of five.
I want to multiply each value
by four and add them together.
22. var x = 0
!
for index in 1…5 {
!
x += (4 * index)
!
}
Code
23. It’s All Greek to
Me
π
Δ
i
θ
Constant: 3.14159…
Change between two values
Square root of negative one
Variable representing an angle
Consolidate slide, get rid of alpha and beta
27. Triangles
A shape with three sides where the
angles add up to 180 degrees
Everything in our world comes back
to triangles
The most stable shape
Foundation of 3D graphics
34. So What Can We Do
Knowing This?
Change the direction a character is
moving in
Check to see if the user is hitting a
target area on the screen
Draw shapes and filters in specific
configurations
36. Linear Algebra
Google “Better Explained Rotation”
Matrices
Complex numbers
Show how to use linear algebra to do more efficient affine transforms
rotation through matrix multiplications
37. What is Linear
Algebra?
Linear Algebra allows you to
perform an action on many values
at the same time.
This action must be consistent
across all values, such as multiplying
every value by two.
38. What is Linear
Algebra?
Values are placed in an object
called a matrix and the actions
performed on the values are called
transforms
Linear algebra is optimized for
parallel mathematical operations.
39. Data Types
vec2, vec3, vec4: 2D, 3D, and 4D
floating point vector objects.
vec2: (x, y)
vec3: (x, y, z)
vec4: (r, g, b, a)
40. Data Types
mat2, mat3, mat4: 2, 3, and 4
element matrices.
mat2: Holds a 2 X 2 number matrix
mat3: Holds a 3 X 3 number matrix,
used for 2D linear algebra
mat4: Holds a 4 X 4 number matrix,
used for 3D linear algebra
46. Affine, Wha?? :(
A transform is any function that
alters the size, position, or rotation
of an object on your screen.
Four types: Identity, Translate,
Rotation, and Scale.
For a transform to be affine, the
lines in your shape must be parallel.
49. new point x = a * x
+ c * y + tx;
new point y = b * x
+ d * y + ty;
Show the matrix of the vector and the actual math around it
50. How Does This
Work?
For each point in your shape, the
computer uses this calculation to
figure out where the point should
be.
If you have a rectangle, this gets
run four times: One for each point
in your shape.
52. void main()
{
highp vec2 textureCoordinateToUse = vec2(textureCoordinate.x, (textureCoordinate.y *
aspectRatio + 0.5 - 0.5 * aspectRatio));
highp float distanceFromCenter = distance(center, textureCoordinateToUse);
lowp float checkForPresenceWithinSphere = step(distanceFromCenter, radius);
distanceFromCenter = distanceFromCenter / radius;
highp float normalizedDepth = radius * sqrt(1.0 - distanceFromCenter *
distanceFromCenter);
highp vec3 sphereNormal = normalize(vec3(textureCoordinateToUse - center,
normalizedDepth));
highp vec3 refractedVector = 2.0 * refract(vec3(0.0, 0.0, -1.0), sphereNormal,
refractiveIndex);
refractedVector.xy = -refractedVector.xy;
highp vec3 finalSphereColor = texture2D(inputImageTexture, (refractedVector.xy + 1.0) *
0.5).rgb;
// Grazing angle lighting
highp float lightingIntensity = 2.5 * (1.0 - pow(clamp(dot(ambientLightPosition,
sphereNormal), 0.0, 1.0), 0.25));
finalSphereColor += lightingIntensity;
// Specular lighting
lightingIntensity = clamp(dot(normalize(lightPosition), sphereNormal), 0.0, 1.0);
lightingIntensity = pow(lightingIntensity, 15.0);
finalSphereColor += vec3(0.8, 0.8, 0.8) * lightingIntensity;
gl_FragColor = vec4(finalSphereColor, 1.0) * checkForPresenceWithinSphere;
}
So what this calculation does is it adjusts for a non-square aspect ratio of the image. The image aspect ratio is passed in as a uniform, and this adjusts the
normally 0.0-1.0 texture coordinate for the Y axis to instead be from 0.0-1.0*(imageHeight/imageWidth). It has to expand the Y axis coordinate about its
center point (0.5), thus the weird addition and subtraction in there. If you don’t do this, your sphere turns into an egg in non-square images.
53. highp vec2 textureCoordinateToUse =
vec2(textureCoordinate.x,
(textureCoordinate.y * aspectRatio +
0.5 - 0.5 * aspectRatio));
So what this calculation does is it adjusts for a non-square aspect ratio of the image. The image aspect ratio is passed in as a uniform, and this adjusts the
normally 0.0-1.0 texture coordinate for the Y axis to instead be from 0.0-1.0*(imageHeight/imageWidth). It has to expand the Y axis coordinate about its
center point (0.5), thus the weird addition and subtraction in there. If you don’t do this, your sphere turns into an egg in non-square images.
54. highp float
distanceFromCenter =
distance(center,
textureCoordinateToUse);
This is a Pythagorean distance calculation to determine how far the current pixel (texture coordinate) is from the center that we’ve provided as a uniform.
It’s a sqrt(xdiff^2 + ydiff^2) calculation.
55. lowp float
checkForPresenceWithinSphere
= step(distanceFromCenter,
radius);
The step() function returns 1 if the second value is greater than the first, 0 if not. I use these to avoid if() statements, which are expensive in fragment
shaders (branching does not work well in massively parallel operations).
56. distanceFromCenter =
distanceFromCenter /
radius;
This normalizes the distance from the center to be 0.0 for a value at the center of the sphere, and 1.0 for a value at the edge of the sphere. Values outside
that range will get filtered out by the product of the above step() calculation later on.
57. highp float normalizedDepth =
radius * sqrt(1.0 -
distanceFromCenter *
distanceFromCenter);
This is where we calculate the Z height that a sphere, cut in half, would extend above the plane of the image. This is another geometrical calculation based
on knowing the distance of our point from the center of the sphere.
58. highp vec3 sphereNormal =
normalize(vec3!
(textureCoordinateToUse -
center, normalizedDepth));
Once we know the height of the spherical cap at that point, we can calculate the normal for that point on the sphere’s surface. Think of it as a ray that
extends from the center of the sphere to the surface at this X, Y coordinate. The normal is based on the center of the sphere, so we subtract our aspect-ratio-
adjusted-coordinate from the center to get the relative X, Y coordinate from the center of the sphere. The Z component is the height of the sphere
we just calculated.
59. highp vec3 refractedVector =
refract(vec3(0.0, 0.0, -1.0), !
sphereNormal,
refractiveIndex);
With the normal, we can calculate the refraction of light from that point on the sphere’s surface. The refraction calculation uses the surface normal, the
refractiveIndex (a material property that you pass in, I think I use glass’s here), and a ray direction. I believe the ray direction here is from the eye going
into the screen, although I can never remember positive/negative Z directions in OpenGL. This then generates a refracted vector, pointing in the direction
light would as it refracts through a sphere.
60. gl_FragColor =
texture2D(inputImageTexture,
(refractedVector.xy + 1.0) * 0.5)
* checkForPresenceWithinSphere;
We then take this refracted vector, which is in the -1.0-1.0 coordinate space, and adjust it to the 0.0-1.0 coordinate space for texture sampling. We read
the texture color at the location pointed to by that vector. The earlier step() function to determine if a point was within the sphere comes into play here,
where we only display a color if the point was within the sphere. If it was not, we output 0.0, 0.0, 0.0, 0.0 as an RGBA color because that’s the result of
multiplying with 0.