实现三星S3蒲公英水波纹效果(二)——Renderscript准备篇
这篇主要是关于Android RenderScript 的使用。
RenderScript简介:RenderScript是Android平台的一种类C脚本语言,Google虽然一直在之前的各个Android版本内置的动态墙纸中使用该技术实现3D图形特效,但一直未将其集成在公开发布的SDK中。至Android3.0版本开始,SDK中已将RenderScript技术集成了进来,开发者可在Eclipse下开发基于RenderScript的3D应用,并在Android3.0版本以上的平板电脑中运行。
SDK链接:http://developer.android.com/guide/topics/renderscript/index.html
要使用Renderscript渲染功能,需要实现的功能如下:
fall.rs实现RenderScript的代码,是水波纹效果实现的关键代码(但关于.rs文件的资料少之又少,希望今后会多起来)
FallRS.java .rs文件的辅助类,用以简化操作fall.rs文件
FallView.java 一个继承于RSSurfaceView的类,用于显示RenderScript的渲染或者用来处理用户的触摸等视图
Fall.java 这是一个Activity,Android 应用程序的界面类。
好了先来看fall.rs文件(中文是我加的注释):
// Copyright (C) 2009 The Android Open Source Project//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at//// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.//编译指示声明(#pragma version(1)),声明了要使用的Renderscript的版本(目前只能是1)#pragma version(1)//编译指示声明(#pragma rs java_package_name(package.name)),它声明了该Renderscript反射所对应的*.java类名#pragma rs java_package_name(com.harlan.waterscreen)#include "rs_graphics.rsh"#define LEAVES_TEXTURES_COUNT 8#define LEAF_SIZE 0.55f#define LEAVES_COUNT 14// Things we need to set from the applicationfloat g_glWidth;float g_glHeight;float g_meshWidth;float g_meshHeight;float g_xOffset;float g_rotate;//着色器处理程序类分为4类:ProgramFragment ProgramFragmentStore ProgramVertext Mesh//ProgramFragment对应片断处理程序,对光栅化的每一个片断做独立的处理,包括映射纹理点,混合,着色等。//ProgramFragmentStore主要负责一些跟片断处理相关的辅助功能,如设置混合模式等。//ProgramVertext对应顶点处理程序,对每一个顶点做独立的处理,包括视景投影变换,法线变换等。//Mesh又叫网格,是方便对一组顶点的处理的类。//以上四个类最终都会被调用setupGL或render这样方法,在这些方法中将用户的配置转换为OpenGL的具体操作序列。rs_program_vertex g_PVWater;rs_program_vertex g_PVSky;rs_program_fragment g_PFSky;rs_program_store g_PFSLeaf;rs_program_fragment g_PFBackground;rs_allocation g_TLeaves;rs_allocation g_TRiverbed;rs_mesh g_WaterMesh;//存储类,主要用来进行数据的存储以及和上层java的交换,包括Type,Element,Allocation。Element可以理解为一个结构体。//下面是一个element;Constants是对这个结构体的类型的命名,Constants_t 就是这个Constants。typedef struct Constants { float4 Drop01; float4 Drop02; float4 Drop03; float4 Drop04; float4 Drop05; float4 Drop06; float4 Drop07; float4 Drop08; float4 Drop09; float4 Drop10; float4 Offset; float Rotate;} Constants_t;//这是一个Constants_t的一个实例,是一个Allocation//在RenderScript运行之前,必要的Allocation要分配好,它们可能是定点坐标,可能是纹理,也可能是用户的数据Constants_t *g_Constants;rs_program_store g_PFSBackground;//float skyOffsetX;//float skyOffsetY;static float g_DT;static int64_t g_LastTime;typedef struct Drop { float ampS; float ampE; float spread; float x; float y;} Drop_t;static Drop_t gDrops[10];static int gMaxDrops;typedef struct Leaves { float x; float y; float scale; float angle; float spin; float u1; float u2; float altitude; float rippled; float deltaX; float deltaY; int newLeaf;} Leaves_t;static Leaves_t gLeavesStore[LEAVES_COUNT];static Leaves_t* gLeaves[LEAVES_COUNT];static Leaves_t* gNextLeaves[LEAVES_COUNT];void initLeaves() { Leaves_t *leaf = gLeavesStore; // globals haven't been set at this point yet. We need to find the correct // function index to call this, we can wait until reflection works float width = 2; //g_glWidth; float height = 3.333; //g_glHeight; int i; for (i = 0; i < LEAVES_COUNT; i ++) { gLeaves[i] = leaf; int sprite = rsRand(LEAVES_TEXTURES_COUNT); leaf->x = rsRand(-width, width); leaf->y = rsRand(-height * 0.5f, height * 0.5f); leaf->scale = rsRand(0.4f, 0.5f); leaf->angle = rsRand(0.0f, 360.0f); leaf->spin = degrees(rsRand(-0.02f, 0.02f)) * 0.25f; leaf->u1 = (float)sprite / (float) LEAVES_TEXTURES_COUNT; leaf->u2 = (float)(sprite + 1) / (float) LEAVES_TEXTURES_COUNT; leaf->altitude = -1.0f; leaf->rippled = 1.0f; leaf->deltaX = rsRand(-0.01f, 0.01f); leaf->deltaY = -rsRand(0.036f, 0.044f); leaf++; }}//一个可选的init()方法,在root()方法调用之前做一些初始化工作,如初始化变量等。//这个函数运行一次,并且在Renderscript启动时,Renderscript中其他工作被执行之前,该方法会被自动的调用。void init() { int ct; gMaxDrops = 10; for (ct=0; ct<gMaxDrops; ct++) { gDrops[ct].ampS = 0; gDrops[ct].ampE = 0; gDrops[ct].spread = 1; } initLeaves(); g_LastTime = rsUptimeMillis(); g_DT = 0.1f;}static void updateDrop(int ct) { gDrops[ct].spread += 30.f * g_DT; gDrops[ct].ampE = gDrops[ct].ampS / gDrops[ct].spread;}static void drop(int x, int y, float s) { int ct; int iMin = 0; float minAmp = 10000.f; for (ct = 0; ct < gMaxDrops; ct++) { if (gDrops[ct].ampE < minAmp) { iMin = ct; minAmp = gDrops[ct].ampE; } } gDrops[iMin].ampS = s; gDrops[iMin].spread = 0; gDrops[iMin].x = x; gDrops[iMin].y = g_meshHeight - y - 1; updateDrop(iMin);}//绘制水波纹涟漪static void generateRipples() { int ct; for (ct = 0; ct < gMaxDrops; ct++) { Drop_t * d = &gDrops[ct]; float *v = (float*)&g_Constants->Drop01; v += ct*4; *(v++) = d->x; *(v++) = d->y; *(v++) = d->ampE * 0.12f; *(v++) = d->spread; } g_Constants->Offset.x = g_xOffset; for (ct = 0; ct < gMaxDrops; ct++) { updateDrop(ct); }}//根据落叶位置绘制水波纹static void genLeafDrop(Leaves_t *leaf, float amp) { float nx = (leaf->x + g_glWidth * 0.5f) / g_glWidth; float ny = (leaf->y + g_glHeight * 0.5f) / g_glHeight; drop(nx * g_meshWidth, g_meshHeight - ny * g_meshHeight, amp);}//绘制单片落叶static int drawLeaf(Leaves_t *leaf) { float x = leaf->x; float y = leaf->y; float u1 = leaf->u1; float u2 = leaf->u2; float a = leaf->altitude; float s = leaf->scale; float r = leaf->angle; float tz = 0.0f; if (a > 0.0f) { tz = -a; } rs_matrix4x4 matrix; if (a > 0.0f) { float alpha = 1.0f; if (a >= 0.4f) alpha = 1.0f - (a - 0.4f) / 0.1f; rsgProgramFragmentConstantColor(g_PFSky, 0.0f, 0.0f, 0.0f, alpha * 0.15f); rsMatrixLoadIdentity(&matrix); if (!g_rotate) { rsMatrixTranslate(&matrix, x - g_xOffset * 2, y, 0); } else { rsMatrixTranslate(&matrix, x, y, 0); rsMatrixRotate(&matrix, 90.0f, 0.0f, 0.0f, 1.0f); } float shadowOffet = a * 0.2f; rsMatrixScale(&matrix, s, s, 1.0f); rsMatrixRotate(&matrix, r, 0.0f, 0.0f, 1.0f); rsgProgramVertexLoadModelMatrix(&matrix); rsgDrawQuadTexCoords(-LEAF_SIZE, -LEAF_SIZE, 0, u1, 1.0f, LEAF_SIZE, -LEAF_SIZE, 0, u2, 1.0f, LEAF_SIZE, LEAF_SIZE, 0, u2, 0.0f, -LEAF_SIZE, LEAF_SIZE, 0, u1, 0.0f); rsgProgramFragmentConstantColor(g_PFSky, 1.0f, 1.0f, 1.0f, alpha); } else { rsgProgramFragmentConstantColor(g_PFSky, 1.0f, 1.0f, 1.0f, 1.0f); } rsMatrixLoadIdentity(&matrix); if (!g_rotate) { rsMatrixTranslate(&matrix, x - g_xOffset * 2, y, tz); } else { rsMatrixTranslate(&matrix, x, y, tz); rsMatrixRotate(&matrix, 90.0f, 0.0f, 0.0f, 1.0f); } rsMatrixScale(&matrix, s, s, 1.0f); rsMatrixRotate(&matrix, r, 0.0f, 0.0f, 1.0f); rsgProgramVertexLoadModelMatrix(&matrix); rsgDrawQuadTexCoords(-LEAF_SIZE, -LEAF_SIZE, 0, u1, 1.0f, LEAF_SIZE, -LEAF_SIZE, 0, u2, 1.0f, LEAF_SIZE, LEAF_SIZE, 0, u2, 0.0f, -LEAF_SIZE, LEAF_SIZE, 0, u1, 0.0f); float spin = leaf->spin; if (a <= 0.0f) { float rippled = leaf->rippled; if (rippled < 0.0f) { genLeafDrop(leaf, 1.5f); //drop(((x + g_glWidth * 0.5f) / g_glWidth) * meshWidth, // meshHeight - ((y + g_glHeight * 0.5f) / g_glHeight) * meshHeight, 1); spin *= 0.25f; leaf->spin = spin; leaf->rippled = 1.0f; } leaf->x = x + leaf->deltaX * g_DT; leaf->y = y + leaf->deltaY * g_DT; r += spin; leaf->angle = r; } else { a -= 0.15f * g_DT; leaf->altitude = a; r += spin * 2.0f; leaf->angle = r; } int newLeaf = 0; if (-LEAF_SIZE * s + x > g_glWidth || LEAF_SIZE * s + x < -g_glWidth || LEAF_SIZE * s + y < -g_glHeight * 0.5f) { int sprite = rsRand(LEAVES_TEXTURES_COUNT); leaf->x = rsRand(-g_glWidth, g_glWidth); leaf->y = rsRand(-g_glHeight * 0.5f, g_glHeight * 0.5f); leaf->scale = rsRand(0.4f, 0.5f); leaf->spin = degrees(rsRand(-0.02f, 0.02f)) * 0.35f; leaf->u1 = sprite / (float) LEAVES_TEXTURES_COUNT; leaf->u2 = (sprite + 1) / (float) LEAVES_TEXTURES_COUNT; leaf->altitude = 0.7f; leaf->rippled = -1.0f; leaf->deltaX = rsRand(-0.01f, 0.01f); leaf->deltaY = -rsRand(0.036f, 0.044f); leaf->newLeaf = 1; newLeaf = 1; } return newLeaf;}//绘制落叶static void drawLeaves() { rsgBindProgramFragment(g_PFSky); rsgBindProgramStore(g_PFSLeaf); rsgBindProgramVertex(g_PVSky); rsgBindTexture(g_PFSky, 0, g_TLeaves); int newLeaves = 0; int i = 0; for ( ; i < LEAVES_COUNT; i += 1) { if (drawLeaf(gLeaves[i])) { newLeaves = 1; } } if (newLeaves > 0) { int index = 0; // Copy all the old leaves to the beginning of gNextLeaves for (i=0; i < LEAVES_COUNT; i++) { if (gLeaves[i]->newLeaf == 0) { gNextLeaves[index] = gLeaves[i]; index++; } } // Now copy all the newly falling leaves to the end of gNextLeaves for (i=0; i < LEAVES_COUNT; i++) { if (gLeaves[i]->newLeaf > 0) { gNextLeaves[index] = gLeaves[i]; gNextLeaves[index]->newLeaf = 0; index++; } } // And move everything in gNextLeaves back to gLeaves for (i=0; i < LEAVES_COUNT; i++) { gLeaves[i] = gNextLeaves[i]; } } rs_matrix4x4 matrix; rsMatrixLoadIdentity(&matrix); rsgProgramVertexLoadModelMatrix(&matrix);}//绘制水中的倒影static void drawRiverbed() { rsgBindProgramFragment(g_PFBackground); rsgBindProgramStore(g_PFSBackground); rsgBindTexture(g_PFBackground, 0, g_TRiverbed); rsgDrawMesh(g_WaterMesh);}//增加水滴的方法,该方法可以在java中被调用void addDrop(int x, int y) { drop(x, y, 2);}//主函数,按指定频率反复调用int root(void) { rsgClearColor(0.f, 0.f, 0.f, 1.f); // Compute dt in seconds. int64_t newTime = rsUptimeMillis(); g_DT = (newTime - g_LastTime) * 0.001f; g_DT = min(g_DT, 0.2f); g_LastTime = newTime; g_Constants->Rotate = (float) g_rotate; int ct; int add = 0; for (ct = 0; ct < gMaxDrops; ct++) { if (gDrops[ct].ampE < 0.005f) { add = 1; } } if (add) { int i = (int)rsRand(LEAVES_COUNT); genLeafDrop(gLeaves[i], rsRand(0.3f) + 0.1f); } rsgBindProgramVertex(g_PVWater); generateRipples(); rsgAllocationSyncAll(rsGetAllocation(g_Constants)); drawRiverbed();//程序中我们不需要绘制落叶,所以讲下面这行注释掉 //drawLeaves();//这个表示界面刷新的频率,50ms return 50;}
其实整个fall.rs源码我们就只改动了一行,注释掉了主函数中的drawLeaves(),这样,就没有落叶飘下了。
下面,是FallRS.java 文件。原来这几行报错:
import static android.util.MathUtils.*;import com.android.wallpaper.R;import com.android.wallpaper.RenderScriptScene;
So Easy,ctrl+O解决。顺便将这个工程里类似的错误都改下。
结果只报一个错,FallRS.java里面的random(float,float)方法没有定义。
那就加上一个random方法:百度android.util.MathUtils,得到其中的random方法,将其加到FallRS.java文件的末尾:
public static float random(float howsmall, float howbig) { if (howsmall >= howbig) return howsmall; Random sRandom = new Random(); return sRandom.nextFloat() * (howbig - howsmall) + howsmall; }
此时,整个工程都没有错误了。
FallRS继承自RenderScriptScene,并覆写了其中两个方法:
@Override public void setOffset(float xOffset, float yOffset, int xPixels, int yPixels) { mWorldState.xOffset = xOffset; mScript.set_g_xOffset(mWorldState.xOffset); } @Override public Bundle onCommand(String action, int x, int y, int z, Bundle extras, boolean resultRequested) { if (WallpaperManager.COMMAND_TAP.equals(action) || WallpaperManager.COMMAND_SECONDARY_TAP.equals(action) || WallpaperManager.COMMAND_DROP.equals(action)) { addDrop(x + (mWorldState.rotate == 0 ? (mWorldState.width * mWorldState.xOffset) : 0), y); } return null; }
显然,onCommand方法告诉我们,源码只有在壁纸状态上才调用addDrop方法,而我们是要使其在activity中便能生效。
为了直观,将父类的成员直接写到FallRS里。FallRS不再继承RenderScriptScene类。
修改后的FallRS代码(中文是我加的注释):
/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.harlan.waterscreen;import static android.renderscript.ProgramStore.DepthFunc.ALWAYS;import static android.renderscript.Sampler.Value.CLAMP;import static android.renderscript.Sampler.Value.LINEAR;import java.util.Random;import java.util.TimeZone;import android.content.res.Resources;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.renderscript.Allocation;import android.renderscript.Matrix4f;import android.renderscript.Mesh;import android.renderscript.ProgramFragment;import android.renderscript.ProgramFragmentFixedFunction;import android.renderscript.ProgramStore;import android.renderscript.ProgramStore.BlendDstFunc;import android.renderscript.ProgramStore.BlendSrcFunc;import android.renderscript.ProgramVertex;import android.renderscript.ProgramVertexFixedFunction;import android.renderscript.RenderScriptGL;import android.renderscript.Sampler;import com.android.wallpaper.fall.ScriptC_fall;import com.android.wallpaper.fall.ScriptField_Constants;//class FallRS extends RenderScriptScene {class FallRS{ private static final int MESH_RESOLUTION = 48; private static final int RSID_STATE = 0; private static final int RSID_CONSTANTS = 1; private static final int RSID_DROP = 2; private static final int TEXTURES_COUNT = 2; private static final int RSID_TEXTURE_RIVERBED = 0; private static final int RSID_TEXTURE_LEAVES = 1; private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options(); @SuppressWarnings({"FieldCanBeLocal"}) private ProgramFragment mPfBackground; @SuppressWarnings({"FieldCanBeLocal"}) private ProgramFragment mPfSky; @SuppressWarnings({"FieldCanBeLocal"}) private ProgramStore mPfsBackground; @SuppressWarnings({"FieldCanBeLocal"}) private ProgramStore mPfsLeaf; @SuppressWarnings({"FieldCanBeLocal"}) private ProgramVertex mPvSky; @SuppressWarnings({"FieldCanBeLocal"}) private ProgramVertex mPvWater; private ProgramVertexFixedFunction.Constants mPvOrthoAlloc; @SuppressWarnings({"FieldCanBeLocal"}) private Sampler mSampler; private int mMeshWidth; private Allocation mUniformAlloc; private int mMeshHeight; @SuppressWarnings({"FieldCanBeLocal"}) private Mesh mMesh; private WorldState mWorldState; private ScriptC_fall mScript; private ScriptField_Constants mConstants; private float mGlHeight; /*******add by harlan****************/ protected int mWidth; protected int mHeight; protected boolean mPreview; protected Resources mResources; protected RenderScriptGL mRS;// protected ScriptC mScript; /**************************************/ public FallRS(int width, int height) {// super(width, height); mWidth = width; mHeight = height; mOptionsARGB.inScaled = false; mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888; }// @Override// public void setOffset(float xOffset, float yOffset, int xPixels, int yPixels) {// mWorldState.xOffset = xOffset;// mScript.set_g_xOffset(mWorldState.xOffset);// }//// @Override// public Bundle onCommand(String action, int x, int y, int z, Bundle extras,// boolean resultRequested) {// if (WallpaperManager.COMMAND_TAP.equals(action)// || WallpaperManager.COMMAND_SECONDARY_TAP.equals(action)// || WallpaperManager.COMMAND_DROP.equals(action)) {// addDrop(x + (mWorldState.rotate == 0 ? (mWorldState.width * mWorldState.xOffset) : 0), y);// }// return null;// } /** * 绑定脚本 * <功能详细描述> * @see [类、类#方法、类#成员] */// @Override public void start() {// super.start(); mRS.bindRootScript(mScript); final WorldState worldState = mWorldState; final int width = worldState.width; final int x = width / 4 + (int)(Math.random() * (width / 2)); final int y = worldState.height / 4 + (int)(Math.random() * (worldState.height / 2)); addDrop(x + (mWorldState.rotate == 0 ? (width * worldState.xOffset) : 0), y); }// @Override public void resize(int width, int height) {// super.resize(width, height); mWidth = width; mHeight = height; mWorldState.width = width; mWorldState.height = height; mWorldState.rotate = width > height ? 1 : 0; mScript.set_g_glWidth(mWorldState.width); mScript.set_g_glHeight(mWorldState.height); mScript.set_g_rotate(mWorldState.rotate); mScript.invoke_initLeaves(); Matrix4f proj = new Matrix4f(); proj.loadProjectionNormalized(mWidth, mHeight); mPvOrthoAlloc.setProjection(proj); } /** *生成脚本文件,并做一系列的初始化工作 * <功能详细描述> * @return * @see [类、类#方法、类#成员] */// @Override// protected ScriptC createScript() { protected ScriptC_fall createScript() { mScript = new ScriptC_fall(mRS, mResources, R.raw.fall); createMesh(); createState(); createProgramVertex(); createProgramFragmentStore(); createProgramFragment(); loadTextures(); mScript.setTimeZone(TimeZone.getDefault().getID()); mScript.bind_g_Constants(mConstants); return mScript; } private void createMesh() { Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS, 2, 0); final int width = mWidth > mHeight ? mHeight : mWidth; final int height = mWidth > mHeight ? mWidth : mHeight; int wResolution = MESH_RESOLUTION; int hResolution = (int) (MESH_RESOLUTION * height / (float) width); mGlHeight = 2.0f * height / (float) width; wResolution += 2; hResolution += 2; for (int y = 0; y <= hResolution; y++) { final float yOffset = (((float)y / hResolution) * 2.f - 1.f) * height / width; for (int x = 0; x <= wResolution; x++) { tmb.addVertex(((float)x / wResolution) * 2.f - 1.f, yOffset); } } for (int y = 0; y < hResolution; y++) { final boolean shift = (y & 0x1) == 0; final int yOffset = y * (wResolution + 1); for (int x = 0; x < wResolution; x++) { final int index = yOffset + x; final int iWR1 = index + wResolution + 1; if (shift) { tmb.addTriangle(index, index + 1, iWR1); tmb.addTriangle(index + 1, iWR1 + 1, iWR1); } else { tmb.addTriangle(index, iWR1 + 1, iWR1); tmb.addTriangle(index, index + 1, iWR1 + 1); } } } mMesh = tmb.create(true); mMeshWidth = wResolution + 1; mMeshHeight = hResolution + 1; mScript.set_g_WaterMesh(mMesh); } static class WorldState { public int frameCount; public int width; public int height; public int meshWidth; public int meshHeight; public int rippleIndex; public float glWidth; public float glHeight; public float skySpeedX; public float skySpeedY; public int rotate; public int isPreview; public float xOffset; } private void createState() { mWorldState = new WorldState(); mWorldState.width = mWidth; mWorldState.height = mHeight; mWorldState.meshWidth = mMeshWidth; mWorldState.meshHeight = mMeshHeight; mWorldState.rippleIndex = 0; mWorldState.glWidth = 2.0f; mWorldState.glHeight = mGlHeight; mWorldState.skySpeedX = random(-0.001f, 0.001f); mWorldState.skySpeedY = random(0.00008f, 0.0002f); mWorldState.rotate = mWidth > mHeight ? 1 : 0;// mWorldState.isPreview = isPreview() ? 1 : 0; mScript.set_g_glWidth(mWorldState.glWidth); mScript.set_g_glHeight(mWorldState.glHeight); mScript.set_g_meshWidth(mWorldState.meshWidth); mScript.set_g_meshHeight(mWorldState.meshHeight); mScript.set_g_xOffset(0); mScript.set_g_rotate(mWorldState.rotate); } private void loadTextures() { mScript.set_g_TLeaves(loadTextureARGB(R.drawable.leaves)); mScript.set_g_TRiverbed(loadTexture(R.drawable.pond)); } private Allocation loadTexture(int id) { final Allocation allocation = Allocation.createFromBitmapResource(mRS, mResources, id); return allocation; } private Allocation loadTextureARGB(int id) { Bitmap b = BitmapFactory.decodeResource(mResources, id, mOptionsARGB); final Allocation allocation = Allocation.createFromBitmap(mRS, b); return allocation; } private void createProgramFragment() { Sampler.Builder sampleBuilder = new Sampler.Builder(mRS); sampleBuilder.setMinification(LINEAR); sampleBuilder.setMagnification(LINEAR); sampleBuilder.setWrapS(CLAMP); sampleBuilder.setWrapT(CLAMP); mSampler = sampleBuilder.create(); ProgramFragmentFixedFunction.Builder builder = new ProgramFragmentFixedFunction.Builder(mRS); builder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); mPfBackground = builder.create(); mPfBackground.bindSampler(mSampler, 0); mScript.set_g_PFBackground(mPfBackground); builder = new ProgramFragmentFixedFunction.Builder(mRS); builder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.MODULATE, ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); mPfSky = builder.create(); mPfSky.bindSampler(mSampler, 0); mScript.set_g_PFSky(mPfSky); } private void createProgramFragmentStore() { ProgramStore.Builder builder = new ProgramStore.Builder(mRS); builder.setDepthFunc(ALWAYS); builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE); builder.setDitherEnabled(false); builder.setDepthMaskEnabled(true); mPfsBackground = builder.create(); builder = new ProgramStore.Builder(mRS); builder.setDepthFunc(ALWAYS); builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE_MINUS_SRC_ALPHA); builder.setDitherEnabled(false); builder.setDepthMaskEnabled(true); mPfsLeaf = builder.create(); mScript.set_g_PFSLeaf(mPfsLeaf); mScript.set_g_PFSBackground(mPfsBackground); } private void createProgramVertex() { mPvOrthoAlloc = new ProgramVertexFixedFunction.Constants(mRS); Matrix4f proj = new Matrix4f(); proj.loadProjectionNormalized(mWidth, mHeight); mPvOrthoAlloc.setProjection(proj); ProgramVertexFixedFunction.Builder builder = new ProgramVertexFixedFunction.Builder(mRS); mPvSky = builder.create(); ((ProgramVertexFixedFunction)mPvSky).bindConstants(mPvOrthoAlloc); mScript.set_g_PVSky(mPvSky); mConstants = new ScriptField_Constants(mRS, 1); mUniformAlloc = mConstants.getAllocation(); ProgramVertex.Builder sb = new ProgramVertex.Builder(mRS); String t = "\n" + "varying vec4 varColor;\n" + "varying vec2 varTex0;\n" + "vec2 addDrop(vec4 d, vec2 pos, float dxMul) {\n" + " vec2 ret = vec2(0.0, 0.0);\n" + " vec2 delta = d.xy - pos;\n" + " delta.x *= dxMul;\n" + " float dist = length(delta);\n" + " if (dist < d.w) { \n" + " float amp = d.z * dist;\n" + " amp /= d.w * d.w;\n" + " amp *= sin(d.w - dist);\n" + " ret = delta * amp;\n" + " }\n" + " return ret;\n" + "}\n" + "void main() {\n" + " vec2 pos = ATTRIB_position.xy;\n" + " gl_Position = vec4(pos.x, pos.y, 0.0, 1.0);\n" + " float dxMul = 1.0;\n" + " varTex0 = vec2((pos.x + 1.0), (pos.y + 1.6666));\n" + " if (UNI_Rotate < 0.9) {\n" + " varTex0.xy *= vec2(0.25, 0.33);\n" + " varTex0.x += UNI_Offset.x * 0.5;\n" + " pos.x += UNI_Offset.x * 2.0;\n" + " } else {\n" + " varTex0.xy *= vec2(0.5, 0.3125);\n" + " dxMul = 2.5;\n" + " }\n" + " varColor = vec4(1.0, 1.0, 1.0, 1.0);\n" + " pos.xy += vec2(1.0, 1.0);\n" + " pos.xy *= vec2(25.0, 42.0);\n" + " varTex0.xy += addDrop(UNI_Drop01, pos, dxMul);\n" + " varTex0.xy += addDrop(UNI_Drop02, pos, dxMul);\n" + " varTex0.xy += addDrop(UNI_Drop03, pos, dxMul);\n" + " varTex0.xy += addDrop(UNI_Drop04, pos, dxMul);\n" + " varTex0.xy += addDrop(UNI_Drop05, pos, dxMul);\n" + " varTex0.xy += addDrop(UNI_Drop06, pos, dxMul);\n" + " varTex0.xy += addDrop(UNI_Drop07, pos, dxMul);\n" + " varTex0.xy += addDrop(UNI_Drop08, pos, dxMul);\n" + " varTex0.xy += addDrop(UNI_Drop09, pos, dxMul);\n" + " varTex0.xy += addDrop(UNI_Drop10, pos, dxMul);\n" + "}\n"; sb.setShader(t); sb.addConstant(mUniformAlloc.getType()); sb.addInput(mMesh.getVertexAllocation(0).getType().getElement()); mPvWater = sb.create(); mPvWater.bindConstants(mUniformAlloc, 0); mScript.set_g_PVWater(mPvWater); } /** * 根据传入的坐标生成水波纹特效 * <功能详细描述> * @param x * @param y * @see [类、类#方法、类#成员] */ void addDrop(float x, float y) { int dropX = (int) ((x / mWidth) * mMeshWidth); int dropY = (int) ((y / mHeight) * mMeshHeight); mScript.invoke_addDrop(dropX, dropY); } /*******add by harlan************************/ public static float random(float howsmall, float howbig) { if (howsmall >= howbig) return howsmall; Random sRandom = new Random(); return sRandom.nextFloat() * (howbig - howsmall) + howsmall; } public void init(RenderScriptGL rs, Resources res, boolean isPreview) { mRS = rs; mResources = res; mPreview = isPreview; mScript = createScript(); } public void stop() { mRS.bindRootScript(null); } /****************************************************/}
好了,至此,RenderScript准备工作完毕,下面就是修改FallView.java文件,以及在activity中加载FallView。
更多相关文章
- Android Studio 使用Gradle引入第三方库文件的总结
- Android signed APK程序正式签名方法详解
- Android Studio中获取sha1证书指纹数据的方法
- Android 虚拟机Dalvik、Android各种java包功能、Android相关文件
- Android内置应用到系统的方法总结
- android实现横竖屏不间断播放文件
- Android mediaplayer 播放本地音乐文件
- Android NDK开发(一)——ndk-build编译生成so库文件并使用