Jason McKesson avatar Jason McKesson committed be610bc

Issue #41: Banding and close lights.

Comments (0)

Files changed (5)

Documents/Illumination/GenGradientDiagram.lua

+require "SvgWriter"
+require "vmath"
+require "Viewport"
+require "SubImage"
+require "_utils"
+
+local subImageSize = 200;
+
+local subImages = SubImage.SubImage(1, 1, subImageSize, subImageSize, 50, 0);
+
+local coordSize = 2;
+
+local vp = Viewport.Viewport(subImages:SubSize(), {0, 0}, coordSize)
+local trans2 = Viewport.Transform2D()
+vp:SetTransform(trans2);
+
+local scaleFactor = 0.25;
+
+-- Styles
+local styleLib = SvgWriter.StyleLibrary();
+local pointSize = 9;
+local textSize = 25;
+
+styleLib:AddStyle(nil, "line",
+	SvgWriter.Style():stroke("red"):stroke_width("1.5px"):fill("none"));
+	
+styleLib:AddStyle(nil, "axes",
+	SvgWriter.Style():stroke("black"):stroke_width("2.5px"):fill("none"));
+	
+
+--Vertices
+local bottom = -0.6;
+local left = -0.8;
+
+local linePts =
+{
+	vmath.vec2(left, bottom),
+	vmath.vec2(0.0, 0.3),
+	vmath.vec2(0.8, 0.6),
+};
+
+linePts = vp:Transform(linePts);
+
+local axesPts =
+{
+	vmath.vec2(left, 1.0),
+	vmath.vec2(left, bottom),
+	vmath.vec2(1.0, bottom),
+};
+
+axesPts = vp:Transform(axesPts);
+
+--Vertices
+local pointRadius = 5;
+local radiusPt = vmath.vec2(pointRadius, pointRadius);
+
+local writer = SvgWriter.SvgWriter(ConstructSVGName(arg[0]), subImages:SvgSize());
+	writer:StyleLibrary(styleLib);
+
+	writer:Polyline(axesPts, {"axes"});
+	writer:Polyline(linePts, {"line"});
+writer:Close();

Documents/Illumination/GenGradientIssue.lua

+require "SvgWriter"
+require "vmath"
+require "Viewport"
+require "SubImage"
+require "_utils"
+
+local subImageSize = 200;
+
+local subImages = SubImage.SubImage(1, 1, subImageSize, subImageSize, 50, 0);
+
+local coordSize = 2;
+
+local vp = Viewport.Viewport(subImages:SubSize(), {0, 0}, coordSize)
+local trans2 = Viewport.Transform2D()
+vp:SetTransform(trans2);
+
+local scaleFactor = 0.25;
+
+-- Styles
+local styleLib = SvgWriter.StyleLibrary();
+local pointSize = 9;
+local textSize = 25;
+
+styleLib:AddStyle(nil, "quad",
+	SvgWriter.Style():stroke("none"):fill(SvgWriter.uriLocalElement("issue_grad")));
+	
+
+--Vertices
+local quadPts =
+{
+	vmath.vec2(-1.0, 1.0),
+	vmath.vec2(1.0, 1.0),
+	vmath.vec2(1.0, -1.0),
+	vmath.vec2(-1.0, -1.0),
+};
+
+quadPts = vp:Transform(quadPts);
+
+
+--Vertices
+local pointRadius = 5;
+local radiusPt = vmath.vec2(pointRadius, pointRadius);
+
+local writer = SvgWriter.SvgWriter(ConstructSVGName(arg[0]), subImages:SvgSize());
+	writer:StyleLibrary(styleLib);
+	writer:BeginDefinitions();
+		writer:LinearGradient("issue_grad",
+			{
+				{offset="0%", color="black"},
+				{offset="50%", color="#AAA"},
+				{offset="100%", color="#CCC"},
+			},
+			{"0%", "100%"}, {"100%", "0%"}
+		);
+	writer:EndDefinitions();
+
+	writer:Polygon(quadPts, {"quad"});
+writer:Close();
Add a comment to this file

Documents/Illumination/GradientDiagram.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="200px" >
+	<style type="text/css" ><![CDATA[.line
+{
+	stroke: red;
+	stroke-width: 1.5px;
+	fill: none;
+}
+
+.axes
+{
+	stroke: black;
+	stroke-width: 2.5px;
+	fill: none;
+}]]></style>
+	<polyline points="20,0 20,160 200,160" class="axes" />
+	<polyline points="20,160 100,70 180,40" class="line" />
+</svg>
Add a comment to this file

Documents/Illumination/GradientIssue.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="200px" >
+	<style type="text/css" ><![CDATA[.quad
+{
+	fill: url(#issue_grad);
+	stroke: none;
+}]]></style>
+	<defs >
+		<linearGradient y1="100%" x1="0%" x2="100%" y2="0%" id="issue_grad" >
+			<stop offset="0%" stop-color="black" />
+			<stop offset="50%" stop-color="#AAA" />
+			<stop offset="100%" stop-color="#CCC" />
+		</linearGradient>
+	</defs>
+	<polygon points="0,0 200,0 200,200 0,200" class="quad" />
+</svg>

Documents/Illumination/Tutorial 10.xml

             necessary because interpolating between two unit vectors does not mean you will get a
             unit vector after interpolation. Indeed, interpolating the 3 components guarantees that
             you will not get a unit vector.</para>
-        <!-- 
         <section>
-            <title>Caught in a Lie</title>
+            <title>Gradient Matters</title>
             <para>While this may look perfect, there is still one problem. Use the <keycombo>
                     <keycap>Shift</keycap>
                     <keycap>J</keycap>
             <para>Notice the vertical bands on the cylinder. This are reminiscent of the same
                 interpolation problem we had before. Was not doing lighting at the fragment level
                 supposed to fix this?</para>
-            <para>Actually, this is a completely different problem. And it is one that is
-                essentially impossible to solve. Well, not without changing our rendered
-                mesh.</para>
-            <para>The source of the problem is this: the light finally caught us in our lie.
-                Remember what we are actually doing. We are not rendering a true cylinder; we are
-                rendering a group of flat triangles that we attempt to make
-                    <emphasis>appear</emphasis> to be a round cylinder. We are rendering a polygonal
-                approximation of a cylinder, then using our lighting computations to make it seem
-                like the faceted shape is really round.</para>
-            <para>This works quite well when the light is fairly far from the surface. But when the
-                light is very close, as it is here, it reveals our fakery for what it is.
-                Why?</para>
-            <para>Let's take a top-down view of our cylinder approximation, but let's also draw what
-                the actual cylinder would look like from the top down:</para>
+            <para>It is similar to the original problem, but technically different. Per-vertex
+                lighting caused lines because of color interpolation artifacts. This is caused by an
+                optical illusion created by adjacent linear gradients.</para>
+            <para>The normal is being interpolated linearly across the surface. This also means that
+                the lighting is changing somewhat linearly across the surface. While the lighting
+                isn't a linear change, it can be approximated as one over a small area of the
+                surface.</para>
+            <para>The edge between two triangles changes how the light interacts. On one side, the
+                nearly-linear gradient has one slope, and on the other side, it has a different one.
+                That is, the rate at which the gradients change abruptly changes.</para>
+            <para>Here is a simple demonstration of this:</para>
             <figure>
-                <title>Faceted Cylinder</title>
+                <title>Adjacent Gradient</title>
                 <mediaobject>
                     <imageobject>
-                        <imagedata fileref="FacetedCircle.svg" />
+                        <imagedata fileref="GradientIssue.svg"/>
                     </imageobject>
                 </mediaobject>
             </figure>
-            <para>Now, consider our lighting equation at a particular point on the fake
-                cylinder:</para>
+            <para>These are two adjacent linear gradients, from the bottom left corner to the top
+                right. The color value increases in intensity as it goes from the bottom left to the
+                top right. They meet along the diagonal in the middle. Both gradients have the same
+                color value in the middle, yet it appears that there is a line down the center that
+                is brighter than the colors on both sides. But it is not; the color on the right
+                side of the diagonal is actually brighter than the diagonal itself.</para>
+            <para>That is the optical illusion. Here is a diagram that shows the color intensity as
+                it moves across the above gradient:</para>
             <figure>
-                <title>Light Directions on Faceted Cylinder</title>
+                <title>Gradient Intensity Plot</title>
                 <mediaobject>
                     <imageobject>
-                        <imagedata fileref="FacetedNearVsFar.svg" />
+                        <imagedata fileref="GradientDiagram.svg"/>
                     </imageobject>
                 </mediaobject>
             </figure>
-            <para>The problem comes from the difference between the actual position being rendered
-                and the corresponding position on the circle that has the normal that we are
-                pretending our point has. When the light is somewhat distant, the difference between
-                the actual light direction we use and the one we would use on a real cylinder is
-                pretty small. But when the light is very close, the difference is
-                substantial.</para>
-            <para>The lighting computations are correct for the vertices near the edges of a
-                triangle. But the farther from the edges you get, the more incorrect it
-                becomes.</para>
-            <para>The key point is that there is not much we can do about this problem. The only
-                solution is to add more vertices to the approximation of the cylinder. It should
-                also be noted that adding more triangles would also make per-vertex lighting look
-                more correct. If you add infinitely many vertices to the cylinder, then the results
-                of per-vertex lighting are indistinguishable from per-fragment lighting.</para>
-            <para>For our simple case, adding triangles is easy, since a cylinder is a
-                mathematically defined object. For a complicated case like a human being, this is
-                usually rather more difficult. It also takes up more performance, since there are
-                more vertices, more executions of our (admittedly simple) vertex shader, and more
-                triangles rasterized or discarded for being back-facing.</para>
+            <para>The color curve is continuous; there are no breaks or sudden jumps. But it is not
+                a smooth curve; there is a sharp edge.</para>
+            <para>It turns out that human vision really wants to find sharp edges in smooth
+                gradients. Anytime we see a sharp edge, our brains try to turn that into some kind
+                of shape. And if there is a shape to the gradient intersection, such as a line, we
+                tend to see that intersection <quote>pop</quote> out at us.</para>
+            <para>The solution to this problem is not yet available to us. One of the reasons we can
+                see this so clearly is that the surface has a very regular diffuse reflectance (ie:
+                color). If the surface color was irregular, if it changed at most every fragment,
+                then the effect would be virtually impossible to notice.</para>
+            <para>But the real source of the problem is that the normal is being linearly
+                interpolated. While this is certainly much better than interpolating the per-vertex
+                lighting output, it does not produce a normal that matches with the normal of a
+                perfect cylinder. The correct solution, which we will get to eventually, is to
+                provide a way to encode the normal for a surface at many points, rather than simply
+                interpolating vertex normals.</para>
         </section>
-        -->
     </section>
     <section>
         <?dbhtml filename="Tut10 Distant Points of Light.html" ?>
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.