Merge pull request #7736 from dabingnn/v3_addSkinnedOutline

V3 add skinned outline
This commit is contained in:
minggo 2014-08-12 15:07:21 +08:00
commit cc37780861
4 changed files with 252 additions and 30 deletions

View File

@ -28,6 +28,7 @@
#include <unordered_map> #include <unordered_map>
#include "3d/CCBundle3DData.h" #include "3d/CCBundle3DData.h"
#include "3d/CCSkeleton3D.h"
#include "base/ccMacros.h" #include "base/ccMacros.h"
#include "base/CCRef.h" #include "base/CCRef.h"
@ -44,7 +45,7 @@ class Skeleton3D;
* MeshSkin, A class maintain a collection of bones that affect Mesh vertex. * MeshSkin, A class maintain a collection of bones that affect Mesh vertex.
* And it is responsible for computing matrix palletes that used by skin mesh rendering. * And it is responsible for computing matrix palletes that used by skin mesh rendering.
*/ */
class MeshSkin: public Ref class CC_DLL MeshSkin: public Ref
{ {
public: public:

View File

@ -51,6 +51,9 @@ static std::function<Layer*()> createFunctions[] =
CL(Sprite3DEffectTest), CL(Sprite3DEffectTest),
#endif #endif
CL(Sprite3DWithSkinTest), CL(Sprite3DWithSkinTest),
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WP8) && (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT)
CL(Sprite3DWithSkinOutlineTest),
#endif
CL(Animate3DTest), CL(Animate3DTest),
CL(AttachmentTest) CL(AttachmentTest)
}; };
@ -316,6 +319,7 @@ EffectSprite3D* EffectSprite3D::createFromObjFileAndTexture(const std::string &o
if (sprite && sprite->initWithFile(objFilePath)) if (sprite && sprite->initWithFile(objFilePath))
{ {
sprite->autorelease(); sprite->autorelease();
if(textureFilePath.size() > 0)
sprite->setTexture(textureFilePath); sprite->setTexture(textureFilePath);
return sprite; return sprite;
} }
@ -323,6 +327,21 @@ EffectSprite3D* EffectSprite3D::createFromObjFileAndTexture(const std::string &o
return nullptr; return nullptr;
} }
EffectSprite3D* EffectSprite3D::create(const std::string &path)
{
if (path.length() < 4)
CCASSERT(false, "improper name specified when creating Sprite3D");
auto sprite = new EffectSprite3D();
if (sprite && sprite->initWithFile(path))
{
sprite->autorelease();
return sprite;
}
CC_SAFE_DELETE(sprite);
return nullptr;
}
EffectSprite3D::EffectSprite3D() EffectSprite3D::EffectSprite3D()
: _defaultEffect(nullptr) : _defaultEffect(nullptr)
{ {
@ -360,8 +379,24 @@ void EffectSprite3D::addEffect(Effect3DOutline* effect, ssize_t order)
const std::string Effect3DOutline::_vertShaderFile = "Shaders3D/OutLine.vert"; const std::string Effect3DOutline::_vertShaderFile = "Shaders3D/OutLine.vert";
const std::string Effect3DOutline::_fragShaderFile = "Shaders3D/OutLine.frag"; const std::string Effect3DOutline::_fragShaderFile = "Shaders3D/OutLine.frag";
const std::string Effect3DOutline::_keyInGLProgramCache = "Effect3DLibrary_Outline"; const std::string Effect3DOutline::_keyInGLProgramCache = "Effect3DLibrary_Outline";
GLProgram* Effect3DOutline::getOrCreateProgram()
const std::string Effect3DOutline::_vertSkinnedShaderFile = "Shaders3D/SkinnedOutLine.vert";
const std::string Effect3DOutline::_fragSkinnedShaderFile = "Shaders3D/OutLine.frag";
const std::string Effect3DOutline::_keySkinnedInGLProgramCache = "Effect3DLibrary_Outline";
GLProgram* Effect3DOutline::getOrCreateProgram(bool isSkinned /* = false */ )
{ {
if(isSkinned)
{
auto program = GLProgramCache::getInstance()->getGLProgram(_keySkinnedInGLProgramCache);
if(program == nullptr)
{
program = GLProgram::createWithFilenames(_vertSkinnedShaderFile, _fragSkinnedShaderFile);
GLProgramCache::getInstance()->addGLProgram(program, _keySkinnedInGLProgramCache);
}
return program;
}
else
{
auto program = GLProgramCache::getInstance()->getGLProgram(_keyInGLProgramCache); auto program = GLProgramCache::getInstance()->getGLProgram(_keyInGLProgramCache);
if(program == nullptr) if(program == nullptr)
{ {
@ -369,6 +404,8 @@ GLProgram* Effect3DOutline::getOrCreateProgram()
GLProgramCache::getInstance()->addGLProgram(program, _keyInGLProgramCache); GLProgramCache::getInstance()->addGLProgram(program, _keyInGLProgramCache);
} }
return program; return program;
}
} }
Effect3DOutline* Effect3DOutline::create() Effect3DOutline* Effect3DOutline::create()
@ -389,21 +426,6 @@ Effect3DOutline* Effect3DOutline::create()
bool Effect3DOutline::init() bool Effect3DOutline::init()
{ {
GLProgram* glprogram = GLProgram::createWithFilenames(_vertShaderFile, _fragShaderFile);
if(nullptr == glprogram)
{
CC_SAFE_DELETE(glprogram);
return false;
}
_glProgramState = GLProgramState::create(glprogram);
if(nullptr == _glProgramState)
{
return false;
}
_glProgramState->retain();
_glProgramState->setUniformVec3("OutLineColor", _outlineColor);
_glProgramState->setUniformFloat("OutlineWidth", _outlineWidth);
return true; return true;
} }
@ -439,6 +461,7 @@ void Effect3DOutline::setOutlineColor(const Vec3& color)
if(_outlineColor != color) if(_outlineColor != color)
{ {
_outlineColor = color; _outlineColor = color;
if(_glProgramState)
_glProgramState->setUniformVec3("OutLineColor", _outlineColor); _glProgramState->setUniformVec3("OutLineColor", _outlineColor);
} }
} }
@ -448,6 +471,7 @@ void Effect3DOutline::setOutlineWidth(float width)
if(_outlineWidth != width) if(_outlineWidth != width)
{ {
_outlineWidth = width; _outlineWidth = width;
if(_glProgramState)
_glProgramState->setUniformFloat("OutlineWidth", _outlineWidth); _glProgramState->setUniformFloat("OutlineWidth", _outlineWidth);
} }
} }
@ -458,6 +482,19 @@ void Effect3DOutline::setTarget(EffectSprite3D *sprite)
if(sprite != _sprite) if(sprite != _sprite)
{ {
GLProgram* glprogram;
if(!sprite->getSkin())
glprogram = GLProgram::createWithFilenames(_vertShaderFile, _fragShaderFile);
else
glprogram = GLProgram::createWithFilenames(_vertSkinnedShaderFile, _fragSkinnedShaderFile);
_glProgramState = GLProgramState::create(glprogram);
_glProgramState->retain();
_glProgramState->setUniformVec3("OutLineColor", _outlineColor);
_glProgramState->setUniformFloat("OutlineWidth", _outlineWidth);
_sprite = sprite; _sprite = sprite;
auto mesh = sprite->getMesh(); auto mesh = sprite->getMesh();
@ -482,6 +519,11 @@ void Effect3DOutline::setTarget(EffectSprite3D *sprite)
} }
static void MatrixPalleteCallBack( GLProgram* glProgram, Uniform* uniform, int paletteSize, const float* palette)
{
glUniform4fv( uniform->location, (GLsizei)paletteSize, (const float*)palette );
}
void Effect3DOutline::draw(const Mat4 &transform) void Effect3DOutline::draw(const Mat4 &transform)
{ {
//draw //draw
@ -496,7 +538,17 @@ void Effect3DOutline::draw(const Mat4 &transform)
auto mesh = _sprite->getMesh(); auto mesh = _sprite->getMesh();
glBindBuffer(GL_ARRAY_BUFFER, mesh->getVertexBuffer()); glBindBuffer(GL_ARRAY_BUFFER, mesh->getVertexBuffer());
if(_sprite && _sprite->getSkin())
{
auto function = std::bind(MatrixPalleteCallBack, std::placeholders::_1, std::placeholders::_2,
_sprite->getSkin()->getMatrixPaletteSize(), (float*)_sprite->getSkin()->getMatrixPalette());
_glProgramState->setUniformCallback("u_matrixPalette", function);
}
if(_sprite)
_glProgramState->apply(transform); _glProgramState->apply(transform);
for (ssize_t i = 0; i < mesh->getSubMeshCount(); i++) { for (ssize_t i = 0; i < mesh->getSubMeshCount(); i++) {
auto submesh = mesh->getSubMesh((int)i); auto submesh = mesh->getSubMesh((int)i);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, submesh->getIndexBuffer()); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, submesh->getIndexBuffer());
@ -569,13 +621,14 @@ void Sprite3DEffectTest::addNewSpriteWithCoords(Vec2 p)
//option 2: load obj and assign the texture //option 2: load obj and assign the texture
auto sprite = EffectSprite3D::createFromObjFileAndTexture("Sprite3DTest/boss1.obj", "Sprite3DTest/boss.png"); auto sprite = EffectSprite3D::createFromObjFileAndTexture("Sprite3DTest/boss1.obj", "Sprite3DTest/boss.png");
Effect3DOutline* effect = Effect3DOutline::create(); Effect3DOutline* effect = Effect3DOutline::create();
sprite->addEffect(effect, -1);
effect->setOutlineColor(Vec3(1,0,0)); effect->setOutlineColor(Vec3(1,0,0));
effect->setOutlineWidth(0.01f); effect->setOutlineWidth(0.01f);
sprite->addEffect(effect, -1);
Effect3DOutline* effect2 = Effect3DOutline::create(); Effect3DOutline* effect2 = Effect3DOutline::create();
sprite->addEffect(effect2, -2);
effect2->setOutlineWidth(0.02f); effect2->setOutlineWidth(0.02f);
effect2->setOutlineColor(Vec3(1,1,0)); effect2->setOutlineColor(Vec3(1,1,0));
sprite->addEffect(effect2, -2);
//sprite->setEffect3D(effect); //sprite->setEffect3D(effect);
sprite->setScale(6.f); sprite->setScale(6.f);
@ -634,7 +687,7 @@ std::string Sprite3DWithSkinTest::subtitle() const
void Sprite3DWithSkinTest::addNewSpriteWithCoords(Vec2 p) void Sprite3DWithSkinTest::addNewSpriteWithCoords(Vec2 p)
{ {
std::string fileName = "Sprite3DTest/orc.c3b"; std::string fileName = "Sprite3DTest/orc.c3b";
auto sprite = Sprite3D::create(fileName); auto sprite = EffectSprite3D::create(fileName);
sprite->setScale(3); sprite->setScale(3);
sprite->setRotation3D(Vec3(0,180,0)); sprite->setRotation3D(Vec3(0,180,0));
addChild(sprite); addChild(sprite);
@ -672,6 +725,79 @@ void Sprite3DWithSkinTest::onTouchesEnded(const std::vector<Touch*>& touches, Ev
} }
} }
Sprite3DWithSkinOutlineTest::Sprite3DWithSkinOutlineTest()
{
auto listener = EventListenerTouchAllAtOnce::create();
listener->onTouchesEnded = CC_CALLBACK_2(Sprite3DWithSkinOutlineTest::onTouchesEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
auto s = Director::getInstance()->getWinSize();
addNewSpriteWithCoords( Vec2(s.width/2, s.height/2) );
}
std::string Sprite3DWithSkinOutlineTest::title() const
{
return "Testing Sprite3D for skinned outline";
}
std::string Sprite3DWithSkinOutlineTest::subtitle() const
{
return "Tap screen to add more sprite3D";
}
void Sprite3DWithSkinOutlineTest::addNewSpriteWithCoords(Vec2 p)
{
std::string fileName = "Sprite3DTest/orc.c3b";
auto sprite = EffectSprite3D::create(fileName);
Effect3DOutline* effect = Effect3DOutline::create();
effect->setOutlineColor(Vec3(1,0,0));
effect->setOutlineWidth(0.01f);
sprite->addEffect(effect, -1);
Effect3DOutline* effect2 = Effect3DOutline::create();
effect2->setOutlineWidth(0.02f);
effect2->setOutlineColor(Vec3(1,1,0));
sprite->addEffect(effect2, -2);
sprite->setScale(3);
sprite->setRotation3D(Vec3(0,180,0));
addChild(sprite);
sprite->setPosition( Vec2( p.x, p.y) );
auto animation = Animation3D::create(fileName);
if (animation)
{
auto animate = Animate3D::create(animation);
bool inverse = (std::rand() % 3 == 0);
int rand2 = std::rand();
float speed = 1.0f;
if(rand2 % 3 == 1)
{
speed = animate->getSpeed() + CCRANDOM_0_1();
}
else if(rand2 % 3 == 2)
{
speed = animate->getSpeed() - 0.5 * CCRANDOM_0_1();
}
animate->setSpeed(inverse ? -speed : speed);
sprite->runAction(RepeatForever::create(animate));
}
}
void Sprite3DWithSkinOutlineTest::onTouchesEnded(const std::vector<Touch*>& touches, Event* event)
{
for (auto touch: touches)
{
auto location = touch->getLocation();
addNewSpriteWithCoords( location );
}
}
Animate3DTest::Animate3DTest() Animate3DTest::Animate3DTest()
: _hurt(nullptr) : _hurt(nullptr)
, _swim(nullptr) , _swim(nullptr)

View File

@ -113,7 +113,12 @@ protected:
static const std::string _vertShaderFile; static const std::string _vertShaderFile;
static const std::string _fragShaderFile; static const std::string _fragShaderFile;
static const std::string _keyInGLProgramCache; static const std::string _keyInGLProgramCache;
static GLProgram* getOrCreateProgram();
static const std::string _vertSkinnedShaderFile;
static const std::string _fragSkinnedShaderFile;
static const std::string _keySkinnedInGLProgramCache;
static GLProgram* getOrCreateProgram(bool isSkinned = false);
}; };
class Sprite3DHitTest : public Sprite3DTestDemo class Sprite3DHitTest : public Sprite3DTestDemo
@ -129,6 +134,8 @@ class EffectSprite3D : public Sprite3D
{ {
public: public:
static EffectSprite3D* createFromObjFileAndTexture(const std::string& objFilePath, const std::string& textureFilePath); static EffectSprite3D* createFromObjFileAndTexture(const std::string& objFilePath, const std::string& textureFilePath);
static EffectSprite3D* create(const std::string& path);
void setEffect3D(Effect3D* effect); void setEffect3D(Effect3D* effect);
void addEffect(Effect3DOutline* effect, ssize_t order); void addEffect(Effect3DOutline* effect, ssize_t order);
virtual void draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) override; virtual void draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) override;
@ -167,6 +174,19 @@ public:
void onTouchesEnded(const std::vector<Touch*>& touches, Event* event); void onTouchesEnded(const std::vector<Touch*>& touches, Event* event);
}; };
class Sprite3DWithSkinOutlineTest : public Sprite3DTestDemo
{
public:
CREATE_FUNC(Sprite3DWithSkinOutlineTest);
Sprite3DWithSkinOutlineTest();
virtual std::string title() const override;
virtual std::string subtitle() const override;
void addNewSpriteWithCoords(Vec2 p);
void onTouchesEnded(const std::vector<Touch*>& touches, Event* event);
};
class Animate3DTest : public Sprite3DTestDemo class Animate3DTest : public Sprite3DTestDemo
{ {
public: public:

View File

@ -0,0 +1,75 @@
attribute vec3 a_position;
attribute vec3 a_normal;
attribute vec4 a_blendWeight;
attribute vec4 a_blendIndex;
attribute vec2 a_texCoord;
uniform float OutlineWidth;
const int SKINNING_JOINT_COUNT = 60;
// Uniforms
uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];
// Varyings
varying vec2 TextureCoordOut;
vec4 SkinnedVec3(vec3 vec)
{
float blendWeight = a_blendWeight[0];
int matrixIndex = int (a_blendIndex[0]) * 3;
vec4 matrixPalette1 = u_matrixPalette[matrixIndex] * blendWeight;
vec4 matrixPalette2 = u_matrixPalette[matrixIndex + 1] * blendWeight;
vec4 matrixPalette3 = u_matrixPalette[matrixIndex + 2] * blendWeight;
blendWeight = a_blendWeight[1];
if (blendWeight > 0.0)
{
matrixIndex = int(a_blendIndex[1]) * 3;
matrixPalette1 += u_matrixPalette[matrixIndex] * blendWeight;
matrixPalette2 += u_matrixPalette[matrixIndex + 1] * blendWeight;
matrixPalette3 += u_matrixPalette[matrixIndex + 2] * blendWeight;
}
blendWeight = a_blendWeight[2];
if (blendWeight > 0.0)
{
matrixIndex = int(a_blendIndex[2]) * 3;
matrixPalette1 += u_matrixPalette[matrixIndex] * blendWeight;
matrixPalette2 += u_matrixPalette[matrixIndex + 1] * blendWeight;
matrixPalette3 += u_matrixPalette[matrixIndex + 2] * blendWeight;
}
blendWeight = a_blendWeight[3];
if (blendWeight > 0.0)
{
matrixIndex = int(a_blendIndex[3]) * 3;
matrixPalette1 += u_matrixPalette[matrixIndex] * blendWeight;
matrixPalette2 += u_matrixPalette[matrixIndex + 1] * blendWeight;
matrixPalette3 += u_matrixPalette[matrixIndex + 2] * blendWeight;
}
vec4 _skinnedPosition;
vec4 postion = vec4(vec, 1.0);
_skinnedPosition.x = dot(postion, matrixPalette1);
_skinnedPosition.y = dot(postion, matrixPalette2);
_skinnedPosition.z = dot(postion, matrixPalette3);
_skinnedPosition.w = postion.w;
return _skinnedPosition;
}
void main()
{
vec4 pos = CC_MVPMatrix * SkinnedVec3(a_position);
vec4 normalproj = CC_MVPMatrix * vec4(SkinnedVec3(a_normal).xyz, 0);
normalproj = normalize(normalproj);
pos.xy += normalproj.xy * (OutlineWidth * (pos.z * 0.5 + 0.5));
gl_Position = pos;
}