|
SilverLining for Android
1.0
Skies, 3D clouds, and weather for Android
|
We also provide an integration example for SilverLining with OpenSceneGraph (OSG) for Android. To try it out, you must first have a working OpenSceneGraph built for Android and OpenGL ES 2.0 on your system. http://forum.openscenegraph.org/viewtopic.php?t=10076 provides a good tutorial for getting up and running with OSG for Android.
Specifically, our sample assumes that the ANDROID_NDK environment variable is set to point to your NDK directory, and ANDROID_SDK points to where your Android SDK's are installed (this is where the Android SDK manager installs individual SDK's to, NOT to where you installed the Android SDK itself.)
To try out the OSGAndroidSilverLiningDemo, you must first build its native code. First, you must edit the jni/Android.mk file in the sample to specify where your OSG for Android build is located:
### Main Install dir OSG_ANDROID_DIR := /home/fkane/osgAndroidExampleGLES2
Then from the OSGAndroidSilverLiningDemo directory, run:
$ANDROID_NDK/ndk-build
Next, import this directory into Eclipse as existing Android code (Import / Android / Existing Android Code into Workspace under Eclipse Juno), right click the project, and "run as" an Android application. Your tethered OpenGL ES 2.0 capable device should then run OpenSceneGraph with SilverLining's 3D clouds and skybox in the background, and the OSG cow in the foreground:
Let's explore how it works, so you may integrate SilverLining into your own OSG application for Android.
First, you'll need to include the SilverLining static libraries for gnustl as part of your Android.mk file:
include $(CLEAR_VARS) LOCAL_MODULE := silverlining_prebuilt LOCAL_SRC_FILES := ../../static_lib_gnustl/$(TARGET_ARCH_ABI)/libsilverlining_static.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../../include include $(PREBUILT_STATIC_LIBRARY)
You may then add silverlining_prebuilt to your activity's LOCAL_STATIC_LIBRARIES line. You'll also want to include the SkyDrawable.cpp and CloudsDrawable.cpp files from our OSG example and their associated headers as part of your own project, adding the cpp files to your LOCAL_SRC_FILES.
SkyDrawable and CloudsDrawable wrap SilverLining in OSG-friendly objects. The OsgMainApp.cpp file included with the sample provides a good example on how to use these classes in your OSG application. Its integrateSilverLining method is of particular interest:
void integrateSilverLining(osg::ref_ptr<osg::Node> sceneGraphRoot, osgViewer::Viewer& viewer, AAssetManager *assetManager) { // No need for OSG to clear the color buffer, the sky will fill it for you. viewer.getCamera()->setClearMask(GL_DEPTH_BUFFER_BIT); // Make sure lighting mode is correct for setting sun direction in SilverLining's world space viewer.setLightingMode(osgViewer::View::SKY_LIGHT); // Instantiate an Atmosphere and associate it with this camera. If you have multiple cameras // in multiple contexts, be sure to instantiate seperate Atmosphere objects for each. SilverLining::Atmosphere *atm = new SilverLining::Atmosphere("Your user name", "Your license code"); osg::notify(osg::ALWAYS)<<"Creating SilverLining resource loader..."<<std::endl; // Pass the Android asset manager to SilverLining so it can load its own resources AndroidResourceLoader *rl = SL_NEW AndroidResourceLoader(assetManager); atm->SetResourceLoader(rl); // Add the sky (calls Atmosphere::DrawSky and handles initialization once you're in // the rendering thread) osg::Geode *skyGeode = new osg::Geode; SkyDrawable *skyDrawable = new SkyDrawable(&viewer); skyGeode->addDrawable(skyDrawable); skyGeode->setCullingActive(false); /* If you let OSG auto-calculate the near and far clip planes; it'll exclude the sky box and clouds. One solution is to set the near and far clip planes explicitly like this: */ #ifdef FIXED_NEAR_FAR viewer.getCamera()->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR); double fovy, aspect, zNear, zFar; viewer.getCamera()->getProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); viewer.getCamera()->setProjectionMatrixAsPerspective(fovy, aspect, 10, 100000); #endif /* or, you can use the included projection matrix callback to intercept how OSG computes the near and far clip planes and take SilverLining's objects into account, like this: */ #ifndef FIXED_NEAR_FAR SilverLiningProjectionMatrixCallback *cb = new SilverLiningProjectionMatrixCallback( atm, viewer.getCamera()); viewer.getCamera()->setClampProjectionMatrixCallback(cb); cb->setSkyDrawable(skyDrawable); #endif AtmosphereReference *ar = new AtmosphereReference; ar->atmosphere = atm; viewer.getCamera()->setUserData(ar); // Use a RenderBin to enforce that the scene gets drawn first, then the sky, then the clouds skyGeode->getOrCreateStateSet()->setRenderBinDetails(98, "RenderBin"); skyGeode->getOrCreateStateSet()->setAttributeAndModes( new osg::Depth( osg::Depth::LEQUAL, 0.0, 1.0, false ) ); // Add the models sceneGraphRoot.get()->getOrCreateStateSet()->setRenderBinDetails(1, "RenderBin"); // Add the clouds (note, you need this even if you don't want clouds - it calls // Atmosphere::DrawObjects() ) osg::Geode *cloudsGeode = new osg::Geode; CloudsDrawable * cloudsDrawable = new CloudsDrawable(&viewer); cloudsGeode->addDrawable(cloudsDrawable); cloudsGeode->getOrCreateStateSet()->setRenderBinDetails(99, "RenderBin"); cloudsGeode->setCullingActive(false); #ifndef FIXED_NEAR_FAR cb->setCloudsDrawable(cloudsDrawable); #endif viewer.getSceneData()->asGroup()->addChild(skyGeode); viewer.getSceneData()->asGroup()->addChild(cloudsGeode); osg::notify(osg::ALWAYS)<<"SilverLining integration completed..."<<std::endl; }
To modify the conditions being simulated, you may modify the SkyDrawable::initializeSilverLining method to meet your own needs:
void SkyDrawable::initializeSilverLining(AtmosphereReference *ar) const { if (ar && !ar->atmosphereInitialized) { ar->atmosphereInitialized = true; // only try once. SilverLining::Atmosphere *atmosphere = ar->atmosphere; if (atmosphere) { srand(1234); // constant random seed to ensure consistent clouds across windows #ifdef ANDROID std::string resPath("Resources/"); int ret = atmosphere->Initialize(SilverLining::Atmosphere::OPENGLES2, resPath.c_str(), true, 0); #else // Update the path below to where you installed SilverLining's resources folder. const char *slPath = getenv("SILVERLINING_PATH"); if (!slPath) { printf("Can't find SilverLining; set the SILVERLINING_PATH environment variable "); printf("to point to the directory containing the SDK.\n"); exit(0); } std::string resPath(slPath); resPath += "\\Resources\\"; int ret = atmosphere->Initialize(SilverLining::Atmosphere::OPENGL, resPath.c_str(), true, 0); #endif if (ret != SilverLining::Atmosphere::E_NOERROR) { printf("SilverLining failed to initialize; error code %d.\n", ret); printf("Check that the path to the SilverLining installation directory is set properly "); printf("in SkyDrawable.cpp (in SkyDrawable::initializeSilverLining)\n"); exit(0); } // Let SilverLining know which way is up. OSG usually has Z going up. atmosphere->SetUpVector(0, 0, 1); atmosphere->SetRightVector(1, 0, 0); // Set our location (change this to your own latitude and longitude) SilverLining::Location loc; loc.SetAltitude(0); loc.SetLatitude(45); loc.SetLongitude(-122); atmosphere->GetConditions()->SetLocation(loc); // Set the time to noon in PST SilverLining::LocalTime t; t.SetFromSystemTime(); t.SetHour(12); t.SetTimeZone(PST); atmosphere->GetConditions()->SetTime(t); // Center the clouds around the camera's initial position osg::Vec3d pos = _view->getCameraManipulator()->getMatrix().getTrans(); SilverLining::CloudLayer *cumulusCongestusLayer; cumulusCongestusLayer = SilverLining::CloudLayerFactory::Create(CUMULUS_CONGESTUS); cumulusCongestusLayer->SetIsInfinite(true); cumulusCongestusLayer->SetBaseAltitude(4000); cumulusCongestusLayer->SetThickness(500); cumulusCongestusLayer->SetBaseLength(40000); cumulusCongestusLayer->SetBaseWidth(40000); cumulusCongestusLayer->SetDensity(0.3); // Note, we pass in X and -Y since this accepts "east" and "south" coordinates. cumulusCongestusLayer->SetLayerPosition(pos.x(), -pos.y()); cumulusCongestusLayer->SeedClouds(*atmosphere); cumulusCongestusLayer->GenerateShadowMaps(false); atmosphere->GetConditions()->AddCloudLayer(cumulusCongestusLayer); } } }
The complete SilverLining C++ API is available to you, as documented in Integrating SilverLining into a Native Activity and at http://www.sundog-soft.com/docs/html/index.html
1.7.5