[Solved] ResolutionPolicy::FIXED_HEIGHT adds weird offset to Shader positions

Hello i’m using a custom shader and things were working just fine till my ResolutionPolicy was default or ResolutionPolicy::FIXED_WIDTH but my game required ResolutionPolicy::FIXED_HEIGHT so as soon as i changed my policy to FIXED_HEIGHT , i started getting this weird offset to my shader positions its like everything generated by my shader is shifted bit right side , here is code for my vertex shader and how i change my ResolutionPolicy

I changed my Resolution Policy by adding this line in AppDelegate.cpp

director->getOpenGLView()->setDesignResolutionSize(480, 800 ,ResolutionPolicy::FIXED_HEIGHT);

Vertex Shader

attribute vec4 a_position;
uniform vec4 u_color;
uniform float u_pointSize;

attribute vec2 a_texCoord;
attribute vec4 a_color;

varying vec4 v_fragmentColor;
varying vec2 v_texCoord;

void main()
{
    gl_Position = CC_PMatrix * a_position;
    v_fragmentColor = a_color;
    v_texCoord = a_texCoord;
}

Try using CC_MVPMatrix instead of CC_PMatrix

I believe the ModelView matrix is required to transform into design space correctly.

@almax27 thanks for the reply but i already tried it out with CC_MVPMatrix i did not worked
@stevetranby any thought about this problem

i talked about this on a OpenGl group and people were saying it might be engine (cocos2d-x) bug

Are you sure you’re not seeing expected behavior since FIXED_HEIGHT will draw the game centered with vertical black bars. You can quickly test this by adding a LayerColor into the scene and you’ll notice it’ll be offset by (screen width - design width with aspect scaling) / 2. You could also test regular sprites (without custom shader) to examine how positioning works with FIXED_HEIGHT.

@stevetranby No i’m not seeing any sort of black bars , also the problem is something like this i have a shader which generates a circle , and i can manipulate the center of the circle from my c++ code like this shaderLayer->setCirclePosition(Pos); , so earlier with default resolution policy or with FIXED_WIDTH , i used to do mapping of the shader generated circle with my hero sprite’s position and i used to do it like this shaderLayer->setCirclePosition(heroSprite->getPosition()); so my shader circle used to overlap my sprite but when i tried the same thing i.e shaderLayer->setCirclePosition(heroSprite->getPosition()); with resolution policy FIXED_HEIGHT they never overlapped like they used to do before, and when i change back the resolution again to FIXED_WIDTH or default it works

There’s possibly other ways to handle the drawing or visual of what you’re trying to accomplish that is policy agnostic.

Have you found out what heroSprite->getPosition() gives you (and if they’re equal) in when using each policy?
Have you tested specific values for Pos: {0,0}, {-100,0}, {0,-100}, {100,0}, {0,100}, etc?

It’s possibly an issue with what shaderLayer is and how it’s drawing the “circle” that you’re defining the position.

It’s possibly the projection matrix since it varies depending on design resolution and policy. See GLViewImpl::setViewPortInPoints.

@stevetranby okay i tried setting coordinates manually ,

Added screenshot sample of {100,100} test case

with FIXED_WIDTH:
Hero’s coordinate {0,0} - Shader’s coordinate {0,0} -> They both were overlapping however only 1/4 of circle (of both of them) was visible to me as rest went out of the view.

Hero’s coordinate {0,100} - Shader’s coordinate {0,100} -> Perfectly Overlapping
Hero’s coordinate {100,0} - Shader’s coordinate {100,0} -> Perfectly Overlapping
Hero’s coordinate {100,100} - Shader’s coordinate {100,100} -> Perfectly Overlapping

with FIXED_HEIGHT:
Hero’s coordinate {0,0} - Shader’s coordinate {0,0} -> Only 1/4 of circle (of both of them) was visible to me as rest went out of the view so cant say if they were perfectly overlapping or not

Hero’s coordinate {0,100} - Shader’s coordinate {0,100} -> Did not overlap
Hero’s coordinate {100,0} - Shader’s coordinate {100,0} -> Did not overlap
Hero’s coordinate {100,100} - Shader’s coordinate {100,100} -> Did not overlap

ShaderLayer->setCirclePosition(pos) just takes pos and update uniform vec2 position with argument pos

My shader is also simple nothing complex, here is my fragment shader code and vertex shader i already pasted on top of this thread.

varying vec4 v_fragmentColor;
varying vec2 v_texCoord;

uniform vec2 position;
uniform float lightSize;

void main()
{
    float abs;
    float darkness = 0.9;
    
    vec4 diffuseColor = texture2D(CC_Texture0,v_texCoord);
    
    gl_FragColor = vec4(vec3(gl_FragColor.xyz), 0.9);
    vec2 centerPos = gl_FragCoord.xy - vec2(position.x, position.y);


    //calculate light density
    float z = sqrt(lightSize*lightSize - centerPos.x*centerPos.x - centerPos.y*centerPos.y);
    z /= lightSize;

    
    if (length(centerPos) < lightSize) {
        abs = darkness - z;

        gl_FragColor = v_fragmentColor * vec4(255.0, 255.0, 51.0, 0.4*255.0)/255.0;
    }
}

I’m also attaching the screenshots of how things vary for me (red ball is hero)
FIXED_HEIGHT

Default or FIXED_WIDTH

It’s effectively based on the fact that the regular sprite positioning is based on relative position and scale depending on whether you use FIXED_HEIGHT or FIXED_WIDTH.

Check the getWinSize() for each of these two policies and you’ll likely find that one is larger size than the other. Your shader will need to probably take in the “resolution” of the OpenGL viewport as well as the light position.

For example here’s a quick test:
design resolution: 480 x 800
window(device) resolution: 540 x 1136 (for testing, non-standard)
FIXED_WIDTH -> ws = 381, 800 (looks “larger” because it’s “drawing” less pixels)
FIXED_HEIGHT -> ws = 480, 1010 (looks “smaller” because it’s “drawing” more pixels)

Can try this, to fix the position.

auto dr = Director::getInstance()->getOpenGLView()->getDesignResolutionSize();
auto fs = Director::getInstance()->getOpenGLView()->getFrameSize();
auto ws = Director::getInstance()->getWinSize();
auto vs = Director::getInstance()->getVisibleSize();
log("dr = %f,%f", dr.width, dr.height);
log("fs = %f,%f", fs.width, fs.height);
log("ws = %f,%f", ws.width, ws.height);
log("vs = %f,%f", vs.width, vs.height);
auto pos = hero->getPosition();
auto ratio = Vec2(fs.width/ws.width, fs.height/ws.height);
glstate->setUniformVec2("position", Vec2(pos.x * ratio.x, pos.y * ratio.y));
1 Like

@stevetranby You are a Genius bro ! :open_mouth: it worked , i just pasted your code there and it worked , Thanks man Problem Solved