因为工作原因,开始转向cocos2d-x开发方向了。
自然的,凭着之前引擎的经验偏向底层渲染研究。
在此期间看了两本书
《cocos2d-x 权威指南》
《cocos2d-x 高级开发教程》
不得不说,第一本书完全是API介绍,也许适合新手入门,但是于我,只是烂书一本。
第二本书还是不错的,最后的项目有全套源码,教程的风格也很有我的风格,哈哈,就是文章中不一定贴全代码,只贴核心,后期还要自己领会补全。
言归正传,在 《高级开发教程》 中有一篇是实现海底水纹效果的文章,里面代码不全,且代码和Shader并没有对应起来,于是我决定按照自己思路来将其补全,并贴上完整源码。
先上效果图:
动态GIF图地址: http://pan.baidu.com/share/link?shareid=1858640040&uk=3221530571
首先创建一个 ShaderNode.h 类并继承CCNode
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#ifndef __FishingJoy_ShaderNode__
#define __FishingJoy_ShaderNode__ #include "cocos2d.h" USING_NS_CC ; class ShaderNode : public CCNode { public : ShaderNode ( ) ; bool initWithVertex ( const char *vert, const char *frag ) ; void loadShaderVertex ( const char *vert, const char *frag ) ; virtual void update ( float delta ) ; virtual void setContentSize ( const CCSize & var ) ; virtual void setColor (ccColor4F newColor ) ; virtual void draw ( ) ; static ShaderNode * shaderNodeWithVertex ( const char *vert, const char *frag ) ; private : GLuint m_uniformResolution, m_uniformTime, m_uniformTex0 ; GLuint m_attributeColor, m_attributePosition ; float m_time ; ccVertex2F m_resolution,m_center ; GLuint m_texture ; GLfloat color [ 4 ] ; } ; #endif |
之后创建ShaderNode.cpp 并实现 ShaderNode.h 中的各方法
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
#include "ShaderNode.h"
ShaderNode :: ShaderNode ( ) { } ShaderNode * ShaderNode :: shaderNodeWithVertex ( const char *vert, const char *frag ) { ShaderNode * shader = new ShaderNode ( ) ; if (shader && shader - >initWithVertex (vert,frag ) ) { shader - >autorelease ( ) ; return shader ; } CC_SAFE_DELETE (shader ) ; return NULL ; } void ShaderNode :: loadShaderVertex ( const char *vert, const char *frag ) { CCGLProgram * shader = new CCGLProgram ( ) ; shader - >initWithVertexShaderFilename (vert, frag ) ; //载入着色器程序 //绑定attribute变量 shader - >addAttribute ( "a_position", 0 ) ; shader - >addAttribute ( "a_color", 1 ) ; shader - >link ( ) ; //获取attribute变量标识 m_attributeColor = glGetAttribLocation (shader - >getProgram ( ), "a_color" ) ; m_attributePosition = glGetAttribLocation ( shader - >getProgram ( ), "a_position" ) ; shader - >updateUniforms ( ) ; //获取uniform变量标识 m_uniformResolution = glGetUniformLocation (shader - >getProgram ( ), "resolution" ) ; m_uniformTime = glGetUniformLocation (shader - >getProgram ( ), "time" ) ; m_uniformTex0 = glGetUniformLocation (shader - >getProgram ( ), "tex0" ) ; //使用着色器程序 this - >setShaderProgram (shader ) ; shader - >release ( ) ; } void ShaderNode :: setColor (ccColor4F newColor ) { color [ 0 ] = newColor. r ; color [ 1 ] = newColor. g ; color [ 2 ] = newColor. b ; color [ 3 ] = newColor. a ; } bool ShaderNode :: initWithVertex ( const char *vert, const char *frag ) { loadShaderVertex (vert,frag ) ; m_texture = CCTextureCache :: sharedTextureCache ( ) - >addImage ( "HelloWorld.png" ) - >getName ( ) ; setContentSize (CCSizeMake ( 1024, 768 ) ) ; setColor (ccc4f ( 0.5, 0.5, 1, 1 ) ) ; m_time = 0 ; scheduleUpdate ( ) ; return true ; } void ShaderNode :: update ( float dt ) { m_time + = dt ; } void ShaderNode :: setContentSize ( const CCSize & var ) { CCNode :: setContentSize (var ) ; m_resolution = vertex2 (getContentSize ( ). width,getContentSize ( ). height ) ; m_center. x = m_resolution. x / 2 ; m_center. y = m_resolution. y / 2 ; } void ShaderNode :: draw ( ) { CC_NODE_DRAW_SETUP ( ) ; //传递uniform变量 CCGLProgram * shader = getShaderProgram ( ) ; shader - >setUniformLocationWith2f (m_uniformResolution, m_resolution. x, m_resolution. y ) ; shader - >setUniformLocationWith1i (m_uniformTex0, 0 ) ; glUniform1f (m_uniformTime, m_time ) ; //获取attribute变量 CCSize size = this - >getContentSize ( ) ; float w = size. width ; float h = size. height ; ccGLBindTexture2D (m_texture ) ; //绑定纹理到槽位 glCopyTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, w, h, 0 ) ; //截取屏幕数据到纹理 glEnableVertexAttribArray (m_attributePosition ) ; glDisableVertexAttribArray (m_attributeColor ) ; //传递attribute变量 GLfloat vertices [ 12 ] = { 0, 0, //左下0 w, 0, //右下1 w, h, //右上2 0, 0, //左下0 0, h, //左上3 w, h, //右上2 } ; glVertexAttribPointer (m_attributePosition, 2, GL_FLOAT, GL_FALSE, 0, vertices ) ; glVertexAttrib4fv (m_attributeColor, color ) ; //绘制 glDrawArrays (GL_TRIANGLES, 0, 6 ) ; } |
之后在场景类中添加ShaderNode 即可
1
2 3 4 |
ShaderNode
* shader
= ShaderNode
::
shaderNodeWithVertex
(
"shader.vsh",
"shader.fsh"
)
;
shader - >setContentSize (getContentSize ( ) ) ; shader - >setColor (ccc4f ( 1, 1, 1.0, .5 ) ) ; this - >addChild (shader, 2 ) ; |
shader.vsh 和 shader.fsh 可以从网络中得到,就是glsl文件
shader.vsh 的内容为
1
2 3 4 5 6 7 8 9 |
attribute vec4 a_color
;
attribute vec4 a_position ; varying vec4 v_color ; uniform mat4 u_MVPMatrix ; void main ( ) { v_color = a_color ; gl_Position = u_MVPMatrix * a_position ; } |
shader.fsh 的内容为
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
varying vec4 v_color
;
uniform sampler2D tex0 ; precision highp float ; uniform float time ; uniform vec2 resolution ; const float PI = 3.1415926535897932 ; const float speed = 0.2 ; const float speed_x = 0.3 ; const float speed_y = 0.3 ; const float intensity = 3.0 ; const int steps = 8 ; const float frequency = 4.0 ; const int angle = 7 ; const float delta = 20.0 ; const float intence = 400.0 ; const float emboss = 0.3 ; float col (vec2 coord ) { float delta_theta = 2.0 * PI / float (angle ) ; float col = 0.0 ; float theta = 0.0 ; for ( int i = 0 ; i < steps ; i ++ ) { vec2 adjc = coord ; theta = delta_theta * float (i ) ; adjc. x + = cos (theta ) * time *speed + time * speed_x ; adjc. y - = sin (theta ) * time *speed - time * speed_y ; col = col + cos ( (adjc. x * cos (theta ) - adjc. y * sin (theta ) ) *frequency ) *intensity ; } return cos (col ) ; } void main ( void ) { vec2 p = (gl_FragCoord. xy ) / resolution. xy, c1 = p, c2 = p ; float cc1 = col (c1 ) ; c2. x + = resolution. x /delta ; float dx = emboss * (cc1 -col (c2 ) ) /delta ; c2. x = p. x ; c2. y + = resolution. y /delta ; float dy = emboss * (cc1 -col (c2 ) ) /delta ; c1. x + = dx ; c1. y + = dy ; float alpha = 1. +dot (dx,dy ) *intence ; gl_FragColor = texture2D (tex0,c1 ) * (alpha ) *v_color * (alpha ) ; } |
github地址为:
https://github.com/AlexandreRangel/QuaseCinemaFeijoada/blob/master/QuaseCinemaFeijoada07d/data/water.glsl
在使用顶点程序的时候,里面有个模型世界投影矩阵 u_MVPMatrix
我们在cocos2d-x中使用它的时候,需要把 CC_MVPMatrix 赋值给 u_MVPMatrix
或者直接把 u_MVPMatrix 删除,替换成 CC_MVPMatrix
like this
1
2 3 4 5 6 7 8 9 |
attribute vec4 a_color
;
attribute vec4 a_position ; varying vec4 v_color ; void main ( ) { v_color = a_color ; gl_Position = CC_MVPMatrix * a_position ; } |
cocos2d-x 在创建 GLProgram 的时候,会自动在 GLSL的文件之前加上 cocos2d-x 自身需要的参数
1
2 3 4 5 6 7 8 9 10 11 12 13 14 |
const GLchar
*sources
[
]
=
{
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32 && CC_TARGET_PLATFORM != CC_PLATFORM_LINUX && CC_TARGET_PLATFORM != CC_PLATFORM_MAC) (type == GL_VERTEX_SHADER ? "precision highp float;\n" : "precision mediump float;\n" ), #endif "uniform mat4 CC_PMatrix;\n" "uniform mat4 CC_MVMatrix;\n" "uniform mat4 CC_MVPMatrix;\n" "uniform vec4 CC_Time;\n" "uniform vec4 CC_SinTime;\n" "uniform vec4 CC_CosTime;\n" "uniform vec4 CC_Random01;\n" "//CC INCLUDES END\n\n", source, } ; |
that’s all.
本文对于原书教程补充的地方如下
修改 shader.vsh 替换 u_MVPMatrix 为 CC_MVPMatrix
删除 ShaderNode.cpp 中全部的 m_uniformCenter 的相关代码, m_uniformCenter 在Shader中并没有该字段,没有补完的意义
添加 ShaderNode.cpp 构造函数及SetColor方法
修改 ShaderNode.h 中 update 的参数