Ogr*_*amp 5 iphone opengl-es objective-c ipad
我正在开发绘画应用程序.我试过用CoreGraphics/Quartz 2D和绘图曲线算法做的很慢.所以我们决定改用OpenGL ES.我从未有过任何OpenGL经验,所以我从苹果中找到了glPaint示例并开始玩它.
我改变了erase方法做白色背景.我如何坚持刷和混合.在示例中,Apple使用"白色黑色"纹理作为画笔(首先在下面的图片中).但它对我不起作用(我使用不同的混合模式).所以我决定使用不同的画笔,但我找不到合适的方法.我在stackoverflow上发现了一些问题,但是所有问题都没有得到答复.这是一张照片(来自另一个问题,感谢Kevin Beimers).
结果http://www.straandlooper.com/GLPaint.png
所以问题是如何在图片中实现类似"所需"的笔画.如何将2个笔画更接近现实生活体验(蓝色比黄色=深绿色).
谢谢.
刷子的当前代码(从glPaint修改的位)(来自initWithFrame方法:
// Make sure the image exists
if(brushImage) {
// Allocate memory needed for the bitmap context
brushData = (GLubyte *) calloc(width * height * 4, sizeof(GLubyte));
// Use the bitmatp creation function provided by the Core Graphics framework.
brushContext = CGBitmapContextCreate(brushData, width, width, 8, width * 4, CGImageGetColorSpace(brushImage), kCGImageAlphaPremultipliedLast);
// After you create the context, you can draw the image to the context.
CGContextDrawImage(brushContext, CGRectMake(0.0, 0.0, (CGFloat)width, (CGFloat)height), brushImage);
// You don't need the context at this point, so you need to release it to avoid memory leaks.
CGContextRelease(brushContext);
// Use OpenGL ES to generate a name for the texture.
glGenTextures(1, &brushTexture);
// Bind the texture name.
glBindTexture(GL_TEXTURE_2D, brushTexture);
// Set the texture parameters to use a minifying filter and a linear filer (weighted average)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// Specify a 2D texture image, providing the a pointer to the image data in memory
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, brushData);
// Release the image data; it's no longer needed
free(brushData);
// Make the current material colour track the current color
glEnable( GL_COLOR_MATERIAL );
// Enable use of the texture
glEnable(GL_TEXTURE_2D);
// Set a blending function to use
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
// Enable blending
glEnable(GL_BLEND);
// Multiply the texture colour by the material colour.
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
}
//Set up OpenGL states
glMatrixMode(GL_PROJECTION);
CGRect frame = self.bounds;
glOrthof(0, frame.size.width, 0, frame.size.height, -1, 1);
glViewport(0, 0, frame.size.width, frame.size.height);
glMatrixMode(GL_MODELVIEW);
glDisable(GL_DITHER);
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_VERTEX_ARRAY);
glEnable(GL_BLEND);
// Alpha blend each "dab" of paint onto background
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
//glBlendFunc(GL_SRC_COLOR, GL_ONE);
glEnable(GL_POINT_SPRITE_OES);
glTexEnvf(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, GL_TRUE);
self.brushScale = 3;
self.brushStep = 3;
self.brushOpacity = (1.0 / 1.5);
glPointSize(width / brushScale);
//Make sure to start with a cleared buffer
needsErase = YES;
[self erase];
Run Code Online (Sandbox Code Playgroud)
Piv*_*vot 18
让我们从定义您正在寻找的混合类型开始.听起来你希望你的缓冲区开始变白并让你的颜色混合服从减色模型.最简单的方法是在C dst上定义混合C brush的结果:
C = C 刷 × C dst
请注意,使用此等式,混合黄色(1,1,0)和青色(0,1,1)的结果为绿色(0,1,0),这是您所期望的.
有一个在边缘渐弱的画笔使事情略微复杂化.比方说,你现在有一个画笔的不透明度值一刷 -where 一刷就是1,你希望你的画笔颜色为充满力量相融合,并在一个刷是0,你想要原来的颜色保持.现在你要找的是:
C =(C 刷 × C dst)× A 刷 + C dst ×(1 - A 刷)
由于在OpenGL ES结果中混合计算C = C src × S + C dst × D,如果我们进行以下替换,我们可以得到我们想要的结果:
Ç SRC = Ç 刷 × 甲刷
一个src = A 画笔
S = C dst
d =(1 - 甲刷)
现在让我们来看看在OpenGL ES中设置它需要什么.这里有4个步骤:
将背景颜色更改为白色.
将画笔纹理更改为Alpha纹理.
默认情况下,GLPaint将其画笔纹理创建为RGBA纹理,并在RGB通道中绘制画笔形状,这有点不直观.由于后面会看到的原因,在alpha通道中使用画笔形状会很有用.最好的方法是使用CG绘制灰度刷子形状并创建纹理GL_ALPHA:
CGColorSpaceRef brushColorSpace = CGColorSpaceCreateDeviceGray();
brushData = (GLubyte *) calloc(width * height, sizeof(GLubyte));
brushContext = CGBitmapContextCreate(brushData, width, width, 8, width, brushColorSpace, kCGImageAlphaNone);
CGColorSpaceRelease(brushColorSpace);
Run Code Online (Sandbox Code Playgroud)
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, brushData);
Run Code Online (Sandbox Code Playgroud)建立Ç SRC,一个SRC,小号和d.
在切换到alpha纹理后,假设您的画笔颜色仍在指定glColor4f,您将发现默认的OpenGL ES纹理环境将为您提供:
C src = C 刷
一个src = A 画笔
为了通过A 刷子为C src获得额外的乘法,你需要在纹理环境中设置一个自定义组合器函数,如下所示(你可以在初始化函数中执行此操作PaintingView):
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
Run Code Online (Sandbox Code Playgroud)
改变GL_TEXTURE_ENV_MODE到GL_COMBINE给你ç 刷 ×0(看到为什么是这样的情况下,读入部分3.7.12 的OpenGL ES 1.1规范).更改GL_OPERAND0_RGB为GL_SRC_ALPHA将乘法中的第二项更改为我们想要的.
要设置S和D,您需要做的就是更改混合因子(这可以在之前设置混合因子的地方完成):
glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA);
Run Code Online (Sandbox Code Playgroud)确保在画笔纹理之外对A 画笔的任何修改都会反映在其他通道上.
对纹理环境的上述修改仅考虑了来自画笔纹理的画笔不透明度的部分.如果您在其他地方修改Alpha通道中的画笔不透明度(即通过缩放它,如同AppController),则必须确保对其他三个通道进行相同的修改:
glColor4f(components[0] * kBrushOpacity, components[1] * kBrushOpacity, components[2] * kBrushOpacity, kBrushOpacity);
Run Code Online (Sandbox Code Playgroud)请注意,使用减色颜色模型实现画笔的缺点是颜色只会变暗,如果不是主要的减色(青色,品红色,则为蓝色,品红色等),重复绘制相同颜色本身最终会导致颜色偏移.或黄色).如果在执行此操作后,您发现颜色偏移是不可接受的,请尝试将画笔纹理更改为alpha纹理,如步骤2所示,并更改混合因子,如下所示:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Run Code Online (Sandbox Code Playgroud)
这将使您可以在白色上简单地绘制画笔颜色,但不会实际混合颜色(画笔颜色最终会覆盖背景).
| 归档时间: |
|
| 查看次数: |
3176 次 |
| 最近记录: |