Здесь я выложу код модифицированного шейдера под названием Metablob (автор Adrian Boeing). Исходник взят от сюда Shader Toy.
Как, что и почему я тут расписывать не буду. Более детальное прикручивание шейдера к Android можно посмотреть в моем сообщении "Пример шейдера на Android. Ripple Effect.". Здесь будет интересен уже результат шейдера.
Выглядит он *примерно* так, плюс оно шевелиться всячески =):
Изменению подверглись количество и радиусы сгустков (свой! уникальный! аррргххх....=( ).
А вот и код активити:
Копируйте, пользуйтесь, не забывайте про Adrian-а Boeing-а! :-)
Продвинутый пример смотрите в статье "Немного о Render-to-Texture..."
Скачать исходник с апк внутри.
Как, что и почему я тут расписывать не буду. Более детальное прикручивание шейдера к Android можно посмотреть в моем сообщении "Пример шейдера на Android. Ripple Effect.". Здесь будет интересен уже результат шейдера.
Выглядит он *примерно* так, плюс оно шевелиться всячески =):
Изменению подверглись количество и радиусы сгустков (свой! уникальный! аррргххх....=( ).
А вот и код активити:
package com.expedition107.shader.test;
import java.io.IOException;
import java.io.InputStream;
import org.andengine.engine.Engine;
import org.andengine.engine.LimitedFPSEngine;
import org.andengine.engine.camera.Camera;
import org.andengine.engine.handler.IUpdateHandler;
import org.andengine.engine.options.EngineOptions;
import org.andengine.engine.options.ScreenOrientation;
import org.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.andengine.entity.scene.IOnAreaTouchListener;
import org.andengine.entity.scene.IOnSceneTouchListener;
import org.andengine.entity.scene.ITouchArea;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.scene.background.Background;
import org.andengine.entity.sprite.Sprite;
import org.andengine.entity.sprite.UncoloredSprite;
import org.andengine.entity.util.FPSLogger;
import org.andengine.input.touch.TouchEvent;
import org.andengine.input.touch.detector.ClickDetector;
import org.andengine.input.touch.detector.ClickDetector.IClickDetectorListener;
import org.andengine.opengl.shader.PositionTextureCoordinatesShaderProgram;
import org.andengine.opengl.shader.ShaderProgram;
import org.andengine.opengl.shader.constants.ShaderProgramConstants;
import org.andengine.opengl.shader.exception.ShaderProgramException;
import org.andengine.opengl.shader.exception.ShaderProgramLinkException;
import org.andengine.opengl.texture.ITexture;
import org.andengine.opengl.texture.PixelFormat;
import org.andengine.opengl.texture.bitmap.BitmapTexture;
import org.andengine.opengl.texture.region.ITextureRegion;
import org.andengine.opengl.texture.region.TextureRegionFactory;
import org.andengine.opengl.texture.render.RenderTexture;
import org.andengine.opengl.util.GLState;
import org.andengine.opengl.vbo.attribute.VertexBufferObjectAttributes;
import org.andengine.ui.activity.BaseGameActivity;
import org.andengine.util.adt.io.in.IInputStreamOpener;
import org.andengine.util.color.Color;
import com.expedition107.shader.test.ShockwaveTest.ShockwaveShaderProgram;
import android.opengl.GLES20;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.WindowManager;
public class MetablobTest extends BaseGameActivity implements IOnSceneTouchListener {
public static int WIDTH = 800;
public static int HEIGHT = 480;
protected static MetablobTest Instance;
private Camera mCamera;
private Sprite mSprite;
private ITexture mTexture;
private ITextureRegion mTextureRegion;
private boolean mRenderTextureInitialized = false;
private RenderTexture mRenderTexture;
private Sprite mRenderTextureSprite;
private float mShockwaveTime = 0f;
private float mCenterX = 0.5f;
private float mCenterY= 0.5f;
@Override
public EngineOptions onCreateEngineOptions() {
DisplayMetrics displayMetrics = new DisplayMetrics();
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.getDefaultDisplay().getMetrics(displayMetrics);
wm.getDefaultDisplay().getRotation();
WIDTH = displayMetrics.widthPixels;
HEIGHT = displayMetrics.heightPixels;
mCamera = new Camera(0, 0, WIDTH, HEIGHT);
final EngineOptions engineOptions = new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED, new RatioResolutionPolicy(WIDTH, HEIGHT), this.mCamera);
return engineOptions;
}
@Override
public Engine onCreateEngine(final EngineOptions pEngineOptions) {
return new LimitedFPSEngine(pEngineOptions, 120) {
@Override
public void onDrawFrame(GLState pGLState)
throws InterruptedException {
if (!mRenderTextureInitialized) {
initRenderTexture(pGLState);
mRenderTextureInitialized = true;
}
mRenderTexture.begin(pGLState, false, true, Color.TRANSPARENT);
{
super.onDrawFrame(pGLState);
}
mRenderTexture.end(pGLState);
pGLState.pushProjectionGLMatrix();
pGLState.orthoProjectionGLMatrixf(0, mCamera.getSurfaceWidth(), 0, mCamera.getSurfaceHeight(), -1, 1);
{
mRenderTextureSprite.onDraw(pGLState, mCamera);
}
pGLState.popProjectionGLMatrix();
}
private void initRenderTexture(GLState pGLState) {
mRenderTexture = new RenderTexture(this.getTextureManager(),mCamera.getSurfaceWidth(), mCamera.getSurfaceHeight(), PixelFormat.RGBA_8888);
mRenderTexture.init(pGLState);
mRenderTextureSprite = new UncoloredSprite(0f, 0f, TextureRegionFactory.extractFromTexture(mRenderTexture), getVertexBufferObjectManager());
mRenderTextureSprite.setShaderProgram(ShockwaveShaderProgram.getInstance());
}
};
}
@Override
public void onCreateResources(OnCreateResourcesCallback pOnCreateResourcesCallback) throws Exception {
Instance = this;
try {
this.mTexture = new BitmapTexture(this.getTextureManager(), new IInputStreamOpener() {
@Override
public InputStream open() throws IOException {
// TODO Auto-generated method stub
return getAssets().open("gfx/sw_12_23.jpg");
}
});
this.mTextureRegion = TextureRegionFactory.extractFromTexture(mTexture);
this.mTexture.load();
} catch (IOException e) {
}
this.getShaderProgramManager().loadShaderProgram(ShockwaveShaderProgram.getInstance());
pOnCreateResourcesCallback.onCreateResourcesFinished();
}
@Override
public void onCreateScene(OnCreateSceneCallback pOnCreateSceneCallback) throws Exception {
this.mEngine.registerUpdateHandler(new FPSLogger());
final Scene scene = new Scene();
scene.setBackground(new Background(0.09804f, 0.6274f, 0.8784f));
this.mSprite = new Sprite(0f, 0f,40,40, this.mTextureRegion, getVertexBufferObjectManager());
scene.attachChild(mSprite);
getEngine().registerUpdateHandler(new IUpdateHandler() {
@Override
public void reset() {
}
@Override
public void onUpdate(float pSecondsElapsed) {
mShockwaveTime += pSecondsElapsed*0.5;
}
});
scene.setOnSceneTouchListener(this);
pOnCreateSceneCallback.onCreateSceneFinished(scene);
}
@Override
public void onPopulateScene(Scene pScene,
OnPopulateSceneCallback pOnPopulateSceneCallback) throws Exception {
pOnPopulateSceneCallback.onPopulateSceneFinished();
}
public static class ShockwaveShaderProgram extends ShaderProgram {
private static ShockwaveShaderProgram instance;
public static ShockwaveShaderProgram getInstance() {
if (instance == null) instance = new ShockwaveShaderProgram();
return instance;
}
public static final String FRAGMENTSHADER =
"precision highp float;\n" +
"uniform float time;\n" +
"uniform vec2 resolution;\n" +
"void main() \n" +
"{\n" +
//центры сгустков
" vec2 move1;\n" +
" move1.x = cos(time)*0.4;\n" +
" move1.y = sin(time*1.5)*0.4;\n" +
" vec2 move2;\n" +
" move2.x = cos(time*2.0)*0.6;\n" +
" move2.y = sin(time*3.0)*0.6;\n" +
" vec2 move3;\n" +
" move3.x = sin(time*2.0)*0.8;\n" +
" move3.y = cos(time*3.0)*0.8;\n" +
" vec2 move4;\n" +
" move4.x = cos(time*1.8)*0.2;\n" +
" move4.y = sin(time*3.0)*0.2;\n" +
" vec2 move5;\n" +
" move5.x = cos(time*4.8)*1.2;\n" +
" move5.y = sin(time*1.0)*0.5;\n" +
" vec2 move6;\n" +
" move6.x = sin(time*1.8)*0.2;\n" +
" move6.y = cos(time*1.1)*0.2;\n" +
" vec2 move7;\n" +
" move7.x = cos(time*1.8)*0.2;\n" +
" move7.y = sin(time*3.0)*0.2;\n" +
" vec2 move8;\n" +
" move8.x = sin(time*0.8)*0.2;\n" +
" move8.y = cos(time*0.3)*0.5;\n" +
" vec2 move9;\n" +
" move9.x = cos(time*1.8)*0.9;\n" +
" move9.y = sin(time)*5.4;\n" +
//координаты
" vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy;\n" +
//радиусы
" float r1 =(dot(p-move1,p-move1))*16.0;\n" +
" float r2 =(dot(p+move2,p+move2))*24.0;\n" +
" float r3 =(dot(p+move3,p+move3))*32.0;\n" +
" float r4 =(dot(p+move4,p+move4))*40.0;\n" +
" float r5 =(dot(p+move5,p+move5))*42.0;\n" +
" float r6 =(dot(p+move6,p+move6))*50.0;\n" +
" float r7 =(dot(p+move7,p+move7))*56.0;\n" +
" float r8 =(dot(p+move8,p+move8))*65.0;\n" +
" float r9 =(dot(p+move9,p+move9))*70.0;\n" +
//сумма сгустков
" float metaball =(1.0/r1-1.0/r2+1.0/r3-1.0/r4+1.0/r5-1.0/r6+1.0/r7-1.0/r8+1.0/r9);\n" +
//места разрыва сгустков
" float col = pow(metaball,8.0);\n" +
//вывод конечного цвета фрагмента
" gl_FragColor = vec4(col+move2.x,col+move1.x,col+move4.y,0.8);\n" +
"}\n";
private ShockwaveShaderProgram() {
super(PositionTextureCoordinatesShaderProgram.VERTEXSHADER, FRAGMENTSHADER);
}
public static int sUniformModelViewPositionMatrixLocation = ShaderProgramConstants.LOCATION_INVALID;
public static int sUniformTexture0Location = ShaderProgramConstants.LOCATION_INVALID;
public static int sUniformTimeLocation = ShaderProgramConstants.LOCATION_INVALID;
public static int sUniformResolutionLocation = ShaderProgramConstants.LOCATION_INVALID;
@Override
protected void link(final GLState pGLState) throws ShaderProgramLinkException {
GLES20.glBindAttribLocation(this.mProgramID, ShaderProgramConstants.ATTRIBUTE_POSITION_LOCATION, ShaderProgramConstants.ATTRIBUTE_POSITION);
GLES20.glBindAttribLocation(this.mProgramID, ShaderProgramConstants.ATTRIBUTE_TEXTURECOORDINATES_LOCATION, ShaderProgramConstants.ATTRIBUTE_TEXTURECOORDINATES);
super.link(pGLState);
ShockwaveShaderProgram.sUniformModelViewPositionMatrixLocation = this.getUniformLocation(ShaderProgramConstants.UNIFORM_MODELVIEWPROJECTIONMATRIX);
ShockwaveShaderProgram.sUniformResolutionLocation = this.getUniformLocation("resolution");
ShockwaveShaderProgram.sUniformTimeLocation = this.getUniformLocation("time");
}
@Override
public void bind(final GLState pGLState, final VertexBufferObjectAttributes pVertexBufferObjectAttributes) {
GLES20.glDisableVertexAttribArray(ShaderProgramConstants.ATTRIBUTE_COLOR_LOCATION);
super.bind(pGLState, pVertexBufferObjectAttributes);
GLES20.glUniformMatrix4fv(ShockwaveShaderProgram.sUniformModelViewPositionMatrixLocation, 1, false, pGLState.getModelViewProjectionGLMatrix(), 0);
GLES20.glUniform2f(ShockwaveShaderProgram.sUniformResolutionLocation, WIDTH, HEIGHT);
GLES20.glUniform1f(ShockwaveShaderProgram.sUniformTimeLocation, MetablobTest.Instance.mShockwaveTime);
}
@Override
public void unbind(final GLState pGLState) throws ShaderProgramException {
GLES20.glEnableVertexAttribArray(ShaderProgramConstants.ATTRIBUTE_COLOR_LOCATION);
super.unbind(pGLState);
}
}
@Override
public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
if (pSceneTouchEvent.getAction() == TouchEvent.ACTION_DOWN){
mCenterX = pSceneTouchEvent.getMotionEvent().getX() / this.mCamera.getSurfaceWidth();
mCenterY = 1-pSceneTouchEvent.getMotionEvent().getY() / this.mCamera.getSurfaceHeight();
return true;
}
return false;
}
}
Копируйте, пользуйтесь, не забывайте про Adrian-а Boeing-а! :-)
Продвинутый пример смотрите в статье "Немного о Render-to-Texture..."
Скачать исходник с апк внутри.

