shader - Radial gradient - procedural texture for cocos2d-x v3.15+ -
in cocos2d-x there already layerradialgradient
. works well, i've other shaders running on game scene, performance in problem now. it's using shader.
i want replace sprite generated radial gradient texture.
here example of layerradialgradient
drawing result:
layerradialgradient::create( color4b(179, 232, 184, 89), color4b(0, 90, 128, 0), 620, center, 0.0f);
i've code suggestions like:
static color4b lerp(const color4b& value1, const color4b& value2, float amount) { amount = clampf(amount, 0.0f, 1.0f); return color4b( (int)mathutil::lerp(value1.r, value2.r, amount), (int)mathutil::lerp(value1.g, value2.g, amount), (int)mathutil::lerp(value1.b, value2.b, amount), (int)mathutil::lerp(value1.a, value2.a, amount) ); } static float falloff(float distance, float maxdistance, float scalingfactor) { if (distance <= maxdistance / 3) { return scalingfactor * (1 - 3 * distance * distance / (maxdistance * maxdistance)); } else if (distance <= maxdistance) { float x = 1 - distance / maxdistance; return (3.f / 2.f) * scalingfactor * x * x; } else return 0; } static float falloff(float distance, float maxdistance) { return falloff(distance, maxdistance, 1.f); } static texture2d* generateradialgradienttexture(int size) { auto radius = size / 2; auto colors = new (std::nothrow) glubyte[size * size * 4]; color4b centercolor(color4b(179, 232, 184, 89)); color4b bordercolor(color4b(0, 90, 128, 0)); (int y = 0; y < size; y++) { (int x = 0; x < size; x++) { float distance = vec2::one.distance(vec2(x, y) / radius); float alpha = falloff(distance, 1, 1); int idx = (y * size + x) * 4; float innergradient = falloff(distance, 0.6f, 0.8f); auto color = lerp(bordercolor, centercolor, innergradient); colors[idx + 0] = color.r; colors[idx + 1] = color.g; colors[idx + 2] = color.b; //alpha colors[idx + 3] = (glbyte)clampf(alpha * 256.f + 0.5f, 0.f, 255.f); } } auto txt = new texture2d(); txt->initwithdata(colors, size * size * 4, texture2d::pixelformat::rgba8888, size, size, size(size, size)); delete[] colors; return txt; }
and use just:
sprite::createwithtexture(generateradialgradienttexture(radius));
but result different:
i investigated shader code of questions , developed similar algorithm in c++. algorithm linearly interpolates between 2 colors, starting @ center point, inner color, radially outwards outer color.
c++ algorithm generates texture size, specified input parameters:
#include <vector> // std::vector #include <math.h> // sqrt texture2d * textureradialgradientcreate( int widht, int height, const color4b &startcolor, const color4b &endcolor, float radius, const vec2 ¢er, float expand ) { vec4 scol( startcolor.r / 255.0, startcolor.g / 255.0, startcolor.b / 255.0, startcolor.a / 255.0 ); vec4 ecol( endcolor.r / 255.0, endcolor.g / 255.0, endcolor.b / 255.0, endcolor.a / 255.0 ); std::vector<unsigned char> plane( widht * height * 4, 0 ); ( int y = 0; y < height; ++ y ) { ( int x = 0; x < widht; ++ x ) { float dx = x - center.x; float dy = y - center.y; float d = sqrt( dx*dx + dy*dy ) / radius; vec4 mixcol( 0.0f, 0.0f, 0.0f, 0.0f ); if ( expand < 1.0f && d < 1.0f ) { float = ( d - expand ) / ( 1.0 - expand ); mixcol = (d <= expand) ? scol : ( 1.0 - ) * scol + a*ecol; } size_t = ( y * widht + x ) * 4; plane[i+0] = (unsigned char)(mixcol.x * 255.0f); plane[i+1] = (unsigned char)(mixcol.y * 255.0f); plane[i+2] = (unsigned char)(mixcol.z * 255.0f); plane[i+3] = (unsigned char)(mixcol.w * 255.0f); } } texture2d *texture = new texture2d(); if ( texture != nullptr ) texture->initwithdata( plane.data(), plane.size() / 4, texture2d::pixelformat::rgba8888, widht, height, cocos2d::size(widht, height) ); return texture; }
e.g. quadratic texture wiht size of 600*600 , gradient highlight in center of texture:
int w = 600; int h = 600; float rad = ( w < h ? w : h ) / 2.0f; vec2 cpt( w / 2.0f, h / 2.0f ); texture = textureradialgradientcreate( w, h, layer_startcolor, layer_endcolor, rad, cpt, layer_expand );
extension answer
i don't know, maybe radial shader can optimized?
the conditional branches can avoided, using glsl clamp
function, limiting interpolation parameter of mix
function range (0, 1).
suggest optimize fragment shader this:
#ifdef gl_es varying lowp vec4 v_position; #else varying vec4 v_position; #endif uniform vec4 u_startcolor; uniform vec4 u_endcolor; uniform vec2 u_center; uniform float u_radius; uniform float u_expand; void main() { float d = distance(v_position.xy, u_center) / u_radius; float = (d - u_expand) / (1.0 - u_expand); gl_fragcolor = mix( u_startcolor, u_endcolor, clamp(0.0, 1.0, a) ); }
Comments
Post a Comment