Phân tích
Ảnh grayscale, hay còn gọi là ảnh trắng đen, là ảnh chỉ có 1 kênh màu duy nhất. Mỗi pixel là 1 mẩu đơn giản, chứa thông tin cường độ của pixel đó. Giá trị lớn nhất tương ứng với pixel màu trắng và giá trị nhỏ nhất tương ứng với pixel màu đen. Cường độ này có giá trị thường được chọn trong khoảng từ 0 đến 1 hoặc từ 0 đến 255.
Theo nghiên cứu, mắt người nhạy cảm nhất với màu xanh lá cây và ít nhạy cảm với màu xanh dương nên có thể áp dụng công thức sau đây để tính toán cường độ xám của ảnh grayscale.
GrayFactor = 0.2126*R + 0.7152*G + 0.0722*B
Trong đó:
- R là cường độ của kênh màu đỏ.
- G là cường độ của kênh xanh lá cây.
- B là cường độ của kênh xanh dương.
Hiện thực
Sau khi kết thúc bài viết này, có thể tạo được hiệu ứng có dạng như sau:
Vertex shader giữ giống như shader của Cocos2d-x Vì grayscale sprite chỉ khác sprite thông thường trong Cocos2d-x ở giai đoạn tính toán màu cho từng fragment nên sẽ tận dụng những phần có sẵn của Cocos2d-x và viết thêm fragment shader.
Để hoàn thành bài viết này, chỉ cần sử dụng hình ảnh HelloWorld.png được đính kèm trong dự án mẫu của Cocos2d-x.
attribute vec4 a_position; attribute vec2 a_texCoord; attribute vec4 a_color; #ifdef GL_ES varying lowp vec4 v_fragmentColor; varying mediump vec2 v_texCoord; #else varying vec4 v_fragmentColor; varying vec2 v_texCoord; #endif void main() { gl_Position = CC_MVPMatrix * a_position; v_fragmentColor = a_color; v_texCoord = a_texCoord; }
Fragment shader:
#ifdef GL_ES precision lowp float; #endif varying vec4 v_fragmentColor; varying vec2 v_texCoord; uniform sampler2D u_texture; void main() { vec4 texColor = texture2D(u_texture, v_texCoord); float grayscaleFactor = 0.2126*texColor.r + 0.7152*texColor.g + 0.0722*texColor.b; vec4 finalColor = vec4(grayscaleFactor, grayscaleFactor, grayscaleFactor, texColor.a); gl_FragColor = v_fragmentColor * finalColor; }
- Điểm mấu chốt của shader này nằm ở dòng 12. Tại dòng này đã áp dụng công thức đã được nghiên cứu đã nêu ở trên để tính toán cường độ xám của pixel màu.
- Tại dòng 13, chọn cường độ xám trên làm giá trị cho các kênh màu đỏ, xanh lá cây, xanh dương trong màu được tạo ra.
Sau khi đã viết shader cho grayscale sprite, bắt phần hiện thực component GrayScaleSprite
. Đây là phần khởi tạo component:
bool GrayScaleSprite::init(const char *textureName) { if(!CCSprite::initWithFile(textureName)) { return false; } CCGLProgram* pProgram = new CCGLProgram(); pProgram->initWithVertexShaderFilename("GrayScaleSprite.vert", "GrayScaleSprite.frag"); setShaderProgram(pProgram); pProgram->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position); pProgram->addAttribute(kCCAttributeNameColor, kCCVertexAttrib_Color); pProgram->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords); pProgram->link(); pProgram->updateUniforms(); pProgram->release(); return true; }
Ở đây, dùng lại hàm khởi tạo với texture của CCSprite
và viết thêm phần khởi tạo shader cho component.
Phần render của component hoàn toàn giống với của CCSprite
nên không cần viết lại, Cocos2d-x sẽ tự liên kết component với shader đã viết thêm.
Code
Mã nguồn đầy đủ của component: GrayScaleSprite.zip
Cách dùng Component
CCSize winSize = CCDirector::sharedDirector()->getWinSize(); GrayScaleSprite* pSprite = GrayScaleSprite::create("HelloWorld.png"); pSprite->setPosition(ccp(winSize.width/2.0f, winSize.height/2.0f)); this->addChild(pSprite);