Débuter avec RenderScript sur Android

RenderScript est un langage de script sur Android qui vous permet d’écrire un rendu graphique hautes performances et du code de calcul brut. En savoir plus sur RenderScript et écrire votre première application graphique utilisant RenderScript dans ce tutoriel..

Les API RenderScript ont été officiellement intégrées au SDK Android dans les API de niveau 11 (également appelé Android 3.0, Honeycomb). RenderScript fournit un moyen d'écrire du code critique pour les performances que le système compilera ultérieurement en code natif pour le processeur sur lequel il peut s'exécuter. Cela peut être le processeur du périphérique, un processeur multi-cœur ou même le GPU. Son fonctionnement dépend de nombreux facteurs qui ne sont pas facilement accessibles au développeur, mais également de l’architecture prise en charge par le compilateur de la plateforme interne..

Ce tutoriel va vous aider à démarrer avec un script de rendu simple que nous appelons "Falling Snow". C'est un système de particules où chaque flocon de neige est représenté par un point qui tombe, accélérant vers le bas de l'écran. Le vent et d'autres aléas créent un léger effet tourbillonnant.


Étape 0: Mise en route

RenderScript est basé sur le langage de programmation C. Si vous ne maîtrisez pas le langage C, nous vous recommandons de vous familiariser avec ce dernier avant d'essayer d'utiliser RenderScript. Bien que RenderScript ne soit pas OpenGL, il ne nécessite pas non plus que vous l'utilisiez pour le rendu graphique, les concepts pour l'utiliser sont similaires aux concepts OpenGL. Par conséquent, la connaissance de la terminologie graphique OpenGL et 3D aidera à.

Le code open source de ce tutoriel est disponible au téléchargement. Nous vous recommandons de l'utiliser pour suivre. Les listes de codes de ce tutoriel n'incluent pas le contenu complet de chaque fichier..


Étape 1: Création du script de rendu

Commençons par l'étape la plus détaillée et travaillons jusqu'à l'utilisation du script dans une activité Android typique..

Créez un nouveau fichier projet appelé snow.rs dans votre arborescence src, sous le package dans lequel vous travaillerez. En haut, définissez la version de RenderScript avec laquelle vous travaillez:

 #pragma version (1)

Ensuite, définissez le package Java auquel ce script appartient, par exemple:

 #pragma rs java_package_name (com.mamlambo.fallingsnow)

Nous allons utiliser certaines fonctions de l'API graphique RenderScript, donc incluez cet en-tête:

 #include "rs_graphics.rsh"

Maintenant, définissez deux fonctions, root () et init ():

 int root () // à déterminer void init () // à déterminer

La fonction root () sera le point d’entrée de ce script. La valeur de retour définit si le script est exécuté une fois (return 0) ou à des intervalles de N millisecondes (return N). Si le matériel ne parvient pas à suivre la fréquence demandée, alors root () sera exécuté aussi souvent que possible..

La fonction init () est appelée une fois lors du chargement du script et constitue un bon emplacement pour initialiser des variables et d'autres paramètres d'état..

Créez une variable de maillage qui sera initialisée du côté Android et créez une structure simple pour stocker des informations sur chaque flocon de neige. Pendant que vous y êtes, créez quelques variables pour conserver les valeurs de vent et de gravité.

 rs_mesh snowMesh; typedef struct __attribute __ ((compacté, aligné (4))) Snow float2 vélocité; position float2; uchar4 couleur;  Snow_t; Snow_t * snow; float2 vent; float2 grav;

Initialise le vent et la gravité dans la fonction init ():

 grav.x = 0; grav.y = 18; wind.x = rsRand (50) +20; wind.y = rsRand (4) - 2;

Initialiser la neige dans sa propre fonction:

 void initSnow () const float w = rsgGetWidth (); const float h = rsgGetHeight (); int snowCount = rsAllocationGetDimX (rsGetAllocation (neige)); Snow_t * pSnow = neige; pour (int i = 0; i < snowCount; i++)  pSnow->position.x = rsRand (w); pSnow-> position.y = rsRand (h); pSnow-> velocity.y = rsRand (60); pSnow-> velocity.x = rsRand (100); pSnow-> velocity.x - = 50; uchar4 c = rsPackColorTo8888 (255, 255, 255); pSnow-> color = c; pSnow ++; 

Avant de poursuivre, parlons de la fonction initSnow (). Pour commencer, la largeur et la hauteur de la zone de dessin sont récupérées. Ensuite, le script doit savoir combien de structures en flocon de neige nous allons créer. Pour cela, il obtient les dimensions de l’allocation référencée par le pointeur neige. Mais où est le pointeur en cours d'initialisation et qu'est-ce qu'une allocation? Le pointeur est initialisé à partir du code Android. Une allocation est l'un des moyens par lequel la mémoire est gérée par le code Android, mais utilisée par le script. Les détails internes ne sont pas importants pour le moment. Pour nos besoins, nous pouvons le considérer comme un tableau d’objets struct Snow_t.

La boucle itère sur chaque structure et définit des valeurs aléatoires pour donner à la scène de départ un aspect naturel..

Maintenant, implémentons une simple fonction root () qui dessine la scène sans animation. Nous allons utiliser ceci pour mettre en place le reste du système:

 int root () rsgClearColor (0,0f, 0,0f, 0,0f, 0,0f); rsgDrawMesh (snowMesh); retourne 0; 

Lorsque vous enregistrez le fichier de projet de script dans Eclipse, les constructeurs créent automatiquement un fichier nommé snow.bc dans le répertoire / res / raw. Ce fichier généré automatiquement ne doit pas être archivé dans le contrôle de source, ni modifié. De plus, certains fichiers Java sont créés dans le dossier / gen. Ce sont les fichiers d'interface utilisés pour appeler le script depuis Android.


Étape 2: initialiser le script

Maintenant que le script est créé, nous devons l’initialiser pour l’utiliser à partir de vos classes Android. Pour ce faire, nous avons créé une classe Java d'assistance appelée SnowRS. Dans celui-ci, nous allouons la mémoire pour les flocons de neige, initialisons le script et lions les allocations de maillage et de flocons de neige. Cette classe utilise également un objet RenderScriptGL. Cet objet est créé à l'étape suivante dans le cadre de la classe View que nous allons créer..

 classe publique SnowRS public static final int SNOW_FLAKES = 4000; private ScriptC_snow mScript; protected int mWidth; protégé int mHauteur; mPreview booléen protégé; Ressources protégées mRessources; protégé RenderScriptGL mRS; public SnowRS (int width, int height) mWidth = width; mHauteur = hauteur;  public void stop () mRS.bindRootScript (null);  public void start () mRS.bindRootScript (mScript);  public void init (RenderScriptGL rs, ressources res, boolean isPreview) mRS = rs; mRessources = res; mPreview = isPreview; mScript = (ScriptC_snow) createScript ();  public RenderScriptGL getRS () return mRS;  ressources publiques getResources () return mResources;  public ScriptC createScript () ScriptField_Snow snow = new ScriptField_Snow (mRS, SNOW_FLAKES); Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder (mRS); smb.addVertexAllocation (snow.getAllocation ()); smb.addIndexSetType (Mesh.Primitive.POINT); Mesh sm = smb.create (); ScriptC_snow script; script = new ScriptC_snow (mRS, getResources (), R.raw.snow); script.set_snowMesh (sm); script.bind_snow (neige); script.invoke_initSnow (); script de retour; 

En particulier, regardons la méthode createScript (). La première section crée le tableau de structure avec 4 000 entrées (SNOW_FLAKES = 4000). Il l'utilise ensuite pour créer un objet maillé, utilisé pour le rendu. La construction de rendu est définie sur POINT, ainsi chaque flocon de neige apparaîtra sous forme de pixel à l'écran..

Ensuite, nous initialisons le script lui-même à l'aide de l'entrée de ressource brute créée par le générateur Eclipse. Ensuite, nous affectons le maillage et l'allocation de tableau au script via les appels set_snowMesh () et bind_snow (), respectivement. Enfin, nous initialisons la neige avec un appel à la fonction initSnow () créée précédemment en appelant invoke_initSnow ()..

Le script ne commence pas à s'exécuter à ce stade, mais la fonction init () a été appelée. Pour que le script s'exécute, appelez bindRootScript () sur l'objet de script, comme indiqué dans la méthode start ()..


Étape 3: Rendu à une vue

Le SDK Android fournit uniquement l’objet dont nous avons besoin pour la sortie de RenderScript: la classe RSSurfaceView. Implémentez une classe appelée FallingSnowView qui étend cette classe, comme suit:

 Classe publique FallingSnowView étend RSSurfaceView private RenderScriptGL mRSGL; SnowRS mRender privé; public FallingSnowView (contexte de contexte) super (contexte);  @Override public void surfaceChanged (titulaire SurfaceHolder, format int, int w, int h) super.surfaceChanged (titulaire, format, w, h); if (mRSGL == null) RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig (); mRSGL = createRenderScriptGL (sc); mRSGL.setSurface (titulaire, w, h); mRender = new SnowRS (w, h); mRender.init (mRSGL, getResources (), false); mRender.start ();  @ Override protected void onDetachedFromWindow () if (mRSGL! = Null) mRSGL = null; destroyRenderScriptGL (); 

La méthode surfaceChanged () crée un objet RenderScriptGL à partir du SurfaceHolder transmis, si nécessaire. Ensuite, notre objet SnowRS est créé et le rendu est lancé..


Étape 4: Remplir l'application

Tout est en place pour utiliser la classe FallingSnowView dans une classe d'activité. La méthode onCreate () de votre classe d'activité pourrait être aussi simple que cela:

 public void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); snowView = new FallingSnowView (this); setContentView (snowView); 

Étape 5: Animation de la neige

Mais attendez! C'est juste une image statique. Pas très intéressant, n'est-ce pas? Revenons au fichier snow.rs et éditons la fonction root (). Pour une simulation de style pseudo-physique simple, vous voudrez itérer sur chaque flocon de neige et appliquer sa vitesse et son vent actuels à sa position. Ajustez ensuite la vitesse en fonction de l'accélération de la gravité. Enfin, vérifiez si de la neige est tombée du bas de l’écran. Le niveau de complexité et l'efficacité du codage ici auront une incidence sur le type de fréquence d'images que vous obtiendrez finalement. Nous avons essayé de le garder très simplement pour ce tutoriel.

Voici ce que nous avons fait:

 int root () // Efface la couleur de fond rsgClearColor (0.0f, 0.0f, 0.0f, 0.0f); // temps écoulé depuis la dernière mise à jour float dt = min (rsGetDt (), 0.1f); // dimens float w = rsgGetWidth (); float h = rsgGetHeight (); int snowCount = rsAllocationGetDimX (rsGetAllocation (neige)); Snow_t * pSnow = neige; pour (int i = 0; i < snowCount; i++)  pSnow->position.x + = ((pSnow-> velocity.x + wind.x) * dt); pSnow-> position.y + = ((pSnow-> velocity.y + wind.y) * dt); si (pSnow-> position.y> h) pSnow-> position.y = 0; pSnow-> position.x = rsRand (w); pSnow-> velocity.y = rsRand (60);  pSnow-> velocity.x + = (grav.x) * dt; pSnow-> velocity.y + = (grav.y) * dt; pSnow ++;  rsgDrawMesh (snowMesh); si (rsRand (32) == 1) wind.x = 0-wind.x;  retourne 30; 

Et le voici en mouvement:


Étape 5: Sujets avancés

Ce didacticiel vient de rayer la surface de ce que RenderScript peut faire (Haha, compris? Surface?). Vous pouvez utiliser un script de calcul RenderScript pour appliquer des effets graphiques aux images bitmap. Vous pouvez ajouter des shaders pour tirer parti du matériel graphique du périphérique afin de dessiner la scène différemment. Vous pouvez configurer des transformations pour dessiner dans un espace 3D. Vous pouvez configurer des textures pour dessiner. Il y a beaucoup plus que vous pouvez faire avec RenderScript.

Tandis que RenderScript est plus contraignant qu'OpenGL ES dans la zone de rendu 3D, l'ajout de RenderScript uniquement en calcul ajoute des fonctionnalités bienvenues. Dessiner une scène 3D rapide avec RenderScript peut s'avérer plus efficace, en termes de codage, qu'OpenGL. L'utilisation de RenderScript pour les calculs lourds ou la manipulation d'images peut être plus rapide à développer et à offrir de meilleures performances que les solutions NDK similaires (en raison de la distribution automatique entre les cœurs matériels). Contrairement au développement avec le NDK Android, vous n'avez pas à vous soucier de l'architecture matérielle sous-jacente..

Le principal inconvénient de RenderScript est le manque de portabilité du code existant. Si vous avez déjà du code OpenGL ou des fonctions de calcul en C que vous souhaitez exploiter dans vos applications Android, vous voudrez peut-être simplement vous en tenir au NDK Android..


Conclusion

Ce tutoriel vous a donné un aperçu de l'utilisation de RenderScript avec vos applications Android. Vous avez appris les bases de l'écriture et de l'initialisation d'un script, ainsi que du rendu à l'écran. Tout cela a été réalisé dans le cadre d'un système de particules simple simulant des flocons de neige de la taille d'un pixel..

Dites-nous quelles applis RenderScript intéressantes vous intégrez dans les commentaires!

à propos des auteurs

Les développeurs mobiles Lauren Darcey et Shane Conder ont co-écrit plusieurs livres sur le développement Android: un livre de programmation en profondeur intitulé Développement d'applications sans fil Android et Sams Teach Yourself Développement d'applications Android en 24 heures. Lorsqu'ils n'écrivent pas, ils passent leur temps à développer des logiciels mobiles dans leur entreprise et à fournir des services de conseil. Vous pouvez les contacter par courrier électronique à l'adresse [email protected], via leur blog à l'adresse androidbook.blogspot.com et sur Twitter @androidwireless..

Besoin d'aide pour écrire des applications Android? Consultez nos derniers livres et ressources!