Shader 和 RenderTexture
先贴上两张效果图
(Shader)
(RenderTexture)
说一下实现的原因,因为项目中需要夜景,光影的效果。最初想到使用Shader来实现。实现之后。效果还不错。因为最初的测试是在Mac上跑的客户端,效果不错。但是放到手机端上之后。发现效率太低。超过3个光源之后,效率下降的太严重。不过既然做了,就拿出来分享一下。另一个则是用RenderTexture来实现的。效率则比Shader效率高很多。
Shader篇
思路讲解
- Shader中的所有的数据都是真实像素点来进项渲染的,而程序中则更多的是逻辑像素点来进行的,所以代码中又关于Zoom相关的字段都是处理相关的位置转换的代码
- 前文提到过关于光源超过三个的时候出现的问题。主要原因是,所有的渲染点都需要跟不同的光点位置进行运算。然后计算出他最后的使用哪个光电最亮(不透明度最低),然后取用这个值,所以一个光点运行一次,两个光点运行两次,以此类推。所以我做出的优化是减少判断的个数
- 能够减少的位置有 全透明区域 全黑区域。其实全透明区域最容易判断,下文中的等于0就直接Break则是对于全透明区域的优化。全黑区域则相对复杂一些。
- 全黑区域的优化。在C++代码中,我吧屏幕分成了24*16的网格,然后用C++代码与光点进行运算,初始化网格。然后把网格传入Shader中。Shader中则判定自己是不是处于全黑网格,如果处于全黑网格,则直接渲染为黑色不做后续处理
- 其他内容应该非常容易理解了。不做赘述
Shader 代码
1 #ifdef GL_ES
2 precision highp float;
3 #endif
4
5 int screen_width = 24;
6 int screen_height = 16;
7 uniform float shader_zoom;
8 uniform vec4 night_color;
9 uniform vec2 light_pos[10];
10 uniform float light_lenght[10];
11 uniform float light_glare_lenght[10];
12 uniform float light_all_length[10];
13 uniform float light_all_length_sq[10];
14 uniform float light_glare_lenght_sq[10];
15 uniform int light_count;
16 uniform float screen_zoom;
17 uniform float screen_mapping[24 * 16];
18 //uniform sampler2D screen_mapping;
19
20 float po_2_light_lenght[10];
21
22 void main(void)
23 {
24 float f = 1.0;
25
26 int i = 0;
27 vec2 p;
28 float color;
29 float color_f;
30 float length_sq;
31 float length_f;
32
33 int type = 0;
34
35 int x = int(gl_FragCoord.x / screen_zoom / shader_zoom);
36 int y = int(gl_FragCoord.y / screen_zoom / shader_zoom);
37
38 while (i < light_count)
39 {
40 if(screen_mapping[y * screen_width + x] == 1.0)
41 {
42 break;
43 }
44
45 if(f == 0.0)
46 {
47 break;
48 }
49
50 p = gl_FragCoord.xy - light_pos[i].xy;
51
52 length_sq = dot(p, p);
53
54
55 if(length_sq >= light_all_length_sq[i])
56 {
57 i++;
58 continue;
59 }
60
61 if(length_sq <= light_glare_lenght_sq[i])
62 {
63 f = 0.0;
64 i++;
65 continue;
66 }
67
68 color = length(p) - light_glare_lenght[i];
69 color_f = clamp(color / light_lenght[i], 0.0, 1.0);
70
71 if(color_f < f)
72 {
73 f = color_f;
74 }
75
76 i++;
77 }
78
79 gl_FragColor = vec4(f * night_color);
80 }
调用Shader的代码(C++)
1 void NightLayer::onDraw(const cocos2d::Mat4& transform, uint32_t flags)
2 {
3 int x, y, i;
4 Vec2 postion;
5
6 float screen_zoom = DataManager::getInstance()->getScreenZoom();
7 for (i = 0; i < kScreenWidth * kScreenHeight; ++i)
8 {
9 _screen_mapping[i] = 1.f;
10 }
11
12
13 for (y = 0; y < kScreenHeight; ++y)
14 {
15 for (x = 0; x < kScreenWidth ; ++x)
16 {
17 for (i = 0; i < _light_count; ++i)
18 {
19 postion.x = (x + 0.5f) * kShaderZoom * screen_zoom;
20 postion.y = (y + 0.5f) * kShaderZoom * screen_zoom;
21
22 if((postion - _light_pos[i]).lengthSquared() < pow((_light_all_length[i] + 14.2 * kShaderBaseZoom), 2))
23 {
24 _screen_mapping[y * kScreenWidth + x] = 0.f;
25 }
26 }
27 }
28 }
29
30 float w = _contentSize.width, h = _contentSize.height;
31 GLfloat vertices[12] = {0,0, w,0, w,h, 0,0, 0,h, w,h};
32
33 auto glProgramState = getGLProgramState();
34 glProgramState->setVertexAttribPointer("a_position", 2, GL_FLOAT, GL_FALSE, 0, vertices);
35
36 glProgramState->setUniformFloat("screen_zoom", screen_zoom);
37 glProgramState->setUniformFloat("shader_zoom", kShaderZoom);
38 glProgramState->setUniformInt("light_count", _light_count);
39 glProgramState->setUniformVec4("night_color", Vec4(0.055, 0.008, 0.008, 1));
40 glProgramState->setUniformVec2v("light_pos", _light_count, _light_pos);
41 glProgramState->setUniformFloatv("light_lenght", _light_count, _light_length);
42 glProgramState->setUniformFloatv("light_glare_lenght", _light_count, _light_glare_lenght);
43 glProgramState->setUniformFloatv("light_all_length_sq", _light_count, _light_all_length_sq);
44 glProgramState->setUniformFloatv("light_glare_lenght_sq", _light_count, _light_glare_lenght_sq);
45 glProgramState->setUniformFloatv("screen_mapping", kScreenWidth * kScreenHeight, _screen_mapping);
46
47 glProgramState->apply(transform);
48
49 glDrawArrays(GL_TRIANGLES, 0, 6);
50
51 CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,6);
52 }
相关参数注解
- int screen_width = 24; 映射屏幕的宽度
- int screen_height = 16; 映射屏幕的高度
- uniform float shader_zoom; Shader的缩放值
- uniform vec4 night_color; 夜晚的颜色
- uniform vec2 light_pos[10]; 光点的位置
- uniform float light_lenght[10]; 光点强光圈长度
- uniform float light_glare_lenght[10]; 光点弱光圈长度
- uniform float light_all_length[10]; 光点的总长度(强光跟弱光距离相加)
- uniform float light_all_length_sq[10]; 光电总长度的平方
- uniform float light_glare_lenght_sq[10]; 光电弱光圈的平方
- uniform int light_count; 光点的个数
- uniform float screen_zoom; 屏幕缩放比例
- uniform float screen_mapping[24 * 16]; 屏幕映射字典
ScreenZoom的计算方式
额,这个并不是所有的游戏都是这么计算的。需要跟游戏的适配方式配合
1 Size w_size = Director::getInstance()->getOpenGLView()->getFrameSize();
2 Size designResolutionSize = Director::getInstance()->getWinSize();
3 DataManager::getInstance()->setScreenZoom(w_size.height / designResolutionSize.height * Director::getInstance()->getOpenGLView()->getRetinaFactor());
我们的游戏适配方式
关键是第三个参数,以高度适配,所以上边的缩放计算也是以高度计算的
1 glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::FIXED_HEIGHT);
RenderTexture 篇
思路讲解
先比对Shader RenderTexture 则更加简单暴力。简单来说就是在RenderTexture上贴图,只要把对应的图片放到对应的位置,然后展示出来就好。
相关代码
1 void NightLayer::update(float dt)
2 {
3 _render->clear(0, 0, 0, 1.f);
4 _render->begin();
5 // _render->beginWithClear(0, 0, 0, 1.f, 0, 0);
6
7 for (int i = 0; i < kPlayerMaxCount; ++i)
8 {
9 bool is_show = _light_player_count > i;
10 if(is_show)
11 {
12 _spr_lights_player[i]->setPosition(_light_player_pos[i]);
13 _spr_lights_player[i]->setScale(_light_player_length[i] / 300.f * 2.8f);
14 _spr_lights_player[i]->visit();
15 }
16 }
17
18 for (int i = 0; i < kCandleMaxCount; ++i)
19 {
20 bool is_show = _light_candle_count > i;
21 if(is_show)
22 {
23 _spr_lights_candle[i]->setPosition(_light_candle_pos[i]);
24 _spr_lights_candle[i]->setScale(_light_candle_length[i] / 150.f);
25 _spr_lights_candle[i]->visit();
26 }
27 }
28
29 _render->end();
30 }
全文件大放送
NightLayer.hpp
1 //
2 // NightLayer.hpp
3 // 4 //
5 // 6 //
7 //
8
9 #ifndef NightLayer_hpp
10 #define NightLayer_hpp
11
12 #include "cocos2d.h"
13
14 //#define USING_SHADER
15 #define USING_RENDER_TEXTURE
16
17 #include <stdio.h>
18
19 class NightLayer : public cocos2d::Node
20 {
21 public:
22 CREATE_FUNC(NightLayer);
23
24 virtual bool init() override;
25
26 #ifdef USING_RENDER_TEXTURE
27 virtual void update(float dt) override;
28 #endif
29
30 #ifdef USING_SHADER
31 virtual void draw(cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t flags) override;
32 #endif
33
34 public:
35 #ifdef USING_SHADER
36 const static int kLightMaxCount = 10;
37 cocos2d::Vec2 _light_pos[kLightMaxCount];
38 float _light_length[kLightMaxCount];
39 float _light_glare_lenght[kLightMaxCount];
40 float _light_all_length[kLightMaxCount];
41 float _light_all_length_sq[kLightMaxCount];
42 float _light_glare_lenght_sq[kLightMaxCount];
43
44 int _light_count;
45 #endif
46
47 #ifdef USING_RENDER_TEXTURE
48 const static int kCandleMaxCount = 9;
49 const static int kPlayerMaxCount = 1;
50
51 cocos2d::Vec2 _light_candle_pos[kCandleMaxCount];
52 cocos2d::Vec2 _light_player_pos[kPlayerMaxCount];
53
54 float _light_candle_length[kCandleMaxCount];
55 float _light_player_length[kPlayerMaxCount];
56
57 int _light_candle_count;
58 int _light_player_count;
59
60 #endif
61
62 protected:
63 NightLayer()
64 #ifdef USING_SHADER
65 :_light_count(0)
66 #endif
67 #ifdef USING_RENDER_TEXTURE
68 :_light_candle_count(0)
69 ,_light_player_count(0)
70 ,_render(nullptr)
71 #endif
72 { }
73 virtual ~NightLayer();
74
75
76 #ifdef USING_RENDER_TEXTURE
77 cocos2d::RenderTexture * _render;
78 cocos2d::Sprite * _spr_lights_candle[kCandleMaxCount];
79 cocos2d::Sprite * _spr_lights_player[kPlayerMaxCount];
80 #endif
81
82 #ifdef USING_SHADER
83
84 cocos2d::Vec2 _resolution;
85 void onDraw(const cocos2d::Mat4& transform, uint32_t flags);
86
87 bool initWithVertex(const std::string &vert, const std::string &frag);
88 void loadShaderVertex(const std::string &vert, const std::string &frag);
89
90 cocos2d::CustomCommand _customCommand;
91 std::string _vertFileName;
92 std::string _fragFileName;
93
94 const static int kScreenWidth = 24;
95 const static int kScreenHeight = 16;
96 float _screen_mapping[kScreenWidth * kScreenHeight];
97 #endif
98 };
99
100 #endif /* NightLayer_hpp */
NightLayer.cpp
1 //
2 // NightLayer.cpp
3 // 4 //
5 // 6 //
7 //
8
9 #include "NightLayer.hpp"
10 #include "DataManager.h"
11
12 USING_NS_CC;
13
14
15 namespace
16 {
17 #ifdef USING_SHADER
18 const float kShaderBaseZoom = 4.f;
19 const float kShaderZoom = kShaderBaseZoom * 10.f;
20 #endif
21 }
22
23 #ifdef USING_SHADER
24
25 bool NightLayer::initWithVertex(const std::string &vert, const std::string &frag)
26 {
27 _vertFileName = vert;
28 _fragFileName = frag;
29 #if CC_ENABLE_CACHE_TEXTURE_DATA
30 auto listener = EventListenerCustom::create(EVENT_RENDERER_RECREATED, [this](EventCustom* event){
31 this->setGLProgramState(nullptr);
32 loadShaderVertex(_vertFileName, _fragFileName);
33 });
34
35 _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
36 #endif
37
38 loadShaderVertex(vert, frag);
39
40 scheduleUpdate();
41
42 Size size = Director::getInstance()->getWinSize();
43 setContentSize(size);
44 setAnchorPoint(Vec2(0.5f, 0.5f));
45
46
47 return true;
48 }
49
50 void NightLayer::loadShaderVertex(const std::string &vert, const std::string &frag)
51 {
52 auto fileUtiles = FileUtils::getInstance();
53
54 // frag
55 auto fragmentFilePath = fileUtiles->fullPathForFilename(frag);
56 auto fragSource = fileUtiles->getStringFromFile(fragmentFilePath);
57
58 // vert
59 std::string vertSource;
60 if (vert.empty()) {
61 vertSource = ccPositionTextureColor_vert;
62 } else {
63 std::string vertexFilePath = fileUtiles->fullPathForFilename(vert);
64 vertSource = fileUtiles->getStringFromFile(vertexFilePath);
65 }
66
67 auto glprogram = GLProgram::createWithByteArrays(vertSource.c_str(), fragSource.c_str());
68 auto glprogramstate = GLProgramState::getOrCreateWithGLProgram(glprogram);
69 setGLProgramState(glprogramstate);
70 }
71
72 #endif
73
74 NightLayer::~NightLayer()
75 {
76 #ifdef USING_RENDER_TEXTURE
77
78 for (int i = 0; i < kCandleMaxCount; ++i)
79 {
80 CC_SAFE_RELEASE(_spr_lights_candle[i]);
81 }
82
83 for (int i = 0; i < kPlayerMaxCount; ++i)
84 {
85 CC_SAFE_RELEASE(_spr_lights_player[i]);
86 }
87
88 #endif
89 }
90
91 bool NightLayer::init()
92 {
93 bool success = false;
94
95 do {
96 if(!Node::init())
97 {
98 break;
99 }
100
101 #ifdef USING_SHADER
102 initWithVertex("", "shaders/night.fsh");
103 _resolution = Director::getInstance()->getOpenGLView()->getFrameSize();
104 #endif
105
106 #ifdef USING_RENDER_TEXTURE
107 Size size = Director::getInstance()->getWinSize();
108
109 for (int i = 0; i < kCandleMaxCount; ++i)
110 {
111 _spr_lights_candle[i] = Sprite::create("imgs/light_candle.png");
112 _spr_lights_candle[i]->retain();
113 _spr_lights_candle[i]->setBlendFunc({GL_DST_COLOR, GL_ZERO});
114 }
115
116 for (int i = 0; i < kPlayerMaxCount; ++i)
117 {
118 _spr_lights_player[i] = Sprite::create("imgs/light_player.png");
119 _spr_lights_player[i]->retain();
120 _spr_lights_player[i]->setBlendFunc({GL_DST_COLOR, GL_ZERO});
121 }
122
123
124 _render = RenderTexture::create(size.width, size.height, Texture2D::PixelFormat::RGBA4444, GL_DEPTH24_STENCIL8);;
125 this->addChild(_render);
126 #endif
127
128
129 success = true;
130 } while (0);
131
132 return success;
133 }
134
135 #ifdef USING_RENDER_TEXTURE
136 void NightLayer::update(float dt)
137 {
138 _render->clear(0, 0, 0, 1.f);
139 _render->begin();
140 // _render->beginWithClear(0, 0, 0, 1.f, 0, 0);
141
142 for (int i = 0; i < kPlayerMaxCount; ++i)
143 {
144 bool is_show = _light_player_count > i;
145 if(is_show)
146 {
147 _spr_lights_player[i]->setPosition(_light_player_pos[i]);
148 _spr_lights_player[i]->setScale(_light_player_length[i] / 300.f * 2.8f);
149 _spr_lights_player[i]->visit();
150 }
151 }
152
153 for (int i = 0; i < kCandleMaxCount; ++i)
154 {
155 bool is_show = _light_candle_count > i;
156 if(is_show)
157 {
158 _spr_lights_candle[i]->setPosition(_light_candle_pos[i]);
159 _spr_lights_candle[i]->setScale(_light_candle_length[i] / 150.f);
160 _spr_lights_candle[i]->visit();
161 }
162 }
163
164 _render->end();
165 }
166 #endif
167
168 #ifdef USING_SHADER
169 void NightLayer::draw(cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t flags)
170 {
171 _customCommand.init(_globalZOrder, transform, flags);
172 _customCommand.func = CC_CALLBACK_0(NightLayer::onDraw, this, transform, flags);
173 renderer->addCommand(&_customCommand);
174 }
175 #endif
176
177 #ifdef USING_SHADER
178 void NightLayer::onDraw(const cocos2d::Mat4& transform, uint32_t flags)
179 {
180 int x, y, i;
181 Vec2 postion;
182
183 float screen_zoom = DataManager::getInstance()->getScreenZoom();
184 for (i = 0; i < kScreenWidth * kScreenHeight; ++i)
185 {
186 _screen_mapping[i] = 1.f;
187 }
188
189
190 for (y = 0; y < kScreenHeight; ++y)
191 {
192 for (x = 0; x < kScreenWidth ; ++x)
193 {
194 for (i = 0; i < _light_count; ++i)
195 {
196 postion.x = (x + 0.5f) * kShaderZoom * screen_zoom;
197 postion.y = (y + 0.5f) * kShaderZoom * screen_zoom;
198
199 if((postion - _light_pos[i]).lengthSquared() < pow((_light_all_length[i] + 14.2 * kShaderBaseZoom), 2))
200 {
201 _screen_mapping[y * kScreenWidth + x] = 0.f;
202 }
203 }
204 }
205 }
206
207 float w = _contentSize.width, h = _contentSize.height;
208 GLfloat vertices[12] = {0,0, w,0, w,h, 0,0, 0,h, w,h};
209
210 auto glProgramState = getGLProgramState();
211 glProgramState->setVertexAttribPointer("a_position", 2, GL_FLOAT, GL_FALSE, 0, vertices);
212
213 glProgramState->setUniformFloat("screen_zoom", screen_zoom);
214 glProgramState->setUniformFloat("shader_zoom", kShaderZoom);
215 glProgramState->setUniformInt("light_count", _light_count);
216 glProgramState->setUniformVec4("night_color", Vec4(0.055, 0.008, 0.008, 1));
217 glProgramState->setUniformVec2v("light_pos", _light_count, _light_pos);
218 glProgramState->setUniformFloatv("light_lenght", _light_count, _light_length);
219 glProgramState->setUniformFloatv("light_glare_lenght", _light_count, _light_glare_lenght);
220 glProgramState->setUniformFloatv("light_all_length_sq", _light_count, _light_all_length_sq);
221 glProgramState->setUniformFloatv("light_glare_lenght_sq", _light_count, _light_glare_lenght_sq);
222 glProgramState->setUniformFloatv("screen_mapping", kScreenWidth * kScreenHeight, _screen_mapping);
223
224 glProgramState->apply(transform);
225
226 glDrawArrays(GL_TRIANGLES, 0, 6);
227
228 CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,6);
229 }
230
231 #endif
night.fsh
1 #ifdef GL_ES
2 precision highp float;
3 #endif
4
5 int screen_width = 24;
6 int screen_height = 16;
7 uniform float shader_zoom;
8 uniform vec2 resolution;
9 uniform vec4 night_color;
10 uniform vec2 light_pos[10];
11 uniform float light_lenght[10];
12 uniform float light_glare_lenght[10];
13 uniform float light_all_length[10];
14 uniform float light_all_length_sq[10];
15 uniform float light_glare_lenght_sq[10];
16 uniform int light_count;
17 uniform float screen_zoom;
18 uniform float screen_mapping[24 * 16];
19 //uniform sampler2D screen_mapping;
20
21 float po_2_light_lenght[10];
22
23 void main(void)
24 {
25 float f = 1.0;
26
27 int i = 0;
28 vec2 p;
29 float color;
30 float color_f;
31 float length_sq;
32 float length_f;
33
34 int type = 0;
35
36 int x = int(gl_FragCoord.x / screen_zoom / shader_zoom);
37 int y = int(gl_FragCoord.y / screen_zoom / shader_zoom);
38
39 // f = screen_mapping[y * screen_width + x];
40
41 while (i < light_count)
42 {
43 if(screen_mapping[y * screen_width + x] == 1.0)
44 {
45 break;
46 }
47
48 if(f == 0.0)
49 {
50 break;
51 }
52
53 p = gl_FragCoord.xy - light_pos[i].xy;
54
55 length_sq = dot(p, p);
56
57
58 if(length_sq >= light_all_length_sq[i])
59 {
60 i++;
61 continue;
62 }
63
64 if(length_sq <= light_glare_lenght_sq[i])
65 {
66 f = 0.0;
67 i++;
68 continue;
69 }
70
71 color = length(p) - light_glare_lenght[i];
72 color_f = clamp(color / light_lenght[i], 0.0, 1.0);
73
74 if(color_f < f)
75 {
76 f = color_f;
77 }
78
79 i++;
80 }
81
82 gl_FragColor = vec4(f * night_color);
83 }
原文链接: https://www.cnblogs.com/anxin1225/p/5069289.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/226321
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!