Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Pixel draw imprecision on android. #2000

Closed
dganzella opened this issue Sep 25, 2017 · 30 comments
Closed

[BUG] Pixel draw imprecision on android. #2000

dganzella opened this issue Sep 25, 2017 · 30 comments
Assignees
Labels

Comments

@dganzella
Copy link

dganzella commented Sep 25, 2017

Hello!

Im having trouble with pixel perfect on Android.

The pixels size are varying. It seems that it happening around the borders.

Image

You can also see that on a web build the pixels size are rendering properly.

Specs:
Zenfone 2, Android 5.0, 1920x1080
Cocos Creator 1.6.1 Windows
Mode: Portrait

Sample Project

ps2. On the extra info, this happens too with tiled maps. Also, weirdly enough, "mask" component is working properly on android, but on web its offseting by 1 pixel (reducing 1 pixel on width and height makes the desired rect size).

@jareguo
Copy link
Contributor

jareguo commented Sep 25, 2017

Is it the same problem as #1963 ?

ps2. The mask size should be fixed in 1.6.2.

@dganzella
Copy link
Author

Hmm i dont think so, because im testing on Android. That issue is for iOS.

@jareguo
Copy link
Contributor

jareguo commented Sep 25, 2017

Not just iOS, that issue maybe happens on every platform.

@dganzella
Copy link
Author

I see.

I tried changing ccShader_PositionTextureColor_noMVP.vert and ccShader_PositionTextureColor_noMVP.frag with highp, into \build\jsb-default\frameworks\cocos2d-x\cocos\renderer but it didnt work. :(

These lines:
https://github.com/cocos2d/cocos2d-x/blob/v3/cocos/renderer/ccShader_PositionTextureColor_noMVP.frag#L28

https://github.com/cocos2d/cocos2d-x/blob/v3/cocos/renderer/ccShader_PositionTextureColor.vert#L33

no changes :(

@dganzella
Copy link
Author

I also tried replacing every ocurrence of lowp and mediump with highp, and no changes too :(

@ivcoder
Copy link

ivcoder commented Sep 26, 2017

Please, try this
cocos2d/cocos2d-x#17487

@dganzella
Copy link
Author

dganzella commented Sep 26, 2017

ok, I tried changing:

return (_winSizeInPoints.height / 1.1566f);
to
return (_winSizeInPoints.height / 1.154700538379252f);

on

build\jsb-default\frameworks\cocos2d-x\cocos\base\CCDirector.cpp

file.

It recompiled:
[armeabi-v7a] Compile++ arm : cocos2dx_internal_static <= CCDirector.cpp

but didnt work :(

any tips on where I can start to debug it?

I was thinking about going to CCTexture2D.cpp drawAtPoint and drawInRect and start logging from there and backwards.

@dganzella
Copy link
Author

this is the log:

09-26 09:46:27.251: I/art(17938): Late-enabling -Xcheck:jni
09-26 09:46:27.251: D/houdini(17938): [17938] Initialize library(version: 5.0.7a_y.48167 RELEASE)... successfully.
09-26 09:46:27.311: V/Monotype(17938): SetAppTypeFace- try to flip, app = org.cocos2d.helloworld
09-26 09:46:27.317: V/Monotype(17938): Typeface getFontPathFlipFont - systemFont = default#default
09-26 09:46:27.326: V/Monotype(17938): SetAppTypeFace- try to flip, app = org.cocos2d.helloworld
09-26 09:46:27.326: V/Monotype(17938): Typeface getFontPathFlipFont - systemFont = default#default
09-26 09:46:27.657: D/houdini(17938): [17938] Added shared library /data/app/org.cocos2d.helloworld-1/lib/arm/libcocos2djs.so for ClassLoader by Native Bridge.
09-26 09:46:27.659: D/JniHelper(17938): JniHelper::setJavaVM(0xf0b61644), pthread_self() = -142773920
09-26 09:46:27.659: D/main(17938): cocos_android_app_init
09-26 09:46:27.661: D/Cocos2dxHelper(17938): isSupportLowLatency:false
09-26 09:46:27.667: D/Cocos2dxHelper(17938): sampleRate: 48000, framesPerBuffer: 1152
09-26 09:46:27.667: D/Java_org_cocos2dx_lib_Cocos2dxHelper.cpp(17938): nativeSetAudioDeviceInfo: sampleRate: 48000, bufferSizeInFrames: 1152
09-26 09:46:27.706: D/Cocos2dxActivity(17938): model=ASUS_Z00AD
09-26 09:46:27.706: D/Cocos2dxActivity(17938): product=WW_Z00A
09-26 09:46:27.707: D/Cocos2dxActivity(17938): isEmulator=false
09-26 09:46:27.821: D/Cocos2dxActivity(17938): onResume()
09-26 09:46:27.826: D/AudioFocusManager(17938): requestAudioFocus succeed
09-26 09:46:27.835: D/OpenGLRenderer(17938): Render dirty regions requested: true
09-26 09:46:27.847: D/Atlas(17938): Validating map...
09-26 09:46:27.907: I/OpenGLRenderer(17938): Initialized EGL, version 1.4
09-26 09:46:27.907: W/OpenGLRenderer(17938): Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...
09-26 09:46:27.919: D/OpenGLRenderer(17938): Enabling debug mode 0
09-26 09:46:28.037: D/cocos2d-x(17938): {
09-26 09:46:28.037: D/cocos2d-x(17938): gl.supports_OES_packed_depth_stencil: true
09-26 09:46:28.037: D/cocos2d-x(17938): gl.supports_vertex_array_object: true
09-26 09:46:28.037: D/cocos2d-x(17938): gl.supports_BGRA8888: true
09-26 09:46:28.037: D/cocos2d-x(17938): cocos2d.x.version: 1.6.1
09-26 09:46:28.037: D/cocos2d-x(17938): gl.supports_discard_framebuffer: true
09-26 09:46:28.037: D/cocos2d-x(17938): cocos2d.x.compiled_with_profiler: false
09-26 09:46:28.037: D/cocos2d-x(17938): gl.supports_PVRTC: true
09-26 09:46:28.037: D/cocos2d-x(17938): cocos2d.x.build_type: DEBUG
09-26 09:46:28.037: D/cocos2d-x(17938): gl.renderer: PowerVR Rogue G6430
09-26 09:46:28.037: D/cocos2d-x(17938): gl.supports_OES_depth24: true
09-26 09:46:28.037: D/cocos2d-x(17938): gl.supports_ETC1: true
09-26 09:46:28.037: D/cocos2d-x(17938): gl.supports_OES_map_buffer: true
09-26 09:46:28.037: D/cocos2d-x(17938): cocos2d.x.compiled_with_gl_state_cache: true
09-26 09:46:28.037: D/cocos2d-x(17938): gl.version: OpenGL ES 3.1 build 1.4@3283119
09-26 09:46:28.037: D/cocos2d-x(17938): gl.supports_NPOT: true
09-26 09:46:28.037: D/cocos2d-x(17938): gl.max_texture_units: 48
09-26 09:46:28.037: D/cocos2d-x(17938): gl.vendor: Imagination Technologies
09-26 09:46:28.037: D/cocos2d-x(17938): gl.max_texture_size: 8192
09-26 09:46:28.037: D/cocos2d-x(17938): }
09-26 09:46:28.038: E/cocos2d-x(17938): cocos2d: warning, Director::setProjection() failed because size is 0
09-26 09:46:28.195: D/Cocos2dxActivity(17938): onWindowFocusChanged() hasFocus=true
09-26 09:46:31.219: D/cocos2d-x debug info(17938): Cocos2d-x-lite v1.6.0
09-26 09:46:35.927: D/cocos2d-x(17938): create rendererRecreatedListener for GLProgramState
09-26 09:46:36.040: D/cocos2d-x(17938): cocos2d: QuadCommand: resizing index size from [-1] to [2560]
09-26 09:46:36.123: D/cocos2d-x debug info(17938): LoadScene 55sO21Jv9Nz6mHAWOcT9fd: 454.4950000000008ms
09-26 09:46:36.139: D/cocos2d-x debug info(17938): InitScene: 13.345000000000255ms
09-26 09:46:36.142: D/cocos2d-x debug info(17938): AutoRelease: 1.443000000000211ms
09-26 09:46:36.144: D/cocos2d-x debug info(17938): Destroy: 0.7969999999995707ms
09-26 09:46:36.146: D/cocos2d-x debug info(17938): Success to load scene: db://assets/Scenes/Main.fire
09-26 09:46:36.148: D/cocos2d-x debug info(17938): AttachPersist: 0.24699999999938882ms
09-26 09:46:36.189: D/cocos2d-x debug info(17938): Activate: 40.33399999999983ms

@dganzella
Copy link
Author

took me two days but i finnaly started to make progress..

it seems that

Scale9SpriteV2 is the "sprite panacea" of cocos creator.

so the mistake should be somewhere between the sacred silence:

void Scale9SpriteV2::draw(cocos2d::Renderer *renderer, const cocos2d::Mat4 &transform, uint32_t flags)

and sleep. I will continue my research

@dganzella
Copy link
Author

dganzella commented Sep 27, 2017

VERT: 0 _ 2.000000, 16.000000, 0.000000
VERT: 0 TEXCOORDINATES _ 0.156250, 0.031250

VERT: 1 _ 2.000000, 0.000000, 0.000000
VERT: 1 TEXCOORDINATES _ 0.156250, 0.968750

VERT: 2 _ 15.000000, 16.000000, 0.000000
VERT: 2 _ TEXCOORDINATES 0.906250, 0.031250

VERT: 3 _ 15.000000, 0.000000, 0.000000
VERT: 3 TEXCOORDINATES _ 0.906250, 0.968750

@dganzella
Copy link
Author

dganzella commented Sep 27, 2017

Ok I think I found the issue.

it seems that CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL is the problem.

its saying:

  • To enabled set it to 1. Disabled by default.

  • @SInCE v0.99.5
    */
    #ifndef CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
    #define CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL 1

but its actually enabled by default.

also, "99%" is a very wild guess. as you can see in this case of a 16x16 pixel, you pick up just 96.875%

@dganzella
Copy link
Author

0.031250, mostly known as half of 1/16.

@dganzella
Copy link
Author

Ok everything works now.
screenshot_2017-09-26-23-46-24
screenshot_2017-09-26-23-38-48

ps1. https://www.youtube.com/watch?v=tAP4tH_2iE8 itsa gooda engine
ps2. victory music: https://www.youtube.com/watch?v=iGqiwr3HnCY

@dganzella
Copy link
Author

Whew. To my surprise, after clearing up the mess and just letting the CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL on 0, i found out that it started showing artifacts on screen... aw shucks.. back to the lab again

@jareguo
Copy link
Contributor

jareguo commented Sep 27, 2017

its saying:

To enabled set it to 1. Disabled by default.

@SInCE v0.99.5
*/
#ifndef CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
#define CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL 1

but its actually enabled by default.

Okay, I am very sorry for that. I knew there was a problem of FIX_ARTIFACTS_BY_STRECHING_TEXEL, but we did fix it in Creator. I couldn’t believe the problem still affects NATIVE platfom by default...

FIX_ARTIFACTS_BY_STRECHING_TEXEL is bull shit and should be disabled by default. But if you are using TiledMap, you still need it, there's no good way to workaround...

@dganzella
Copy link
Author

No problem, we are together in this.

I saw this link:

https://www.makeschool.com/docs/#!/cocos2d/1.4/tilemaps/troubleshooting-tilemaps

// Objective-C
CGFloat scale = [CCDirector sharedDirector].contentScaleFactor;
CGFloat newX = round(layerNode.position.x * scale) / scale;
CGFloat newY = round(layerNode.position.y * scale) / scale;
layerNode.position = CGPointMake(newX, newY);

// Swift
let scale = CCDirector.sharedDirector().contentScaleFactor
let newX = round(layerNode.position.x * scale) / scale
let newY = round(layerNode.position.y * scale) / scale
layerNode.position = CGPoint(x: newX, y: newY)

can't we do something similar in cocos creator? I know it probrably reduces performance at some point, but maybe its a good solution. Maybe a new config.

@dganzella
Copy link
Author

dganzella commented Sep 27, 2017

Tomorrow im gonna try to round the transformation matrixes on every node on every draw and see what happens

@dganzella
Copy link
Author

dganzella commented Sep 27, 2017

So .. i found out that the:

float Director::getZEye(void) const
{
return (_winSizeInPoints.height / 1.154700538379252f);//(2 * tanf(M_PI/6))
}
fix

plus

changing all shaders lowp and mediump ocurrences to highp did the trick.

(I dont know if the shader changes is really necessary.)

Seems to be working now.

@dganzella
Copy link
Author

dganzella commented Sep 27, 2017

Did a test with action moveBy and it still produce artifact if the tiled map stay in non integer pixels.

So it seems that:

1 . return (_winSizeInPoints.height / 1.154700538379252f);//(2 * tanf(M_PI/6)) fix
2. Adding highp everywhere (maybe its not necessary, I will check tomorrow).
3. CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL 0
4. keeping the TileMap on an integer pixels:

cc.Class({
extends: cc.Component,

properties: {
	actualX : 0,
	actualY : 0
},

	onLoad: function () {
	this.actualX = this.node.x;
	this.actualY = this.node.y;
},

 update: function (dt) {
	 
	 this.actualX += (64 * dt);
	 this.actualY += (64 * dt);
	 
	this.node.x = Math.floor(this.actualX);
	this.node.y = Math.floor(this.actualY);
 },

});

Does the trick both on web and android.

@dganzella
Copy link
Author

Yeah the highp stuff it not necessary at all.
gif

@dganzella
Copy link
Author

quick question: is therr a reason to use 3d projection as default for cocos creator?

it seems that the eye stuff is just for 3d

@dganzella
Copy link
Author

it seems that using 2d projection as default or using the 3d precision fix + disabling texel bullshit + rounding the tmx nodes on the C++ itself would be a good permanent solution.

@dganzella dganzella reopened this Sep 27, 2017
@jareguo
Copy link
Contributor

jareguo commented Sep 27, 2017

quick question: is therr a reason to use 3d projection as default for cocos creator?

No... it just for historical reasons. Thanks for help!

@dganzella
Copy link
Author

no problem :)

should I make a pull request? I work at a software house, we have tons of android and ios devices there, I could test the solution and make sure it works everywhere.

@jareguo
Copy link
Contributor

jareguo commented Sep 27, 2017

Sure, it will be greatly appreciated!

@jareguo
Copy link
Contributor

jareguo commented Sep 27, 2017

3d precision synced: cocos/engine-native#865

@dganzella
Copy link
Author

dganzella commented Sep 28, 2017

so, after assessing the problem, I think thats more complicated than I expected

There are 3 types of TMX Maps
They can be Rotated
Not only C++ would need change, but also the JS for web support
The C++ matrix Class is not friendly for setting position at all
Theres also need to test on many different devices, and iOS use sub-pixels

This would actually demand a full month test, I think its more than I can bite :(

So for now, I will humbly post this Script here, that solves the TMX moving issue for me:

cc.Class ({

    extends: cc.Component,

    properties:
    {
        brotherPosition: cc.Node,
        worldScale: 1
    },

    onLoad: function ()
    {        
        this.worldScale = this.node.getNodeToWorldTransform().a;
	var action = cc.moveBy(1, 100, 100);
        this.brotherPosition.runAction(action);
    },

    update: function(dt)
    {
       this.node.position = cc.v2(  Math.round(this.brotherPosition.x * this.worldScale) / this.worldScale, Math.round(this.brotherPosition.y * this.worldScale) / this.worldScale );
    }
});

The idea is to put a brother node and use that node as the TMX node actual position. And always copy the rounded-to-canvas-pixel position on update.

This, combined with:

return (_winSizeInPoints.height / 1.154700538379252f);//(2 * tanf(M_PI/6)) fix
and CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL 0

Should solve the issue for at least a part of the situations.

ps. another thing i noticed is that the dt on the update has a quite low precision. Like 0.016 or 0.018, instead of using more decimal places.

@jareguo
Copy link
Contributor

jareguo commented Sep 28, 2017

Never mind, thanks for help~

@dganzella
Copy link
Author

I see, then I think im gonna close the issue.

by the way, you guys will disable the CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL on next release right?

even though disabling it ma cause artifacts on tmx maps, with it is turned on it the tile look bad anyway (I never posted a screen of how bad it look, but it does, and most since tiles are low pixel)

@jareguo
Copy link
Contributor

jareguo commented Sep 28, 2017

Yes, we will. CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL should be disabled on next release

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants