The errata list is a list of errors and their corrections that were found after the product was released.
The following errata were submitted by our customers and have not yet been approved or disproved by the author or editor. They solely represent the opinion of the customer.
Version |
Location |
Description |
Submitted by |
Date submitted |
|
A.3
middle |
The method in Matrix.hpp for multiplying two Matrices with signature:
Matrix4 operator * (const Matrix4& b) const
is implemented incorrectly. The result it gives for A * B is actually B * A (which is different because matrices don't commute).
|
Alex Hunsley |
Sep 03, 2011 |
|
A.4
middle |
In the Quaternion.hpp file, the CreateFromVectors method contains the following lines at the top:
if (v0 == -v1)
return QuaternionT<T>::CreateFromAxisAngle(vec3(1, 0, 0), Pi);
This strategy for when the two input vectors oppose each other is flawed and won't work usually. (It only works when v0 and v1 are at right angles to the X axis.)
|
Alex Hunsley |
Sep 03, 2011 |
Printed |
Page A.4
middle |
In Quaternion.hpp, in the method with signature:
Quaternion::Slerp(T t, const QuaternionT<T>& v1) const
there is an error in the 'use linear interoplation for small angles' edge case. It results in Slerp doing animation backwards for small angles.
The line which reads:
QuaternionT<T> result = v1 + (*this - v1).Scaled(t);
should actually be:
QuaternionT<T> result = *this + (v1 - *this).Scaled(t);
|
Alex Hunsley |
Sep 14, 2011 |
Other Digital Version |
1
in sample code |
with iOS 5 and Xcode 4.2, running the antialiasing demos results in a crash. It appears that
GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
returns an error and "Incomplete FBO" is output to the console.
|
bob sabiston |
Oct 22, 2011 |
Other Digital Version |
1
sample code |
The "Trefoil.Stencil" project crashes with this message:
2011-10-22 12:59:58.245 Stencil[5995:707] Applications are expected to have a root view controller at the end of application launch
This is on ioS5 SDK, Xcode 4.2
Thanks
Bob
|
Bob Sabiston |
Oct 22, 2011 |
Printed |
Page 12
Bottom |
Confirmed previous submission:
Its serious as the example will not run.
Linking in the OpenGL and Quartz Libraries:
The paragraph tells you to load OpenGLES.framework and QuartzCore.framework but since we started with OpenGL template they were already loaded. However,
I needed to explicitly load CoreGraphics.framework for CGRectGetWidth() and CGRectGetWidth() to work.
?
|
Anonymous |
Jan 11, 2011 |
Printed |
Page 13
Top of the page |
The paragraph tells you to load OpenGLES.framework and QuartzCore.framework but since we started with OpenGL template they were already loaded. However, I needed to explicitly load CoreGraphics.framework for CGRectGetWidth() and CGRectGetWidth() to work.
|
Anonymous |
Aug 15, 2010 |
PDF |
Page 17
Underneath the note about memory management in Objective-C |
What is the diference between glGenFramebuffers and glGenFramebuffersOES? The XCode generated template uses the former.
|
Pedro Remedios |
Jul 02, 2011 |
Printed |
Page 23
Example 1.6 |
In that example GLView.h imports IRenderingEngine.hpp, but at its time GLView.h is imported by the app Delegate so inserting c++ code in a pure objective-c class and bringing in an error at the 'virtual' keyword of "struct IRenderingEngine* createRenderer1();"
I also submitted the case to the Apple Developer Forum where I was suggested to substitute the import with a forward struct declaration. Ref: EAGL rendering API a.
|
Fabrizio Bartolomucci |
Oct 12, 2010 |
Printed |
Page 23
Example 1.6 |
In Example 1-6 on page 23, m_timestamp is declared as a float, but it should be a double.
This may seem like a small thing, but it ends up being the root cause behind why the arrow rotation is so shaky.
m_timestamp is set from displayLink's timestamp property which is declared as type CFTimeInterval, which in turn is a typedef for double.
When I displayed the values for displayLink.timestamp and m_timestamp, the former kept changing while the latter appeared constant for about six iterations. This in turn caused the computed elapsedSeconds sent to UpdateAnimation() to fluctuation substantially.
I had tried cacheing the value of displayLink.timestamp in drawView: (page 25) so that the value used to compute elapsedSeconds would be the exact same value saved for later in m_timestamp, but then the cached value appeared to remain constant for a few iterations as well. That's when I discovered the type issue.
|
Glenn |
Dec 05, 2010 |
Printed |
Page 24
Example 1-7 |
The dealloc method for GLView should free the rendering engine. e.g. "delete m_renderingEngine;"
|
Anonymous |
Aug 25, 2010 |
Printed |
Page 26
example 1.8 |
There are only three float initializers for the RGBA values in the second triangle in the array of vertices. As a result their alpha values are not set to 1.
|
Simon Winder |
Sep 08, 2011 |
Printed |
Page 30
absolute 2nd line from the top of the page |
The line reads:
void UpdateAnimation(float timeStep);
when it should read
void UpdateAnimation(float timeStep){}
The difference being at the very end of the line. It reads a semi-colon instead of the correct closed set of parenthesis. I believe this is because the this method has yet to be implemented at this stage in the writing of the code. It is still a stub.
|
Eric Brotto |
Oct 31, 2010 |
Printed |
Page 30
absolute 2nd line from the top of the page |
The line reads:
void UpdateAnimation(float timeStep);
when it should read
void UpdateAnimation(float timeStep){}
The difference being at the very end of the line. It reads a semi-colon instead of the correct closed set of parenthesis. I believe this is because the this method has yet to be implemented at this stage in the writing of the code. It is still a stub.
|
Eric Brotto |
Oct 31, 2010 |
Printed |
Page 38
absolute 7th line from the top of the page |
The include files read as this:
"../Shaders/Simple.vert"
when they should be printed as this:
"Shaders/Simple.vert"
In other words you need to get rid of the ../ at the beginning.
|
Eric Brotto |
Oct 31, 2010 |
Printed |
Page 64
First code example |
The LinearTween function as written has the opposite behavior as the charts in Figure 2.15.
It currently is printed as follows:
--- return t * start + (1 - t) * end;
This causes the value to tween from end to start as t goes from 0 to 1. Instead, it should be listed as this:
--- return (1 - t) * start + t * end;
This correction will allow the tween to go from start to end as t goes from 0 to 1 which is the expected behavior as reinforced by the graphic in Figure 2.15.
Please note that the QuadraticEaseIn function and the QuadraticEaseInOut function (Example 2-4) also rely on this function, so all three do not work properly as a result of this error.
|
Adam Behringer |
Jun 18, 2010 |
Printed |
Page 64
LinearTween function |
I think
float LinearTween(float t, float start, float end)
{
return t*start + (1-t)*end;
}
should be
float LinearTween(float t, float start, float end)
{
return (1-t)*start + t*end;
}
since t goes from 0 to 1.
I dont know, this is just my personal thought.
|
Anonymous |
Jun 27, 2010 |
Other Digital Version |
64
First code example |
Just the same mistake in linear tweening equation (should be read as "return (1-t)*start + t*end;", as Adam Behringer already mentioned), but i have it in ePUB edition.
|
Anton M |
Oct 09, 2010 |
Printed |
Page 64
LinearTween function after paragraph 3. |
Your calculation for LinearTween should be
float LinearTween(float t, float start, float end) {
return t*end + (1 - t) * start ;
}
t should go from 0 to 1 as elapsed time increases where t = (elapsed time) / (desired duration).
|
Steve McFarlin |
Oct 12, 2010 |
PDF |
Page 65
Example 2-4 |
The second half is just repeating the first half.
I think the following code should change from:
float QuadraticEaseInOut(float t, float start, float end)
{
float middle = (start + end) / 2;
t = 2 * t;
if (t <= 1)
return LinearTween(t * t, start, middle);
t -= 1;
return LinearTween(t * t, middle, end);
}
to:
float QuadraticEaseInOut(float t, float start, float end)
{
float middle = (start + end) / 2;
t = 2 * t;
if (t <= 1)
return LinearTween(t * t, start, middle);
t -= 1;
/*******************************/
return LinearTween((1-t) * (1-t), middle, end);
/*******************************/
}
|
Kenny |
Jun 07, 2010 |
PDF |
Page 65
Quadratic Ease In Out |
The second part of the ease-in-out function repeats the ease in (but translated). I haven't very carefully checked this, but I believe the ease out should be a flipped parabola, translated such that it connects with the the (0.5, middle) point in (t, f(t)) space and scaled appropriately.
So I get this:
Parabola 1: f(t) = t^2
Parabola 2: f(t) = -t^2
>>> move upside down parabola to (2,2*end) -- this is moving it to 2 x (1, end); so (x,y) |--> (x-2,y-2*end)
f(t) = -(t-2)^2 + 2*end
>>> normalize both parabolas so that they start at 0 and end at 1 (as opposed to ending at 2), they must get there twice as fast to fit both the parabolas in space where one parabola used to be; so (t) |--> (2t)
>>> normalize the "heights" of the parabolas so that the composite function and the second parabola both end at (1, end) instead of (1, 2*end); so f(t) |--> f(t) / 2
which leaves:
Parabola 1: f(t) = ( (2t)^2 ) /2
Parabola 2: f(t) = ( -(2t-2)^2 + 2*end ) /2
f(t) = { ( (2t)^2 ) /2 } where t <= 0.5 and { ( -(2t-2)^2 + 2*end ) /2 } where t > 0.5
So I think the last line of code should be (but I haven't checked whether I mapped the above composite function to the "code" properly):
return LinearTween( ( (-1) * (2t-2) * (2t-2) + 2*end ) /2, middle, end) ;
|
aeb |
Nov 06, 2010 |
Printed |
Page 89-94
|
After making the changes to RenderingEngine1 and RenderingEngine2 the rotate functionality became impaired.
i.e. OnFingerDown did not rotate to the new touchpoint
and moving did not match where you were touching.
|
Anonymous |
Jul 08, 2012 |
Printed |
Page 96
Last paragraph |
The sentence in parenthesis should change from
(The legal combination of size and type were covered in the previous chapter in Table 2-1.)
To
(The legal combination of size and type were covered in the previous chapter in Table 2-2.)
|
Steve McFarlin |
Oct 12, 2010 |
Printed |
Page 99
second paragraph |
... WireframeSkeleton project from this book's example code (available at http://oreilly.com/catalog/9780596804831)
should read http://examples.oreilly.com/9780596804831/
or
http://my.safaribooksonline.com/9781449388133?bookview=overview
However the WireframeSkeleton is not part of the example code!
|
rowland shepard |
Aug 08, 2010 |
Printed |
Page 107
Second function |
Visual visual;
The address of this struct
is being passed to IRenderingEngine::Render as the address of a vector.
|
rowland shepard |
Aug 12, 2010 |
PDF |
Page 107
ApplicationEngine::Render() function |
The text states:
void ApplicationEngine::Render() const
{
Visual visual;
visual.Color = m_spinning ? vec3(1, 1, 1) : vec3(0, 1, 1);
visual.LowerLeft = ivec2(0, 48);
visual.ViewportSize = ivec2(320, 432);
visual.Orientation = m_orientation;
m_renderingEngine->Render(vis);
}
On page 105 however, the interface for "->Render" looks like this:
virtual void Render(const vector<Visual>& visuals) const = 0;
In other words, expecting a vector of Visuals - instead of a single Visual.
A possible fix would be:
void ApplicationEngine::Render() const
{
Visual visual;
visual.Color = m_spinning ? vec3(1, 1, 1) : vec3(0, 1, 1);
visual.LowerLeft = ivec2(0, 48);
visual.ViewportSize = ivec2(320, 432);
visual.Orientation = m_orientation;
vector<Visual> vis; // empty vector
vis.push_back (visual); // push the above visual into it
m_renderingEngine->Render(vis);
}
|
rboerdijk |
Aug 15, 2010 |
Printed |
Page 135
Last bullet point |
The last bullet point should be labeled '6' and not '2'.
|
Steve McFarlin |
Oct 20, 2010 |
Printed |
Page 139
Example 4-10 |
The directions state: "Example 4-10 shows the new Initialize method (unchanged portions are replaced with ellipses for brevity)."
Then code example is written as such:
void RenderingEngine::Initialize(const vector<ISurface*> &surfaces) {
vector<ISurface*>::const_iterator surface;
for (surface = surfaces.begin(); surface != surfaces.end(); ++surface) {
// Create VBO for the vertices
vector<float> vertices;
(*surface)->GenerateVertices(vertices, VertexFlagsNormals);
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(vertices[0]), &vertices[0], GL_STATIC_DRAW);
// Create a new VBO for the indices if needed.
...
}
// Set up various GL state.
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
// Set up the material properties.
vec4 specular(0.5f, 0.5f, 0.5f, 1);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular.Pointer());
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 50.0f);
m_translation = mat4::Translate(0,0,-7);
}
Though this is a huge problem, because within this area, there should have been an ellipse as well:
// Create a new VBO for the indices if needed.
...
}
// ellipses should have been placed here
// Set up various GL state.
Following those instructions explicitly leads you to omit:
// Extract width and height from the color buffer.
int width, height;
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &width);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &height);
// Create a depth buffer that has the same size as the color buffer.
glGenRenderbuffersOES(1, &m_depthRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_depthRenderbuffer);
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, width, height);
// Create the framebuffer object.
GLuint frameBuffer;
glGenFramebuffersOES(1, &frameBuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, frameBuffer);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, m_colorRenderbuffer);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, m_depthRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorRenderbuffer);
Which in absence makes the program draw a blank magenta screen.
This is a serious technical problem, since, though I found a quick fix to the issue, I don't know if this is the appropriate way to handle this now. I'm under the impression that we should no longer use the colorRenderbuffer since our implementation of the light sourcee; this code is clearly using the colorRenderbuffer.
What should be done here?
|
Matisse VerDuyn |
Mar 06, 2012 |
Printed |
Page 150
Example 4-17 |
SimpleLighting.Vert
has three attributes
and seven uniforms
but RenderingEngine::Initialize
// extract the handles to attributes and uniforms
extracts six attributes
and four uniforms
the names are also 'out of sync' with the shader.
Review of the sample code ObjViewer
reveals the printed Initialize method to be incorrect.
|
rowland shepard |
Aug 18, 2010 |
PDF |
Page 150
structure definition on page 150 - with consequences in code on page 151 and 152 |
Just noticed rowland shepard also reported this - here a few details on how to change to code so it works.
See Example 4-15 (SimpleLighting.vert) - it defines AmbientMaterial, SpecularMaterial and Shininess as uniform. On page 150, these three are incorrectly added to the attributehandles (instead of the uniformhandles struct). It should look like this:
struct UniformHandles
{
GLuint Modelview;
GLuint Projection;
GLuint NormalMatrix;
GLuint LightPosition;
GLint Ambient;
GLint Specular;
GLint Shininess;
};
struct AttributeHandles
{
GLint Position;
GLint Normal;
GLint Diffuse;
};
At the bottom of page 151 (continued of page 152) the relevant code should be changed to:
// Extract the handles to attributes and uniforms.
<...>
m_uniforms.Ambient=glGetUniformLocation(program, "AmbientMaterial");
m_uniforms.Specular=glGetUniformLocation(program,"SpecularMaterial");
m_uniforms.Shininess=glGetUniformLocation(program, "Shininess");
<...>
// and don't forget that it's not an attribute but a uniform now -
// so we have to change the gl-call also
// Set up some default material parameters.
glUniform3f(m_uniforms.Ambient, 0.04f, 0.04f, 0.04f);
glUniform3f(m_uniforms.Specular, 0.5, 0.5, 0.5);
glUniform1f(m_uniforms.Shininess, 50);
... after these changes, you'll see the specular white spot :)
|
rboerdijk |
Aug 18, 2010 |
Printed |
Page 236
Trefoil.Stencil example code |
I've been following the examples in the book successfully but cannot get the Trefoil.Stencil code to work properly (Trefoil.FakeStencil is fine). I see the loading graphic but then it goes to a pink screen on the simulator and a black screen on my iPhone 4.
I have tried both the version from the monolithic zip file and downloaded the individual sample.
I'm using XCode 4.
Do I need to make changes to get it to work?
|
Anonymous |
Mar 26, 2011 |
Printed, PDF |
Page 242
Example 6-10 |
According to the Apple OpenGL Programming Guide (http://bit.ly/9IIK5p):
"In iOS 4.0 and later, separate stencil buffers are not supported. Use a combined depth/stencil buffer."
As a result, example 6-10 produces GL_FRAMEBUFFER_UNSUPPORTED_OES when glCheckFramebufferStatusOES() is called.
The solution is to:
- eliminate m_renderbuffers.BigStencil and the associated renderbuffer calls.
- call glRenderbufferStorageOES( GL_RENDERBUFFER_OES, GL_DEPTH24_STENCIL8_OES, size.x, size.y ) to create a packed depth/stencil buffer as in example 6-2
|
Benj Carson |
Jul 25, 2011 |
PDF |
Page 259
2nd line |
As a description of the float theta, it says "Azimuth in degrees. This is the horizontal angle off east." But is it "off north?"
|
Kazuya Abbey |
Feb 21, 2011 |
Printed |
Page 286
last line |
The current version of PVRTexTool uses different options than the version described in the book -- and I am unable to obtain an earlier version of the tool.
In particular, the command
os.system ("PVRTexTool -h -yflip1 -fOGL8 -iNumeralsTexture.png")
needs to be updated to work with the current tool. I think some of the changes are obvious:
os.system ("PVRTexToolCLI - flip y -i NumeralsTexture.png -o NumeralsTexture.h")
but I have been unable to figure out how to correctly replace the "-fOGL8" option. (I've tried a number of variations -- and get output, but none of my variations reproduce the provided NumeralsTexture.h file.)
Also -- thanks so much for a fantastic book!
|
Anonymous |
Sep 05, 2014 |
PDF |
Page 290
FPSRenderer class |
There are two implementations of this class in the example project:
FpsRenderer.DrawTex.h
and
FpsRenderer.Vbo.h
The DrawTex version works correctly, and is the "easier" of the two implementations. However, it is not portable to desktop OpenGL, and it is claimed on pg 293, is not supported in OpenGL ES 2.0.
The VBO implementation does not seem to work. By changing the include at the top of the RenderingEngine class from
#include "FpsRenderer.DrawTex.h"
to
#include "FpsRenderer.Vbo.h",
the frame rate text disappears, without generating an error message to indicate what is wrong.
If there is a bug in the sample code and text, please advise.
|
Phaedon Sinis |
Dec 01, 2010 |
Other Digital Version |
388
second paragraph, first sentance |
Says Example 2-6 shows 'RenderingEngine1.cpp', should be 'RenderingEngine1.h' since it is the declaration not the definition.
Also the definition of Vertex is moved from the .cpp file, where it was in prior examples, to the .h file which (I believe, but I could be wrong) would conflict with the Vertex declaration in RenderingEngine2.h. Granted the paragraph above says the definition of Vertex is "moved higher up in the file" but that's hardly the case since it is in fact moved to the header file.
|
Brooks Adcock |
Oct 12, 2011 |
Printed |
Page 390
methods: operator/ operator* operator/= operator *= |
In the Vector2 struct, these methods accept parameters of type float, while in the Vector3 struct, they accept parameters of type T. Is there a reason for this difference?
|
Tony Wetmore |
Aug 22, 2010 |
Printed |
Page 395
Matrix4<T> Class |
The function
Vector4<T> operator * (const Vector4<T>& b) const
Is multiplying incorrectly. It is setup to multiply column vectors, and not row vectors. i.e. It is multiplying Av and not vA.
This does not work as expected
mat4 m = mat4::Translate(2,3,4)
vec4 u = vec4(2,2,2,1)
vec4 v = m * u
v = 2,2,2,19
This function should be
Vector4<T> operator * (const Vector4<T>& b) const
{
Vector4<T> v;
v.x = x.x * b.x + y.x * b.y + z.x * b.z + w.x * b.w;
v.y = x.y * b.x + y.y * b.y + z.y * b.z + w.y * b.w;
v.z = x.z * b.x + y.z * b.y + z.z * b.z + w.z * b.w;
v.w = x.w * b.x + y.w * b.y + z.w * b.z + w.w * b.w;
return v;
}
|
Steve McFarlin |
Oct 13, 2010 |
Printed |
Page 395
Matrix Library |
The matrix library assumes row-major with row-ordering (i.e. transposed ordering rather than canonical). That's fine except that the library only provides an overload for matrix*vector, but not vector*matrix. However, in a row-major system, you can only multiply a vector to the left of a matrix (as the book itself explains early on). To require a vector on the right side of a matrix in a row-major library is a serious source of confusion and bugs. It's not clear if the calculation is actually doing what is expected.
|
Jerry Fenly |
Jun 06, 2013 |