Jason McKesson avatar Jason McKesson committed 55a5942 Merge

Merge

Comments (0)

Files changed (78)

+syntax: glob
+*.obj
+*.dll
+*.fo
+*.lib
+*.exp
+*.ilk
+*.pdb
+*.dep
+*.idb
+*.ncb
+*.suo
+*.user
+BuildLog.htm
+*.exe
+*.res
+*.manifest
+*.bsc
+*.sbr
+*.pdf
+obj/*
+FreeImage/Dist/FreeImage.h
+FreeImage/Wrapper/FreeImagePlus/dist/FreeImagePlus.h
+Documents/Build/fo.xsl
+Documents/Build/website.xsl
+desktop.ini
+glIntercept/*
+tinyxml/*.sln
+tinyxml/*.vcproj
+Tut */*.sln
+Tut */*.vcproj
+framework/*.vcproj
+Test/*.sln
+Test/*.vcproj
+AllTutorials.sln
+glloader/*.sln
+glloader/*.vcproj
+website/*
 The source of the documentation is found in the Documents directory. This
 source documentation is in the DocBook 5 format. All other formats were
 generated automatically from these source files.
+
+The License.txt file contains the licensing information for the materials distributed in these tutorials.
 ]===], versionNum))
 readme:close()
 

Documents/Basics/Tutorial 01.xml

             OpenGL to assume that the string is null-terminated. In general, unless you need to use
             the null character in a string, there is no need to use the last parameter.</para>
         <para>Once the strings are in the object, they are compiled with
-                <function>glCompileShader</function>, which simply takes the shader object to
-            compile.</para>
+                <function>glCompileShader</function>, which does exactly what it says.</para>
         <para>After compiling, we need to see if the compilation was successful. We do this by
             calling <function>glGetShaderiv</function> to retrieve the
                 <literal>GL_COMPILE_STATUS</literal>. If this is <literal>GL_FALSE</literal>, then
             the shader failed to compile; otherwise compiling was successful.</para>
         <para>If compilation fails, we do some error reporting. It prints a message to stderr that
             explains what failed to compile. It also prints an info log from OpenGL that describes
-            the error; this of this log as the compiler output from a regular C compilation.</para>
+            the error; think of this log as the compiler output from a regular C compilation.</para>
         <para>After creating both shader objects, we then pass them on to the
                 <function>CreateProgram</function> function:</para>
         <example>
Add a comment to this file

Documents/Illumination/Bad Impostor Intersection.png

Added
New image
Add a comment to this file

Documents/Illumination/Bad vs Good Impostor.png

Added
New image
Add a comment to this file

Documents/Illumination/Bad vs Good Impostor2.png

Added
New image
Add a comment to this file

Documents/Illumination/Basic Impostor.png

Added
New image
Add a comment to this file

Documents/Illumination/CircleInPerspective.svg

Added
New image
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" height="200px" width="300px" >
+	<style type="text/css" ><![CDATA[.line_standard
+{
+	stroke-width: 1px;
+}
+
+.background
+{
+	stroke: none;
+	fill: #E0E0E0;
+}
+
+.line_of_proj
+{
+	stroke: red;
+	stroke-dasharray: 4,8;
+	stroke-width: 1px;
+}
+
+.fill_none
+{
+	fill: none;
+}
+
+.fill_transluscent
+{
+	fill-opacity: 0.1;
+	fill: blue;
+}
+
+.fill_black
+{
+	fill: black;
+}
+
+.circle_plane
+{
+	stroke-width: 2px;
+	stroke: black;
+}
+
+.object_projected
+{
+	stroke-width: 8px;
+	stroke: #00C000;
+}
+
+.object
+{
+	stroke-width: 1px;
+	stroke: #00C000;
+}
+
+.black
+{
+	stroke: black;
+}
+
+.projected
+{
+	stroke-width: 8px;
+}
+
+.red
+{
+	stroke: red;
+}
+
+.dashed
+{
+	stroke-dasharray: 4,8;
+}]]></style>
+	<defs />
+	<polygon points="112.5,137.5 187.5,137.5 325,2.1316282072803e-014 -25,2.1316282072803e-014" class="background" />
+	<line x2="143.75" y2="137.5" y1="62.5" x1="131.25" class="line_of_proj" />
+	<line x2="118.75" y2="137.5" y1="62.5" x1="56.25" class="line_of_proj" />
+	<line x2="118.75" y2="137.5" y1="137.5" x1="143.75" class="object_projected" />
+	<circle r="37.5" cy="62.5" cx="93.75" class="object fill_none" />
+	<line x2="56.25" y2="62.5" y1="62.5" x1="131.25" class="circle_plane" />
+	<line x2="187.5" y2="137.5" y1="137.5" x1="112.5" class="black line_standard" />
+	<line x2="0" y2="137.5" y1="137.5" x1="112.5" class="black line_standard dashed" />
+	<line x2="212.5" y2="137.5" y1="137.5" x1="187.5" class="black line_standard dashed" />
+	<circle r="3" cy="175" cx="150" class="black fill_black" />
+	<line x2="150" y2="175" y1="137.5" x1="112.5" class="black line_standard dashed" />
+	<line x2="150" y2="175" y1="137.5" x1="187.5" class="black line_standard dashed" />
+</svg>
Add a comment to this file

Documents/Illumination/CirclePythagorean.svg

Added
New image
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" height="250px" width="350px" >
+	<style type="text/css" ><![CDATA[.__axis1
+{
+	stroke: black;
+	stroke-width: 1px;
+	fill: none;
+}
+
+.vector
+{
+	marker-end: url(#arrow);
+	stroke: darkgreen;
+	stroke-width: 2px;
+}
+
+.__axis_arrow_end1
+{
+	marker-end: url(#__axis_arrow1);
+}
+
+.text-hyp
+{
+	font-weight: bold;
+	font-size: 25px;
+	stroke: none;
+	font-family: monospace;
+	fill: darkorange;
+}
+
+.arrowhead
+{
+	stroke: darkgreen;
+	fill: darkgreen;
+}
+
+.circle
+{
+	stroke: black;
+	fill: none;
+}
+
+.text
+{
+	font-weight: bold;
+	font-size: 25px;
+	stroke: none;
+	font-family: monospace;
+	fill: darkgreen;
+}
+
+.arrowhead-hyp
+{
+	stroke: darkorange;
+	fill: darkorange;
+}
+
+.vector-hyp
+{
+	marker-end: url(#arrow-hyp);
+	stroke: darkorange;
+	stroke-width: 2px;
+}]]></style>
+	<defs >
+		<marker markerWidth="10" markerHeight="8" refX="10" refY="4" markerUnits="userSpaceOnUse" orient="auto" id="__axis_arrow1" >
+			<path d="M 10 4 L 0 0 L 0 8 Z" class="fill_black thin" />
+		</marker>
+		<g id="g_axes" >
+			<line x2="175" y2="250" y1="183.33333333333" x1="175" class="__axis1 __axis_arrow_end1" />
+			<line x2="175" y2="0" y1="183.33333333333" x1="175" class="__axis1 __axis_arrow_end1" />
+			<line x2="350" y2="183.33333333333" y1="183.33333333333" x1="175" class="__axis1 __axis_arrow_end1" />
+			<line x2="0" y2="183.33333333333" y1="183.33333333333" x1="175" class="__axis1 __axis_arrow_end1" />
+		</g>
+	</defs>
+	<defs >
+		<marker markerWidth="10" markerHeight="8" refX="10" refY="4" markerUnits="userSpaceOnUse" orient="auto" id="arrow" >
+			<path d="M 10 4 L 0 0 L 0 8 Z" class="arrowhead" />
+		</marker>
+		<marker markerWidth="10" markerHeight="8" refX="10" refY="4" markerUnits="userSpaceOnUse" orient="auto" id="arrow-hyp" >
+			<path d="M 10 4 L 0 0 L 0 8 Z" class="arrowhead-hyp" />
+		</marker>
+	</defs>
+	<use xlink:href="#g_axes" y="0" x="0" height="250" width="350" />
+	<path d="M 320.83333333333 183.33333333333 A 145.83333333333 145.83333333333 0 1 0 29.166666666667 183.33333333333" class="circle" />
+	<line x2="292.98164501301" y2="183.33333333333" y1="183.33333333333" x1="175" class="vector" />
+	<text y="205.33333333333" x="233.99082250651" class="text" >X</text>
+	<line x2="292.98164501301" y2="97.614650707348" y1="183.33333333333" x1="292.98164501301" class="vector-hyp" />
+	<text y="150.47399202034" x="297.98164501301" class="text-hyp" >Y</text>
+	<line x2="292.98164501301" y2="97.614650707348" y1="183.33333333333" x1="175" class="vector" />
+	<text y="125.47399202034" x="228.99082250651" class="text" >R</text>
+</svg>
Add a comment to this file

Documents/Illumination/Depth Correct Impostor.png

Added
New image

Documents/Illumination/GenCircleInPerspective.lua

+require "SvgWriter"
+require "vmath"
+require "Viewport"
+require "SubImage"
+require "GridAxis"
+require "_utils"
+
+local imageWidth = 300;
+local imageHeight = 200;
+local imageSize = vmath.vec2(imageWidth, imageHeight);
+
+local subImages = SubImage.SubImage(1, 1, imageWidth, imageHeight, 100, 0);
+
+local coordSize = 8;
+
+local vp = Viewport.Viewport(subImages:SubSize(), {0, -1}, coordSize)
+local trans2 = Viewport.Transform2D()
+vp:SetTransform(trans2);
+
+local worldExtents = vp:Extents();
+worldExtents[1] = -worldExtents[1];
+
+local function ProjectPoint(tPoint, projection)
+	if(vmath.vtype(tPoint) == "table") then
+		local ret = {}
+		for i, realPoint in ipairs(tPoint) do
+			ret[i] = ProjectPoint(realPoint, projection)
+		end
+		return ret;
+	end
+
+	local lineDir = tPoint - projection.eyeLoc;
+	local offset = (projection.lineLoc.y - projection.eyeLoc.y) / lineDir.y;
+	return (lineDir * offset) + projection.eyeLoc;
+end
+
+
+----------------------------------
+-- Styles
+local styleLib = SvgWriter.StyleLibrary();
+
+styleLib:AddStyle(nil, "black",
+	SvgWriter.Style():stroke("black"));
+	
+styleLib:AddStyle(nil, "red",
+	SvgWriter.Style():stroke("red"));
+	
+styleLib:AddStyle(nil, "line_of_proj",
+	SvgWriter.Style():stroke("red"):stroke_width("1px"):stroke_dasharray({4, 8}));
+	
+styleLib:AddStyle(nil, "object",
+	SvgWriter.Style():stroke("#00C000"):stroke_width("1px"));
+	
+styleLib:AddStyle(nil, "object_projected",
+	SvgWriter.Style():stroke("#00C000"):stroke_width("8px"));
+	
+styleLib:AddStyle(nil, "line_standard",
+	SvgWriter.Style():stroke_width("1px"));
+	
+styleLib:AddStyle(nil, "projected",
+	SvgWriter.Style():stroke_width("8px"));
+	
+styleLib:AddStyle(nil, "dashed",
+	SvgWriter.Style():stroke_dasharray({4, 8}));
+
+styleLib:AddStyle(nil, "circle_plane",
+	SvgWriter.Style():stroke("black"):stroke_width("2px"));
+	
+	
+styleLib:AddStyle(nil, "fill_black",
+	SvgWriter.Style():fill("black"));
+	
+styleLib:AddStyle(nil, "fill_transluscent",
+	SvgWriter.Style():fill("blue"):fill_opacity(0.1));
+
+styleLib:AddStyle(nil, "fill_none",
+	SvgWriter.Style():fill("none"));
+	
+styleLib:AddStyle(nil, "background",
+	SvgWriter.Style():fill("#E0E0E0"):stroke("none"));
+	
+
+----------------------------------
+-- Point setup.
+
+local lineProjection = {}
+lineProjection.lineLoc = vmath.vec2(0.0, worldExtents[1] * 0.5);
+lineProjection.eyeLoc = vmath.vec2(0.0, worldExtents[1] * 0.75);
+lineProjection.lineWidth = 2.0;
+lineProjection.lineEndPts =
+{
+	vmath.vec2(-lineProjection.lineWidth / 2, lineProjection.lineLoc.y),
+	vmath.vec2(lineProjection.lineWidth / 2, lineProjection.lineLoc.y),
+}
+lineProjection.finalEndPts = vp:Transform(lineProjection.lineEndPts)
+lineProjection.finalEyeLoc = vp:Transform(lineProjection.eyeLoc)
+
+local sideProjLines = {}
+sideProjLines[1] = vmath.vec2(lineProjection.lineEndPts[1])
+sideProjLines[1].x = worldExtents[1];
+sideProjLines[2] = vmath.vec2(lineProjection.lineEndPts[2])
+sideProjLines[2].x = worldExtents[2];
+
+sideProjLines = vp:Transform(sideProjLines);
+
+local projectFrustum =
+{
+	vmath.vec2(lineProjection.lineEndPts[1]),
+	vmath.vec2(lineProjection.lineEndPts[2]),
+}
+
+do
+	local lineDir = lineProjection.lineEndPts[2] - lineProjection.eyeLoc;
+	local offset = (worldExtents[2] - lineProjection.eyeLoc.y) / lineDir.y;
+	projectFrustum[3] = (lineDir * offset) + lineProjection.eyeLoc;
+	lineDir = lineProjection.eyeLoc - lineProjection.lineEndPts[1];
+	offset = (worldExtents[2] - lineProjection.eyeLoc.y) / lineDir.y;
+	projectFrustum[4] = (lineDir * offset) + lineProjection.eyeLoc;
+end
+
+projectFrustum = vp:Transform(projectFrustum);
+
+
+local rectShape =
+{
+	vmath.vec2(0.8, 0.0),
+	vmath.vec2(0.5, 0.0),
+	vmath.vec2(0.5, 1.5),
+	vmath.vec2(0.8, 1.5),
+}
+
+local rectProj = ProjectPoint(rectShape, lineProjection)
+
+rectShape = vp:Transform(rectShape);
+rectProj = vp:Transform(rectProj);
+
+local rectProjOffset = {}
+for i, tPoint in ipairs(rectProj) do
+	rectProjOffset[i] = tPoint + vmath.vec2(0, -1);
+end
+
+local lineShape =
+{
+	vmath.vec2(-3.3, -1.5),
+	vmath.vec2(-0.5, 3.0),
+}
+
+local lineProj = ProjectPoint(lineShape, lineProjection)
+
+lineShape = vp:Transform(lineShape);
+lineProj = vp:Transform(lineProj);
+
+--Circle Location
+local circleCenter = vmath.vec2(-1.5, 0);
+local circleRadius = 1.0;
+
+local circleSizePlane =
+{
+	circleCenter + vmath.vec2(circleRadius, 0),
+	circleCenter - vmath.vec2(circleRadius, 0),
+}
+
+circleCenter = vp:Transform(circleCenter);
+circleRadius = vp:Length(circleRadius);
+
+local lineProj = ProjectPoint(circleSizePlane, lineProjection)
+
+circleSizePlane = vp:Transform(circleSizePlane);
+lineProj = vp:Transform(lineProj);
+
+
+----------------------------------------
+-- The SVG itself
+local writer = SvgWriter.SvgWriter(ConstructSVGName(arg[0]), {imageWidth .."px", imageHeight .. "px"});
+	writer:StyleLibrary(styleLib);
+	writer:BeginDefinitions();
+	writer:EndDefinitions();
+	
+	--Background
+	writer:Polygon(projectFrustum, {"background"})
+	
+	--Projection
+	writer:Line(circleSizePlane[1], lineProj[1], {"line_of_proj"});
+	writer:Line(circleSizePlane[2], lineProj[2], {"line_of_proj"});
+	writer:Line(lineProj[1], lineProj[2], {"object_projected"});
+
+	--Draw circle.
+	writer:Circle(circleCenter, circleRadius, {"object", "fill_none"});
+	writer:Line(circleSizePlane[1], circleSizePlane[2], {"circle_plane"});
+	
+	--Draw the projection plane.
+	writer:Line(lineProjection.finalEndPts[1], lineProjection.finalEndPts[2],
+		{"black", "line_standard"});
+	writer:Line(lineProjection.finalEndPts[1], sideProjLines[1],
+		{"black", "line_standard", "dashed"});
+	writer:Line(lineProjection.finalEndPts[2], sideProjLines[2],
+		{"black", "line_standard", "dashed"});
+	
+	writer:Circle(lineProjection.finalEyeLoc, imageWidth / 100,
+		{"black", "fill_black"})
+	writer:Line(lineProjection.finalEndPts[1], lineProjection.finalEyeLoc,
+		{"black", "line_standard", "dashed"});
+	writer:Line(lineProjection.finalEndPts[2], lineProjection.finalEyeLoc,
+		{"black", "line_standard", "dashed"});
+writer:Close();

Documents/Illumination/GenCirclePythagorean.lua

+require "SvgWriter"
+require "vmath"
+require "Viewport"
+require "SubImage"
+require "GridAxis"
+require "_utils"
+
+local subImages = SubImage.SubImage(1, 1, 350, 250, 100, 0);
+
+local coordSize = 12;
+
+local vp = Viewport.Viewport(subImages:SubSize(), {0, 2}, coordSize)
+local trans2 = Viewport.Transform2D()
+vp:SetTransform(trans2);
+
+local styleLib = SvgWriter.StyleLibrary();
+
+local vectorColor = "darkgreen";
+local vectorFindColor = "darkorange";
+local circleColor = "black";
+local pointSize = 15;
+
+styleLib:AddStyle(nil, "vector", SvgWriter.Style{
+	stroke=vectorColor, stroke_width="2px", marker_end=SvgWriter.uriLocalElement("arrow")});
+styleLib:AddStyle(nil, "arrowhead", SvgWriter.Style{
+	stroke=vectorColor, fill=vectorColor});
+styleLib:AddStyle(nil, "text", SvgWriter.Style{
+	stroke="none", fill=vectorColor, font_weight="bold",
+	font_size="25px", font_family="monospace"});
+	
+styleLib:AddStyle(nil, "vector-hyp", SvgWriter.Style{
+	stroke=vectorFindColor, stroke_width="2px", marker_end=SvgWriter.uriLocalElement("arrow-hyp")});
+styleLib:AddStyle(nil, "arrowhead-hyp", SvgWriter.Style{
+	stroke=vectorFindColor, fill=vectorFindColor});
+styleLib:AddStyle(nil, "text-hyp", SvgWriter.Style{
+	stroke="none", fill=vectorFindColor, font_weight="bold",
+	font_size="25px", font_family="monospace"});
+	
+styleLib:AddStyle(nil, "circle", SvgWriter.Style{
+	stroke=circleColor, fill="none"});
+
+	
+local axisData = GridAxis.GridAxis2D(vp, 
+	SvgWriter.Style{stroke="black", fill="none", stroke_width="1px"},
+	styleLib, false, nil);
+
+--Compute circle.	
+local circleRadius = (coordSize / 2) - 1;
+local vpRadius = vp:Length(circleRadius);
+
+local circlePts =
+{
+	vmath.vec2(circleRadius, 0),
+	vmath.vec2(-circleRadius, 0),
+}
+
+circlePts = vp:Transform(circlePts);
+
+local circlePath = SvgWriter.Path();
+circlePath:M(circlePts[1]):A({vpRadius, vpRadius}, 0, 1, 0, circlePts[2]);
+
+--Compute vectors
+local angle = math.pi * 0.20;
+local circlePos = vmath.vec2(math.cos(angle), math.sin(angle)) * circleRadius;
+
+local vectors =
+{
+	vmath.vec2(0, 0),
+	vmath.vec2(circlePos.x, 0),
+
+	vmath.vec2(circlePos.x, 0),
+	vmath.vec2(circlePos),
+
+	vmath.vec2(0, 0),
+	vmath.vec2(circlePos),
+};
+
+local vectorLabels = 
+{
+	"X", vmath.vec2(0, 22),
+	"Y", vmath.vec2(5, 10),
+	"R", vmath.vec2(-5, -15),
+}
+
+local styles =
+{
+	{{"vector"}, {"text"}}, 
+	{{"vector-hyp"}, {"text-hyp"}}, 
+	{{"vector"}, {"text"}}, 
+};
+
+vectors = vp:Transform(vectors);
+
+local writer = SvgWriter.SvgWriter(ConstructSVGName(arg[0]), {subImages:Size().x .."px", subImages:Size().y .. "px"});
+	writer:StyleLibrary(styleLib);
+	axisData:AddDefinitions(writer, "g_axes");
+	writer:BeginDefinitions();
+		WriteStandardArrowhead(writer, "arrow", {"arrowhead"});
+		WriteStandardArrowhead(writer, "arrow-hyp", {"arrowhead-hyp"});
+	writer:EndDefinitions();
+
+	writer:Use("g_axes", subImages:Offset(1, 1), subImages:SubSize());
+	
+	writer:Path(circlePath, {"circle"});
+
+	for i=1, #vectors, 2 do
+		writer:Line(vectors[i], vectors[i + 1], styles[(i+1)/2][1]);
+		writer:Text(vectorLabels[i],
+			((vectors[i] + vectors[i + 1]) / 2) + vectorLabels[i + 1], styles[(i+1)/2][2]);
+	end
+writer:Close();
Add a comment to this file

Documents/Illumination/Impostor No Perspective.png

Added
New image

Documents/Illumination/PythagoreanTheorem.mathml

+<?xml version="1.0" encoding="UTF-8"?>
+<math xmlns="http://www.w3.org/1998/Math/MathML" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <mrow>
+        <mtable>
+            <mtr>
+                <mtd>
+                    <msup>
+                        <mi>X</mi>
+                        <mn>2</mn>
+                    </msup>
+                    <mo>+</mo>
+                    <msup>
+                        <mi>Y</mi>
+                        <mn>2</mn>
+                    </msup>
+                </mtd>
+                <mtd>
+                    <mo>=</mo>
+                </mtd>
+                <mtd>
+                    <msup>
+                        <mi>R</mi>
+                        <mn>2</mn>
+                    </msup>
+                </mtd>
+            </mtr>
+            <mtr>
+                <mtd>
+                    <mi>Y</mi>
+                </mtd>
+                <mtd>
+                    <mo>=</mo>
+                </mtd>
+                <mtd>
+                    <mo>&#xb1;</mo>
+                    <msqrt>
+                        <msup>
+                            <mi>R</mi>
+                            <mn>2</mn>
+                        </msup>
+                        <mo>-</mo>
+                        <msup>
+                            <mi>X</mi>
+                            <mn>2</mn>
+                        </msup>
+                    </msqrt>
+                </mtd>
+            </mtr>
+        </mtable>
+    </mrow>
+</math>
Add a comment to this file

Documents/Illumination/PythagoreanTheorem.svg

Added
New image
+<?xml version="1.0" encoding="utf-8"?>
+<svg:svg xmlns="http://www.w3.org/1998/Math/MathML" xmlns:svg="http://www.w3.org/2000/svg" height="29.230195pt" width="118.595722pt" xmlns:svgmath="http://www.grigoriev.ru/svgmath" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 -18.599473 118.595722 29.230195"><svg:metadata><svgmath:metrics top="29.2301953125" axis="14.6150976563" baseline="10.6307226563" bottom="0.0"/></svg:metadata><svg:g transform="translate(0.000000, -3.984375)"><svg:g transform="translate(0.000000, -3.490254)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="4.467773" font-family="Times New Roman" font-style="italic" fill="black">X</svg:text><svg:g transform="translate(9.691406, -5.367188)"><svg:text font-size="8.520000" text-anchor="middle" y="0.000000" x="2.130000" font-family="Times New Roman" fill="black">2</svg:text></svg:g><svg:g transform="translate(16.618070, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">+</svg:text></svg:g><svg:g transform="translate(26.052312, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.336914" font-family="Times New Roman" font-style="italic" fill="black">Y</svg:text><svg:g transform="translate(8.003906, -5.367188)"><svg:text font-size="8.520000" text-anchor="middle" y="0.000000" x="2.130000" font-family="Times New Roman" fill="black">2</svg:text></svg:g></svg:g></svg:g><svg:g transform="translate(47.916219, -7.474629)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">=</svg:text></svg:g><svg:g transform="translate(85.507025, -3.490254)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.940430" font-family="Times New Roman" font-style="italic" fill="black">R</svg:text><svg:g transform="translate(7.605469, -5.367188)"><svg:text font-size="8.520000" text-anchor="middle" y="0.000000" x="2.130000" font-family="Times New Roman" fill="black">2</svg:text></svg:g></svg:g><svg:g transform="translate(15.156156, 14.135098)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.336914" font-family="Times New Roman" font-style="italic" fill="black">Y</svg:text></svg:g><svg:g transform="translate(47.916219, 10.150723)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">=</svg:text></svg:g><svg:g transform="translate(64.283797, 14.135098)"><svg:g transform="translate(0.000000, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.292969" font-family="Times New Roman" fill="black">±</svg:text></svg:g><svg:g transform="translate(7.732605, 0.000000)"><svg:g transform="translate(8.008219, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.940430" font-family="Times New Roman" font-style="italic" fill="black">R</svg:text><svg:g transform="translate(7.605469, -5.367188)"><svg:text font-size="8.520000" text-anchor="middle" y="0.000000" x="2.130000" font-family="Times New Roman" fill="black">2</svg:text></svg:g><svg:g transform="translate(14.532133, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">−</svg:text></svg:g><svg:g transform="translate(23.966375, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="4.467773" font-family="Times New Roman" font-style="italic" fill="black">X</svg:text><svg:g transform="translate(9.691406, -5.367188)"><svg:text font-size="8.520000" text-anchor="middle" y="0.000000" x="2.130000" font-family="Times New Roman" fill="black">2</svg:text></svg:g></svg:g></svg:g><svg:path stroke-linejoin="miter" d="M -0.000000 -5.423012 L 1.950980 -6.129082 L 4.517455 -0.782258 L 4.405271 -0.323976 L 1.826180 -5.697082 L 1.586180 -5.697082 L 4.412939 0.000000 L 7.354898 -12.018164 L 46.579320 -12.018164" stroke="black" stroke-linecap="butt" stroke-miterlimit="10" stroke-width="0.480000" fill="none"/></svg:g></svg:g></svg:g></svg:svg>

Documents/Illumination/RayEquation.mathml

+<?xml version="1.0" encoding="utf-8"?>
+<math display="block" xmlns="http://www.w3.org/1998/Math/MathML">
+	<mtable>
+		<mtr>
+			<mtd>
+				<mover accent="true">
+					<mi>D</mi>
+					<mo>&#x5e;</mo>
+				</mover>
+				<mo>=</mo>
+				<mtext>Ray Direction</mtext>
+			</mtd>
+		</mtr>
+		<mtr>
+			<mtd>
+				<mover accent="true">
+					<mi>O</mi>
+					<mo>&#x21C0;</mo>
+				</mover>
+				<mo>=</mo>
+				<mtext>Ray Origin</mtext>
+			</mtd>
+		</mtr>
+		<mtr>
+			<mtd>
+				<mover accent="true">
+					<mi>P</mi>
+					<mo>&#x21C0;</mo>
+				</mover>
+				<mfenced open="(" close=")" separators=",">
+					<mrow>
+						<mi>t</mi>
+					</mrow>
+				</mfenced>
+				<mo>=</mo>
+				<mover accent="true">
+					<mi>D</mi>
+					<mo>&#x5e;</mo>
+				</mover>
+				<mi>t</mi>
+				<mo>+</mo>
+				<mover accent="true">
+					<mi>O</mi>
+					<mo>&#x21C0;</mo>
+				</mover>
+			</mtd>
+		</mtr>
+	</mtable>
+</math>
Add a comment to this file

Documents/Illumination/RayEquation.svg

Added
New image
+<?xml version="1.0" encoding="utf-8"?>
+<svg:svg xmlns="http://www.w3.org/1998/Math/MathML" xmlns:svg="http://www.w3.org/2000/svg" height="56.531250pt" width="92.104176pt" xmlns:svgmath="http://www.grigoriev.ru/svgmath" viewBox="0 -32.250000 92.104176 56.531250"><svg:metadata><svgmath:metrics top="56.53125" axis="28.265625" baseline="24.28125" bottom="0.0"/></svg:metadata><svg:g transform="translate(0.000000, -3.984375)"><svg:g transform="translate(0.000000, -14.812500)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="4.690430" font-family="Times New Roman" font-style="italic" fill="black">D</svg:text><svg:g transform="translate(1.696289, -9.328125)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="2.815430" font-family="Times New Roman" fill="black">^</svg:text></svg:g><svg:g transform="translate(12.356773, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">=</svg:text></svg:g><svg:g transform="translate(24.457692, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="33.823242" font-family="Times New Roman" fill="black">Ray Direction</svg:text></svg:g></svg:g><svg:g transform="translate(5.868164, 4.312500)"><svg:g transform="translate(1.303711, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="4.333008" font-family="Times New Roman" font-style="italic" fill="black">O</svg:text></svg:g><svg:g transform="translate(0.000000, -9.720703)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="5.636719" font-family="Lucida Sans Unicode" fill="black">⇀</svg:text></svg:g><svg:g transform="translate(14.606773, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">=</svg:text></svg:g><svg:g transform="translate(26.707692, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="26.830078" font-family="Times New Roman" fill="black">Ray Origin</svg:text></svg:g></svg:g><svg:g transform="translate(9.923182, 25.722656)"><svg:g transform="translate(1.766602, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.952148" font-family="Times New Roman" font-style="italic" fill="black">P</svg:text></svg:g><svg:g transform="translate(0.000000, -9.539063)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="5.636719" font-family="Lucida Sans Unicode" fill="black">⇀</svg:text></svg:g><svg:g transform="translate(11.273438, 0.000000)"><svg:g transform="translate(0.000000, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.960938" x="1.998047" font-family="Times New Roman" fill="black">(</svg:text></svg:g><svg:g transform="translate(3.996094, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="1.666992" font-family="Times New Roman" font-style="italic" fill="black">t</svg:text></svg:g><svg:g transform="translate(7.576172, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.960938" x="1.998047" font-family="Times New Roman" fill="black">)</svg:text></svg:g></svg:g><svg:g transform="translate(26.179039, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">=</svg:text></svg:g><svg:g transform="translate(36.279953, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="4.690430" font-family="Times New Roman" font-style="italic" fill="black">D</svg:text><svg:g transform="translate(1.696289, -9.328125)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="2.815430" font-family="Times New Roman" fill="black">^</svg:text></svg:g></svg:g><svg:g transform="translate(45.303391, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="1.666992" font-family="Times New Roman" font-style="italic" fill="black">t</svg:text></svg:g><svg:g transform="translate(51.550133, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">+</svg:text></svg:g><svg:g transform="translate(60.984375, 0.000000)"><svg:g transform="translate(1.303711, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="4.333008" font-family="Times New Roman" font-style="italic" fill="black">O</svg:text></svg:g><svg:g transform="translate(0.000000, -9.720703)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="5.636719" font-family="Lucida Sans Unicode" fill="black">⇀</svg:text></svg:g></svg:g></svg:g></svg:g></svg:svg>

Documents/Illumination/RayTraceDeriv_1.mathml

+<?xml version="1.0" encoding="utf-8"?>
+<math display="block" xmlns="http://www.w3.org/1998/Math/MathML">
+	<mrow>
+		<mfenced open="&#x2225;" close="&#x2225;">
+			<mrow>
+				<mover accent="true">
+					<mi>D</mi>
+					<mo>&#x5e;</mo>
+				</mover>
+				<mi>t</mi>
+				<mo>+</mo>
+				<mover accent="true">
+					<mi>O</mi>
+					<mo>&#x21C0;</mo>
+				</mover>
+				<mo>-</mo>
+				<mover accent="true">
+					<mi>S</mi>
+					<mo>&#x21C0;</mo>
+				</mover>
+			</mrow>
+		</mfenced>
+		<mo>=</mo>
+		<mi>R</mi>
+	</mrow>
+</math>
Add a comment to this file

Documents/Illumination/RayTraceDeriv_1.svg

Added
New image
+<?xml version="1.0" encoding="utf-8"?>
+<svg:svg xmlns="http://www.w3.org/1998/Math/MathML" xmlns:svg="http://www.w3.org/2000/svg" height="16.042969pt" width="104.266930pt" xmlns:svgmath="http://www.grigoriev.ru/svgmath" viewBox="0 -13.453125 104.266930 16.042969"><svg:metadata><svgmath:metrics top="16.04296875" axis="6.57421875" baseline="2.58984375" bottom="1.37109375"/></svg:metadata><svg:g transform="translate(0.000000, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="3.468750" font-family="Lucida Sans Unicode" fill="black">∥</svg:text></svg:g><svg:g transform="translate(10.270836, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="4.690430" font-family="Times New Roman" font-style="italic" fill="black">D</svg:text><svg:g transform="translate(1.696289, -9.328125)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="2.815430" font-family="Times New Roman" fill="black">^</svg:text></svg:g><svg:g transform="translate(9.023438, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="1.666992" font-family="Times New Roman" font-style="italic" fill="black">t</svg:text></svg:g><svg:g transform="translate(15.270180, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">+</svg:text></svg:g><svg:g transform="translate(24.704422, 0.000000)"><svg:g transform="translate(1.303711, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="4.333008" font-family="Times New Roman" font-style="italic" fill="black">O</svg:text></svg:g><svg:g transform="translate(0.000000, -9.720703)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="5.636719" font-family="Lucida Sans Unicode" fill="black">⇀</svg:text></svg:g></svg:g><svg:g transform="translate(38.644523, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">−</svg:text></svg:g><svg:g transform="translate(48.078765, 0.000000)"><svg:g transform="translate(2.384766, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.000000" font-family="Times New Roman" font-style="italic" fill="black">S</svg:text></svg:g><svg:g transform="translate(0.000000, -9.720703)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="5.636719" font-family="Lucida Sans Unicode" fill="black">⇀</svg:text></svg:g></svg:g></svg:g><svg:g transform="translate(72.956375, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="3.468750" font-family="Lucida Sans Unicode" fill="black">∥</svg:text></svg:g><svg:g transform="translate(86.560547, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">=</svg:text></svg:g><svg:g transform="translate(96.661461, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.940430" font-family="Times New Roman" font-style="italic" fill="black">R</svg:text></svg:g></svg:svg>

Documents/Illumination/RayTraceDeriv_2.mathml

+<?xml version="1.0" encoding="utf-8"?>
+<math display="block" xmlns="http://www.w3.org/1998/Math/MathML">
+	<mtable>
+		<mtr>
+			<mtd>
+				<msup>
+					<mfenced open="&#x2225;" close="&#x2225;">
+						<mrow>
+							<mover accent="true">
+								<mi>P</mi>
+								<mo>&#x21C0;</mo>
+							</mover>
+							<mo>-</mo>
+							<mover accent="true">
+								<mi>S</mi>
+								<mo>&#x21C0;</mo>
+							</mover>
+						</mrow>
+					</mfenced>
+					<mn>2</mn>
+				</msup>
+				<mo>=</mo>
+				<msup>
+					<mi>R</mi>
+					<mn>2</mn>
+				</msup>
+			</mtd>
+		</mtr>
+		<mtr>
+			<mtd>
+				<msup>
+					<mfenced open="&#x2225;" close="&#x2225;">
+						<mrow>
+							<mover accent="true">
+								<mi>D</mi>
+								<mo>&#x5e;</mo>
+							</mover>
+							<mi>t</mi>
+							<mo>-</mo>
+							<mover accent="true">
+								<mi>S</mi>
+								<mo>&#x21C0;</mo>
+							</mover>
+						</mrow>
+					</mfenced>
+					<mn>2</mn>
+				</msup>
+				<mo>=</mo>
+				<msup>
+					<mi>R</mi>
+					<mn>2</mn>
+				</msup>
+			</mtd>
+		</mtr>
+	</mtable>
+</math>
Add a comment to this file

Documents/Illumination/RayTraceDeriv_2.svg

Added
New image
+<?xml version="1.0" encoding="utf-8"?>
+<svg:svg xmlns="http://www.w3.org/1998/Math/MathML" xmlns:svg="http://www.w3.org/2000/svg" height="35.109375pt" width="86.079250pt" xmlns:svgmath="http://www.grigoriev.ru/svgmath" viewBox="0 -21.539063 86.079250 35.109375"><svg:metadata><svgmath:metrics top="35.109375" axis="17.5546875" baseline="13.5703125" bottom="0.0"/></svg:metadata><svg:g transform="translate(0.000000, -3.984375)"><svg:g transform="translate(0.665039, -5.044922)"><svg:g transform="translate(0.000000, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="3.468750" font-family="Lucida Sans Unicode" fill="black">∥</svg:text></svg:g><svg:g transform="translate(10.270836, 0.000000)"><svg:g transform="translate(1.766602, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.952148" font-family="Times New Roman" font-style="italic" fill="black">P</svg:text></svg:g><svg:g transform="translate(0.000000, -9.539063)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="5.636719" font-family="Lucida Sans Unicode" fill="black">⇀</svg:text></svg:g><svg:g transform="translate(13.940102, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">−</svg:text></svg:g><svg:g transform="translate(23.374344, 0.000000)"><svg:g transform="translate(2.384766, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.000000" font-family="Times New Roman" font-style="italic" fill="black">S</svg:text></svg:g><svg:g transform="translate(0.000000, -9.720703)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="5.636719" font-family="Lucida Sans Unicode" fill="black">⇀</svg:text></svg:g></svg:g></svg:g><svg:g transform="translate(48.251953, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="3.468750" font-family="Lucida Sans Unicode" fill="black">∥</svg:text></svg:g><svg:g transform="translate(55.189453, -6.752109)"><svg:text font-size="8.520000" text-anchor="middle" y="0.000000" x="2.130000" font-family="Times New Roman" fill="black">2</svg:text></svg:g><svg:g transform="translate(62.782789, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">=</svg:text></svg:g><svg:g transform="translate(72.883703, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.940430" font-family="Times New Roman" font-style="italic" fill="black">R</svg:text><svg:g transform="translate(7.605469, -5.367188)"><svg:text font-size="8.520000" text-anchor="middle" y="0.000000" x="2.130000" font-family="Times New Roman" fill="black">2</svg:text></svg:g></svg:g></svg:g><svg:g transform="translate(0.000000, 16.335938)"><svg:g transform="translate(0.000000, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="3.468750" font-family="Lucida Sans Unicode" fill="black">∥</svg:text></svg:g><svg:g transform="translate(10.270836, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="4.690430" font-family="Times New Roman" font-style="italic" fill="black">D</svg:text><svg:g transform="translate(1.696289, -9.328125)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="2.815430" font-family="Times New Roman" fill="black">^</svg:text></svg:g><svg:g transform="translate(9.023438, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="1.666992" font-family="Times New Roman" font-style="italic" fill="black">t</svg:text></svg:g><svg:g transform="translate(15.270180, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">−</svg:text></svg:g><svg:g transform="translate(24.704422, 0.000000)"><svg:g transform="translate(2.384766, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.000000" font-family="Times New Roman" font-style="italic" fill="black">S</svg:text></svg:g><svg:g transform="translate(0.000000, -9.720703)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="5.636719" font-family="Lucida Sans Unicode" fill="black">⇀</svg:text></svg:g></svg:g></svg:g><svg:g transform="translate(49.582031, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="3.468750" font-family="Lucida Sans Unicode" fill="black">∥</svg:text></svg:g><svg:g transform="translate(56.519531, -9.037266)"><svg:text font-size="8.520000" text-anchor="middle" y="0.000000" x="2.130000" font-family="Times New Roman" fill="black">2</svg:text></svg:g><svg:g transform="translate(64.112867, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">=</svg:text></svg:g><svg:g transform="translate(74.213781, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.940430" font-family="Times New Roman" font-style="italic" fill="black">R</svg:text><svg:g transform="translate(7.605469, -5.367188)"><svg:text font-size="8.520000" text-anchor="middle" y="0.000000" x="2.130000" font-family="Times New Roman" fill="black">2</svg:text></svg:g></svg:g></svg:g></svg:g></svg:svg>

Documents/Illumination/RayTraceDeriv_3.mathml

+<?xml version="1.0" encoding="utf-8"?>
+<math display="block" xmlns="http://www.w3.org/1998/Math/MathML">
+	<mrow>
+		<mfenced open="(" close=")">
+			<mrow>
+				<mover accent="true">
+					<mi>D</mi>
+					<mo>&#x5e;</mo>
+				</mover>
+				<mi>t</mi>
+				<mo>-</mo>
+				<mover accent="true">
+					<mi>S</mi>
+					<mo>&#x21C0;</mo>
+				</mover>
+			</mrow>
+		</mfenced>
+		<mo>&#xb7;</mo>
+		<mfenced open="(" close=")">
+			<mrow>
+				<mover accent="true">
+					<mi>D</mi>
+					<mo>&#x5e;</mo>
+				</mover>
+				<mi>t</mi>
+				<mo>-</mo>
+				<mover accent="true">
+					<mi>S</mi>
+					<mo>&#x21C0;</mo>
+				</mover>
+			</mrow>
+		</mfenced>
+		<mo>=</mo>
+		<msup>
+			<mi>R</mi>
+			<mn>2</mn>
+		</msup>
+	</mrow>
+</math>
Add a comment to this file

Documents/Illumination/RayTraceDeriv_3.svg

Added
New image
+<?xml version="1.0" encoding="utf-8"?>
+<svg:svg xmlns="http://www.w3.org/1998/Math/MathML" xmlns:svg="http://www.w3.org/2000/svg" height="16.071907pt" width="121.235914pt" xmlns:svgmath="http://www.grigoriev.ru/svgmath" viewBox="0 -13.482063 121.235914 16.071907"><svg:metadata><svgmath:metrics top="16.0719068878" axis="6.57421875" baseline="2.58984375" bottom="0.0578762755102"/></svg:metadata><svg:g transform="translate(0.000000, -3.984375)"><svg:text font-size="17.632653" transform="scale(0.680556, 1)" text-anchor="middle" y="2.745297" x="2.935906" font-family="Times New Roman" fill="black">(</svg:text></svg:g><svg:g transform="translate(3.996094, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="4.690430" font-family="Times New Roman" font-style="italic" fill="black">D</svg:text><svg:g transform="translate(1.696289, -9.328125)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="2.815430" font-family="Times New Roman" fill="black">^</svg:text></svg:g><svg:g transform="translate(9.023438, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="1.666992" font-family="Times New Roman" font-style="italic" fill="black">t</svg:text></svg:g><svg:g transform="translate(15.270180, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">−</svg:text></svg:g><svg:g transform="translate(24.704422, 0.000000)"><svg:g transform="translate(2.384766, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.000000" font-family="Times New Roman" font-style="italic" fill="black">S</svg:text></svg:g><svg:g transform="translate(0.000000, -9.720703)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="5.636719" font-family="Lucida Sans Unicode" fill="black">⇀</svg:text></svg:g></svg:g></svg:g><svg:g transform="translate(39.973953, -3.984375)"><svg:text font-size="17.632653" transform="scale(0.680556, 1)" text-anchor="middle" y="2.745297" x="2.935906" font-family="Times New Roman" fill="black">)</svg:text></svg:g><svg:g transform="translate(45.970051, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="1.998047" font-family="Times New Roman" fill="black">·</svg:text></svg:g><svg:g transform="translate(51.966149, 0.000000)"><svg:g transform="translate(0.000000, -3.984375)"><svg:text font-size="17.632653" transform="scale(0.680556, 1)" text-anchor="middle" y="2.745297" x="2.935906" font-family="Times New Roman" fill="black">(</svg:text></svg:g><svg:g transform="translate(3.996094, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="4.690430" font-family="Times New Roman" font-style="italic" fill="black">D</svg:text><svg:g transform="translate(1.696289, -9.328125)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="2.815430" font-family="Times New Roman" fill="black">^</svg:text></svg:g><svg:g transform="translate(9.023438, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="1.666992" font-family="Times New Roman" font-style="italic" fill="black">t</svg:text></svg:g><svg:g transform="translate(15.270180, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">−</svg:text></svg:g><svg:g transform="translate(24.704422, 0.000000)"><svg:g transform="translate(2.384766, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.000000" font-family="Times New Roman" font-style="italic" fill="black">S</svg:text></svg:g><svg:g transform="translate(0.000000, -9.720703)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="5.636719" font-family="Lucida Sans Unicode" fill="black">⇀</svg:text></svg:g></svg:g></svg:g><svg:g transform="translate(39.973953, -3.984375)"><svg:text font-size="17.632653" transform="scale(0.680556, 1)" text-anchor="middle" y="2.745297" x="2.935906" font-family="Times New Roman" fill="black">)</svg:text></svg:g></svg:g><svg:g transform="translate(99.269531, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">=</svg:text></svg:g><svg:g transform="translate(109.370445, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.940430" font-family="Times New Roman" font-style="italic" fill="black">R</svg:text><svg:g transform="translate(7.605469, -5.367188)"><svg:text font-size="8.520000" text-anchor="middle" y="0.000000" x="2.130000" font-family="Times New Roman" fill="black">2</svg:text></svg:g></svg:g></svg:svg>

Documents/Illumination/RayTraceDeriv_4.mathml

+<?xml version="1.0" encoding="utf-8"?>
+<math display="block" xmlns="http://www.w3.org/1998/Math/MathML">
+	<mrow>
+		<mfenced open="(" close=")">
+			<mrow>
+				<mover accent="true">
+					<mi>D</mi>
+					<mo>&#x5e;</mo>
+				</mover>
+				<mo>&#xb7;</mo>
+				<mover accent="true">
+					<mi>D</mi>
+					<mo>&#x5e;</mo>
+				</mover>
+			</mrow>
+		</mfenced>
+		<msup>
+			<mi>t</mi>
+			<mn>2</mn>
+		</msup>
+		<mo>-</mo>
+		<mn>2</mn>
+		<mfenced open="(" close=")">
+			<mrow>
+				<mover accent="true">
+					<mi>D</mi>
+					<mo>&#x5e;</mo>
+				</mover>
+				<mo>&#xb7;</mo>
+				<mover accent="true">
+					<mi>S</mi>
+					<mo>&#x21C0;</mo>
+				</mover>
+			</mrow>
+		</mfenced>
+		<mi>t</mi>
+		<mo>+</mo>
+		<mfenced open="(" close=")">
+			<mrow>
+				<mover accent="true">
+					<mi>S</mi>
+					<mo>&#x21C0;</mo>
+				</mover>
+				<mo>&#xb7;</mo>
+				<mover accent="true">
+					<mi>S</mi>
+					<mo>&#x21C0;</mo>
+				</mover>
+			</mrow>
+		</mfenced>
+		<mo>=</mo>
+		<msup>
+			<mi>R</mi>
+			<mn>2</mn>
+		</msup>
+	</mrow>
+</math>
Add a comment to this file

Documents/Illumination/RayTraceDeriv_4.svg

Added
New image
+<?xml version="1.0" encoding="utf-8"?>
+<svg:svg xmlns="http://www.w3.org/1998/Math/MathML" xmlns:svg="http://www.w3.org/2000/svg" height="16.071907pt" width="175.777180pt" xmlns:svgmath="http://www.grigoriev.ru/svgmath" viewBox="0 -13.482063 175.777180 16.071907"><svg:metadata><svgmath:metrics top="16.0719068878" axis="6.57421875" baseline="2.58984375" bottom="0.0529672395274"/></svg:metadata><svg:g transform="translate(0.000000, -3.984375)"><svg:text font-size="17.632653" transform="scale(0.680556, 1)" text-anchor="middle" y="2.745297" x="2.935906" font-family="Times New Roman" fill="black">(</svg:text></svg:g><svg:g transform="translate(3.996094, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="4.690430" font-family="Times New Roman" font-style="italic" fill="black">D</svg:text><svg:g transform="translate(1.696289, -9.328125)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="2.815430" font-family="Times New Roman" fill="black">^</svg:text></svg:g><svg:g transform="translate(11.023442, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="1.998047" font-family="Times New Roman" fill="black">·</svg:text></svg:g><svg:g transform="translate(17.019539, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="4.690430" font-family="Times New Roman" font-style="italic" fill="black">D</svg:text><svg:g transform="translate(1.696289, -9.328125)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="2.815430" font-family="Times New Roman" fill="black">^</svg:text></svg:g></svg:g></svg:g><svg:g transform="translate(30.039071, -3.984375)"><svg:text font-size="17.632653" transform="scale(0.680556, 1)" text-anchor="middle" y="2.745297" x="2.935906" font-family="Times New Roman" fill="black">)</svg:text></svg:g><svg:g transform="translate(34.035164, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="1.666992" font-family="Times New Roman" font-style="italic" fill="black">t</svg:text><svg:g transform="translate(3.580078, -5.367188)"><svg:text font-size="8.520000" text-anchor="middle" y="0.000000" x="2.130000" font-family="Times New Roman" fill="black">2</svg:text></svg:g></svg:g><svg:g transform="translate(44.541906, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">−</svg:text></svg:g><svg:g transform="translate(53.976148, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.000000" font-family="Times New Roman" fill="black">2</svg:text></svg:g><svg:g transform="translate(59.976148, 0.000000)"><svg:g transform="translate(0.000000, -3.984375)"><svg:text font-size="17.632653" transform="scale(0.680556, 1)" text-anchor="middle" y="2.745297" x="2.935906" font-family="Times New Roman" fill="black">(</svg:text></svg:g><svg:g transform="translate(3.996094, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="4.690430" font-family="Times New Roman" font-style="italic" fill="black">D</svg:text><svg:g transform="translate(1.696289, -9.328125)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="2.815430" font-family="Times New Roman" fill="black">^</svg:text></svg:g><svg:g transform="translate(11.023442, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="1.998047" font-family="Times New Roman" fill="black">·</svg:text></svg:g><svg:g transform="translate(17.019539, 0.000000)"><svg:g transform="translate(2.384766, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.000000" font-family="Times New Roman" font-style="italic" fill="black">S</svg:text></svg:g><svg:g transform="translate(0.000000, -9.720703)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="5.636719" font-family="Lucida Sans Unicode" fill="black">⇀</svg:text></svg:g></svg:g></svg:g><svg:g transform="translate(32.289071, -3.984375)"><svg:text font-size="17.632653" transform="scale(0.680556, 1)" text-anchor="middle" y="2.745297" x="2.935906" font-family="Times New Roman" fill="black">)</svg:text></svg:g></svg:g><svg:g transform="translate(96.261313, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="1.666992" font-family="Times New Roman" font-style="italic" fill="black">t</svg:text></svg:g><svg:g transform="translate(102.508055, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">+</svg:text></svg:g><svg:g transform="translate(111.942297, 0.000000)"><svg:g transform="translate(0.000000, -3.984375)"><svg:text font-size="15.119227" transform="scale(0.793691, 1)" text-anchor="middle" y="3.287745" x="2.517410" font-family="Times New Roman" fill="black">(</svg:text></svg:g><svg:g transform="translate(3.996094, 0.000000)"><svg:g transform="translate(2.384766, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.000000" font-family="Times New Roman" font-style="italic" fill="black">S</svg:text></svg:g><svg:g transform="translate(0.000000, -9.720703)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="5.636719" font-family="Lucida Sans Unicode" fill="black">⇀</svg:text></svg:g><svg:g transform="translate(13.273442, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="1.998047" font-family="Times New Roman" fill="black">·</svg:text></svg:g><svg:g transform="translate(19.269539, 0.000000)"><svg:g transform="translate(2.384766, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.000000" font-family="Times New Roman" font-style="italic" fill="black">S</svg:text></svg:g><svg:g transform="translate(0.000000, -9.720703)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="5.636719" font-family="Lucida Sans Unicode" fill="black">⇀</svg:text></svg:g></svg:g></svg:g><svg:g transform="translate(34.539071, -3.984375)"><svg:text font-size="15.119227" transform="scale(0.793691, 1)" text-anchor="middle" y="3.287745" x="2.517410" font-family="Times New Roman" fill="black">)</svg:text></svg:g></svg:g><svg:g transform="translate(153.810797, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">=</svg:text></svg:g><svg:g transform="translate(163.911711, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.940430" font-family="Times New Roman" font-style="italic" fill="black">R</svg:text><svg:g transform="translate(7.605469, -5.367188)"><svg:text font-size="8.520000" text-anchor="middle" y="0.000000" x="2.130000" font-family="Times New Roman" fill="black">2</svg:text></svg:g></svg:g></svg:svg>

Documents/Illumination/RayTraceDeriv_5.mathml

+<?xml version="1.0" encoding="utf-8"?>
+<math display="block" xmlns="http://www.w3.org/1998/Math/MathML">
+    <mtable columnalign="left">
+        <mtr>
+            <mtd>
+                <mi>A</mi>
+                <msup>
+                    <mi>x</mi>
+                    <mn>2</mn>
+                </msup>
+                <mo>+</mo>
+                <mi>B</mi>
+                <mi>x</mi>
+                <mo>+</mo>
+                <mi>C</mi>
+                <mo>=</mo>
+                <mn>0</mn>
+            </mtd>
+        </mtr>
+        <mtr>
+            <mtd>
+                <mi>x</mi>
+                <mo>=</mo>
+                <mfrac>
+                    <mrow>
+						<mo>-</mo>
+						<mi>B</mi>
+						<mo>&#xb1;</mo>
+						<msqrt>
+							<msup>
+								<mi>B</mi>
+								<mn>2</mn>
+							</msup>
+							<mo>-</mo>
+							<mn>4</mn>
+							<mi>A</mi>
+							<mi>C</mi>
+						</msqrt>
+                    </mrow>
+                    <mrow>
+						<mn>2</mn>
+						<mi>A</mi>
+                    </mrow>
+                </mfrac>
+            </mtd>
+        </mtr>
+        <mtr>
+            <mtd>
+				<mi>A</mi>
+				<mo>=</mo>
+				<mover accent="true">
+					<mi>D</mi>
+					<mo>&#x5e;</mo>
+				</mover>
+				<mo>&#xb7;</mo>
+				<mover accent="true">
+					<mi>D</mi>
+					<mo>&#x5e;</mo>
+				</mover>
+				<mo>=</mo>
+				<mn>1</mn>
+            </mtd>
+        </mtr>
+        <mtr>
+            <mtd>
+				<mi>B</mi>
+				<mo>=</mo>
+				<mo>-</mo>
+				<mn>2</mn>
+				<mfenced open="(" close=")">
+					<mrow>
+						<mover accent="true">
+							<mi>D</mi>
+							<mo>&#x5e;</mo>
+						</mover>
+						<mo>&#xb7;</mo>
+						<mover accent="true">
+							<mi>S</mi>
+							<mo>&#x21C0;</mo>
+						</mover>
+					</mrow>
+				</mfenced>
+			</mtd>
+        </mtr>
+        <mtr>
+            <mtd>
+				<mi>C</mi>
+				<mo>=</mo>
+				<mfenced open="(" close=")">
+					<mrow>
+						<mover accent="true">
+							<mi>S</mi>
+							<mo>&#x21C0;</mo>
+						</mover>
+						<mo>&#xb7;</mo>
+						<mover accent="true">
+							<mi>S</mi>
+							<mo>&#x21C0;</mo>
+						</mover>
+					</mrow>
+				</mfenced>
+				<mo>-</mo>
+				<msup>
+					<mi>R</mi>
+					<mn>2</mn>
+				</msup>
+            </mtd>
+        </mtr>
+    </mtable>
+</math>
Add a comment to this file

Documents/Illumination/RayTraceDeriv_5.svg

Added
New image
+<?xml version="1.0" encoding="utf-8"?>
+<svg:svg xmlns="http://www.w3.org/1998/Math/MathML" xmlns:svg="http://www.w3.org/2000/svg" height="95.305485pt" width="84.379149pt" xmlns:svgmath="http://www.grigoriev.ru/svgmath" viewBox="0 -51.637117 84.379149 95.305485"><svg:metadata><svgmath:metrics top="95.3054848831" axis="47.6527424416" baseline="43.6683674416" bottom="0.0"/></svg:metadata><svg:g transform="translate(0.000000, -3.984375)"><svg:g transform="translate(0.000000, -36.527899)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="4.250977" font-family="Times New Roman" font-style="italic" fill="black">A</svg:text><svg:g transform="translate(7.916016, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.061523" font-family="Times New Roman" font-style="italic" fill="black">x</svg:text><svg:g transform="translate(5.724609, -5.367188)"><svg:text font-size="8.520000" text-anchor="middle" y="0.000000" x="2.130000" font-family="Times New Roman" fill="black">2</svg:text></svg:g></svg:g><svg:g transform="translate(20.567289, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">+</svg:text></svg:g><svg:g transform="translate(30.001531, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.940430" font-family="Times New Roman" font-style="italic" fill="black">B</svg:text></svg:g><svg:g transform="translate(37.607000, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.061523" font-family="Times New Roman" font-style="italic" fill="black">x</svg:text></svg:g><svg:g transform="translate(45.998273, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">+</svg:text></svg:g><svg:g transform="translate(55.432515, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="4.001953" font-family="Times New Roman" font-style="italic" fill="black">C</svg:text></svg:g><svg:g transform="translate(67.209211, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">=</svg:text></svg:g><svg:g transform="translate(77.310125, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.000000" font-family="Times New Roman" fill="black">0</svg:text></svg:g></svg:g><svg:g transform="translate(0.000000, -15.032676)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.061523" font-family="Times New Roman" font-style="italic" fill="black">x</svg:text><svg:g transform="translate(9.057945, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">=</svg:text></svg:g><svg:g transform="translate(19.744797, -3.984375)"><svg:g transform="translate(0.585938, -1.940409)"><svg:g transform="translate(0.000000, -2.828906)"><svg:text font-size="8.520000" text-anchor="middle" y="2.828906" x="2.402490" font-family="Times New Roman" fill="black">−</svg:text></svg:g><svg:g transform="translate(5.278314, 0.000000)"><svg:text font-size="8.520000" text-anchor="middle" y="0.000000" x="2.797705" font-family="Times New Roman" font-style="italic" fill="black">B</svg:text></svg:g><svg:g transform="translate(12.571528, -2.828906)"><svg:text font-size="8.520000" text-anchor="middle" y="2.828906" x="2.338008" font-family="Times New Roman" fill="black">±</svg:text></svg:g><svg:g transform="translate(19.481675, 0.000000)"><svg:g transform="translate(6.476824, 0.000000)"><svg:text font-size="8.520000" text-anchor="middle" y="0.000000" x="2.797705" font-family="Times New Roman" font-style="italic" fill="black">B</svg:text><svg:g transform="translate(5.399883, -3.810703)"><svg:text font-size="8.000000" text-anchor="middle" y="0.000000" x="2.000000" font-family="Times New Roman" fill="black">2</svg:text></svg:g><svg:g transform="translate(11.293214, -2.828906)"><svg:text font-size="8.520000" text-anchor="middle" y="2.828906" x="2.402490" font-family="Times New Roman" fill="black">−</svg:text></svg:g><svg:g transform="translate(17.991526, 0.000000)"><svg:text font-size="8.520000" text-anchor="middle" y="0.000000" x="2.130000" font-family="Times New Roman" fill="black">4</svg:text></svg:g><svg:g transform="translate(22.251526, 0.000000)"><svg:text font-size="8.520000" text-anchor="middle" y="0.000000" x="3.018193" font-family="Times New Roman" font-style="italic" fill="black">A</svg:text></svg:g><svg:g transform="translate(27.871897, 0.000000)"><svg:text font-size="8.520000" text-anchor="middle" y="0.000000" x="2.841387" font-family="Times New Roman" font-style="italic" fill="black">C</svg:text></svg:g></svg:g><svg:path stroke-linejoin="miter" d="M 0.000000 -4.433561 L 1.543393 -5.010805 L 3.681786 -0.555820 L 3.602274 -0.230151 L 1.454785 -4.704085 L 1.284385 -4.704085 L 3.607780 0.000000 L 6.012966 -9.851211 L 40.807364 -9.851211" stroke="black" stroke-linecap="butt" stroke-miterlimit="10" stroke-width="0.340800" fill="none"/></svg:g></svg:g><svg:g transform="translate(25.790271, 7.369746)"><svg:text font-size="8.520000" text-anchor="middle" y="0.000000" x="2.130000" font-family="Times New Roman" fill="black">2</svg:text><svg:g transform="translate(4.260000, 0.000000)"><svg:text font-size="8.520000" text-anchor="middle" y="0.000000" x="3.018193" font-family="Times New Roman" font-style="italic" fill="black">A</svg:text></svg:g></svg:g><svg:line stroke-width="0.585938" x1="0.000000" x2="61.460914" stroke="black" stroke-linecap="butt" stroke-dasharray="none" y1="0.000000" y2="0.000000" fill="none"/></svg:g></svg:g><svg:g transform="translate(0.000000, 7.173008)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="4.250977" font-family="Times New Roman" font-style="italic" fill="black">A</svg:text><svg:g transform="translate(11.249352, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">=</svg:text></svg:g><svg:g transform="translate(21.350266, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="4.690430" font-family="Times New Roman" font-style="italic" fill="black">D</svg:text><svg:g transform="translate(1.696289, -9.328125)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="2.815430" font-family="Times New Roman" fill="black">^</svg:text></svg:g></svg:g><svg:g transform="translate(32.373707, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="1.998047" font-family="Times New Roman" fill="black">·</svg:text></svg:g><svg:g transform="translate(38.369805, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="4.690430" font-family="Times New Roman" font-style="italic" fill="black">D</svg:text><svg:g transform="translate(1.696289, -9.328125)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="2.815430" font-family="Times New Roman" fill="black">^</svg:text></svg:g></svg:g><svg:g transform="translate(50.726579, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">=</svg:text></svg:g><svg:g transform="translate(60.827493, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.000000" font-family="Times New Roman" fill="black">1</svg:text></svg:g></svg:g><svg:g transform="translate(0.000000, 26.022259)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.940430" font-family="Times New Roman" font-style="italic" fill="black">B</svg:text><svg:g transform="translate(10.938805, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">=</svg:text></svg:g><svg:g transform="translate(23.706383, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">−</svg:text></svg:g><svg:g transform="translate(33.140625, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.000000" font-family="Times New Roman" fill="black">2</svg:text></svg:g><svg:g transform="translate(39.140625, 0.000000)"><svg:g transform="translate(0.000000, -3.984375)"><svg:text font-size="17.632653" transform="scale(0.680556, 1)" text-anchor="middle" y="2.745297" x="2.935906" font-family="Times New Roman" fill="black">(</svg:text></svg:g><svg:g transform="translate(3.996094, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="4.690430" font-family="Times New Roman" font-style="italic" fill="black">D</svg:text><svg:g transform="translate(1.696289, -9.328125)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="2.815430" font-family="Times New Roman" fill="black">^</svg:text></svg:g><svg:g transform="translate(11.023442, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="1.998047" font-family="Times New Roman" fill="black">·</svg:text></svg:g><svg:g transform="translate(17.019539, 0.000000)"><svg:g transform="translate(2.384766, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.000000" font-family="Times New Roman" font-style="italic" fill="black">S</svg:text></svg:g><svg:g transform="translate(0.000000, -9.720703)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="5.636719" font-family="Lucida Sans Unicode" fill="black">⇀</svg:text></svg:g></svg:g></svg:g><svg:g transform="translate(32.289071, -3.984375)"><svg:text font-size="17.632653" transform="scale(0.680556, 1)" text-anchor="middle" y="2.745297" x="2.935906" font-family="Times New Roman" fill="black">)</svg:text></svg:g></svg:g></svg:g><svg:g transform="translate(0.000000, 45.115866)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="4.001953" font-family="Times New Roman" font-style="italic" fill="black">C</svg:text><svg:g transform="translate(11.776695, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">=</svg:text></svg:g><svg:g transform="translate(21.877609, 0.000000)"><svg:g transform="translate(0.000000, -3.984375)"><svg:text font-size="15.119227" transform="scale(0.793691, 1)" text-anchor="middle" y="3.287745" x="2.517410" font-family="Times New Roman" fill="black">(</svg:text></svg:g><svg:g transform="translate(3.996094, 0.000000)"><svg:g transform="translate(2.384766, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.000000" font-family="Times New Roman" font-style="italic" fill="black">S</svg:text></svg:g><svg:g transform="translate(0.000000, -9.720703)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="5.636719" font-family="Lucida Sans Unicode" fill="black">⇀</svg:text></svg:g><svg:g transform="translate(13.273442, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="1.998047" font-family="Times New Roman" fill="black">·</svg:text></svg:g><svg:g transform="translate(19.269539, 0.000000)"><svg:g transform="translate(2.384766, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.000000" font-family="Times New Roman" font-style="italic" fill="black">S</svg:text></svg:g><svg:g transform="translate(0.000000, -9.720703)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="5.636719" font-family="Lucida Sans Unicode" fill="black">⇀</svg:text></svg:g></svg:g></svg:g><svg:g transform="translate(34.539071, -3.984375)"><svg:text font-size="15.119227" transform="scale(0.793691, 1)" text-anchor="middle" y="3.287745" x="2.517410" font-family="Times New Roman" fill="black">)</svg:text></svg:g></svg:g><svg:g transform="translate(63.079438, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">−</svg:text></svg:g><svg:g transform="translate(72.513680, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.940430" font-family="Times New Roman" font-style="italic" fill="black">R</svg:text><svg:g transform="translate(7.605469, -5.367188)"><svg:text font-size="8.520000" text-anchor="middle" y="0.000000" x="2.130000" font-family="Times New Roman" fill="black">2</svg:text></svg:g></svg:g></svg:g></svg:g></svg:svg>

Documents/Illumination/SphereEquation.mathml

+<?xml version="1.0" encoding="utf-8"?>
+<math display="block" xmlns="http://www.w3.org/1998/Math/MathML">
+	<mtable>
+		<mtr>
+			<mtd>
+				<mi>R</mi>
+				<mo>=</mo>
+				<mtext>Sphere Radius</mtext>
+			</mtd>
+		</mtr>
+		<mtr>
+			<mtd>
+				<mover accent="true">
+					<mi>S</mi>
+					<mo>&#x21C0;</mo>
+				</mover>
+				<mo>=</mo>
+				<mtext>Sphere Center</mtext>
+			</mtd>
+		</mtr>
+		<mtr>
+			<mtd>
+				<mfenced open="&#x2225;" close="&#x2225;">
+					<mrow>
+						<mover accent="true">
+							<mi>P</mi>
+							<mo>&#x21C0;</mo>
+						</mover>
+						<mo>-</mo>
+						<mover accent="true">
+							<mi>S</mi>
+							<mo>&#x21C0;</mo>
+						</mover>
+					</mrow>
+				</mfenced>
+				<mo>=</mo>
+				<mi>R</mi>
+			</mtd>
+		</mtr>
+	</mtable>
+</math>
Add a comment to this file

Documents/Illumination/SphereEquation.svg

Added
New image
+<?xml version="1.0" encoding="utf-8"?>
+<svg:svg xmlns="http://www.w3.org/1998/Math/MathML" xmlns:svg="http://www.w3.org/2000/svg" height="47.753906pt" width="95.092457pt" xmlns:svgmath="http://www.grigoriev.ru/svgmath" viewBox="0 -27.861328 95.092457 47.753906"><svg:metadata><svgmath:metrics top="47.75390625" axis="23.876953125" baseline="19.892578125" bottom="0.0"/></svg:metadata><svg:g transform="translate(0.000000, -3.984375)"><svg:g transform="translate(1.198242, -15.544922)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.940430" font-family="Times New Roman" font-style="italic" fill="black">R</svg:text><svg:g transform="translate(10.938805, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">=</svg:text></svg:g><svg:g transform="translate(23.039723, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="34.828125" font-family="Times New Roman" fill="black">Sphere Radius</svg:text></svg:g></svg:g><svg:g transform="translate(0.000000, 3.556641)"><svg:g transform="translate(2.384766, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.000000" font-family="Times New Roman" font-style="italic" fill="black">S</svg:text></svg:g><svg:g transform="translate(0.000000, -9.720703)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="5.636719" font-family="Lucida Sans Unicode" fill="black">⇀</svg:text></svg:g><svg:g transform="translate(14.606773, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">=</svg:text></svg:g><svg:g transform="translate(26.707692, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="34.154297" font-family="Times New Roman" fill="black">Sphere Center</svg:text></svg:g></svg:g><svg:g transform="translate(7.764975, 22.658203)"><svg:g transform="translate(0.000000, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="3.468750" font-family="Lucida Sans Unicode" fill="black">∥</svg:text></svg:g><svg:g transform="translate(10.270836, 0.000000)"><svg:g transform="translate(1.766602, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.952148" font-family="Times New Roman" font-style="italic" fill="black">P</svg:text></svg:g><svg:g transform="translate(0.000000, -9.539063)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="5.636719" font-family="Lucida Sans Unicode" fill="black">⇀</svg:text></svg:g><svg:g transform="translate(13.940102, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">−</svg:text></svg:g><svg:g transform="translate(23.374344, 0.000000)"><svg:g transform="translate(2.384766, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.000000" font-family="Times New Roman" font-style="italic" fill="black">S</svg:text></svg:g><svg:g transform="translate(0.000000, -9.720703)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="5.636719" font-family="Lucida Sans Unicode" fill="black">⇀</svg:text></svg:g></svg:g></svg:g><svg:g transform="translate(48.251953, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.468750" x="3.468750" font-family="Lucida Sans Unicode" fill="black">∥</svg:text></svg:g><svg:g transform="translate(61.856125, -3.984375)"><svg:text font-size="12.000000" text-anchor="middle" y="3.984375" x="3.383789" font-family="Times New Roman" fill="black">=</svg:text></svg:g><svg:g transform="translate(71.957039, 0.000000)"><svg:text font-size="12.000000" text-anchor="middle" y="0.000000" x="3.940430" font-family="Times New Roman" font-style="italic" fill="black">R</svg:text></svg:g></svg:g></svg:g></svg:svg>

Documents/Illumination/Tutorial 12.xml

                 don't have to write <quote>layout(std140)</quote> for each of the three uniform
                 blocks we use in each shader file.</para>
             <para>Also, note the use of <literal>Mtl</literal> at the foot of the uniform block
-                definition. When nothing is placed there, then the names in the uniform block are
-                global. If an identifier is placed there, then that name must be used to qualify
-                access to the names within that block. This allows us to have the <literal>in vec4
+                definition. This is called the <glossterm>instance name</glossterm> of an interface
+                block. When no instance name is specified, then the names in the uniform block are
+                global. If an instance name is specified, this name must be used to qualify access
+                to the names within that block. This allows us to have the <literal>in vec4
                     diffuseColor</literal> be separate from the material definition's
                     <varname>Mtl.diffuseColor</varname>.</para>
             <para>What we want to do is put 6 material blocks in a single uniform buffer. One might
                 </glossdef>
             </glossentry>
             <glossentry>
+                <glossterm>instance name</glossterm>
+                <glossdef>
+                    <para>For uniform blocks (or other kinds of interface blocks), this name is used
+                        within a shader to name-qualifier the members of the block. These are
+                        optional, unless there is a naming conflict, or unless an array needs to be
+                        specified.</para>
+                </glossdef>
+            </glossentry>
+            <glossentry>
                 <glossterm>light clipping</glossterm>
                 <glossdef>
                     <para>Light values drawn to the screen are clamped to the range [0, 1]. When

Documents/Illumination/Tutorial 13.xml

+<?xml version="1.0" encoding="UTF-8"?>
+<?oxygen RNGSchema="http://docbook.org/xml/5.0/rng/docbookxi.rng" type="xml"?>
+<?oxygen SCHSchema="http://docbook.org/xml/5.0/rng/docbookxi.rng"?>
+<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xi="http://www.w3.org/2001/XInclude"
+    xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0">
+    <?dbhtml filename="Tutorial 13.html" ?>
+    <title>Lies and Impostors</title>
+    <para>Lighting in these tutorials has ultimately been a form of deception. An increasingly
+        accurate one, but it is deception all the same. We are not rendering round objects; we
+        simply use lighting and interpolation of surface characteristics to make an object appear
+        round. Sometimes we have artifacts or optical illusions that show the lie for what it is.
+        Even when the lie is near-perfect, the geometry of a model still doesn't correspond to what
+        the lighting makes the geometry appear to be.</para>
+    <para>In this tutorial, we will be looking at the ultimate expression of this lie. We will use
+        lighting computations to make an object appear to be something entirely different from its
+        geometry.</para>
+    <section>
+        <?dbhtml filename="Tut13 Simple Sham.html" ?>
+        <title>Simple Sham</title>
+        <para>We want to render a sphere. We could do this as we have done in previous tutorials.
+            That is, generate a mesh of a sphere and render it. But this will never be a
+            mathematically perfect sphere. It is easy to generate a sphere with an arbitrary number
+            of triangles, and thus improve the approximation. But it will always be an
+            approximation.</para>
+        <para>Spheres are very simple, mathematically speaking. They are simply the set of points in
+            a space that are a certain distance from a specific point. This sounds like something we
+            might be able to compute in a shader.</para>
+        <para>Our first attempt to render a sphere will be quite simple. We will use the vertex
+            shader to compute the vertex positions of a <emphasis>square</emphasis> in clip-space.
+            This square will be in the same position and width/height as the actual circle would be,
+            and it will always face the camera. In the fragment shader, we will compute the position
+            and normal of each point along the sphere's surface. By doing this, we can map each
+            point on the square to a point on the sphere we are trying to render. This square is
+            commonly called a <glossterm>flat card</glossterm> or
+            <glossterm>billboard</glossterm>.</para>
+        <para>For those points on the square that do not map to a sphere point (ie: the corners), we
+            have to do something special. Fragment shaders are required to write a value to the
+            output image. But they also have the ability to abort processing and write neither color
+            information nor depth to the color and depth buffers. We will employ this to draw our
+            square-spheres.</para>
+        <para>This technique is commonly called <glossterm>impostors.</glossterm> The idea is that
+            we're actually drawing a square, but we use the fragment shaders to make it look like
+            something else. The geometric shape is just a placeholder, a way to invoke the fragment
+            shader over a certain region of the screen. The fragment shader is where the real magic
+            happens.</para>
+        <para>The tutorial project <phrase role="propername">Basic Impostor</phrase> demonstrates
+            this technique. It shows a scene with several spheres, a directional light, and a moving
+            point light source.</para>
+        <figure>
+            <title>Basic Impostor</title>
+            <mediaobject>
+                <imageobject>
+                    <imagedata fileref="Basic%20Impostor.png"/>
+                </imageobject>
+            </mediaobject>
+        </figure>
+        <para>The camera movement is controlled in the same way as previous tutorials. The
+                <keycap>T</keycap> key will toggle a display showing the look-at point. The
+                <keycap>-</keycap> and <keycap>=</keycap> keys will rewind and fast-forward the
+            time, and the <keycap>P</keycap> key will toggle pausing of the time advancement.</para>
+        <para>The tutorial starts showing mesh spheres, to allow you to switch back and forth
+            between actual meshes and impostor spheres. Each sphere is independently
+            controlled:</para>
+        <table frame="all">
+            <title>Sphere Impostor Control Key Map</title>
+            <tgroup cols="2">
+                <colspec colname="c1" colnum="1" colwidth="1.0*"/>
+                <colspec colname="c2" colnum="2" colwidth="1.0*"/>
+                <thead>
+                    <row>
+                        <entry>Key</entry>
+                        <entry>Sphere</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry><keycap>1</keycap></entry>
+                        <entry>The central blue sphere.</entry>
+                    </row>
+                    <row>
+                        <entry><keycap>2</keycap></entry>
+                        <entry>The orbiting grey sphere.</entry>
+                    </row>
+                    <row>
+                        <entry><keycap>3</keycap></entry>
+                        <entry>The black marble on the left.</entry>
+                    </row>
+                    <row>
+                        <entry><keycap>4</keycap></entry>
+                        <entry>The gold sphere on the right.</entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+        <para>This tutorial uses a rendering setup similar to the last one. The shaders use uniform
+            blocks to control most of the uniforms. There is a shared global lighting uniform block,
+            as well as one for the projection matrix.</para>
+        <section>
+            <title>Grifting Geometry</title>
+            <para>The way this program actually renders the geometry for the impostors is
+                interesting. The vertex shader looks like this:</para>
+            <example>
+                <title>Basic Impostor Vertex Shader</title>
+                <programlisting language="glsl">#version 330
+
+layout(std140) uniform;
+
+out vec2 mapping;
+
+uniform Projection
+{
+	mat4 cameraToClipMatrix;
+};Q
+
+uniform float sphereRadius;
+uniform vec3 cameraSpherePos;
+
+void main()
+{
+    vec2 offset;
+    switch(gl_VertexID)
+    {
+    case 0:
+        //Bottom-left
+        mapping = vec2(-1.0, -1.0);
+        offset = vec2(-sphereRadius, -sphereRadius);
+        break;
+    case 1:
+        //Top-left
+        mapping = vec2(-1.0, 1.0);
+        offset = vec2(-sphereRadius, sphereRadius);
+        break;
+    case 2:
+        //Bottom-right
+        mapping = vec2(1.0, -1.0);
+        offset = vec2(sphereRadius, -sphereRadius);
+        break;
+    case 3:
+        //Top-right
+        mapping = vec2(1.0, 1.0);
+        offset = vec2(sphereRadius, sphereRadius);
+        break;
+    }
+    
+    vec4 cameraCornerPos = vec4(cameraSpherePos, 1.0);
+    cameraCornerPos.xy += offset;
+    
+    gl_Position = cameraToClipMatrix * cameraCornerPos;
+}</programlisting>
+            </example>
+            <para>Notice anything missing? There are no input variables declared anywhere in this
+                vertex shader.</para>
+            <para>It does still use an input variable: <varname>gl_VertexID</varname>. This is a
+                built-in input variable; it contains the current index of this particular vertex.
+                When using array rendering, it's just the count of the vertex we are in. When using
+                indexed rendering, it is the index of this vertex.</para>
+            <para>When we render this mesh, we render 4 vertices as a
+                    <literal>GL_TRIANGLE_STRIP</literal>. This is rendered in array rendering mode,
+                so the <varname>gl_VertexID</varname> will vary from 0 to 3. Our switch/case
+                statement determines which vertex we are rendering. Since we're trying to render a
+                square with a triangle strip, the order of the vertices needs to be appropriate for
+                this.</para>
+            <para>After computing which vertex we are trying to render, we use the radius-based
+                offset as a bias to the camera-space sphere position. The Z value of the sphere
+                position is left alone, since it will always be correct for our square. After that,
+                we transform the camera-space position to clip-space as normal.</para>
+            <para>The output <varname>mapping</varname> is a value that is used by the fragment
+                shader, as we will see below.</para>
+            <para>Since this vertex shader takes no inputs, you might think that you could get away
+                with binding a vertex array object that had no enabled attributes. Alas, this does
+                not work; we must have a dummy attribute enabled and a dummy buffer object to pull
+                data from. We do this in the initialization function of this tutorial.</para>
+            <note>
+                <para>The OpenGL 3.3 core specification says that it should be possible to render
+                    with no enabled attributes. Sadly, certain implementations of OpenGL
+                    (*cough*AMD*cough*) incorrectly forbid it.</para>
+            </note>
+        </section>
+        <section>
+            <title>Racketeering Rasterization</title>
+            <para>Our lighting equations in the past needed only a position and normal in
+                camera-space (as well as other material and lighting parameters) in order to work.
+                So the job of the fragment shader is to provide them. Even though they don't
+                correspond to those of the actual triangles in any way.</para>
+            <para>Here are the salient new parts of the fragment shader for impostors:</para>
+            <example>
+                <title>Basic Impostor Fragment Shader</title>
+                <programlisting language="glsl">in vec2 mapping;
+
+void Impostor(out vec3 cameraPos, out vec3 cameraNormal)
+{
+    float lensqr = dot(mapping, mapping);
+    if(lensqr > 1.0)
+        discard;
+    	
+    cameraNormal = vec3(mapping, sqrt(1.0 - lensqr));
+    cameraPos = (cameraNormal * sphereRadius) + cameraSpherePos;
+}
+
+void main()
+{
+    vec3 cameraPos;
+    vec3 cameraNormal;
+    
+    Impostor(cameraPos, cameraNormal);
+    
+    vec4 accumLighting = Mtl.diffuseColor * Lgt.ambientIntensity;
+    for(int light = 0; light &lt; numberOfLights; light++)
+    {
+        accumLighting += ComputeLighting(Lgt.lights[light],
+            cameraPos, cameraNormal);
+    }
+    
+    outputColor = sqrt(accumLighting); //2.0 gamma correction
+}</programlisting>
+            </example>
+            <para>In order to compute the position and normal, we first need to find the point on
+                the sphere that corresponds with the point on the square that we are currently on.
+                And to do that, we need a way to tell where on the square we are.</para>
+            <para>Using <varname>gl_FragCoord</varname> will not help, as it is relative to the
+                entire screen. We need a value that is relative only to the impostor square. That is
+                the purpose of the <varname>mapping</varname> variable. When this variable is at (0,
+                0), we are in the center of the square, which is the center of the sphere. When it
+                is at (-1, -1), we are at the bottom left corner of the square.</para>
+            <para>Given this, we can now compute the sphere point directly <quote>above</quote> the
+                point on the square, which is the job of the <function>Impostor</function>
+                function.</para>
+            <para>Before we can compute the sphere point however, we must make sure that we are
+                actually on a point that has the sphere above it. This requires only a simple
+                distance check. Since the size of the square is equal to the radius of the sphere,
+                if the distance of the <varname>mapping</varname> variable from its (0, 0) point is
+                greater than 1, then we know that this point is off of the sphere.</para>
+            <para>Here, we use a clever way of computing the length; we don't. Instead, we compute
+                the square of the length. We know that if <inlineequation>
+                    <mathphrase>X<superscript>2</superscript> >
+                        Y<superscript>2</superscript></mathphrase>
+                </inlineequation> is true, then <inlineequation>
+                    <mathphrase>X > Y</mathphrase>
+                </inlineequation> must also be true for all positive real numbers X and Y. So we
+                just do the comparison as squares, rather than taking a square-root to find the true
+                length.</para>
+            <para>If the point is not under the sphere, we execute something new:
+                    <literal>discard</literal>. The <literal>discard</literal> keyword is unique to
+                fragment shaders. It tells OpenGL that the fragment is invalid and its data should
+                not be written to the image or depth buffers. This allows us to carve out a shape in
+                our flat square, turning it into a circle.</para>
+            <sidebar>
+                <title>A Word on Discard</title>
+                <para>Using <literal>discard</literal> sounds a lot like throwing an exception.
+                    Since the fragment's outputs will be ignored and discarded, you might expect
+                    that executing this instruction will cause the fragment shader to stop
+                    executing. This is not necessarily the case.</para>
+                <para>Due to the way that shaders tend to work, multiple executions of the same
+                    shader are often operating at the same time. All of them are running in
+                    lock-step with one another; they all execute instructions at the same time. If
+                    one of them does a discard, it still has to keep doing what it was doing,
+                    because the other three may not have discarded, since the discard was based on
+                    data that may be different between each shader. This is also why branches in
+                    shaders will often execute both sides rather than actually branching; it keeps
+                    the shader logic simpler.</para>
+                <para>However, that doesn't mean <literal>discard</literal> is without use for
+                    stopping unwanted processing. If all of the shaders that are running together
+                    hit a <literal>discard</literal>, then they can all be aborted with no problems.
+                    And hardware often does this where possible.</para>
+            </sidebar>
+            <para>The computation of the normal is based on simple trigonometry. The normal of a
+                sphere does not change based on the sphere's radius. Therefore, we can compute the
+                normal in the space of the mapping, which uses a normalized sphere radius of 1. The
+                normal of a sphere at a point is in the same direction as the direction from the
+                sphere's center to that point on the surface.</para>
+            <para>Let's look at the 2D case. To have a 2D vector direction, we need an X and Y
+                coordinate. If we only have the X, but we know that the vector has a certain length,
+                then we can compute the Y component of the vector based on the Pythagorean
+                theorem:</para>
+            <figure>
+                <title>Circle Point Computation</title>
+                <mediaobject>
+                    <imageobject>
+                        <imagedata fileref="CirclePythagorean.svg" format="SVG"/>
+                    </imageobject>
+                </mediaobject>
+            </figure>
+            <informalfigure>
+                <mediaobject>
+                    <imageobject>
+                        <imagedata fileref="PythagoreanTheorem.svg" format="SVG"/>
+                    </imageobject>
+                </mediaobject>
+            </informalfigure>
+            <para>We simply use the 3D version of this. We have X and Y from
+                    <varname>mapping</varname>, and we know the length is 1.0. So we compute the Z
+                value easily enough. And since we are only interested in the front-side of the
+                sphere, we know that the Z value must be positive.</para>
+            <para>Computing the position is also easy. The position of a point on the surface of a
+                sphere is the normal at that position scaled by the radius and offset by the center
+                point of the sphere.</para>
+        </section>
+    </section>
+    <section>
+        <?dbhtml filename="Tut13 Correct Chicanery.html" ?>
+        <title>Correct Chicanery</title>
+        <para>Our perfect sphere looks pretty nice. However, it is unfortunately very wrong.</para>
+        <para>To see how, toggle back to rendering the mesh on sphere <keycap>1</keycap> (the
+            central blue one). Then move the camera so that the sphere is at the left edge of the
+            screen. Then toggle back to impostor rendering.</para>
+        <figure>
+            <title>Bad Impostor</title>
+            <mediaobject>
+                <imageobject>
+                    <imagedata fileref="Impostor%20No%20Perspective.png"/>
+                </imageobject>
+            </mediaobject>
+        </figure>
+        <para>What's going on here? The mesh sphere seems to be wider than the impostor sphere. This
+            must mean that the mesh sphere is doing something our impostor isn't. Does this have to
+            do with the inaccuracy of the mesh sphere?</para>
+        <para>Quite the opposite, in fact. The mesh sphere is correct. The problem is that our
+            impostor is too simple.</para>
+        <para>Look back at how we did our computations. We map a sphere down to a flat surface. The
+            problem is that <quote>down</quote> in this case is in the camera-space Z direction. The
+            mapping between the surface and the sphere is static; it doesn't change based on the
+            viewing angle.</para>
+        <para>Consider this 2D case:</para>
+        <figure>
+            <title>Circle Projection</title>
+            <mediaobject>
+                <imageobject>
+                    <imagedata fileref="CircleInPerspective.svg" format="SVG"/>
+                </imageobject>
+            </mediaobject>
+        </figure>
+        <para>The line through the circle represents the square we drew. When viewing the sphere off
+            to the side like this, we shouldn't be able to see the left-edge of the sphere facing
+            perpendicular to the camera. And we should see some of the sphere on the right that is
+            behind the plane.</para>
+        <para>So how do we solve this?</para>
+        <para>Use better math. Our last algorithm is a decent approximation if the spheres are
+            somewhat small. But if the spheres are reasonably large (which also can mean close to
+            the camera), then our approximation is shown to be very fake. Our new algorithm needs to
+            take this into account.</para>
+        <para>This algorithm is based on a term you may have heard before: <glossterm>ray
+                tracing.</glossterm> We will not be implementing a full ray tracing algorithm here;
+            instead, we will use it solely to get the position and normal of a sphere at a certain
+            point.</para>
+        <para>A ray is a direction and a position; it represents a line extending from the position
+            along that direction. The points on the ray can be expressed as the following
+            equation:</para>
+        <equation>
+            <title>Ray Equation</title>
+            <mediaobject>
+                <imageobject>
+                    <imagedata fileref="RayEquation.svg" format="SVG"/>
+                </imageobject>
+            </mediaobject>
+        </equation>
+        <para>The <varname>t</varname> value can be positive or negative, but for our needs, we'll
+            stick with positive values.</para>
+        <para>For each fragment, we want to create a ray from the camera position in the direction
+            towards that point on the impostor square. Then we want to detect the point on the
+            sphere that it hits, if any. If the ray intersects the sphere, then we use that point
+            and normal for our lighting equation.</para>
+        <para>The math for this is fairly simple. The equation for the points on a sphere is
+            this:</para>
+        <equation>
+            <title>Sphere Equation</title>
+            <mediaobject>
+                <imageobject>
+                    <imagedata fileref="SphereEquation.svg" format="SVG"/>
+                </imageobject>
+            </mediaobject>
+        </equation>
+        <para>For any point P, if this equation is true, if the length between that point and the
+            sphere's center equals the radius, then P is on the sphere. So we can substitute our ray
+            equation for P:</para>
+        <informalequation>
+            <mediaobject>
+                <imageobject>
+                    <imagedata fileref="RayTraceDeriv_1.svg" format="SVG"/>
+                </imageobject>
+            </mediaobject>
+        </informalequation>
+        <para>Our ray goes from the camera into the scene. Since we're in camera space, the camera
+            is at the origin. So O can be eliminated from the equation. To solve for
+                <varname>t</varname>, we need to get rid of that length. One way to do it is to
+            re-express the sphere equation as the length squared. So then we get:</para>
+        <informalequation>
+            <mediaobject>
+                <imageobject>
+                    <imagedata fileref="RayTraceDeriv_2.svg" format="SVG"/>
+                </imageobject>
+            </mediaobject>
+        </informalequation>
+        <para>The square of the length of a vector is the same as that vector dot-producted with
+            itself. So let's do that:</para>
+        <informalequation>
+            <mediaobject>
+                <imageobject>
+                    <imagedata fileref="RayTraceDeriv_3.svg" format="SVG"/>
+                </imageobject>
+            </mediaobject>
+        </informalequation>
+        <para>The dot product is distributive. Indeed, it follows most of the rules of scalar
+            multiplication. This gives us:</para>
+        <informalequation>
+            <mediaobject>
+                <imageobject>
+                    <imagedata fileref="RayTraceDeriv_4.svg" format="SVG"/>
+                </imageobject>
+            </mediaobject>
+        </informalequation>
+        <para>While this equation has a lot of vector elements in it, as far as t is concerned, it
+            is a scalar equation. Indeed, it is a quadratic equation, with respect to t. Ah, good
+            old algebra.</para>
+        <informalequation>
+            <mediaobject>
+                <imageobject>
+                    <imagedata fileref="RayTraceDeriv_5.svg" format="SVG"/>
+                </imageobject>
+            </mediaobject>
+        </informalequation>
+        <para>In case you've forgotten, the part under the square root in the quadratic formula is
+            called the discriminant. If this value is negative, then the equation has no solution.
+            In terms of our ray test, this means the ray misses the sphere.</para>
+        <para>As you may recall, the square root can be either positive or negative. This gives us
+            two t values. Which makes sense; the ray hits the sphere in two places: once going in,
+            and once coming out. The correct t value that we're interested in is the smallest one.
+            Once we have that, we can use the ray equation to compute the point. With the point and
+            the center of the sphere, we can compute the normal. And we're back in business.</para>
+        <section>
+            <title>Extorting and Expanding</title>
+            <para>To see this done, open up the last tutorial project. Since they use the exact same
+                source, and since they use the same uniforms and other interfaces for their shaders,
+                there was no need to make another code project for it. To see the ray-traced
+                version, press the <keycap>J</keycap> key; all impostors will use the perspective
+                version. To go back to the flat version, press <keycap>L</keycap>.</para>
+            <figure>
+                <title>Bad vs. Good</title>
+                <mediaobject>
+                    <imageobject>
+                        <imagedata fileref="Bad%20vs%20Good%20Impostor2.png"/>
+                    </imageobject>
+                </mediaobject>
+            </figure>
+            <para>The top is the original, the middle is the actual mesh, and the bottom is our new
+                ray traced version.</para>
+            <para>The <function>Impostor</function> function in the fragment shader implements our
+                ray tracing algorithm. More importantly are the changes to the vertex shader's
+                computation of the impostor square:</para>
+            <example>
+                <title>Ray Traced Impostor Square</title>
+                <programlisting language="glsl">const float g_boxCorrection = 1.5;
+
+void main()
+{
+    vec2 offset;
+    switch(gl_VertexID)
+    {
+    case 0:
+        //Bottom-left
+        mapping = vec2(-1.0, -1.0) * g_boxCorrection;
+        offset = vec2(-sphereRadius, -sphereRadius);
+        break;
+    case 1:
+        //Top-left
+        mapping = vec2(-1.0, 1.0) * g_boxCorrection;
+        offset = vec2(-sphereRadius, sphereRadius);
+        break;
+    case 2:
+        //Bottom-right
+        mapping = vec2(1.0, -1.0) * g_boxCorrection;
+        offset = vec2(sphereRadius, -sphereRadius);
+        break;
+    case 3:
+        //Top-right
+        mapping = vec2(1.0, 1.0) * g_boxCorrection;
+        offset = vec2(sphereRadius, sphereRadius);
+        break;
+    }
+
+    vec4 cameraCornerPos = vec4(cameraSpherePos, 1.0);
+    cameraCornerPos.xy += offset * g_boxCorrection;
+    
+    gl_Position = cameraToClipMatrix * cameraCornerPos;
+}</programlisting>
+            </example>
+            <para>We have expanded the size of the square by 50%. What is the purpose of this? Well,
+                let's look at our 2D image again.</para>
+            <informalfigure>
+                <mediaobject>
+                    <imageobject>
+                        <imagedata fileref="CircleInPerspective.svg" format="SVG"/>
+                    </imageobject>
+                </mediaobject>
+            </informalfigure>
+            <para>The black line represents the square we used originally. There is a portion to the
+                left of the projection that we should be able to see. However, with proper ray
+                tracing, it wouldn't fit onto the area of the radius-sized square.</para>
+            <para>This means that we need to expand the size of the square. Rather than finding a
+                clever way to compute the exact extent of the sphere's area projected onto a square,
+                it's much easier to just make the square bigger. This is even moreso considering
+                that such math would have to take into account things like the viewport and the
+                perspective matrix. Sure, we will end up running the rasterizer rather more than
+                strictly necessary. But it's overall much simpler.</para>
+        </section>
+    </section>
+    <section>
+        <?dbhtml filename="Tut13 Deceit in Depth.html" ?>
+        <title>Deceit in Depth</title>
+        <para>While the perspective version looks great, there remains one problem. Move the time
+            around until the rotating grey sphere ducks underneath the ground.</para>
+        <figure>
+            <title>Bad Intersection</title>
+            <mediaobject>
+                <imageobject>
+                    <imagedata fileref="Bad%20Impostor%20Intersection.png"/>
+                </imageobject>
+            </mediaobject>
+        </figure>
+        <para>Hmm. Even though we've made it look like a mathematically perfect sphere, it doesn't
+            act like one to the depth buffer. As far as it is concerned, it's just a circle
+            (remember: <literal>discard</literal> prevents depth writes and tests as well).</para>
+        <para>Is that the end for our impostors? Hardly.</para>
+        <para>Part of the fragment shader's output is a depth value. If you do not write one, then
+            OpenGL will happily use <varname>gl_FragCoord.z</varname> as the depth output from the
+            fragment shader. This value will be depth tested against the current depth value and, if
+            the test passes, written to the depth buffer.</para>
+        <para>But we do have the ability to write a depth value ourselves. To see how this is done,
+            load up the tutorial (using the same code again) and press the <keycap>H</keycap> key.
+            This will cause all impostors to use depth-correct shaders.</para>
+        <figure>
+            <title>Depth Correct Impostor</title>
+            <mediaobject>
+                <imageobject>
+                    <imagedata fileref="Depth%20Correct%20Impostor.png"/>
+                </imageobject>
+            </mediaobject>
+        </figure>
+        <para>This shader is identical to the ray traced version, except for these lines in the
+            fragment shader:</para>
+        <example>
+            <title>Depth Correct Fragment Shader</title>
+            <programlisting>Impostor(cameraPos, cameraNormal);
+	
+//Set the depth based on the new cameraPos.
+vec4 clipPos = cameraToClipMatrix * vec4(cameraPos, 1.0);
+float ndcDepth = clipPos.z / clipPos.w;
+gl_FragDepth = ((gl_DepthRange.diff * ndcDepth) +
+    gl_DepthRange.near + gl_DepthRange.far) / 2.0;</programlisting>
+        </example>
+        <para>Basically, we go through the process OpenGL normally goes through to compute the
+            depth. We just do it on the camera-space position we computed with the ray tracing
+            function. The position is transformed to clip space. The perspective division happens,
+            transforming to normalized device coordinate (<acronym>NDC</acronym>) space. The depth
+            range function is applied, forcing the [-1, 1] range in the fragment shader to the range
+            that the user provided with <function>glDepthRange.</function></para>
+        <para>We write the final depth to a built-in output variable
+                <varname>gl_FragDepth.</varname></para>
+        <section>
+            <section>
+                <sidebar>
+                    <title>Fragments and Depth</title>
+                    <para>The default behavior of OpenGL is, if a fragment shader does not write to
+                        the output depth, then simply take the <varname>gl_FragCoord.z</varname>
+                        depth as the depth of the fragment. Oh, you could do this manually. One
+                        could add the following statement to any fragment shader that uses the
+                        default depth value:</para>
+                    <programlisting language="glsl">gl_FragDepth = gl_FragCoord.z</programlisting>
+                    <para>This is, in terms of behavior a noop; it does nothing OpenGL wouldn't have
+                        done itself. However, in terms of <emphasis>performance</emphasis>, this is
+                        a drastic change.</para>
+                    <para>The reason fragment shaders aren't required to have this line in all of
+                        them is to allow for certain optimizations. If the OpenGL driver can see
+                        that you do not set <varname>gl_FragDepth</varname> anywhere in the fragment
+                        shader, then it can dramatically improve performance in certain
+                        cases.</para>
+                    <para>If the driver knows that the output fragment depth is the same as the
+                        generated one, it can do the whole depth test <emphasis>before</emphasis>
+                        executing the fragment shader. This is called <glossterm>early depth
+                            test</glossterm> or <glossterm>early-z</glossterm>. This means that it
+                        can discard fragments <emphasis>before</emphasis> wasting precious time
+                        executing potentially complex fragment shaders. Indeed, most hardware
+                        nowadays has complicated early z culling hardware that can discard multiple
+                        fragments with a single test.</para>
+                    <para>The moment your fragment shader writes anything to
+                            <varname>gl_FragDepth</varname>, all of those optimizations have to go
+                        away. So generally, you should only write a depth value yourself if you
+                            <emphasis>really</emphasis> need to do it.</para>
+                    <para>Also, if your shader writes <varname>gl_FragDepth</varname> anywhere, it
+                        must ensure that it is <emphasis>always</emphasis> written to, no matter
+                        what conditional branches your shader uses. The value is not initialized to
+                        a default; you either always write to it or never mention
+                                <quote><varname>gl_FragDepth</varname></quote> in your fragment
+                        shader at all. Obviously, you don't always have to write the same value; you
+                        can conditionally write different values. But you cannot write something in
+                        one path and not write something in another. Initialize it explicitly with
+                            <varname>gl_FragCoord.z</varname> if you want to do something like
+                        that.</para>
+                </sidebar>
+            </section>
+        </section>
+    </section>
+    <section>
+        <?dbhtml filename="Tut13 Purloined Primitives.html" ?>
+        <title>Purloined Primitives</title>
+        <para>Our method of rendering impostor spheres is very similar to our method of rendering
+            mesh spheres. In both cases, we set uniforms that define the sphere's position and
+            radius. We bind a material uniform buffer, then bind a VAO and execute a draw command.
+            We do this for each sphere.</para>
+        <para>However, this seems rather wasteful for impostors. Our per-vertex data for the
+            impostor is really the position and the radius. If we could somehow send this data 4
+            times, once for each square, then we could simply put all of our position and radius
+            values in a buffer object and render every sphere in one draw call. Of course, we would
+            also need to find a way to tell it which material to use.</para>
+        <para>We accomplish this task in the <phrase role="propername">Geometry Impostor</phrase>
+            tutorial project. It looks exactly the same as before; it always draws impostors, using
+            the depth-accurate shader.</para>
+        <section>
+            <title>Impostor Interleaving</title>
+            <para>To see how this works, we will start from the front of the rendering pipeline and
+                follow the data. This begins with the buffer object and vertex array object we use
+                to render.</para>
+            <example>
+                <title>Impostor Geometry Creation</title>
+                <programlisting language="cpp">glBindBuffer(GL_ARRAY_BUFFER, g_imposterVBO);
+glBufferData(GL_ARRAY_BUFFER, NUMBER_OF_SPHERES * 4 * sizeof(float), NULL, GL_STREAM_DRAW);
+
+glGenVertexArrays(1, &amp;g_imposterVAO);
+glBindVertexArray(g_imposterVAO);
+glEnableVertexAttribArray(0);
+glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(0));
+glEnableVertexAttribArray(1);
+glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(12));
+
+glBindVertexArray(0);
+glBindBuffer(GL_ARRAY_BUFFER, 0);</programlisting>
+            </example>
+            <para>This code introduces us to a new feature of
+                    <function>glVertexAttribPointer</function>. In all prior cases the fifth