ThreeJS: Weird object clipping in Chrome for Android - android

I have a "2D" scene (Z pointing up) with a plane geometry as the game arena set like this:
var arenaMesh = new THREE.Mesh(
new THREE.PlaneGeometry(SceneWidth, SceneHeight),
new THREE.MeshLambertMaterial({
map: arenaTexture,
emissive: 0xffffff
}));
arenaMesh.position.x = SceneWidth / 2;
arenaMesh.position.y = SceneHeight / 2;
arenaMesh.position.z = 0;
arenaMesh.receiveShadow = true;
The game object is set like this (a really flat box):
var size = 20;
var bodyMesh = new THREE.Mesh(
new THREE.BoxGeometry(size, size, 0.01),
new THREE.MeshLambertMaterial({
map: bodyTexture,
alphaTest: 0.65,
emissive: 0xeeeeee
}));
bodyMesh.position.x = x0;
bodyMesh.position.y = y0;
bodyMesh.position.z = 5.0;
bodyMesh.castShadow = true;
I'm using BoxGeometry here due to some shadow problems I had before.
Now, the problem is that this works perfectly fine on my desktop (FF and Chrome): my fake 2D game object is rendered and it casts a shadow on the game arena. However, on Nexus 7 I can see only the shadow of the object! After some debugging, I noticed that If I set the z-position of the game object to a much bigger value, like z=15.0 it gets rendered. Unfortunately this is not acceptable, because then the object seems like it's flying. Lowering the game arena plane to e.g. z=-15.0 has the same effect. What the heck could cause this? I seems like the precision is somehow completely lost there. Why is the shadow still there correctly?

Based on the comments added to my question, the solution for the problem was to set zNear to a higher value. Apparently the ratio of zNear and zFar affects the precision of Z-buffer and thus fixes problems on Nexus 7.

Related

Unity Normal Maps don't work on Android device

I'm an experienced native iOS developer making my first foray into Android through Unity. I'm trying to set up a custom shader, but I'm having some trouble with the Normal maps. I've got them working perfectly in the Unity simulator on my computer, but when I build to an actual device (Samsung Galaxy S8+), the Normal maps don't work at all.
I'm using Mars as my test case. Here's the model running in the simulator on my computer:
And here's a screenshot from my device, running exactly the same code.
I've done a LOT of research, and apparently using Normal maps on Android with Unity is not an easy thing. There are a lot of people asking about it, but almost every answer I've found has said the trick is to override the texture import settings, and force it to be "Truecolor" which seems to be "RGBA 32 Bit" according to Unity's documentation. This hasn't helped me, though.
Another thread suggested reducing the Asino Level to zero, and another suggested turning off Mip Maps. I don't know what either of those are, but neither helped.
Here's my shader code, simplified but containing all references to Normal mapping:
void surf (Input IN, inout SurfaceOutputStandard o) {
half4 d = tex2D (_MainTex , IN.uv_MainTex);
half4 n = tex2D (_BumpMap , IN.uv_BumpMap);
o.Albedo = d.rgb;
o.Normal = UnpackNormal(n);
o.Metallic = 0.0;
o.Smoothness = 0.0;
}
I've seen some threads suggesting replacements for the "UnpackNormal()" function in the shader code, indicating that it might not be the thing to do on Android or mobile in general, but none of the suggested replacements have changed anything for better or worse: the normal maps continue to work in the simulator, but not on the device.
I've even tried making my own normal maps programmatically from a grayscale heightmap, to try to circumvent any import settings I may have done wrong. Here's the code I used, and again it works in the simulator but not on the device.
public Texture2D NormalMap(Texture2D source, float strength = 10.0f) {
Texture2D normalTexture;
float xLeft;
float xRight;
float yUp;
float yDown;
float yDelta;
float xDelta;
normalTexture = new Texture2D (source.width, source.height, TextureFormat.RGBA32, false, true);
for (int y=0; y<source.height; y++) {
for (int x=0; x<source.width; x++) {
xLeft = source.GetPixel (x - 1, y).grayscale * strength;
xRight = source.GetPixel (x + 1, y).grayscale * strength;
yUp = source.GetPixel (x, y - 1).grayscale * strength;
yDown = source.GetPixel (x, y + 1).grayscale * strength;
xDelta = ((xLeft - xRight) + 1) * 0.5f;
yDelta = ((yUp - yDown) + 1) * 0.5f;
normalTexture.SetPixel(x,y,new Color(xDelta,yDelta,1.0f,yDelta));
}
}
normalTexture.Apply();
return normalTexture;
}
Lastly, in the Build Settings, I've got the Platform set to Android and I've tried it using Texture Compression set to both "Don't Override" and "ETC (default)". The former was the original setting and the latter seemed to be Unity's suggestion both by the name and in the documentation.
I'm sure there's just some flag I haven't checked or some switch I haven't flipped, but I can't for the life of me figure out what I'm doing wrong here, or why there would be such a stubborn difference between the simulator and the device.
Can anyone help a Unity newbie out, and show me how these damn Normal maps are supposed to work on Android?
Check under:
Edit -> Project Settings -> Quality
Android is usually set to Fastest.

How to make TMXTiledMap responsive?

My game is a 2D car-based one, with a straight infinite map where I've finally been able to add some random obstacles. There are only 3 positions the car can be at, and everything is working fine.
The point is that I've recently noticed that it is not responsive, and tried to make it responsive by adding a line like these one to the AppDelegate.cpp:
glview->setDesignResolutionSize(1024.0, 600.0, kResolutionFixedWidth);
I've tried to use kResolutionFixedWidth, kResolutionFixedHeight and all others 5 variables you can put there, but I only got black lines along the screen and every single screen breakdown you can imagine -.-'
I can figure out I need to resize my TMXTiledMap manually because of the nature of tiles (I did it with Tiled), but I don't know how to face this problem.
Note that I'm currently developing for a 1024x600 Android device but I would want to support at least the most common resolutions for both tablets and smartphones.
There are probably 2 resolution policies you want to use.
If you use No Border then you shouldn't see any black bars, but the engine will crop your design resolution so you won't want to put UI in the corners, or you'll want to use Visible Origin and Visible Size to calculate positions.
If you use Exact Fit you should set the design resolution to the devices exact size, and then you're responsible for positioning and scaling everything correctly to avoid distortion.
You will need to scale your art depending on your policy and design resolution choices if you are seeing black bars.
Have you read through this wiki page?
http://www.cocos2d-x.org/wiki/Multi_resolution_support
Here's what we do for one of our games:
auto director = Director::getInstance();
auto glview = director->getOpenGLView();
float contentScaleFactor = 1.f;
// Set the design resolution
Size frameSize = glview->getFrameSize();
Size designSize = glview->getDesignResolutionSize();
CCLOG("defaults:");
CCLOG("framesize = {%f,%f}", frameSize.width, frameSize.height);
CCLOG("visibleSize = {%f,%f}", glview->getVisibleSize().width, glview->getVisibleSize().height);
CCLOG("designSize = {%f,%f}", designSize.width, designSize.height);
CCLOG("contentscalefactor = %f", director->getContentScaleFactor());
Vec2 origin = director->getVisibleOrigin();
CCLOG("visibleSize = %s", CStrFromSize(director->getVisibleSize()));
CCLOG("origin = {%f,%f}", origin.x, origin.y);
// Retina?
contentScaleFactor = director->getContentScaleFactor();
float designWidth = frameSize.width / contentScaleFactor;
float designHeight = frameSize.height / contentScaleFactor;
CCLOG("contentScale = %f, designWidth/Height = {%f,%f}", contentScaleFactor, designWidth, designHeight);
glview->setDesignResolutionSize(designWidth, designHeight, ResolutionPolicy::EXACT_FIT);
// we designed the game for 480x320 (hence the divisors)
// used to scale full screen backgrounds
float fullWidthScaleFactor = designWidth/480.f;
// used to scale up most UI
float largeScaleFactor = floorf(designHeight/320.f);
// round to closest HALF step (1.0,1.5,2.0,2.5,3.0,etc)
// used for scaling UI where pixel art is affected by .1 scales
float largeScaleFactorExact = floorf(designHeight * 2.f / 320.f) * 0.5f;
// used to scale up UI that must be touchable (larger on high desnsity)
float largeScaleFactorUI = STROUND(designHeight / 320.f);
// this forces minimum of 1x scale (we should just not support these devices)
float scaleFitAll = designWidth > designHeight ? designHeight/320.f : designWidth/480.f;
if(largeScaleFactor < 1.f)
largeScaleFactor = scaleFitAll;
if(largeScaleFactorExact < 1.f)
largeScaleFactorExact = scaleFitAll;
if(largeScaleFactorUI < 1.f)
largeScaleFactorUI = scaleFitAll;

Threejs - Import collada model looks funny on Chrome Android, textures are not properly loaded

I tried to import a .dae model using the provided ColladaLoader, it worked great on desktop but on Chrome on Android I'm issuing some problems. The Geometry is loaded, but the textures are not properly loaded. It seems that textures are applied to the object but they are not rendered with the proper colors , it looks all light blue.
Any one has an idea what I'm doing wrong? Is something related with anisotropic filtering (since I noticed that is not supported on chrome mobile ?)
The answer from the three.js creator himself is that this is a bug in the Qualcomm GPU driver related to the fog glsl code. To avoid this bug, turn off all phong mateirals' fog attribute.
phongMaterial.fog = false;
No fog on android until this bug is fixed.
Comparing the working and non-working examples on threejs.org site, I found the culprit for the bluish texture. It is the shadow mapping of directional light. Somehow this code below is causing problem on android devices.
light.castShadow = true;
light.shadowMapWidth = 2048;
light.shadowMapHeight = 2048;
var d = 390;
light.shadowCameraLeft = -d * 2;
light.shadowCameraRight = d * 2;
light.shadowCameraTop = d * 1.5;
light.shadowCameraBottom = -d;
light.shadowCameraFar = 3500;

as3 air and screen size dection issue on devices

I have worked so hard on an app that displays perfectly on my Galaxy Note 3. However, it does not display right on iPhone and also one other Droid I tested on. My issue is with addChild() and then resizing it to fit the screen. For some reason when I add the Background (addBG(); The screen size works but if I load addChild to the BG, this works great on my Note 3 but not on the iPhone or another android device.
My issue is with the screenX, screenY var I created. They seem to be different for devices. Or it is a "rendering order issue" I am not sure. Would be so greatful for the help to fix this issue so it looks great on each phone. I have read some tuts on this subject but they are confusing. I think my code is close, I hope, and maybe it just needs a tweak. !
Here is a shot of the about screen on an IPhone. See the white does not fit the whole screen.
and Here is a shot from my Droid Note 3.
Declared Vars in a package:
This is not my full code, of course but only that which I believe is relevant.
public var screenX:int;
public var screenY:int;
public function Main()
{
if (stage)
{
setStage();
addBG();
}
}
public function setStage()
{
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
if (flash.system.Capabilities.screenResolutionX > stage.stageWidth)
{
screenX = stage.stageWidth;
screenY = stage.stageHeight;
}
else
{
screenX = flash.system.Capabilities.screenResolutionX;
screenY = flash.system.Capabilities.screenResolutionY;
}
}
This works: addBG();
public function addBG()
{
theBG = new BG();
addChild(theBG);
theBG.width = screenX;
theBG.height = screenY;
}
This does not: addAbout();
public function addAbout()
{
About = new viewAbout();
About.width = screenX;
About.height = screenY;
theBG.addChild(About);
TweenMax.fromTo(About,1, {alpha:0}, {alpha:1, ease:Expo.easeOut} );
}
UPDATE: And yet another more complex load is also called from a button and having the same issue. I hope you see the logic of what I am trying to do. First set the BG to the device then load and resize content to fit proportionally into the BG I loaded. The reason being, the BG will be distorted to different proportions and that's ok, but the content can not. So here is the example that loads content into the BG and then content into that container.
public function addRosaryApp()
{
Rosary = new viewRosaryApp();
Rosary.width = screenX;
Rosary.height = screenY;
theBG.addChild(Rosary);
TweenMax.fromTo(Rosary,1, {alpha:0}, {alpha:1, ease:Expo.easeOut} );
contentRosary = new contentRosaryApp();
theBG.addChild(contentRosary);
contentRosary.width = screenX;
contentRosary.scaleY = contentRosary.scaleX;
contentRosary.x = screenX/2 - contentRosary.width/2;
contentRosary.y = menuBanner.height;
}
Have you tried adding the child to stage first, and then setting the size? That's the only difference I can see between addBG and addAbout
About = new viewAbout();
theBG.addChild(About); // do this first
About.width = screenX; // then set width
About.height = screenY; // and height
I think your problem may have to do with either of several things.
My findings so far from my own devices (an Ipad Air, an iphone 4S, an LG G2 and an Acer Iconia A500) is that the only device size that's being reported correctly at all times is the stage.fullScreenWidth and the stage.fullScreenHeight
1st, Android reports Capabilities.screenResolutionX as the LONG side of your Android device.
IOS devices however report the SHORT side of your device to Capabilities.screenResolutionX.
2nd, stage.stageWidth and stage.stageHeight seem to report the wrong size on both Android and IOS.
And in fact if you check these before and after setting stage.scaleMode and stage.align then the values will differ completly (although Android will show it almost correctly).
My suggestion is that you set a base size (width and height) for your app and then compare it with the actual stage.fullScreenWidth and stage.fullScreenHeight reported by the device. That way you can get some nice scaleratios to use to scale your displayobjects. That's what I'm currently on my apps and it scales just fine :-)

Is it a big difference to use Box2D in native Android game instead of Box2Dweb with HTML5 canvas?

I have to write a simulation of balls falling in a container for Android. First, I tried using Box2Dweb in a HTML5 canvas, but with 3 solid bodies and 50 balls, it performs really slow, even in desktop computer with Firefox (curiously, with Chrome it performs really well). Here is the live demo.
And here is the code.
var b2Vec2 = Box2D.Common.Math.b2Vec2
, b2BodyDef = Box2D.Dynamics.b2BodyDef
, b2Body = Box2D.Dynamics.b2Body
, b2FixtureDef = Box2D.Dynamics.b2FixtureDef
, b2Fixture = Box2D.Dynamics.b2Fixture
, b2World = Box2D.Dynamics.b2World
, b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape
, b2CircleShape = Box2D.Collision.Shapes.b2CircleShape
, b2DebugDraw = Box2D.Dynamics.b2DebugDraw
;
var world = new b2World(
new b2Vec2(0, 10) //gravity
, true //allow sleep
);
var fixDef = new b2FixtureDef;
fixDef.density = 1.0;
fixDef.friction = 0.5;
fixDef.restitution = 0.2;
var bodyDef = new b2BodyDef;
//create ground
var canvas = $('#canvas'),
offsetX = (canvas.width() / 30) / 4,
offsetY = (canvas.height() / 30) / 5; //center the machine on the screen.
bodyDef.type = b2Body.b2_staticBody;
fixDef.shape = new b2PolygonShape;
fixDef.shape.SetAsBox(5, 0.5);
bodyDef.position.Set(5 + offsetX, 10 + offsetY);
world.CreateBody(bodyDef).CreateFixture(fixDef);
fixDef.shape.SetAsBox(0.5, 7);
bodyDef.position.Set(0 + offsetX, 3 + offsetY);
world.CreateBody(bodyDef).CreateFixture(fixDef);
bodyDef.position.Set(10 + offsetX, 3 + offsetY);
world.CreateBody(bodyDef).CreateFixture(fixDef);
//create some objects
var numObjects = 50;
bodyDef.type = b2Body.b2_dynamicBody;
for(var i = 0; i < numObjects; ++i) {
fixDef.shape = new b2CircleShape(
0.6 //Math.random() + 0.1 //radius
);
bodyDef.position.x = Math.random() * 9 + offsetX;
bodyDef.position.y = Math.random() * 9 - 2;
world.CreateBody(bodyDef).CreateFixture(fixDef);
}
//setup debug draw
var debugDraw = new b2DebugDraw();
debugDraw.SetSprite(document.getElementById("canvas").getContext("2d"));
debugDraw.SetDrawScale(30.0);
debugDraw.SetFillAlpha(0.5);
debugDraw.SetLineThickness(1.0);
debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
world.SetDebugDraw(debugDraw);
var rate = 60;
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / rate);
};
})();
//update
(function update() {
requestAnimFrame(update);
world.Step(1 / rate, 10, 10);
world.DrawDebugData();
world.ClearForces();
})();
My question is, what if I write a native implementation using Android canvas (no the HTML5 one) and Box2D? Will I achieve a smooth movement for the balls?
And the hidden cuestion is: Is the performance so poor because of drawing or because of so many physical calculus? Usually, how much performance can I win going to native when there are physical calculus involved?
The main difference is that with HTML5 and Box2DWeb your game is limited by the browser optimizations and your own code optimizations.
Some browsers doesn't have hardware accelerated canvas; or the browser's Javascript Engine are not optimized enough. You can see that difference even in desktop browsers. Google Chrome for instance do a lot of optimizations behind the scene inside his V8 engine.
Because there's so many differences between Browser's Javascript Engines (as you notice with Firefox and Chrome) it's harder to do code optimizations for all of them.
Since mobile hardware is usually very limited and the mobile browsers are not evolved enough, make optimizations to active high frame rates is very painful and may not be accomplished at all.
For instance, the code you provide might suffer in browsers that haven't no native requestAnimationFrame. Also, drawing shapes on the fly is too expensive for low hardware devices. So the answer for your last question might be: both, drawing and the physics calculation are killing the performance. But the major bottleneck is the drawing for sure.
The use of native Android canvas allow you quick responses since the game will use the device hardware more efficiently than browsers.
In addiction, the Box2D for android is much more efficient than the Box2DWeb(a nice port of the original Box2D but still suffer with performance gaps).
Bottomline, if your target is primary Android devices you should go with the native implementation. But if you want to target a huge range of browsers and devices without do code again for every platform, go with the beautiful HTML5. (Every choice implies consequences, you have to choose that which best suit your needs).
If you decide goes with HTML5 canvas see this answer. (It's you own question, by the way :) )
And if you are really engaged learn a little about WebGL and OpenGL ES.

Categories

Resources