A家的事业,传给了C,C是A的女人or外孙,C是B家的媳妇or孙子,那往后的事业不就成了B家的吗?
2010年12月29日星期三
吴军的浪潮之巅 - Intel

2011/1/7 update 近来看到news说Microsoft的windows做ARM cpu的版本了。查了一下ARM,原来可以理解为一个公司名or一种CPU架构,于是CPU的架构包括了intel's x86, ARM, IBM's POWER(PowerPC缘由POWER体系架构)等. 其中ARM和Power都是RISC的,而Linux支持CISC和RISC指令集。
于是来了一个问题,OS是怎么支持某种指令集的呢?
OS or other program -> compile to be object file-> link to be execution.
Compile的过程在预编译 词法语法分析得到汇编时候就考虑RISC/CISC?
还是汇编代码-->机器指令这这时候才考虑RISC/CISC?
reference:
[1]
[2] http://www.ibm.com/developerworks/cn/linux/l-powhist/ 人类的POWER IBM芯片制造史
2010年9月13日星期一
Weekly update 2010/9/6~
http://en.wikipedia.org/wiki/HSL_and_HSV
http://www.manifold.net/doc/colors_as_hue_saturation_and_brightness.htm
讲述GUI的history,也是发展了2/30年嘛. keyword: xerox, windows, mac.
http://www.gladdengraphics.com/academics/GradCourses/ComputerGraphicsHistory/ResearchPaper/parcgui01.pdf
There is a case that pointer is needed. for example,
class GLSLShaderProgram {
public:
GLSLShaderProgram *createInstanceFromSource(vs string, fs string);
protected:
GLSLShaderProgram(...);
...
};
In this case, we cannot define something like this:
class App {
public:
App(): ... {}
private:
GLSLShaderProgram m_programHandle;
};
Because the m_programHandle will be initialized in the initialization list with constructor, which is not available from outside.
后来我才意识到:
shading effect = lighting + material of geometry.
而shading shader 就是那个”+”加号, 根据特定的shading stype来计算.
所以GLSLShadingProgram不该直接放到App里面, 而是例如:
而且具体的某一个shading shader 就是用于某一种shading effect的.
class App {
PhongShading m_phong;
};
class PhongShading {
bool initialize() {
m_programHandle = createProgramFromFile(phong.glsl);
return m_programHandle != 0;
}
GLSLShadingProgram m_programHandle;};
class Model {
void render() {
get m_phong from app;
set the lighting and material parameters;
active the shading program to draw the model;
};
How the mask is effecting on a image layer?
Blend mode 用于有一个background image, 当上面加一个image做blending and composing时候用的。
Masks是附加于a specified image layer, 不修改影响那个image layer本身(un-destructive), 只是觉得那些pixel可以透过mask被看到, 那些被遮挡了不能看到.
Shader中是怎么实现的呢?
What is the l-value and r-value, difference?
http://blogs.msdn.com/b/vcblog/archive/2009/02/03/rvalue-references-c-0x-features-in-vc10-part-2.aspx
2010年8月31日星期二
Weekly update 2010/8/23-29
跟UI打交道的一周.
Qt Model/View architecture:
Model: QModelIndex, internalPainter is used to associate the custom item pointer to the QModelIndex, the custom item class is defined by us and is used to store the custom data.
View: there are mouse press/release/doubleclick/move event, the row and tree branches(grew lines) can be redraw by overriding drawRow/drawBranches function.
Others:
1. 之前假如不是跟geometry/mesh相关的工作,我都有一点点抵触, 觉得不对口。现在发觉不能这样子,想做跟geometry/mesh相关的工作内容是因为想在那方面做深入, 但是有时候做做别的东西也能扩展知识面, 而且东西都不是独立而是相联系的。例如现在在看Qt的model/view architecture, 从pattern从编程方面都是会有益的。例如做paint layer blend mode, paint layer transfer, layer mask就能扩展texture/material这方向的认识。
2. 写代码,接触一个feature甚至是fix 一个bug时候,一定要进行做的完善完美鲁棒, 否则之后的bugs会不断过来,弄得无法开始or专心于下一步的工作。
3. 要到LayerModel/LayerView(custom 的Model/View)中加入新的model item, 而且这些item还是新的类型, 于是觉得:冷静->逻辑清晰->快速的理解能力很重要.
4. 想起了去年面试被问过的一个question: 给出三角形的三个边长, 怎么求出三角形的面积?
假如在初高中时候要是这个问题都不懂的话肯定考不上大学,如今却真的模糊了。后来复习时候发现那个公式原来有个不错的名字Heron’s (or Hero’s) formula. A=sqrt(s*(s-a)*(s-b)*(s-c)), where s = (a+b+c)*0.5, http://en.wikipedia.org/wiki/Heron's_formula, 链接中还给出了利用余弦定理law of cosines的证明(这个更重要). 这些其实都是应该牢记的。最后提到了这个公式的数学稳定性不好numerically unstable, http://en.wikipedia.org/wiki/Numerical_stability, 里面对一个array 求sum的例子不错, 求一百个数, 假如一个是1,另外99个都是0.01,精确解释1.99,但是看上去正确的算法得到的结果不同,有些甚至是错误的(错误的是先加1再加0.01, 较好的做法是先排序, 从小到大来加. 排序?复习)。这可能是2进制计算机中由于round-off error and truncation error而引入的 (ok, 又涉及到了floating point numer了, 怎么表示,跟0的比较,之前看过一个用它生成random number的)。
然后又从truncation提到了Taylor series (这个我在研二暑假找实习时候被问及), 除了能写出这个公式之外,还得想想它有什么实际用处. (1). F(x) = F(a) + F’(a)x +…当 a=0时候就变为Maclaurin series, 然后就可以求例如the exponential function e^x的近似值了, sin(x)的近似值等。
5. 有这么一个Camera model, 有意思的是我想在初始化时候都是给出position, target等参数parameters, 但是这个camera model中确实根据给出的scene center and scene radius来计算那些参数.
6. Tree data structure.
Qt Model/View architecture:
Model: QModelIndex, internalPainter is used to associate the custom item pointer to the QModelIndex, the custom item class is defined by us and is used to store the custom data.
View: there are mouse press/release/doubleclick/move event, the row and tree branches(grew lines) can be redraw by overriding drawRow/drawBranches function.
Others:
1. 之前假如不是跟geometry/mesh相关的工作,我都有一点点抵触, 觉得不对口。现在发觉不能这样子,想做跟geometry/mesh相关的工作内容是因为想在那方面做深入, 但是有时候做做别的东西也能扩展知识面, 而且东西都不是独立而是相联系的。例如现在在看Qt的model/view architecture, 从pattern从编程方面都是会有益的。例如做paint layer blend mode, paint layer transfer, layer mask就能扩展texture/material这方向的认识。
2. 写代码,接触一个feature甚至是fix 一个bug时候,一定要进行做的完善完美鲁棒, 否则之后的bugs会不断过来,弄得无法开始or专心于下一步的工作。
3. 要到LayerModel/LayerView(custom 的Model/View)中加入新的model item, 而且这些item还是新的类型, 于是觉得:冷静->逻辑清晰->快速的理解能力很重要.
4. 想起了去年面试被问过的一个question: 给出三角形的三个边长, 怎么求出三角形的面积?
假如在初高中时候要是这个问题都不懂的话肯定考不上大学,如今却真的模糊了。后来复习时候发现那个公式原来有个不错的名字Heron’s (or Hero’s) formula. A=sqrt(s*(s-a)*(s-b)*(s-c)), where s = (a+b+c)*0.5, http://en.wikipedia.org/wiki/Heron's_formula, 链接中还给出了利用余弦定理law of cosines的证明(这个更重要). 这些其实都是应该牢记的。最后提到了这个公式的数学稳定性不好numerically unstable, http://en.wikipedia.org/wiki/Numerical_stability, 里面对一个array 求sum的例子不错, 求一百个数, 假如一个是1,另外99个都是0.01,精确解释1.99,但是看上去正确的算法得到的结果不同,有些甚至是错误的(错误的是先加1再加0.01, 较好的做法是先排序, 从小到大来加. 排序?复习)。这可能是2进制计算机中由于round-off error and truncation error而引入的 (ok, 又涉及到了floating point numer了, 怎么表示,跟0的比较,之前看过一个用它生成random number的)。
然后又从truncation提到了Taylor series (这个我在研二暑假找实习时候被问及), 除了能写出这个公式之外,还得想想它有什么实际用处. (1). F(x) = F(a) + F’(a)x +…当 a=0时候就变为Maclaurin series, 然后就可以求例如the exponential function e^x的近似值了, sin(x)的近似值等。
5. 有这么一个Camera model, 有意思的是我想在初始化时候都是给出position, target等参数parameters, 但是这个camera model中确实根据给出的scene center and scene radius来计算那些参数.
for example, max-heap is a complete binary tree, which used to build the priority-queue;
the RB-tree is binary search tree, which is used to build the set and map container.
there are many other examples of course. scene tree...
标签:
camera,
qt,
tree,
ui,
weekly update
2010年8月22日星期日
2010年8月20日星期五
Weekly update - 2010/8/16
Basic shader manager and vertex batch
There are many things to learn and do. In order to render the curvature tensor, which is property of mesh, i need to add shader step-up and organize the vertices from curvatures into vbo (OpenGL 3.x is used).
However, there is already shader step-up and vbo using in the scene::render(), i don’t want to duplicate the code in the class Model. So, shader manager and vertex batch classes are need.
After googling, i come across to http://www.informit.com/articles/article.aspx?p=1616796&seqNum=4, the free chapters of OpenGL SuperBible 5th, and the greatest thing is its code is stored in google code project, from where i can download it. Must read!
Another resource is http://prideout.net/blog/?p=22 (anti-aliased cel shading, and shader wrapper).
Expected result:
1. Refactor the shader loading, create the batch class, render the scene(world frame, grid, mesh) using this new one.
2. render the curvature tonsor.
3. integrate the anti-aliased cel shading.
Notes:
1. there are two ways to get the vertex attribute location(index). The explicit way, use the
glBindAttribLocation(uint program, int index, char *name);
The inexplicit way, use the
int index = glGetAttribLocation( uint program, const char *name );
the index will be used later by puting vertex data into it.
2. To render the model, there is only mesh data at the current time, which is a polygon/n-sided mesh, using GL_TRIANGLES, a triangle mesh is created. The triangle mesh is used exclusively on rendering, but the mesh adjacency information is not used so data is wasted to record that. After integrate the GLBatch from GLTools of OpenGL SuperBible 5th, I wonder how about remove the triangle mesh, put the triangle data of the polygon mesh into the a instance of class GLBatch.
After further investigation, it is found that there is no index buffer object in the class GLBatch, for example if a quad is needed to be drew, six vertices are needed, and the
glDrawArray(GL_TRIANGLES, 0, 6);
is used. There are two vertices are duplicated. The GLBatch cannot be used directly.
But the triangle mesh is still needed to be removed. I want to create a vertex batch for all the vertices data, and create two index buffer object, one for regularly drawing triangle(GL_TRIANGLES) and one for drawing polygon wireframe(GL_LINES).
2010/8/17
Curvature tonsor
The principal curvature directions (red line for KMax, green line for KMin) are renderred using the the flat shader of the stock shaders in GLTools/GLShadermanager.h/cpp.
To build up the 3*3 tensor matrix (used by the Normal Cycle approximation algorithm), need to loop and search a neighborhood region of a start vertex.
push the start vertex into a stack (why use stack);
while stack is not empty
v = pop up the top vertex;
loop the one-ring neighbor of v;
if the neighbor meets the qualify, operate on it and push it into stack.
This search algorithm remind me of the Dijkstra’s algo.
To improve the curvature quality, some smoothing steps are need.
Triangle is evil?
Doing with mesh, i always asking why the quad mesh is used so often and i saw most of the model created by so-called artist are quad mesh, not triangle mesh, not even the n-sided mesh.
Maybe, this is one of the reason.
(a). Two quad faces share one edge, it is easy to set these two faces are symmetric.
(b). Tessellate those two faces in (a) into triangles, what happen the red triangles are set to symmetric? It’s wrong i guess, the topology are not symmetric, though the vertices are symmetric.
(c). even worse.
Thinking about managing ImageFilter/MeshBrush
In the plugin “Image Filter Tool”, there are some image filters can be applied to the image. There is a base class ImageFilter, i can write derive class of it in another plugin(dll) to define new image filter. My question is after the new image filter type is defined, how to add it into the main application, and create ui(for example button, or combo item) for it?
The function registerImageFilters(...) can be put into a ImageFilterFactory class as a static member functon:
typedef (ImageFilter *)(FuntionPointer)();
void ImageFilterFactor::registerImageFilter(string name, FuntionPointer funcPointer);
Can it be better?
(1). do not create the instance until the filter is selected.
(2). do not use the callback function to create the instance in plugin, but use running time type info(rtti) to create a instance in the main application. Declare a new image filter like this:
class ImageFilter : public XObject {
X_OBJECT
...
};
in plugin:
class XImageFilter: public ImageFilter {
X_OBJECT
...
};
Something looks like the object system in Qt :-) then the XImageFilter type is added into the object system, later we can check whether we have a type named “XImageFilter” in the object system, if yes, we use:
ClassInfo * findClassInfo(“XImageFilter”);
ImageFilter *pIF = pCI->createInstance();
Recommended book: Design of Design http://www.informit.com/store/product.aspx?isbn=0201362988 sample chapters are on the right hand side.
(some one said “Run, you run” can be translated into 跑啊, 你丫快跑啊:-)
There are many things to learn and do. In order to render the curvature tensor, which is property of mesh, i need to add shader step-up and organize the vertices from curvatures into vbo (OpenGL 3.x is used).
However, there is already shader step-up and vbo using in the scene::render(), i don’t want to duplicate the code in the class Model. So, shader manager and vertex batch classes are need.
After googling, i come across to http://www.informit.com/articles/article.aspx?p=1616796&seqNum=4, the free chapters of OpenGL SuperBible 5th, and the greatest thing is its code is stored in google code project, from where i can download it. Must read!
Another resource is http://prideout.net/blog/?p=22 (anti-aliased cel shading, and shader wrapper).
Expected result:
1. Refactor the shader loading, create the batch class, render the scene(world frame, grid, mesh) using this new one.
2. render the curvature tonsor.
3. integrate the anti-aliased cel shading.
Notes:
1. there are two ways to get the vertex attribute location(index). The explicit way, use the
glBindAttribLocation(uint program, int index, char *name);
The inexplicit way, use the
int index = glGetAttribLocation( uint program, const char *name );
the index will be used later by puting vertex data into it.
2. To render the model, there is only mesh data at the current time, which is a polygon/n-sided mesh, using GL_TRIANGLES, a triangle mesh is created. The triangle mesh is used exclusively on rendering, but the mesh adjacency information is not used so data is wasted to record that. After integrate the GLBatch from GLTools of OpenGL SuperBible 5th, I wonder how about remove the triangle mesh, put the triangle data of the polygon mesh into the a instance of class GLBatch.
After further investigation, it is found that there is no index buffer object in the class GLBatch, for example if a quad is needed to be drew, six vertices are needed, and the
glDrawArray(GL_TRIANGLES, 0, 6);
is used. There are two vertices are duplicated. The GLBatch cannot be used directly.
But the triangle mesh is still needed to be removed. I want to create a vertex batch for all the vertices data, and create two index buffer object, one for regularly drawing triangle(GL_TRIANGLES) and one for drawing polygon wireframe(GL_LINES).
2010/8/17
Curvature tonsor
The principal curvature directions (red line for KMax, green line for KMin) are renderred using the the flat shader of the stock shaders in GLTools/GLShadermanager.h/cpp.
To build up the 3*3 tensor matrix (used by the Normal Cycle approximation algorithm), need to loop and search a neighborhood region of a start vertex.
push the start vertex into a stack (why use stack);
while stack is not empty
v = pop up the top vertex;
loop the one-ring neighbor of v;
if the neighbor meets the qualify, operate on it and push it into stack.
This search algorithm remind me of the Dijkstra’s algo.
To improve the curvature quality, some smoothing steps are need.
Triangle is evil?
Doing with mesh, i always asking why the quad mesh is used so often and i saw most of the model created by so-called artist are quad mesh, not triangle mesh, not even the n-sided mesh.
Maybe, this is one of the reason.
(a). Two quad faces share one edge, it is easy to set these two faces are symmetric.
(b). Tessellate those two faces in (a) into triangles, what happen the red triangles are set to symmetric? It’s wrong i guess, the topology are not symmetric, though the vertices are symmetric.
(c). even worse.
Thinking about managing ImageFilter/MeshBrush
In the plugin “Image Filter Tool”, there are some image filters can be applied to the image. There is a base class ImageFilter, i can write derive class of it in another plugin(dll) to define new image filter. My question is after the new image filter type is defined, how to add it into the main application, and create ui(for example button, or combo item) for it?
The function registerImageFilters(...) can be put into a ImageFilterFactory class as a static member functon:
typedef (ImageFilter *)(FuntionPointer)();
void ImageFilterFactor::registerImageFilter(string name, FuntionPointer funcPointer);
Can it be better?
(1). do not create the instance until the filter is selected.
(2). do not use the callback function to create the instance in plugin, but use running time type info(rtti) to create a instance in the main application. Declare a new image filter like this:
class ImageFilter : public XObject {
X_OBJECT
...
};
in plugin:
class XImageFilter: public ImageFilter {
X_OBJECT
...
};
Something looks like the object system in Qt :-) then the XImageFilter type is added into the object system, later we can check whether we have a type named “XImageFilter” in the object system, if yes, we use:
ClassInfo * findClassInfo(“XImageFilter”);
ImageFilter *pIF = pCI->createInstance();
Recommended book: Design of Design http://www.informit.com/store/product.aspx?isbn=0201362988 sample chapters are on the right hand side.
(some one said “Run, you run” can be translated into 跑啊, 你丫快跑啊:-)
标签:
book,
curvature,
shader,
vertex batch,
weekly update
Bug Series - angle between two vectors
float dot = dot(v0, v1);
float radian = acos(dot);
more safe:
dot = Max(-1, Min(dot(v0, v1), 1); // make sure the dot is [-1, 1].
radian = acos(dot);
float radian = acos(dot);
more safe:
dot = Max(-1, Min(dot(v0, v1), 1); // make sure the dot is [-1, 1].
radian = acos(dot);
https://docs.google.com/document/pub?id=1KyKbHUXfrXh-7L0g4cP-l2QcqVDsmYPTyBJXjGAtXhA
Bug Series_Programing_link error_unresolved external symbol
之前
最上层的基础库都是static library(.lib), 中间的core要是static library(.lib), 然后被应用层的main.cpp直接生成application.exe.
这么弄一直没有问题, 直到...
直到我想加入一个ImageEditor的plugin, 作为一个dynamic library(.dll)存在, 这个plugin需要使用core提供的interface来调用application里面的类和member function, 而core在里面也需要能检查到这个加入的plugin并使用它。
compilation没有问题,但是在link时候就出错了:
error LNK2019: unresolved external symbol "__declspec(dllimport) public ...
后来发现那个core作为static library是有问题,因为static library不能包含别的static library和dynamic library . 于是我把core作为dynamic library就ok了.
但是这样又引入了新的问题, dynamic library需要导出一些接口,别的.dll/.exe才能使用, 否则例如main.cpp和ImageEditor中就不能使用了。
于是就引入了__declspec attributes.
http://blog.csdn.net/alicehyxx/archive/2010/01/08/5161868.aspx
http://msdn.microsoft.com/zh-cn/library/9h658af8(v=VS.80).aspx
http://msdn.microsoft.com/zh-cn/library/z4zxe9k8(v=VS.80).aspx
http://msdn.microsoft.com/zh-cn/library/fdy23fx6(v=VS.80).aspx
http://msdn.microsoft.com/zh-cn/library/a90k134d(v=VS.80).aspx
http://msdn.microsoft.com/zh-cn/library/900axts6(v=VS.80).aspx
最上层的基础库都是static library(.lib), 中间的core要是static library(.lib), 然后被应用层的main.cpp直接生成application.exe.
这么弄一直没有问题, 直到...
直到我想加入一个ImageEditor的plugin, 作为一个dynamic library(.dll)存在, 这个plugin需要使用core提供的interface来调用application里面的类和member function, 而core在里面也需要能检查到这个加入的plugin并使用它。
compilation没有问题,但是在link时候就出错了:
error LNK2019: unresolved external symbol "__declspec(dllimport) public ...
后来发现那个core作为static library是有问题,因为static library不能包含别的static library和dynamic library . 于是我把core作为dynamic library就ok了.
但是这样又引入了新的问题, dynamic library需要导出一些接口,别的.dll/.exe才能使用, 否则例如main.cpp和ImageEditor中就不能使用了。
于是就引入了__declspec attributes.
http://blog.csdn.net/alicehyxx/archive/2010/01/08/5161868.aspx
http://msdn.microsoft.com/zh-cn/library/9h658af8(v=VS.80).aspx
http://msdn.microsoft.com/zh-cn/library/z4zxe9k8(v=VS.80).aspx
http://msdn.microsoft.com/zh-cn/library/fdy23fx6(v=VS.80).aspx
http://msdn.microsoft.com/zh-cn/library/a90k134d(v=VS.80).aspx
http://msdn.microsoft.com/zh-cn/library/900axts6(v=VS.80).aspx
Math Series - Cycloid 摆线 轮滚线
想象这么一个情景:车子来开,一个车轮压到地面的口香糖,口香糖粘到轮子上了(会这样子么?) 假如问轮子转一圈之后口香糖划过的距离长?:-)
首先这个划过的曲线叫做轮滚线,一个很形象的名字,至于那个长度怎么求了嘛,以及这个曲线跟地面的面积怎么求,请看:
http://tutorial.math.lamar.edu/Classes/CalcII/ParaArea.aspx and the next section.
首先这个划过的曲线叫做轮滚线,一个很形象的名字,至于那个长度怎么求了嘛,以及这个曲线跟地面的面积怎么求,请看:
http://tutorial.math.lamar.edu/Classes/CalcII/ParaArea.aspx and the next section.
2010年8月3日星期二
interesting stuff about geometry
1. a mesh composes of vertex attributes(geometry information) and adjacency(topology information). How about compress they independently? http://openctm.sourceforge.net/
2. Some special mesh can be generated automatically, does not need to add faces/vertices manually. check http://prideout.net/blog/?p=44 and http://structuresynth.sourceforge.net/
3. I'm always interested in the geometry engine of CAD or something like that. http://wildcat-cad.blogspot.com/
2010年6月20日星期日
To render the vertex
目的是用OpenGL 3.2来画东西, 而不是glVertex, glColor.
Step 1:
使用glVertex的特点是容易入手, 现在需要自己手工来完成上面好几个steps才可以。但是特点是思路很清晰,先打包好vertex data,往shader program里面放这些数据,条理清晰。
Step 1:
准备Vertex Data:
(1). vertex count 有多少个数据? (2). 具体的vertex data, (3)这些数据的大小(in byte)
例如:
const GLint coordinateLineVertexCount = 6;
const GLint coordinateLineVertexSize = sizeof(dgp::vec3f) * 2 * coordinateLineVertexCount;
dgp::vec3f coordinateLineVertexData[] = {
// vertex position // vertex color
dgp::vec3f(0, 0, 0), dgp::vec3f(1, 0, 0),
dgp::vec3f(fLength, 0, 0), dgp::vec3f(1, 0, 0),
dgp::vec3f(0, 0, 0), dgp::vec3f(0, 1, 0),
dgp::vec3f(0, fLength, 0), dgp::vec3f(0, 1, 0),
dgp::vec3f(0, 0, 0), dgp::vec3f(0, 0, 1),
dgp::vec3f(0, 0, fLength), dgp::vec3f(0, 0, 1)
};
注意每一个vertex data包含了两部分, position and color.Step 2:
生成一个buffer object放这些vertex data.
Step 3:
生成一个shader program,
Step 4:
当真正需要render的时候, 往shader program的相应的location里面写入对应的数据.Step 4:
例如: projection matrix, model view matrix, the vertex data (position, normal, color) ....
然后指定画成什么primitive形式。
相对于glColor来给出顶点的颜色, 在shader里面的做法 我用了下面三种最简单的(每一种对应一个shader program):
例如图中的Cube, 用Blinn Phong lighting,fragment shader中计算color.
例如图中的Grid,all the vertices are the same color, they are same color in fragment too, 所以我在fragment shader中用了一个uniform vec3 fragmentColor;程序中指定这个颜色,黑色,就ok了。
例如图中的coordinate system line,一个红线,一个绿色的线,一个蓝色的线。就需要每一个vertex 给出 color 信息. vertex shader 中:
in vec3 position;
in vec3 color; // 之后取他们的location并写入准备好的data.
例如图中的Cube, 用Blinn Phong lighting,fragment shader中计算color.
2010年6月18日星期五
Thinking about Singleton
1. The constructor should not have parameters?
In the GoF Design Patterns, there is no parameter for the constructor. That makes it very easy, because the constructor is invoked by the instance() method, if the constructor needs parameters, do we send the parameters to the instance() method, which pass them to the constructor? It is not clean and clear.
class Singleton {
public:
static Singleton *instance();
protected:
Singleton();
private:
static Singleton *s_pInstance;
};
But if the the constructor do need some parameters, how to do that?
2. The constructor need to be protected/privated?
In the GoF Design Patterns, the constructor is protected, which make sure that the clients (from outside) can not instantiate objects directly. But if we want to create a new Singleton instance?
class Singleton {
public:
static Singleton* createNewInstance();
static Singleton* instance();
protected:
Singleton();
private:
static Singleton *s_pInstance;
};
The following is an example. For example, a new scene is created whenever a scene file is loaded/read.
Scene* Scene::s_pThis= 0;
Scene* Scene::instance() {
if (s_pThis) {
return s_pThis;
} else {
return createNewScene();
}
}
Scene* createNewScene() {
if (s_pInstance ) {
// delete, this will call the deconstructor.
delete s_pThis;
s_pThis= 0;
}
s_pThis= new Scene;
return s_pThis;
}
In this case, the instance() returns the object instance which is active, others are discarded.
And in this case, we can change it a little bit:
(1) firstly, call this method to create instance.
static Singleton* createNewInstance(...parameters...);(2) call the instance() use the instance object.
This makes a assumption that, create it before you use it.
3. The copy constructor and assignment operator ?
See this example:
Scene s = *Scene::instance(); // this will call the copy constructor.
Scene s; // this will call the default constructor.void functionX(Scene s) {
s is a temp instance object...
}
functionX(*Scene::instance()); // this will call the copy constructor;
Maybe, it would be safer to private these two methods.
Maybe, it would be safer to private these two methods.
4. How about the s_pInstance in derived class?
2010年6月16日星期三
Math Series - Quadratic equation
the solutions are:
Case 1. Points on a sphere, and Ray - Sphere intersection.
2010年6月11日星期五
Bug Series - 无效的int变成了有效的unsigned char
Today, i came across this kind of bug:
When iIndex = -1, the ucIdx is 255, so even you think iIndex is invaluable, but the ucIdx >= 0 is ture, so error happens.
int iIndex = -1 ;// -1 means invaluable value. >=0 means valuable.
unsigned char ucIdx = iIndex;
if (ucIdx >= 0) { // this is error-prone, most of time ucIdx >= 0 is true.
do sth here;
}
When iIndex = -1, the ucIdx is 255, so even you think iIndex is invaluable, but the ucIdx >= 0 is ture, so error happens.
Why?
Take a two bits value as an example. 2 bits can express 4 values,
unsigned: 00, 01, 10, 11
0, 1, 2, 3.
signed: 11, 00, 01, 10
-1, 0, 1, 2.
It is clear that the signed value -1 means 3 at unsigned value.
so, the ucIdx = iIndex = -1 means 255, which obviously/obviously >= 0. The bug comes from here.
Bug Series - 数组变小了
Let see look the a tree structure first:
一个Scene底下有两个geometry, 后来在Scene下还多建立了一个Skeleton来做skinning, 这个skinning与那两个geometry有关,是作用于它们上面的, 具体的skinning操作变换在各自的SkeletonReference中。
可见问题在于 after executing the blue line, one element has been removed from the array. so let take a look at the de-constructor of SkeletonReference.
并且为了记录这个Skeleton 是操作哪些Geometry的,于是Skeleton有一个成员m_arrGeo[]是一个数组, 这个例子中记录的是两个指针.
下面的问题是: 我要删除这个skinning操作, 也就是将Skeleton和两个SkeletonReference删除掉.
code:
for (int i = 0; i < skeleton->m_arrGeo.size(); ++i) {
delete skeleton->m_arrGeo[i]->skeleton_reference;
}
delete skeleton;
这个代码段在Skeleton只作用于一个Geometry时候运行正常, 但是当作用于两个和多个Geometry时候就错误了(错误是隐晦地遗留到后面别的地方才造成的,不是在这里就造成,这才是恐怖的地方).
for (int i = 0; i < skeleton->m_arrGeo.size(); ++i) {
print out the size = 2;
delete skeleton->m_arrGeo[i]->skeleton_reference;
print out the size = 1;
}
delete skeleton;
可见问题在于 after executing the blue line, one element has been removed from the array. so let take a look at the de-constructor of SkeletonReference.
~SkeletonReference() {
find if the parent (the Geometry_i) is in the m_arrGeo[],
if yes, remove it.
}
Actually, this method makes sense, because when a geometry do not possess a SkeleteReference, there is no need to be recorded in the m_arrGeo[] array.So, the problem is in the for sentence.
for (int i = 0; i < skeleton->m_arrGeo.size(); ++i) { // we are iterating a dynamic array.
// we can not make sure that we can visit all the elements.
...
}
change it to:
std::vector<Geometry *> arrGeo = skeleton->m_arrGeo;
for (int i = 0; i < arrGeo.size(); ++i) {
// this is right.
delete arrGeo[i]->skeleton_reference;
}
2010年6月7日星期一
ComboBox - model/view
但是有时候E中有些元素有不想显示在ComboBox中.
这里的解决方法是将某一部分ei作为itemI, 当用户选择了某一个item时候返回其string,再到E中找对应的idx.
2010年5月30日星期日
Bug Series - crash at delete pointer
void Scene::setCamera(Camera *_camera) {
if (m_pCamera) {
delete m_pCamera;
m_pCamera = 0;
}
this->m_pCamera = _camera;
}
这个是错的, 因为第一次到if时候, m_pCamera之前不一定是new出来的而因为垃圾数据而非零, 于是在delete时候就crash了.
所以m_pCamera需要在构造函数中初始化为0.
2010年5月16日星期日
Gaussian Blur
需求: 在看OpenCL的Gaussian Blur例子.
基本概念看http://en.wikipedia.org/wiki/Gaussian_blur,有一个新的概念是linearly separable, 原本是一个有权值组成的方形矩阵来对周围的pixel做加权和,现在分开horizaontal and vertical direction方向各一个pass来先后做,好处是什么?提高performance, 对每一个pixel的求值从width * height个乘法降低到width + height个。
那么水平(or 竖直)一个方向的blur结果就是:
左边是原图,右边我做出来后倒是像某种海底的浮游动物。
.这个curve的特点包括the total area under it is equal to one. 为什么需要这个requirement呢? 很可能是因为Guassian函数作为probability distribution functions的一种,而后者有这个要求,那Gaussian函数自然也需要满足. 那个mean
控制是curve的中心值, 而standard deviation控制的是曲线形状的宽度.
那么为什么高斯分布在自然中这么常见呢?甚至说一个学校里面学生的考试成绩也是成高斯分布。Central Limit Theorem 是一种解释. "In its simplest form, the Central Limit Theorem states that a sum of random numbers becomes normally distributed as more and more of the random numbers are added together. It does not require the individual random numbers be from any particular distribution, or even that the random numbers be from the same distribution"[The Scientist and Engineer's Guide to Digital Signal Processing, Steven W. Smith].
基本概念看http://en.wikipedia.org/wiki/Gaussian_blur,有一个新的概念是linearly separable, 原本是一个有权值组成的方形矩阵来对周围的pixel做加权和,现在分开horizaontal and vertical direction方向各一个pass来先后做,好处是什么?提高performance, 对每一个pixel的求值从width * height个乘法降低到width + height个。
例如对于blur宽度是5的情况, 有以下两个预想求得的table值 (取不同的宽度值就对应不同的两个tables. 至于这些table值是怎么求出来的,standard deviation去什么值, 是不是直接代入坐标算出来的呢?有待考证):
static float const blurOffsets5[] = { -4.37988, -2.43235, -0.486391, 1.45925, 3.40585, 5 };
static float const blurWeights5[] = {0.0953448, 0.200199, 0.275104, 0.24745, 0.145682, 0.0362198 };
那么水平(or 竖直)一个方向的blur结果就是:
for (index = 0; index < 5; ++index) {
pixel += read_imagef(srcImage, 当前坐标 + (float2)(blurOffsets5[index], 0.0f)) * blurWeights5[index];
}
另一个话题 Guassian distribution,(normal distribution).
一维情况下,这个高斯分布(正态分布)的curve的函数是 那么为什么高斯分布在自然中这么常见呢?甚至说一个学校里面学生的考试成绩也是成高斯分布。Central Limit Theorem 是一种解释. "In its simplest form, the Central Limit Theorem states that a sum of random numbers becomes normally distributed as more and more of the random numbers are added together. It does not require the individual random numbers be from any particular distribution, or even that the random numbers be from the same distribution"[The Scientist and Engineer's Guide to Digital Signal Processing, Steven W. Smith].
2010年5月15日星期六
How to locate the work item in OpenCL?
How to locate the work item in OpenCL?
- Reading Notes of OpenCL Specification version 1.0.
Global ID: A global ID is used to uniquely identify a work-item and is derived from the number
of global work-items specified when executing a kernel. The global ID is a N-dimensional value
that starts at (0, 0, 0). See also Local ID.
Local ID: A local ID specifies a unique work-item ID within a given work-group that is
executing a kernel. The local ID is a N-dimensional value that starts at (0, 0, 0). See also
Global ID.
Work-item: One of a collection of parallel executions of a kernel invoked on a device by a
command. A work-item is executed by one or more processing elements as part of a work-group
executing on a compute unit. A work-item is distinguished from other executions within the
collection by its global ID and local ID.
a single work-item can be uniquely identified by its global ID or by a combination of its local ID and work-group ID.
Each work-item is identifiable in two ways; in terms of a global index, and in terms of a work-group index plus a
local index within a work group.\
下图显示这些id的计算:
uint get_work_dim(); Returns the number of dimensions in use.
size_t get_global_size(uint dimindx);
图中是 Gx * Sx = get_global_size(0); Gy * Sy = get_global_size(1); 一行or一列的总的items数目.size_t get_gloabl_id (uint dimindx);
例如上图中gx = get_global_id(0); gy = get_global_id(1); 一行or一列中的第几个.
size_t get_local_size(uint dimindx);
图中的 Sx and Sy. 表示一个work group中一行的items数目or 一列的items数目.
size_t get_local_id (uint dimindx);
例如上图中sx = get_local_id(0); sx = get_local_id(1); 表示某一个work group中一行or一列中的第几个.
size_t get_num_groups(uint dimindx);
图中的 Gx or Gy. 表示每行or每列有多少个work group.
size_t get_group_id(uint dimindx);
图中的wx or wy. 表示一行or一列中的第几个work group.
这些build-in function是足够计算几种id的转化了.
这两个值可以通过函数取得: size_t get_global_size(uint dimindx); valid values of dimindx are 0 to get_work_dim() - 1;
local_work_size can also be a NULL value in which case the OpenCL implementation will
global_work_size: points to an array of work_dim unsigned values that describe the number of
global work-items in work_dim dimensions that will execute the kernel function. The total
number of global work-items is computed as global_work_size[0] * ... * global_work_size[work_dim - 1].
我理解在上图, work_dim 就是2指二维, global_work_size[0] = Gx, global_work_size[1] = Gy.这两个值可以通过函数取得: size_t get_global_size(uint dimindx); valid values of dimindx are 0 to get_work_dim() - 1;
local_work_size points to an array of work_dim unsigned values that describe the number of
work-items that make up a work-group (also referred to as the size of the work-group) that will
execute the kernel specified by kernel. The total number of work-items in a work-group is
computed as local_work_size[0] * ... * local_work_size[work_dim - 1].
我理解在上图, work_dim 就是2指二维, local_work_size[0] = Sx, local_work_size[1] = Sy.
这两个值可以通过函数取得: size_t get_local_size(uint dimindx); valid values of dimindx are 0 to get_work_dim() - 1;
local_work_size can also be a NULL value in which case the OpenCL implementation will
determine how to be break the global work-items into appropriate work-group instances.
If local_work_size is specified, the values specified in global_work_size[0], … global_work_size[work_dim - 1]
must be evenly divisible by the corresponding values specified in local_work_size[0], … local_work_size[work_dim – 1].
这个就很容易出错了, 例如一个image是300 * 300, 我就不能设置local size为 8 * 8.
2010年5月8日星期六
premultiplied alpha
什么是Compositing (Alpha Composition) ?

平时我看到的alpha blending好像就是所谓的simple alpha compositing, 好像就是Porter-Duff paper中的over operation.[2]: http://www.svgopen.org/2005/papers/abstractsvgopen/simplealpha.png
Classic paper: Compositing Digital Image, 1984. http://keithp.com/~keithp/porterduff/
第2节The Alpha Channel 解释了为什么需要因为alpha channel,因为需要"retain the matte information. the extent of the coverage of an element at a pixel. An alpha of 0 indicate no coverage, 1 means full coverage, fractions corresponding to partial coverage."
里面有一个问题: "how do we express that a pixel is half covered by a full red object?
然后区分了两个:
这公式是不是就是看上去很像我们上面提到的simple alpha compositing/blending的线性插值的结果呢? 其实就是嘛。paper的“This is almost the wll used linear interpolation of foreground F with the background B
[ ] http://www.mail-archive.com/gimp-developer@lists.xcf.berkeley.edu/msg08096.html GIMP中多个layers时候也是从低往上来做composition的"the layer compositing works from the bottom to the top". 注意这种合并是非associative的,所以次序很关键.
[ ] https://mmack.wordpress.com/ 里面的Sprite mipmaps文中将到pre-mulitplied 的另一个用处.
上面讲了什么是pre-multiplied alpha,也提到了它的一个好处是不用在每次求compositing时候做乘以alpha value. 那么它还有什么好处呢? 这就是下一个话题了.
[] http://www.kxcad.net/autodesk/3ds_max/Autodesk_3ds_Max_9_Reference/premultiplied_alpha_glossary.html
当然了, 它也有缺点的. "To be clear: premultiplied alpha is not a perfect panacea for all problems".
讲完了 what is premultiplied alpha and why it solves all the world's problems. 下面讲一下它跟blend mode的关系,其实我是因为要做blend mode的操作,而1. blend mode的某些操作中用到了over operator等;2. the formulas in that photoshop document are assuming the pixels are unpremultiplied. 3. Mudbox uses premultiplied alpha, so the math will be different in some cases.
首先, "While every pixel has transparency information associated with it, every layer also has an associated opacity value. The two terms are similar and in most cases can be treated as the same. You may think of a layer's opacity value as a "dimmer" for the alpha values of every pixel in the layer."http://www.getpaint.net/doc/latest/en/LayersAndBlendModes.html
svg的specifications都是用pre-multiplied的.
在svg 1.1 中[http://www.w3.org/TR/SVG11/filters.html#feBlend, http://www.w3.org/TR/2003/REC-SVG11-20030114/filters.html#feBlend 这两个是一样的]中可以找到normal, multiply, screen, darken, lighten的公式,都是premultiplied的, 相关的实现在google code search中找nr-filter-blend.cpp 可以找到。是不是意味着在svg 1.1中只是支持这5个Porter-Duff操作呢? 后面提到1.2版本做了扩展的.
下面看看Cairo的实现(它利用了一个叫做Pixman: the pixel-manipulation library for X and cairo的库).
然后在P328中说"The preceding formula represents a simplification of the following formula, which presents the relative contributions of backdrop, source, and blended colours in a more straightforward way":
这公式其实更好,为什么呢?
其实在pixman-combine32.c代码中, Benjamin做实现时候大部分的blend mode就是用了pre-multiplied format的blending mode function. 然后Color, Luminosity, Saturation, Hue这四种blend mode是例外, 还是照着PDF一样用non-premultiplied colors. 前者和否则分别对应他代码中的PDF_SEPARABLE_BLEND_MODE和PDF_NON_SEPARABLE_BLEND_MODE。

这样就很直观了,感觉好像就是Layer 全透明(full transparency, clear(0,0,0,0))的地方不影响背景, 公式中解释为Sa = 0, 所以(1 - Sa) * Bca + (1 - Ba) * Sa= (1 - 0) * Bca + (1 - Ba) * (0,0,0) = Bca; 而Layer中非透明的地方,就不好直观地说了,要代入公式来算了。这本例中因为非透明的地方Ba = Sa = 1, 所以结果是(0,0,0)黑色.
于是最后的结果应该就是: (Rca, Ra), in premultiplied format.
"Compositing is the process by which graphical objects are combined. Alpha compositing uses the alpha values, or channel (bit mask) to represent the coverage of each pixel. The alpha channel is often said to represent the 'opacity'. This coverage information is used to control the compositing of colors. " [2]
"In computer graphics, alpha compositing is the process of combining an image with a background to create the appearance of partial transparency. It is often useful to render image elements in separate passes, and then combine the resulting multiple 2D images into a single, final image in a process called compositing."[1]
平时我看到的alpha blending好像就是所谓的simple alpha compositing, 好像就是Porter-Duff paper中的over operation.[2]: http://www.svgopen.org/2005/papers/abstractsvgopen/simplealpha.png
涉及在对两个bitmaps做blending的时候: 左边的表述是已有的底片,右边的表述是要画在上面的,
backdrop layer/source
based image blend image
target source image
framebuffer texel
background foreground-----------------foreground * alpha
-----------------background *(1-alpha) => result.
想象一种situation,已经在framebuffer上画好了model,上面加一个painting layer,需要将这个painting layer放到上面去。
fig "". 这个图片用到公式就是很常用的,我觉得就是上面讲到的simple alpha compositing. 而且这公式的color compenent是un-premultiplied的,所以公式中加号+后面blend * blend.a.
想象一种situation,已经在framebuffer上画好了model,上面加一个painting layer,需要将这个painting layer放到上面去。
如果是用了pre-multiplied color compenent的话, result = based * (1 - blend.a) + blend. 这就是Porter-Duffer paper中的"over" operator. 这就说明了我们平时常见的blending和Porter-Duffer compositing的关系了,并不contrary矛盾的。
Classic paper: Compositing Digital Image, 1984. http://keithp.com/~keithp/porterduff/
第2节The Alpha Channel 解释了为什么需要因为alpha channel,因为需要"retain the matte information. the extent of the coverage of an element at a pixel. An alpha of 0 indicate no coverage, 1 means full coverage, fractions corresponding to partial coverage."
里面有一个问题: "how do we express that a pixel is half covered by a full red object?
One obvious suggestion is to assign (1, 0, 0, .5) to that pixel: the .5 indicates the coverage and the (1, 0, 0) is the color.
There are a few reasons to dismiss this proposal, the most severe being that all composting operations will involve multiplying the 1 in the red channel by the 0.5 in the alpha channel to compute the red contribution of this object at this pixel. 这种un-pre-multiplied alpah的表示方式的缺点是每次做compositing时候都需要乘以alpha. The desire to avoid this multiplication points up a better solution, storing the pre-multiplied value in the color component, so that (0.5, 0, 0, 0.5) will indicate a full red object half covering a pixel."
然后区分了两个:
black = (0, 0, 0, 1); // an opaque black, alpha = 1 means full coverage = opaque.
clear = (0, 0, 0, 0); // transparent.
什么是"clear"呢? 就是下面看到的格子背景(在gimp, photoshop中才能看到的). 我用红色的圈圈表示picker的位置. "transparent pixels cannot be displayed on a computer monitor", so a "checker board pattern" is used.

第4节 讲了12种composition operations. 这部分很难懂,需要参考[2],[3],
为什么说12种呢? 组合问题。
并且假如颜色是用了pre-multiplied的话, composition后的color and alpha components都是用 equation 1: c0 = c_a * F_a + c_b * F_b来求的。那个F_a, F_b在每一种operator中的取值都不一样,F的意思是"which indicate the extend of contribution of A and B" 跟alpha不是一样的.
"It is important to note that the equations defined by the Porter and Duff paper are all defined to operate on color components that are premultiplied by their corresponding alpha components. "[5] 说Porter-Duff paper中的公式用到是color components are pre-multiplied.
先回顾alpha value的意义啊:这个color component在这个pixel上覆盖了多少, 0表示没有覆盖, 1表示全覆盖.
先回顾alpha value的意义啊:这个color component在这个pixel上覆盖了多少, 0表示没有覆盖, 1表示全覆盖.
例如一个pixel上有picture A和picture B两个color component (element) 同时出现了,A.alpha = 1, B.alpha = 1. 这并不conflict冲突的, A的color component full coverage this pixel, and B's color component full coverage this pixel too. 当我们做alpha blending时候我们会先假设一个在某一个上面, 例如A在B上面,如果A.alpha=1,那B就看不到了. 所以我感觉alpha 是说我覆盖占这个pixel多少了, 控制的是pixel的transparency.
再来看over operator, paper p256左边最后几行的公式是:
cO = cA * Fa + cB * Fa, 然后查表(A over B)就可得到Fa and Fb的value,代入公式:
cO = cA * 1 + cB * (1 - aA) = cA + cB * (1 - aA)。
这公式是不是就是看上去很像我们上面提到的simple alpha compositing/blending的线性插值的结果呢? 其实就是嘛。paper的“This is almost the wll used linear interpolation of foreground F with the background B
B' = F * a + B * (1 - a),
except that our foreground is pre-multiplied by alpha.” 公式中的a是指F.alpha, 我觉得.
Until now, 终于将我们平时看到的linear interpolation和Porter-Duffer paper中的over operator联系起来了. 另一个证明, 在[6]中有"'normal' blend mode is equivalent to operator="over" on the 'feComposite' filter primitive, matches the blending method used by 'feMerge' and matches the simple alpha compositing technique used in SVG for all compositing outside of filter effects."
[4] http://greenshoes.free.fr/dotclear/index.php?post/2008/12/02/Using-alpha-composites-in-PulpCore
[5] http://java.sun.com/javase/6/docs/api/java/awt/AlphaComposite.html 这里也有解释和公式.
[1] Compositing Digital Image, 1984. http://keithp.com/~keithp/porterduff/
[2] http://www.svgopen.org/2005/papers/abstractsvgopen/index.html
[3] http://en.wikipedia.org/wiki/Alpha_compositing [4] http://greenshoes.free.fr/dotclear/index.php?post/2008/12/02/Using-alpha-composites-in-PulpCore
[5] http://java.sun.com/javase/6/docs/api/java/awt/AlphaComposite.html 这里也有解释和公式.
[6] http://www.w3.org/TR/SVG/filters.html#feBlend 这是SVG1.1 20030114.
[ ] http://www.mail-archive.com/gimp-developer@lists.xcf.berkeley.edu/msg08096.html GIMP中多个layers时候也是从低往上来做composition的"the layer compositing works from the bottom to the top". 注意这种合并是非associative的,所以次序很关键.
[ ] https://mmack.wordpress.com/ 里面的Sprite mipmaps文中将到pre-mulitplied 的另一个用处.
上面讲了什么是pre-multiplied alpha,也提到了它的一个好处是不用在每次求compositing时候做乘以alpha value. 那么它还有什么好处呢? 这就是下一个话题了.
[] http://www.kxcad.net/autodesk/3ds_max/Autodesk_3ds_Max_9_Reference/premultiplied_alpha_glossary.html
当然了, 它也有缺点的. "To be clear: premultiplied alpha is not a perfect panacea for all problems".
[] http://kriscg.blogspot.com/2009/11/premultiplied-alpha.html
[] http://msdnrss.thecoderblogs.com/2010/04/08/premultiplied-alpha-in-xna-game-studio-40/
[] http://msdnrss.thecoderblogs.com/2010/04/08/premultiplied-alpha-in-xna-game-studio-40/
讲完了 what is premultiplied alpha and why it solves all the world's problems. 下面讲一下它跟blend mode的关系,其实我是因为要做blend mode的操作,而1. blend mode的某些操作中用到了over operator等;2. the formulas in that photoshop document are assuming the pixels are unpremultiplied. 3. Mudbox uses premultiplied alpha, so the math will be different in some cases.
才涉及到Porter-Duff Compositing的. 下面回归blend mode.
首先, "While every pixel has transparency information associated with it, every layer also has an associated opacity value. The two terms are similar and in most cases can be treated as the same. You may think of a layer's opacity value as a "dimmer" for the alpha values of every pixel in the layer."http://www.getpaint.net/doc/latest/en/LayersAndBlendModes.html
先f' = foreground image * opacity,再来用这个f'去继续的.
svg的specifications都是用pre-multiplied的.
在svg 1.1 中[http://www.w3.org/TR/SVG11/filters.html#feBlend, http://www.w3.org/TR/2003/REC-SVG11-20030114/filters.html#feBlend 这两个是一样的]中可以找到normal, multiply, screen, darken, lighten的公式,都是premultiplied的, 相关的实现在google code search中找nr-filter-blend.cpp 可以找到。是不是意味着在svg 1.1中只是支持这5个Porter-Duff操作呢? 后面提到1.2版本做了扩展的.
在svg filter 1.2 [http://www.w3.org/TR/2007/WD-SVGFilter12-20070501/#feBlendElement] 中也一样,
但是在svg 1.2[http://www.w3.org/TR/2004/WD-SVG12-20041027/rendering.html]就好像对alpha compositing做了扩展,加入了Compositing module.
但是在svg 1.2[http://www.w3.org/TR/2004/WD-SVG12-20041027/rendering.html]就好像对alpha compositing做了扩展,加入了Compositing module.
这里给我的感觉就是后续的出现在PDF specification中的其它例如darken/lighten, soft light等都是Porter-Duffer 之后的扩展, 如上说的Normal mode就是Over operator.
上面那是svg的specifications, 至于具体在一个library中怎么实现,那还是有区别的.
下面看看Cairo的实现(它利用了一个叫做Pixman: the pixel-manipulation library for X and cairo的库).
首先, 貌似是Benjamin Otte这家伙(后来在red hat中上班)在Cairo中加入blend mode的(March 2008, http://old.nabble.com/Blend-modes-td15856879.html ), 然后他发现了SVG标准中的soft-light mode跟PDF中描述的algorithm不一样,所以在October 2008就给SVG提了个建议:
[之后被raised 作为issue 2095], 后面有人跟进:
http://markmail.org/message/f4tsfvm2wjevxyh6#query:+page:1+mid:vuxzgn53rls7aq3o+state:results 这里面Alex Danilo的回答"while I was working on this, we had to deduce the functions from various sources, since the equations were not published. The starting point was some Japanese site that had reverse engineered the equations from looking at Photoshop. We extended the base equations to include alpha correctly." 可见SVG初始的实现(2002年)是对Photoshop做逆向工程得到的, 而且考虑了pre-multiplied alpha, 然后Alex他还给出了soft-light的公式(可能是逆向工程得到的, 这公式就是上面提到的svg 1.2 http://www.w3.org/TR/2004/WD-SVG12-20041027/rendering.html中所用的公式). 之后Benjamin又给出了他根据PDF specification推导的公式(这公式就是他在pixman-combine32.c代码中所用的), 后来Anthony Grasso 在2009 Feb 12又给出了他根据PDF specification推导的公式, 讨论时候还提到的 Color Dodge and Color Burn的公式,Benjamin和Anthony对这两个公式是没有异议的.
下面就是Benjamin提出问题的地方.
http://lists.w3.org/Archives/Public/www-svg/2008Oct/0029.html Benjamin在这mailing list里提了问题 (然后被SVG里面的人 raised as issue 2095). 顺着这个mailing list下去会看到有人会回应的, 在http://lists.w3.org/Archives/Public/www-svg/2008Oct/ 页面中搜索blend 或者 soft关键字,一直到2009年Feb 12号的http://lists.w3.org/Archives/Public/public-svg-wg/2009JanMar/0132.html.
[之后被raised 作为issue 2095], 后面有人跟进:
http://markmail.org/message/f4tsfvm2wjevxyh6#query:+page:1+mid:vuxzgn53rls7aq3o+state:results 这里面Alex Danilo的回答"while I was working on this, we had to deduce the functions from various sources, since the equations were not published. The starting point was some Japanese site that had reverse engineered the equations from looking at Photoshop. We extended the base equations to include alpha correctly." 可见SVG初始的实现(2002年)是对Photoshop做逆向工程得到的, 而且考虑了pre-multiplied alpha, 然后Alex他还给出了soft-light的公式(可能是逆向工程得到的, 这公式就是上面提到的svg 1.2 http://www.w3.org/TR/2004/WD-SVG12-20041027/rendering.html中所用的公式). 之后Benjamin又给出了他根据PDF specification推导的公式(这公式就是他在pixman-combine32.c代码中所用的), 后来Anthony Grasso 在2009 Feb 12又给出了他根据PDF specification推导的公式, 讨论时候还提到的 Color Dodge and Color Burn的公式,Benjamin和Anthony对这两个公式是没有异议的.
他们SVG Working Group 后来还在Teleconference中提到了这个问题, 在http://www.w3.org/2009/02/16-svg-minutes.html 页面中找soft-light关键字.
他们比较完整的email整理在http://www.w3.org/Graphics/SVG/WG/track/issues/2095
上面的公式都是从un-pre-multiplied格式中他们自己推导过去的,原始的公式和参考文档Benjamin Otte在:
http://lists.freedesktop.org/archives/cairo/2008-October/015362.html 里面提到Adobe PDF specification分别是[http://www.adobe.com/devnet/acrobat/pdfs/PDF32000_2008.pdf chapter 11] and [http://www.adobe.com/devnet/pdf/pdfs/blend_modes.pdf] 估计Photoshop也是类似的算法.GIMP, 18 Oct 2008也对Benjamin的实现有点兴趣,于是有了http://www.mail-archive.com/xorg@lists.freedesktop.org/msg01141.html,他们也支持svg 1.2中使用的公式有点旧了, 而PDF specification是2008年出来,更新一点. 而且他们讨论了觉得大部分的formula都是对的,那两个来自Flash的Invent和谁是PDF spec里面没有的.
至于推导公式的细节,就找不到了. 自己做一下试试.
首先,在PDF32000_2008(所谓的PDF Spec)P322中给出了basic (colour) compositing formula:
至于推导公式的细节,就找不到了. 自己做一下试试.
首先,在PDF32000_2008(所谓的PDF Spec)P322中给出了basic (colour) compositing formula:
我暂时觉得有两个原因.
1. 例如我们已经画好了backdrop,然后在上面多加一个source(以layer形式出现), 并且这个source中不是整个图片都是有painting结果的(例如这个layer是用stroke做painting画出来的), 在stroking不到的部位就为clear(0,0,0,0)全透明full transparency. 看下面我在GIMP中例子:

图中有two layers, 上面一个作为source layer它的大部分区域都是全透明的,alpha=0, 注意它的color component=(0,0,0)是黑色,假如我们做blending时候用到了这个黑色的话,那效果就不好了,因为本来它是全透明的,底线的background应该不受影响的.
那么上面的p328的公式就比p322的公式更准确了.
2. p328的公式前半部分更容易转化为pre-multiplied alpha的形式. 看下图:我需要猜懂他为什么得到这样的结果,并且在上面也说了对于soft light 也要格外小心 “Anthony Grasso 在2009 Feb 12又给出了他根据PDF specification推导的公式”。
有一点其实挺奇怪的是,上面的pre-multiplied format公式中前面的一部分就是Porter-Duff paper中的XOR operator, 应该不是巧合coincidence吧,是什么原因呢?
pic, pic,
// B is the backdrop image, S is the source layer image.
float3 Bca = backdrop.rgb; float Ba = backdrop.a;
float3 Sca = source.rgb; float Sa = source.a;
float3 tmp = Bca * (1 - Sa) + Sca * (1 - Ba);
if (Ba < 0.001 || Sa < 0.001) {
// when either Ba and Sa is zero, Ba * Sa * Blend(Bc, Sc) = 0.
// so the color is XOR of Bca and Sca, which is the current tmp value.
} else {
if (2 * Sca.r <= Sa && 2 * Sca.g <= Sa && 2 * Sca.b <= Sa) {
tmp += Bca * Sa - (Sa - 2*Sca) * Bca * (1 - Bca/Ba);
} else {
float3 D;
if (4 * Bca.r <= Ba && 4 * Bca.g <= Ba && 4 * Bca.b <= Ba) {
D = ((16*Bca/Ba - 12) * Bca/Ba + 4) * Bca;
} else {
D = sqrt(Bca * Ba);
}
tmp += Bca * Sa + (2 * Sca - Sa) * (D - Bca);
}
}
float alpha = UnionOp(Ba, Sa); //Õâ¶«Î÷ºóÃæ»á½²µ½.
float4 result = float4(tmp, alpha)
有一点其实挺奇怪的是,上面的pre-multiplied format公式中前面的一部分就是Porter-Duff paper中的XOR operator, 应该不是巧合coincidence吧,是什么原因呢?
上面列举了几个简单的blend mode 从non-premultiplied 到 premultiplied的转化,下面看看复杂一点的例子soft light blend mode.
// B is the backdrop image, S is the source layer image.
float3 Bca = backdrop.rgb; float Ba = backdrop.a;
float3 Sca = source.rgb; float Sa = source.a;
float3 tmp = Bca * (1 - Sa) + Sca * (1 - Ba);
if (Ba < 0.001 || Sa < 0.001) {
// when either Ba and Sa is zero, Ba * Sa * Blend(Bc, Sc) = 0.
// so the color is XOR of Bca and Sca, which is the current tmp value.
} else {
if (2 * Sca.r <= Sa && 2 * Sca.g <= Sa && 2 * Sca.b <= Sa) {
tmp += Bca * Sa - (Sa - 2*Sca) * Bca * (1 - Bca/Ba);
} else {
float3 D;
if (4 * Bca.r <= Ba && 4 * Bca.g <= Ba && 4 * Bca.b <= Ba) {
D = ((16*Bca/Ba - 12) * Bca/Ba + 4) * Bca;
} else {
D = sqrt(Bca * Ba);
}
tmp += Bca * Sa + (2 * Sca - Sa) * (D - Bca);
}
}
float alpha = UnionOp(Ba, Sa); //Õâ¶«Î÷ºóÃæ»á½²µ½.
float4 result = float4(tmp, alpha)
再回去看看那个XOR operator是怎么回事,下面看看假如Rca = XOR(Bca, Ba, Sca, Sa)的效果:
这样就很直观了,感觉好像就是Layer 全透明(full transparency, clear(0,0,0,0))的地方不影响背景, 公式中解释为Sa = 0, 所以(1 - Sa) * Bca + (1 - Ba) * Sa= (1 - 0) * Bca + (1 - Ba) * (0,0,0) = Bca; 而Layer中非透明的地方,就不好直观地说了,要代入公式来算了。这本例中因为非透明的地方Ba = Sa = 1, 所以结果是(0,0,0)黑色.
上面解决了怎么从basic (colour) compositing formula中求出colour, 在PDF spec chapter 11.3.7.3中讲了result alpha的求法:
Ra = union(Sa, Ba) = Ba + Sa - (Ba * Sa).
这公式很像求color时候用的scree blend mode. “The result tends toward 1.0: if either input is 1.0, the result is 1.0”.
于是最后的结果应该就是: (Rca, Ra), in premultiplied format.
扩展:
Cairo 是跨平台的, 应用广泛,例如在Mozilla Firefox, GTK/Gnome, OpenOffice中用到了,
http://cairographics.org/operators 这是blend mode的例子.
SKia图形引擎, 在Google Chrome/Android中用到了.
Quartz 2D是 mac/iphone上的graphics render engine, 不开源的,
http://developer.apple.com/mac/library/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_paths/dq_paths.html 页面中找"blend mode" 可看到介绍.
Cairo 是跨平台的, 应用广泛,例如在Mozilla Firefox, GTK/Gnome, OpenOffice中用到了,
http://cairographics.org/operators 这是blend mode的例子.
SKia图形引擎, 在Google Chrome/Android中用到了.
标签:
alpha,
blend mode,
blending,
image,
tech
订阅:
博文 (Atom)