3.x最大的变化就是绘制,通过绘制命令添加到渲染队列中,优化相邻两个渲染命中,如果使用的是同一张纹理,则会并到一个批次中绘制出来,具体流程可以看看之前的文章
http://blog.csdn.net/yangxuan0261/article/details/49981347
下面的例子还顺带开了vbo,vao的话opengles2.0还不支持,所以都被我注释了
头文件.h
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
using namespace cocos2d;
class HelloWorld : public cocos2d::Layer
{
public:
virtual ~HelloWorld();
static cocos2d::Scene* createScene();
virtual bool init() override;
//重写这个方法很重要,node节点递归visit完后就会调这个draw函数,所以我们在这里添加绘制命令绑定自己的绘制函数OnDraw
virtual void draw(Renderer *renderer, const Mat4 &transform, bool transformUpdated) override;
//自己的绘制函数
void onDraw();
void menuCloseCallback4(cocos2d::Ref* pSender);
CREATE_FUNC(HelloWorld);
private:
CustomCommand _customCommand;
//GLuint vao;
GLuint vertexVBO; //缓冲区对象句柄 - 顶点
GLuint indexVBO; //缓冲区对象句柄 - 顶点索引
//当然,你可以可以Gluint vbo[2]用数组去装
};
#endif // __HELLOWORLD_SCENE_H__
#include "HelloWorldScene.h"
#include "MySprite.h"
#include "CubeTexture.h"
USING_NS_CC;
Scene* HelloWorld::createScene()
{
// 'scene' is an autorelease object
auto scene = Scene::create();
Size size = Director::getInstance()->getWinSize();
auto layer2 = Layer::create();
Sprite* sp = Sprite::create("HelloWorld.png");
//MoveTo* move = MoveTo::create(5.0f, Vec2(400, 400));
//sp->runAction(move);
sp->setPosition(size.width / 2, size.height / 2);
//sp->setScale(2.0f);
FontDefinition fd;
fd._fontSize = 40;
FontShadow fs;
fs._shadowEnabled = true;
fs._shadowBlur = 0.1f;
fs._shadowOffset = Size(10.0f, 20.0f);
fs._shadowOpacity = 1.0f;
fd._shadow = fs;
LabelTTF* lb = LabelTTF::createWithFontDefinition("Hello world", fd);
lb->setPosition(size.width / 3, size.height / 3);
layer2->addChild(sp);
layer2->addChild(lb);
//scene->addChild(layer2);
// 'layer' is an autorelease object
auto layer = HelloWorld::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
void HelloWorld::menuCloseCallback4(cocos2d::Ref* pSender)
{
auto scene = CubeTexture::createScene();
Director::getInstance()->replaceScene(scene);
}
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
//
// 1. super init first
if ( !Layer::init() )
{
return false;
}
auto closeItem4 = MenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
CC_CALLBACK_1(HelloWorld::menuCloseCallback4, this));
Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
closeItem4->setPosition(Vec2(origin.x + visibleSize.width / 2 - closeItem4->getContentSize().width / 2,
origin.y + visibleSize.height / 2 + closeItem4->getContentSize().height / 2));
// create menu, it's an autorelease object
auto menu = Menu::create(closeItem4, NULL);
menu->setPosition(Vec2::ZERO);
this->addChild(menu, 100);
//create my own program
auto glprogram = new GLProgram;
glprogram->initWithFilenames("myVertextShader.vert", "myFragmentShader.frag");
glprogram->link();
//set uniform locations
glprogram->updateUniforms();
setGLProgram(glprogram); //设置为自己的shader
//glGenVertexArrays(1, &vao);
//glBindVertexArray(vao);
glGenBuffers(1, &vertexVBO); //创建缓冲区句柄
glGenBuffers(1, &indexVBO);
return true;
}
void HelloWorld::draw(cocos2d::Renderer *renderer, const Mat4 &transform, bool transformUpdated)
{
_customCommand.init(_globalZOrder); //绘制优先级
_customCommand.func = CC_CALLBACK_0(HelloWorld::onDraw, this);//绑定自定义绘制函数,由于是用自己定于的顶点数据,所以没用矩阵信息
renderer->addCommand(&_customCommand); //把渲染命令丢进绘制队列
}
void HelloWorld::onDraw()
{
//如果使用对等矩阵,则三角形绘制会在最前面
Director::getInstance()->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
Director::getInstance()->loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
Director::getInstance()->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
Director::getInstance()->loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
Mat4 modelViewMatrix;
Mat4::createLookAt(Vec3(0,0,1), Vec3(0,0,0), Vec3(0,1,0), &modelViewMatrix);
modelViewMatrix.translate(2, 2, -5);
//static float move = 0;
//modelViewMatrix.translate(sinf(move*0.05)*2, 2, -5);
//move++;
//static float rotation = 0;
//modelViewMatrix.rotate(Vec3(1,1,1),CC_DEGREES_TO_RADIANS(rotation));
//rotation++;
//if (rotation > 360) {
// rotation = 0;
//}
Mat4 projectionMatrix;
Mat4::createPerspective(60, 480/320, 1.0, 42, &projectionMatrix);
Director::getInstance()->multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION, projectionMatrix);
Director::getInstance()->multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, modelViewMatrix);
auto glProgram = getGLProgram();
glProgram->use();
glProgram->setUniformsForBuiltins();
Director::getInstance()->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
Director::getInstance()->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
typedef struct {
float Position[3];
float Color[4];
} Vertex;
// auto size = Director::getInstance()->getVisibleSize();
Vertex data[] =
{
// Front
{ { 1, -1, 0 }, { 1, 0, 0, 1 } },
{ { 1, 1, 0 }, { 0, 1, 0, 1 } },
{ { -1, 1, 0 }, { 0, 0, 1, 1 } },
{ { -1, -1, 0 }, { 0, 0, 0, 1 } },
// Back
{ { 1, 1, -2 }, { 1, 0, 0, 1 } },
{ { -1, -1, -2 }, { 0, 1, 0, 1 } },
{ { 1, -1, -2 }, { 0, 0, 1, 1 } },
{ { -1, 1, -2 }, { 0, 0, 0, 1 } },
// Left
{ { -1, -1, 0 }, { 1, 0, 0, 1 } },
{ { -1, 1, 0 }, { 0, 1, 0, 1 } },
{ { -1, 1, -2 }, { 0, 0, 1, 1 } },
{ { -1, -1, -2 }, { 0, 0, 0, 1 } },
// Right
{ { 1, -1, -2 }, { 1, 0, 0, 1 } },
{ { 1, 1, -2 }, { 0, 1, 0, 1 } },
{ { 1, 1, 0 }, { 0, 0, 1, 1 } },
{ { 1, -1, 0 }, { 0, 0, 0, 1 } },
// Top
{ { 1, 1, 0 }, { 1, 0, 0, 1 } },
{ { 1, 1, -2 }, { 0, 1, 0, 1 } },
{ { -1, 1, -2 }, { 0, 0, 1, 1 } },
{ { -1, 1, 0 }, { 0, 0, 0, 1 } },
// Bottom
{ { 1, -1, -2 }, { 1, 0, 0, 1 } },
{ { 1, -1, 0 }, { 0, 1, 0, 1 } },
{ { -1, -1, 0 }, { 0, 0, 1, 1 } },
{ { -1, -1, -2 }, { 0, 0, 0, 1 } }
};
GLubyte indices[] = {
// Front
0, 1, 2,
2, 3, 0,
// Back
4, 5, 6,
4, 5, 7,
// Left
8, 9, 10,
10, 11, 8,
// Right
12, 13, 14,
14, 15, 12,
// Top
16, 17, 18,
18, 19, 16,
// Bottom
20, 21, 22,
22, 23, 20
};
glBindBuffer(GL_ARRAY_BUFFER, vertexVBO); //绑定这个缓冲区句柄为顶点类型
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); //申请内存大小和绑定数据,静态绘制,有几种枚举类型这里就不说了,自行百度
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexVBO);//绑定这个缓冲区句柄为索引类型
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
GLuint positionLocation = glGetAttribLocation(glProgram->getProgram(), "a_position"); //获取自定义shader中的属性变量的地址
GLuint colorLocation = glGetAttribLocation(glProgram->getProgram(), "a_color");
glEnableVertexAttribArray(positionLocation);//激活
glEnableVertexAttribArray(colorLocation);
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Position));
glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Color));
// 0 ~ 1 之间波动
static float colorCount = 0;
float tmp = sinf(colorCount*0.01);
tmp = tmp < 0 ? -tmp : tmp;
colorCount++;
/* ---------------------- test1, 为一个float赋值 */
//GLuint uColorLocation1 = glGetUniformLocation(glProgram->getProgram(), "specIntensity");
//float specIntensity = tmp;
//glUniform1f(uColorLocation1, specIntensity);
/* ---------------------- test2, 为1个由4个float组成的vec4赋值 */
//GLuint uColorLocation2 = glGetUniformLocation(glProgram->getProgram(), "u_color");
//float uColor2[] = { tmp, tmp, tmp, tmp };
//glUniform4fv(uColorLocation2, 1, uColor2);
/* ---------------------- test3, 为float[]数组中的两个元素赋值 */
//GLuint uColorLocation3 = glGetUniformLocation(glProgram->getProgram(), "threshold");
//float threshold[2] = { 0.5, tmp };
//glUniform1fv(uColorLocation3, 2, threshold);
/* ---------------------- test4, 为vec4[]数组中的3个元素赋值 */
//GLuint uColorLocation4 = glGetUniformLocation(glProgram->getProgram(), "colors");
//float colors[12] = { 0.4, 0.4, 0.8, 1.0,
// 0.2, 0.2, 0.4, 1.0,
// 1.0, 1.0, 1.0, tmp };
//glUniform4fv(uColorLocation4, 3, colors);
/* ---------------------- test5, 为float[]数组中的某个元素赋值,根据下标索引 */
GLuint uColorLocation5 = glGetUniformLocation(glProgram->getProgram(), "threshold[0]"); //传入自定shader中的uniform变量,控制alpha透明度
float asd = tmp;
glUniform1f(uColorLocation5, asd);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE,(GLvoid*)0); //绘制三角形,由于索引也上传到缓冲区了,所以这里的索引直接传0地址
//解除激活的缓冲区
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1, 36);
CHECK_GL_ERROR_DEBUG();
}
HelloWorld::~HelloWorld()
{
//清除缓冲区句柄
glDeleteBuffers(1, &vertexVBO);
glDeleteBuffers(1, &indexVBO);
}
attribute vec3 a_position;
attribute vec4 a_color;
varying vec4 v_fragmentColor;
varying vec3 normal;
void main()
{
gl_Position = CC_MVPMatrix * vec4(a_position.xyz,1.0);
v_fragmentColor = a_color;
}
varying vec4 v_fragmentColor;
uniform float specIntensity;
uniform vec4 u_color;
uniform float threshold[2];
uniform vec4 colors[3];
vec4 toonify(float intensity)
{
vec4 color;
if (intensity < 0.3)
color = vec4(1.0, 0.0 , 0.0, 0.5);
else if (intensity < 0.5)
color = vec4(0.0, 1.0 , 0.0, 0.5);
else if (intensity < 0.7)
color = vec4(0.0, 0.0 , 1.0, 0.5);
else
{
color = vec4(1.0, 1.0, 1.0, 0.5);
//discard; //最后的discard关键字只能在片断shader中使用,它将在不写入帧缓存或者深度缓存的情况下,终止当前片断的shader程序。
}
return(color);
}
void main()
{
// ---------------------- test1
// gl_FragColor = v_fragmentColor * vec4(1.0, 1.0, 1.0, specIntensity);
// ---------------------- test2
//gl_FragColor = v_fragmentColor * u_color;
// ---------------------- test3
//gl_FragColor = v_fragmentColor * vec4(1.0, 1.0, 1.0, threshold[1]);
// ---------------------- test4
//gl_FragColor = v_fragmentColor * colors[2];
// ---------------------- test5
gl_FragColor = v_fragmentColor * vec4(1.0, 1.0, 1.0, threshold[0]);
// ---------------------- test6
//gl_FragColor = toonify(threshold[0]);
}
shader编写需要注意的是
如果shader中定义了uniform属性名但没有使用,会在编译shader时优化调,所以在c++中获取uniform中的变量地址会是个空地址
其次就是类型需要严格一直,在windows平台体现不出来,应为win平台用的是opengl4.0的,而手机平台的是opengles2.0标准,类型不一致在运行时导致异常崩溃,崩溃信息可以重eclipse中看到,比如 float a = 4.0 * 123就是错的,float*int,应改为 float a = 4.0 * float(123)才正确