├── Resources ├── res │ └── .gitkeep ├── test.png ├── test2.png ├── CloseNormal.png ├── HelloWorld.png ├── CloseSelected.png ├── fonts │ └── Marker Felt.ttf └── shaders │ ├── pass.vsh │ ├── shadowMap.fsh │ └── shadowRender.fsh ├── README.md └── Classes ├── HelloWorldScene.h ├── AppDelegate.h ├── AppDelegate.cpp ├── DynamicLight.h ├── HelloWorldScene.cpp └── DynamicLight.cpp /Resources/res/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Resources/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/namkazt/DynamicLight/HEAD/Resources/test.png -------------------------------------------------------------------------------- /Resources/test2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/namkazt/DynamicLight/HEAD/Resources/test2.png -------------------------------------------------------------------------------- /Resources/CloseNormal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/namkazt/DynamicLight/HEAD/Resources/CloseNormal.png -------------------------------------------------------------------------------- /Resources/HelloWorld.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/namkazt/DynamicLight/HEAD/Resources/HelloWorld.png -------------------------------------------------------------------------------- /Resources/CloseSelected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/namkazt/DynamicLight/HEAD/Resources/CloseSelected.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DynamicLight 2 | A new Dynamic Light fixed from avalon's sample to work with cocos2dx version 3.x 3 | -------------------------------------------------------------------------------- /Resources/fonts/Marker Felt.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/namkazt/DynamicLight/HEAD/Resources/fonts/Marker Felt.ttf -------------------------------------------------------------------------------- /Resources/shaders/pass.vsh: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | precision lowp float; 3 | #endif 4 | 5 | attribute vec4 a_position; 6 | attribute vec2 a_texCoord; 7 | attribute vec4 a_color; 8 | 9 | varying vec2 v_texCoord; 10 | varying vec4 v_color; 11 | 12 | void main() { 13 | v_color = a_color; 14 | gl_Position = CC_MVPMatrix * a_position; 15 | v_texCoord = a_texCoord; 16 | } 17 | -------------------------------------------------------------------------------- /Classes/HelloWorldScene.h: -------------------------------------------------------------------------------- 1 | #ifndef __HELLOWORLD_SCENE_H__ 2 | #define __HELLOWORLD_SCENE_H__ 3 | 4 | #include "cocos2d.h" 5 | #include "DynamicLight.h" 6 | 7 | class HelloWorld : public cocos2d::Layer 8 | { 9 | private: 10 | DynamicLight* dynLight; 11 | cocos2d::Sprite* shadowCaster; 12 | int lightSize; 13 | public: 14 | // there's no 'id' in cpp, so we recommend returning the class instance pointer 15 | static cocos2d::Scene* createScene(); 16 | // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone 17 | virtual bool init(); 18 | // implement the "static create()" method manually 19 | CREATE_FUNC(HelloWorld); 20 | 21 | bool onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event); 22 | void onTouchEnded(cocos2d::Touch* touch, cocos2d::Event* event); 23 | void onTouchMoved(cocos2d::Touch* touch, cocos2d::Event* event); 24 | 25 | void onKeyPressed(cocos2d::EventKeyboard::KeyCode keyCode, cocos2d::Event* event); 26 | void onKeyReleased(cocos2d::EventKeyboard::KeyCode keyCode, cocos2d::Event* event); 27 | }; 28 | 29 | #endif // __HELLOWORLD_SCENE_H__ 30 | -------------------------------------------------------------------------------- /Classes/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #ifndef _APP_DELEGATE_H_ 2 | #define _APP_DELEGATE_H_ 3 | 4 | #include "cocos2d.h" 5 | 6 | /** 7 | @brief The cocos2d Application. 8 | 9 | The reason for implement as private inheritance is to hide some interface call by Director. 10 | */ 11 | class AppDelegate : private cocos2d::Application 12 | { 13 | public: 14 | AppDelegate(); 15 | virtual ~AppDelegate(); 16 | 17 | virtual void initGLContextAttrs(); 18 | 19 | /** 20 | @brief Implement Director and Scene init code here. 21 | @return true Initialize success, app continue. 22 | @return false Initialize failed, app terminate. 23 | */ 24 | virtual bool applicationDidFinishLaunching(); 25 | 26 | /** 27 | @brief The function be called when the application enter background 28 | @param the pointer of the application 29 | */ 30 | virtual void applicationDidEnterBackground(); 31 | 32 | /** 33 | @brief The function be called when the application enter foreground 34 | @param the pointer of the application 35 | */ 36 | virtual void applicationWillEnterForeground(); 37 | }; 38 | 39 | #endif // _APP_DELEGATE_H_ 40 | 41 | -------------------------------------------------------------------------------- /Classes/AppDelegate.cpp: -------------------------------------------------------------------------------- 1 | #include "AppDelegate.h" 2 | #include "HelloWorldScene.h" 3 | 4 | USING_NS_CC; 5 | 6 | AppDelegate::AppDelegate() { 7 | 8 | } 9 | 10 | AppDelegate::~AppDelegate() 11 | { 12 | } 13 | 14 | //if you want a different context,just modify the value of glContextAttrs 15 | //it will takes effect on all platforms 16 | void AppDelegate::initGLContextAttrs() 17 | { 18 | //set OpenGL context attributions,now can only set six attributions: 19 | //red,green,blue,alpha,depth,stencil 20 | GLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8}; 21 | 22 | GLView::setGLContextAttrs(glContextAttrs); 23 | } 24 | 25 | bool AppDelegate::applicationDidFinishLaunching() { 26 | // initialize director 27 | auto director = Director::getInstance(); 28 | auto glview = director->getOpenGLView(); 29 | if(!glview) { 30 | glview = GLViewImpl::create("My Game"); 31 | director->setOpenGLView(glview); 32 | } 33 | 34 | // turn on display FPS 35 | director->setDisplayStats(true); 36 | 37 | // set FPS. the default value is 1.0/60 if you don't call this 38 | director->setAnimationInterval(1.0 / 60); 39 | 40 | // create a scene. it's an autorelease object 41 | auto scene = HelloWorld::createScene(); 42 | 43 | // run 44 | director->runWithScene(scene); 45 | 46 | return true; 47 | } 48 | 49 | // This function will be called when the app is inactive. When comes a phone call,it's be invoked too 50 | void AppDelegate::applicationDidEnterBackground() { 51 | Director::getInstance()->stopAnimation(); 52 | 53 | // if you use SimpleAudioEngine, it must be pause 54 | // SimpleAudioEngine::getInstance()->pauseBackgroundMusic(); 55 | } 56 | 57 | // this function will be called when the app is active again 58 | void AppDelegate::applicationWillEnterForeground() { 59 | Director::getInstance()->startAnimation(); 60 | 61 | // if you use SimpleAudioEngine, it must resume here 62 | // SimpleAudioEngine::getInstance()->resumeBackgroundMusic(); 63 | } 64 | -------------------------------------------------------------------------------- /Classes/DynamicLight.h: -------------------------------------------------------------------------------- 1 | #ifndef AVALON_GRAPHICS_DYNAMICLIGHT_H 2 | #define AVALON_GRAPHICS_DYNAMICLIGHT_H 3 | 4 | #include "cocos2d.h" 5 | 6 | class DynamicLight : public cocos2d::Node 7 | { 8 | private: 9 | bool bakedMapIsValid = false; 10 | bool softShadows = true; 11 | bool additive = true; 12 | float upScale = 1.0; 13 | float finalSize = lightSize * upScale; 14 | float accuracy = 1.0; 15 | int lightSize = 256; 16 | cocos2d::Color4B color = {64, 130, 77, 255}; 17 | cocos2d::Node* shadowCasters = nullptr; 18 | 19 | cocos2d::RenderTexture* occlusionMap = nullptr; 20 | cocos2d::Sprite* occlusionMapSprite = nullptr; 21 | cocos2d::RenderTexture* shadowMap1D = nullptr; 22 | cocos2d::Sprite* shadowMap1DSprite = nullptr; 23 | cocos2d::RenderTexture* finalShadowMap = nullptr; 24 | cocos2d::Sprite* finalShadowMapSprite = nullptr; 25 | 26 | cocos2d::GLProgramState* shadowMapShader = nullptr; 27 | cocos2d::GLProgramState* shadowRenderShader = nullptr; 28 | 29 | void initOcclusionMap(); 30 | void initShadowMap1D(); 31 | void initFinalShadowMap(); 32 | void updateUniforms(); 33 | void createOcclusionMap(); 34 | void createShadowMap(cocos2d::Renderer *renderer, const cocos2d::Mat4 &transform, bool transformUpdated); 35 | void updateShadowMap(cocos2d::Renderer *renderer, const cocos2d::Mat4 &transform, bool transformUpdated); 36 | cocos2d::GLProgram* loadShader(const GLchar* vertexShader, const GLchar* fragmentShader); 37 | public: 38 | int updateFrequency = 0; 39 | int updateCount = 0; 40 | bool debugDrawEnabled = false; 41 | 42 | CREATE_FUNC(DynamicLight); 43 | virtual bool init(); 44 | ~DynamicLight(); 45 | 46 | void draw(cocos2d::Renderer *renderer, const cocos2d::Mat4 &transform, uint32_t flags) override; 47 | void debugDraw(cocos2d::Renderer *renderer, const cocos2d::Mat4 &transform, bool transformUpdated); 48 | 49 | void setPosition(const cocos2d::Point& position) override; 50 | void setSoftShadows(bool shadows); 51 | void setLightSize(int lightSize); 52 | void setUpScale(float upScale); 53 | void setAccuracy(float accuracy); 54 | void setAdditive(bool additive); 55 | void setColor(const cocos2d::Color4B& color); 56 | void setShadowCasters(cocos2d::Node* casters); 57 | }; 58 | 59 | #endif /* AVALON_GRAPHICS_DYNAMICLIGHT_H */ -------------------------------------------------------------------------------- /Classes/HelloWorldScene.cpp: -------------------------------------------------------------------------------- 1 | #include "HelloWorldScene.h" 2 | 3 | USING_NS_CC; 4 | 5 | Scene* HelloWorld::createScene() 6 | { 7 | // 'scene' is an autorelease object 8 | auto scene = Scene::create(); 9 | 10 | // 'layer' is an autorelease object 11 | auto layer = HelloWorld::create(); 12 | 13 | // add layer as a child to scene 14 | scene->addChild(layer); 15 | 16 | // return the scene 17 | return scene; 18 | } 19 | 20 | // on "init" you need to initialize your instance 21 | bool HelloWorld::init() 22 | { 23 | ////////////////////////////// 24 | // 1. super init first 25 | if ( !Layer::init() ) 26 | { 27 | return false; 28 | } 29 | 30 | Size visibleSize = Director::getInstance()->getVisibleSize(); 31 | Vec2 origin = Director::getInstance()->getVisibleOrigin(); 32 | 33 | shadowCaster = Sprite::create("test.png"); 34 | shadowCaster->retain(); 35 | shadowCaster->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y)); 36 | this->addChild(shadowCaster, 10); 37 | 38 | lightSize = 256; 39 | 40 | dynLight = DynamicLight::create(); 41 | dynLight->retain(); 42 | //dynLight->debugDrawEnabled = true; 43 | dynLight->setShadowCasters(shadowCaster); 44 | dynLight->setColor(Color4B::WHITE); 45 | dynLight->setPosition({ 300,150 }); 46 | this->addChild(dynLight, 9); 47 | 48 | ////////////////////////////////////////////////////////////////////// 49 | // Setup listener 50 | auto dispatcher = Director::getInstance()->getEventDispatcher(); 51 | auto listener = EventListenerTouchOneByOne::create(); 52 | listener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this); 53 | listener->onTouchMoved = CC_CALLBACK_2(HelloWorld::onTouchMoved, this); 54 | listener->onTouchEnded = CC_CALLBACK_2(HelloWorld::onTouchEnded, this); 55 | dispatcher->addEventListenerWithSceneGraphPriority(listener, this); 56 | auto keylistener = EventListenerKeyboard::create(); 57 | keylistener->onKeyPressed = CC_CALLBACK_2(HelloWorld::onKeyPressed, this); 58 | keylistener->onKeyReleased = CC_CALLBACK_2(HelloWorld::onKeyReleased, this); 59 | dispatcher->addEventListenerWithSceneGraphPriority(keylistener, this); 60 | return true; 61 | } 62 | 63 | 64 | 65 | /////////////////////////////////////////////////////////////////////// 66 | /// INPUT EVENT LISNTENER 67 | /////////////////////////////////////////////////////////////////////// 68 | void HelloWorld::onKeyPressed(EventKeyboard::KeyCode keyCode, Event* event) 69 | { 70 | if (keyCode == EventKeyboard::KeyCode::KEY_1) 71 | { 72 | lightSize -= 32; 73 | dynLight->setLightSize(lightSize); 74 | } 75 | if (keyCode == EventKeyboard::KeyCode::KEY_2) 76 | { 77 | lightSize += 32; 78 | dynLight->setLightSize(lightSize); 79 | } 80 | } 81 | 82 | void HelloWorld::onKeyReleased(EventKeyboard::KeyCode keyCode, Event* event) 83 | { 84 | 85 | } 86 | 87 | bool HelloWorld::onTouchBegan(Touch* touch, Event* event) 88 | { 89 | return true; 90 | } 91 | 92 | void HelloWorld::onTouchMoved(Touch* touch, Event* event) 93 | { 94 | Point pos = touch->getLocation(); 95 | log("Tile: %f-%f", pos.x, pos.y); 96 | 97 | dynLight->setPosition(pos); 98 | } 99 | 100 | 101 | void HelloWorld::onTouchEnded(Touch* touch, Event* event) 102 | { 103 | } -------------------------------------------------------------------------------- /Resources/shaders/shadowMap.fsh: -------------------------------------------------------------------------------- 1 | 2 | #ifdef GL_ES 3 | precision lowp float; 4 | #endif 5 | 6 | #define PI 3.14 7 | 8 | varying vec2 v_texCoord; 9 | varying vec4 v_color; 10 | 11 | uniform sampler2D u_texture; 12 | uniform vec2 resolution; 13 | 14 | //for debugging; use a constant value in final release 15 | uniform float upScale; 16 | 17 | uniform float accuracy; 18 | 19 | //alpha threshold for our occlusion map 20 | const float THRESHOLD = 0.99; 21 | 22 | 23 | void main(void) { 24 | 25 | float distance = 1.0; 26 | 27 | for (float y=0.0; y THRESHOLD) { 46 | distance = min(distance, dst); 47 | } 48 | } 49 | gl_FragColor = vec4(vec3(distance), 1.0); 50 | } 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /Resources/shaders/shadowRender.fsh: -------------------------------------------------------------------------------- 1 | 2 | #ifdef GL_ES 3 | precision lowp float; 4 | #endif 5 | 6 | #define PI 3.14 7 | varying vec2 v_texCoord; 8 | varying vec4 v_color; 9 | 10 | uniform sampler2D u_texture; 11 | uniform sampler2D u_texture2; 12 | uniform vec2 resolution; 13 | 14 | uniform float softShadows; 15 | 16 | //sample from the distance map 17 | float sample(vec2 coord, float r) { 18 | return step(r, texture2D(u_texture2, coord).r); 19 | } 20 | 21 | void main(void) { 22 | //rectangular to polar 23 | vec2 norm = v_texCoord.st * 2.0 - 1.0; 24 | float theta = atan(norm.y, norm.x); 25 | 26 | /* example: directional light! */ 27 | /*if (theta < -0.7 || theta > 0.3) { 28 | gl_FragColor = vec4(0,0,0,0); 29 | return; 30 | } 31 | */ 32 | 33 | float r = length(norm); 34 | float coord = (theta + PI) / (2.0*PI); 35 | 36 | //the tex coord to sample our 1D lookup texture2D 37 | //always 0.0 on y axis 38 | vec2 tc = vec2(coord, 0.0); 39 | 40 | //the center tex coord, which gives us hard shadows 41 | float center = sample(vec2(tc.x, tc.y), r); 42 | 43 | //we multiply the blur amount by our distance from center 44 | //this leads to more blurriness as the shadow fades away 45 | float blur = (1./resolution.x) * smoothstep(0., 1., r); 46 | 47 | //now we use a simple gaussian blurriness 48 | float sum = 0.0; 49 | 50 | sum += sample(vec2(tc.x - 4.0*blur, tc.y), r) * 0.05; 51 | sum += sample(vec2(tc.x - 3.0*blur, tc.y), r) * 0.09; 52 | sum += sample(vec2(tc.x - 2.0*blur, tc.y), r) * 0.12; 53 | sum += sample(vec2(tc.x - 1.0*blur, tc.y), r) * 0.15; 54 | 55 | sum += center * 0.16; 56 | 57 | sum += sample(vec2(tc.x + 1.0*blur, tc.y), r) * 0.15; 58 | sum += sample(vec2(tc.x + 2.0*blur, tc.y), r) * 0.12; 59 | sum += sample(vec2(tc.x + 3.0*blur, tc.y), r) * 0.09; 60 | sum += sample(vec2(tc.x + 4.0*blur, tc.y), r) * 0.05; 61 | 62 | //1.0 -> in light, 0.0 -> in shadow 63 | float lit = mix(center, sum, softShadows); 64 | //multiply the summed amount by our distance, which 65 | //gives us a radial falloff 66 | //then multiply by vertex (light) color 67 | gl_FragColor = v_color * vec4(lit * smoothstep(1.0, 0.0, r)); 68 | } 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /Classes/DynamicLight.cpp: -------------------------------------------------------------------------------- 1 | #include "DynamicLight.h" 2 | 3 | USING_NS_CC; 4 | 5 | DynamicLight::~DynamicLight() 6 | { 7 | CC_SAFE_RELEASE(shadowRenderShader); 8 | CC_SAFE_RELEASE(shadowMapShader); 9 | CC_SAFE_RELEASE(occlusionMap); 10 | CC_SAFE_RELEASE(shadowMap1D); 11 | CC_SAFE_RELEASE(finalShadowMap); 12 | CC_SAFE_RELEASE(shadowCasters); 13 | } 14 | 15 | bool DynamicLight::init() 16 | { 17 | if (!Node::init()) { 18 | return false; 19 | } 20 | 21 | auto shadowMapShaderP = this->loadShader("shaders/pass.vsh", "shaders/shadowMap.fsh"); 22 | auto shadowRenderShaderP = this->loadShader("shaders/pass.vsh", "shaders/shadowRender.fsh"); 23 | 24 | shadowMapShader = GLProgramState::getOrCreateWithGLProgram(shadowMapShaderP); 25 | shadowRenderShader = GLProgramState::getOrCreateWithGLProgram(shadowRenderShaderP); 26 | 27 | initOcclusionMap(); 28 | initShadowMap1D(); 29 | initFinalShadowMap(); 30 | bakedMapIsValid = false; 31 | 32 | return true; 33 | } 34 | 35 | GLProgram* DynamicLight::loadShader(const GLchar* vertexShader, const GLchar* fragmentShader) 36 | { 37 | auto shader = ShaderCache::getInstance()->getGLProgram(fragmentShader); 38 | if (!shader) { 39 | shader = new GLProgram(); 40 | shader->initWithVertexShaderFilename(vertexShader, fragmentShader); 41 | shader->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION); 42 | shader->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORDS); 43 | shader->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_COLOR); 44 | shader->link(); 45 | shader->updateUniforms(); 46 | shader->use(); 47 | } 48 | 49 | return shader; 50 | } 51 | 52 | 53 | void DynamicLight::initOcclusionMap() 54 | { 55 | CC_SAFE_RELEASE(occlusionMap); 56 | CC_SAFE_RELEASE(occlusionMapSprite); 57 | 58 | occlusionMap = RenderTexture::create(lightSize, lightSize); 59 | occlusionMap->retain(); 60 | 61 | occlusionMapSprite = Sprite::createWithTexture(occlusionMap->getSprite()->getTexture()); 62 | occlusionMapSprite->retain(); 63 | } 64 | 65 | void DynamicLight::initShadowMap1D() 66 | { 67 | CC_SAFE_RELEASE(shadowMap1D); 68 | CC_SAFE_RELEASE(shadowMap1DSprite); 69 | 70 | // seems like 16 pixel is the minimum height of a texture (on ios) 71 | shadowMap1D = RenderTexture::create(lightSize, 16); 72 | shadowMap1D->retain(); 73 | 74 | shadowMap1DSprite = Sprite::createWithTexture(shadowMap1D->getSprite()->getTexture()); 75 | shadowMap1DSprite->retain(); 76 | } 77 | 78 | void DynamicLight::initFinalShadowMap() 79 | { 80 | CC_SAFE_RELEASE(finalShadowMap); 81 | CC_SAFE_RELEASE(finalShadowMapSprite); 82 | 83 | finalSize = lightSize * upScale; 84 | 85 | finalShadowMap = RenderTexture::create(finalSize, finalSize); 86 | finalShadowMap->retain(); 87 | 88 | finalShadowMapSprite = Sprite::createWithTexture(finalShadowMap->getSprite()->getTexture()); 89 | finalShadowMapSprite->retain(); 90 | } 91 | 92 | void DynamicLight::setShadowCasters(Node* casters) 93 | { 94 | CC_SAFE_RELEASE(shadowCasters); 95 | 96 | bakedMapIsValid = false; 97 | 98 | shadowCasters = Sprite::createWithTexture(dynamic_cast(casters)->getTexture()); 99 | shadowCasters->setAnchorPoint(casters->getAnchorPoint()); 100 | shadowCasters->setPosition(casters->getPosition()); 101 | shadowCasters->retain(); 102 | } 103 | 104 | void DynamicLight::updateShadowMap(cocos2d::Renderer *renderer, const cocos2d::Mat4 &transform, bool transformUpdated) 105 | { 106 | 107 | } 108 | 109 | void DynamicLight::setPosition(const Point& position) 110 | { 111 | if (position.x == getPosition().x && position.y == getPosition().y) { 112 | return; 113 | } 114 | 115 | Node::setPosition(position); 116 | 117 | ++updateCount; 118 | if (updateCount > updateFrequency) { 119 | updateCount = 0; 120 | bakedMapIsValid = false; 121 | } 122 | } 123 | 124 | void DynamicLight::draw(cocos2d::Renderer *renderer, const cocos2d::Mat4 &transform, uint32_t flags) 125 | { 126 | if (!bakedMapIsValid) { 127 | bakedMapIsValid = true; 128 | 129 | updateUniforms(); 130 | createShadowMap(renderer, transform, flags); 131 | 132 | // update shadowRenderShader textures 133 | shadowRenderShader->setUniformTexture("u_texture", occlusionMapSprite->getTexture()); 134 | shadowRenderShader->setUniformTexture("u_texture2", shadowMap1DSprite->getTexture()); 135 | 136 | finalShadowMapSprite->setColor({ 255, 255, 255 }); 137 | finalShadowMapSprite->setGLProgramState(shadowRenderShader); 138 | finalShadowMapSprite->setAnchorPoint({ 0.5, 0.5 }); 139 | finalShadowMapSprite->setPosition((-getPositionX() + lightSize / 2) / 2, (-getPositionY() + lightSize / 2) / 2); 140 | finalShadowMapSprite->setBlendFunc({ GL_SRC_COLOR , GL_ONE }); 141 | } 142 | 143 | finalShadowMapSprite->visit(renderer, transform, flags); 144 | 145 | if (debugDrawEnabled) { 146 | debugDraw(renderer, transform, flags); 147 | } 148 | } 149 | 150 | void DynamicLight::debugDraw(cocos2d::Renderer *renderer, const cocos2d::Mat4 &transform, bool transformUpdated) 151 | { 152 | auto glView = Director::getInstance()->getOpenGLView(); 153 | auto width = glView->getDesignResolutionSize().width; 154 | auto height = glView->getDesignResolutionSize().height; 155 | 156 | auto occlusionX = width - lightSize / 2 - getPositionX(); 157 | auto occlusionY = height - lightSize / 2 - getPositionY(); 158 | 159 | auto shadowX = width - lightSize / 2 - getPositionX(); 160 | auto shadowY = height - lightSize - 15 - getPositionY(); 161 | 162 | occlusionMap->getSprite()->setColor(Color3B::RED); 163 | occlusionMap->setAnchorPoint({0, 0}); 164 | occlusionMap->setPosition({occlusionX, occlusionY}); 165 | occlusionMap->visit(renderer, transform, transformUpdated); 166 | occlusionMap->getSprite()->setColor(Color3B::WHITE); 167 | 168 | shadowMap1D->setAnchorPoint({0, 0}); 169 | shadowMap1D->setPosition({shadowX, shadowY}); 170 | shadowMap1D->visit(renderer, transform, transformUpdated); 171 | } 172 | 173 | void DynamicLight::updateUniforms() 174 | { 175 | // update other uniforms 176 | shadowMapShader->setUniformVec2("resolution", Vec2(lightSize, lightSize)); 177 | shadowMapShader->setUniformFloat("upScale", 1.0); 178 | shadowMapShader->setUniformFloat("accuracy", 1.0); 179 | 180 | shadowRenderShader->setUniformVec2("resolution", Vec2(lightSize, lightSize)); 181 | shadowRenderShader->setUniformFloat("softShadows", softShadows ? 1.0f : 0.0f); 182 | } 183 | 184 | void DynamicLight::createOcclusionMap() 185 | { 186 | 187 | } 188 | 189 | void DynamicLight::createShadowMap(cocos2d::Renderer *renderer, const cocos2d::Mat4 &transform, bool transformUpdated) 190 | { 191 | if (!shadowCasters) { 192 | occlusionMap->beginWithClear(0.0, 0.0, 0.0, 0.0); 193 | occlusionMap->end(); 194 | return; 195 | } 196 | Point p1 = shadowCasters->getAnchorPoint(); 197 | Point p2 = shadowCasters->getPosition(); 198 | auto x = shadowCasters->getPositionX() - (getPositionX() - (lightSize / 2)); 199 | auto y = shadowCasters->getPositionY() - (getPositionY() - (lightSize / 2)); 200 | // Render light region to occluder FBO 201 | //occlusionMap->beginWithClear(255.0, 255.0, 255.0, 1.0); 202 | occlusionMap->beginWithClear(0, 0, 0, 0); 203 | shadowCasters->setPosition(x, y); 204 | shadowCasters->visit(); 205 | occlusionMap->end(); 206 | shadowCasters->setAnchorPoint(p1); 207 | shadowCasters->setPosition(p2); 208 | 209 | //////////////////////////////////////////////////////////////// 210 | // set texture to shadow map shader 211 | occlusionMapSprite->setFlippedY(true); 212 | occlusionMapSprite->setAnchorPoint({ 0, 0 }); 213 | occlusionMapSprite->setPosition({ -getPositionX(), -getPositionY() }); 214 | shadowMapShader->setUniformTexture("u_texture", occlusionMapSprite->getTexture()); 215 | occlusionMapSprite->setGLProgramState(shadowMapShader); 216 | 217 | // Build a 1D shadow map from occlude FBO 218 | shadowMap1D->beginWithClear(0.0, 0.0, 0.0, 0.0); 219 | occlusionMapSprite->visit(renderer, transform, transformUpdated); 220 | shadowMap1D->end(); 221 | 222 | } 223 | 224 | void DynamicLight::setSoftShadows(bool shadows) 225 | { 226 | if (softShadows != shadows) { 227 | softShadows = shadows; 228 | bakedMapIsValid = false; 229 | } 230 | } 231 | 232 | void DynamicLight::setLightSize(int lightSize) 233 | { 234 | if (this->lightSize != lightSize) { 235 | if (lightSize < 0) lightSize = 0; 236 | this->lightSize = lightSize > 1200 ? 1200 : lightSize; 237 | initOcclusionMap(); 238 | initShadowMap1D(); 239 | initFinalShadowMap(); 240 | 241 | bakedMapIsValid = false; 242 | } 243 | } 244 | 245 | void DynamicLight::setUpScale(float upScale) 246 | { 247 | if (this->upScale != upScale) { 248 | this->upScale = upScale; 249 | bakedMapIsValid = false; 250 | } 251 | } 252 | 253 | void DynamicLight::setAccuracy(float accuracy) 254 | { 255 | if (this->accuracy != accuracy) { 256 | this->accuracy = accuracy; 257 | bakedMapIsValid = false; 258 | } 259 | } 260 | 261 | void DynamicLight::setAdditive(bool additive) 262 | { 263 | if (this->additive != additive) { 264 | this->additive = additive; 265 | bakedMapIsValid = false; 266 | } 267 | } 268 | 269 | void DynamicLight::setColor(const Color4B& color) 270 | { 271 | if (this->color != color) { 272 | this->color = color; 273 | bakedMapIsValid = false; 274 | } 275 | } --------------------------------------------------------------------------------