cocos2d-x / android 探照燈特效(SpotLight)

來源:互聯網
上載者:User

想法:使用openGL畫圓,頂點為圓心+圓周上的點,頂點顏色值(0, 0, 0, 0),圓周點上的顏色值(0, 0, 0, 0xFF),開啟Alpha混合,使用glBlendFunc(GL_ZERO, GL_SRC_ALPHA);方式,中間地區openGL會自動漸層。

效果:

代碼:

Cococs2d-x實現

SpotLight.h

#ifndef __SPOT_LIGHT_H__#define __SPOT_LIGHT_H__class CCSpotLight: public CCSprite{public:CCSpotLight();~CCSpotLight();static CCSpotLight* spotLightWithRenderTexture(CCRenderTexture* texture, float radius, ccColor4B color);CC_SYNTHESIZE_RETAIN(CCRenderTexture*, m_renderTexture, RenderTexture)CC_SYNTHESIZE(float, m_spotLightRadius, SpotLightRadius)CC_SYNTHESIZE_PASS_BY_REF(ccColor4B, m_renderColor, RenderColor)private:bool initWithRenderTexture(CCRenderTexture* texture, float radius, ccColor4B color);void draw();};#endif// __SPOT_LIGHT_H__

SpotLight.cpp

#include <cocos2d.h>using namespace cocos2d;#include "SpotLight.h"const int SPOT_LIGHT_VERTICES_COUNT = 45;// 必須大於5, 圓心和圓周上的頂點數const ccColor4B SPOT_LIGHT_CENTER_COLOR = ccc4(0, 0, 0, 0);const ccColor4B SPOT_LIGHT_EDGE_COLOR = ccc4(0, 0, 0, 0xFF);CCSpotLight::CCSpotLight(){m_renderTexture = NULL;m_spotLightRadius = 0;m_renderColor.r = 0;m_renderColor.g = 0;m_renderColor.b = 0;m_renderColor.a = 0;}CCSpotLight::~CCSpotLight(){CC_SAFE_RELEASE(m_renderTexture);}CCSpotLight* CCSpotLight::spotLightWithRenderTexture(CCRenderTexture* texture, float radius, ccColor4B color){CCSpotLight* spotLight = NULL;spotLight = new CCSpotLight();if (spotLight && spotLight->initWithRenderTexture(texture, radius, color)){spotLight->autorelease();return spotLight;}CC_SAFE_DELETE(spotLight);return spotLight;}bool CCSpotLight::initWithRenderTexture(CCRenderTexture* texture, float radius, ccColor4B color){bool bRet = false;do{bRet = CCSprite::init();CC_BREAK_IF(!bRet);setRenderTexture(texture);setSpotLightRadius(radius);setRenderColor(color);bRet = true;}while(0);return bRet;}void CCSpotLight::draw(){CCSprite::draw();int segs = SPOT_LIGHT_VERTICES_COUNT;GLfloat *vertices = new GLfloat[2*segs];//malloc( sizeof(GLfloat)*2*(segs));GLfloat *coordinates = new GLfloat[2*segs];////malloc( sizeof(GLfloat)*2*(segs));ccColor4B *colors = new ccColor4B[segs];//malloc( sizeof(ccColor4B)*(segs));memset(vertices,0, sizeof(GLfloat)*2*(segs));memset(coordinates,0, sizeof(GLfloat)*2*(segs));CCSize winSize = CCDirector::sharedDirector()->getWinSize();m_renderTexture->clear(m_renderColor.r, m_renderColor.g, m_renderColor.b, m_renderColor.a);//m_renderTexture->clear(0, 0, 0, 0xFF);colors[0] = SPOT_LIGHT_CENTER_COLOR;for (int i = 1; i < segs; i++){colors[i] = SPOT_LIGHT_EDGE_COLOR;}const float coef = 2.0f * (float)M_PI/(segs-2) ;CCPoint pos = getPosition();CCSize size = this->getContentSize();vertices[0] = 0;//pos.x;vertices[1] = 0;//pos.y;coordinates[0] = vertices[0]/winSize.width;coordinates[1] = (size.height - vertices[1])/winSize.height;for(int i=1;i<segs;i++){float rads = i*coef;float j = m_spotLightRadius * cosf(rads);// + pos.x;float k = m_spotLightRadius * sinf(rads);// + pos.y;vertices[i*2] = j;vertices[i*2+1] = k;coordinates[i*2] = (j)/winSize.width;coordinates[i*2+1] = (size.height-k)/winSize.height;}    // Update the render texture    //[self.renderTexture begin];m_renderTexture->begin();    glBindTexture(GL_TEXTURE_2D, (GLuint)m_renderTexture);glBlendFunc(GL_ZERO, GL_SRC_ALPHA);glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);glVertexPointer(2, GL_FLOAT, 0, vertices);glTexCoordPointer(2, GL_FLOAT, 0, coordinates);glColorPointer(4, GL_UNSIGNED_BYTE, 0, colors);glDrawArrays(GL_TRIANGLE_FAN, 0, segs);glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST);    //[self.renderTexture end];m_renderTexture->end();CC_SAFE_DELETE(vertices);CC_SAFE_DELETE(coordinates);CC_SAFE_DELETE(colors);}

調用方式:

CCRenderTexture* renderLayer = CCRenderTexture::renderTextureWithWidthAndHeight(size.width, size.height);renderLayer->setPosition(ccp(size.width/2, size.height/2));ccBlendFunc bf = {GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA};renderLayer->getSprite()->setBlendFunc(bf);addChild(renderLayer);CCSpotLight* spotLight = CCSpotLight::spotLightWithRenderTexture(renderLayer, 60.0f, ccc4(0, 0, 0, 0xFF));CC_BREAK_IF(!spotLight);spotLight->setAnchorPoint(ccp(0, 0));spotLight->setPosition(ccp(size.width/2, size.height/2));//spotLight->setPosition(ccp(0, 0));addChild(spotLight);

參考:

1.ios版聚光燈效果示範程式http://www.supersuraccoon-cocos2d.com/zh/2011/09/09/spot-light-demo/

===================================================================================

Android

main.xml

<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="vertical" >    <ImageView        android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:src="@drawable/dota"         />        <TextView        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:layout_gravity="center_vertical"        android:textColor="@android:color/primary_text_light"        android:text="@string/hello" />        <Button        android:id="@+id/btn_click_me"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="@string/btn_click"         />    <com.kle.SpotLight.SpotLightGLSurfaceView        android:id="@+id/spotlight_gl_surfaceview"        android:layout_width="fill_parent"        android:layout_height="fill_parent"        /></FrameLayout>

SpotLightActivity.java

package com.gr.SpotLight;import android.app.Activity;import android.os.Bundle;public class SpotLightActivity extends Activity {    /** Called when the activity is first created. */    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);                m_glView = (SpotLightGLSurfaceView)findViewById(R.id.spotlight_gl_surfaceview);                SpotLightRender renderer = new SpotLightRender(480, 800);        m_glView.setRenderer(renderer);                SpotLight sLight = new SpotLight(0, 480, 100, 5);// 座標係為GL座標系,即螢幕左下角為座標原點,向右為x軸正方向,向上為y軸正方向        m_glView.addSpotLight(sLight);        sLight = new SpotLight(0, 480, 400, 10);// 座標係為GL座標系,即螢幕左下角為座標原點,向右為x軸正方向,向上為y軸正方向        m_glView.addSpotLight(sLight);                //sLight.setPosition(240, 400);//可以自己設定座標                Button btn = (Button)findViewById(R.id.btn_click_me);        btn.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v)            {                // TODO Auto-generated method stub                Toast.makeText(getApplicationContext(), "Click Me!", Toast.LENGTH_SHORT).show();            }                    });    }    SpotLightGLSurfaceView m_glView = null;}

SpotLightGLSurfaceView.java

package com.gr.SpotLight;import android.content.Context;import android.graphics.PixelFormat;import android.opengl.GLSurfaceView;import android.util.AttributeSet;import android.view.SurfaceHolder;public class SpotLightGLSurfaceView extends GLSurfaceView{    public SpotLightGLSurfaceView(Context context, AttributeSet attrs)    {        super(context, attrs);        // TODO Auto-generated constructor stub                // 這部分代碼必須在 setRenderer 前        setZOrderOnTop(true);        setEGLConfigChooser(8, 8, 8, 8, 16, 0);        SurfaceHolder holder = getHolder();        holder.setFormat(PixelFormat.TRANSLUCENT);    }        public void setRenderer(Renderer renderer)    {        super.setRenderer(renderer);        m_renderer = (SpotLightRender)renderer;    }        public int addSpotLight(SpotLight sl)    {        int nRet = 0;                if (m_renderer != null)        {            m_renderer.addSpotLight(sl);        }                return nRet;    }        public void updateSpotLights()    {        if (m_renderer != null)        {            m_renderer.updateMove();        }    }    private SpotLightRender m_renderer= null;}

SpotLightRender.java

package com.gr.SpotLight;import java.util.ArrayList;import javax.microedition.khronos.egl.EGLConfig;import javax.microedition.khronos.opengles.GL10;import android.opengl.GLSurfaceView.Renderer;public class SpotLightRender implements Renderer{    public SpotLightRender(int width, int height)    {        super();        m_width = width;        m_height = height;    }        @Override    public void onSurfaceCreated(GL10 gl, EGLConfig config)    {        // TODO Auto-generated method stub        gl.glDisable(GL10.GL_DITHER);                gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);                gl.glClearColor(0, 0, 0, 1);                gl.glShadeModel(GL10.GL_SMOOTH);        //gl.glEnable(GL10.GL_CULL_FACE);        gl.glOrthof(0, m_width, 0, m_height, 1, -1);    }    @Override    public void onSurfaceChanged(GL10 gl, int width, int height)    {        // TODO Auto-generated method stub        m_width = width;        m_height = height;        gl.glViewport(0, 0, width, height);        // make adjustments for screen ratio        float ratio = (float)width / height;        gl.glMatrixMode(GL10.GL_PROJECTION);// set matrix to projection mode        gl.glLoadIdentity();// reset the matrix to its default state        gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);// apply the projection matrix    }    @Override    public void onDrawFrame(GL10 gl)    {        // TODO Auto-generated method stub        gl.glClear(GL10.GL_COLOR_BUFFER_BIT);        gl.glMatrixMode(GL10.GL_PROJECTION);        gl.glLoadIdentity();        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);                for (int i = 0; i < m_spotLightArray.size(); i++)        {            ((SpotLight)m_spotLightArray.get(i)).moveByFrame();            ((SpotLight)m_spotLightArray.get(i)).draw(gl);        }    }        public int addSpotLight(SpotLight spotLight)    {        int nRet = 0;                if (m_spotLightArray == null)        {            m_spotLightArray = new ArrayList<SpotLight>();        }                if (m_spotLightArray != null && spotLight != null)        {            m_spotLightArray.add(spotLight);            nRet = m_spotLightArray.size();        }                return nRet;    }        public void clearSpotLightArray()    {        if (m_spotLightArray != null)        {            m_spotLightArray.clear();            m_spotLightArray = null;        }    }        public void updateMove()    {        for (int i = 0; i < m_spotLightArray.size(); i++)        {            ((SpotLight)m_spotLightArray.get(i)).moveByFrame();        }    }    private ArrayList<SpotLight> m_spotLightArray = new ArrayList<SpotLight>();    private int m_width = 480;    private int m_height = 800;}

SpotLight.java

package com.gr.SpotLight;import java.nio.ByteBuffer;import java.nio.ByteOrder;import java.nio.FloatBuffer;import java.nio.IntBuffer;import javax.microedition.khronos.opengles.GL10;import android.graphics.Color;import android.graphics.Point;import android.graphics.PointF;public class SpotLight{    public SpotLight()    {        init(0, 0, 0, VELOCITY_DEFAULT, RADIUS_DEFAULT, VERTEX_COUNT_DEFAULT);    }        public SpotLight(float lx, float rx, float y, float v)    {        init(lx, rx, y, v, RADIUS_DEFAULT, VERTEX_COUNT_DEFAULT);    }        public SpotLight(float lx, float rx, float y, float v, float radius)    {        init(lx, rx, y, v, radius, VERTEX_COUNT_DEFAULT);    }        public SpotLight(float lx, float rx, float y, float v, float radius, int vertexCount)    {        init(lx, rx, y, v, radius, vertexCount);    }        private void init(float lx, float rx, float y, float v, float radius, int vertexCount)    {        if (lx > rx)        {            float tmp = rx;            rx = lx;            lx = tmp;        }        m_leftX = lx;        m_rightX = rx;        m_myDirector = m_rand.nextBoolean()?DIRECTOR_LEFT:DIRECTOR_RIGHT;        float x = m_rand.nextFloat() * (m_rightX - m_leftX) + m_leftX;        m_position.set(x, y);        m_vByFrame = v;        m_radius = radius;        m_vertexCount = vertexCount;                initVertices();    }        private void initVertices()    {        int i = 0;                m_vertices = new float[POINT_SIZE * m_vertexCount];        m_colors = new int[COLOR_SIZE * m_vertexCount];                double coef = 2.0 * Math.PI / (m_vertexCount - 2);        // 圓心        m_vertices[0] = 0;//m_position.x;        m_vertices[1] = 0;//m_position.y;        m_colors[0] = 0;        m_colors[1] = 0;        m_colors[2] = 0;        m_colors[3] = 0;                for (i = 1; i < m_vertexCount; i++)        {            double rads = i * coef;                        m_vertices[i * POINT_SIZE] = (float)(m_vertices[0] + m_radius * Math.cos(rads));            m_vertices[i * POINT_SIZE + 1] = (float)(m_vertices[1] + m_radius * Math.sin(rads));                                    m_colors[i * COLOR_SIZE] = 0;//0xFFFF;            m_colors[i * COLOR_SIZE + 1] = 0;            m_colors[i * COLOR_SIZE + 2] = 0;            m_colors[i * COLOR_SIZE + 3] = 0xFFFF;//0;        }                convert2GLpos();        ByteBuffer cbb = ByteBuffer.allocateDirect(m_colors.length * Integer.SIZE / Byte.SIZE);        cbb.order(ByteOrder.nativeOrder());        m_ColorBuffer = cbb.asIntBuffer();        m_ColorBuffer.put(m_colors);        m_ColorBuffer.position(0);    }        private void convert2GLpos()    {        float vt[] = new float[POINT_SIZE * m_vertexCount];        int i = 0;        for (i = 0; i < m_vertexCount; i++)        {            vt[i * POINT_SIZE] = m_vertices[i * POINT_SIZE] + m_position.x;            vt[i * POINT_SIZE + 1] = m_vertices[i * POINT_SIZE + 1] + m_position.y;        }                ByteBuffer vbb = ByteBuffer.allocateDirect(vt.length * Float.SIZE / Byte.SIZE);        vbb.order(ByteOrder.nativeOrder());        m_VertexBuffer = vbb.asFloatBuffer();        m_VertexBuffer.put(vt);        m_VertexBuffer.position(0);    }        public void draw(GL10 gl)    {        gl.glFrontFace(GL10.GL_CW);        gl.glVertexPointer(POINT_SIZE, GL10.GL_FLOAT, 0, m_VertexBuffer);        gl.glColorPointer(COLOR_SIZE, GL10.GL_FIXED, 0, m_ColorBuffer);                gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, m_vertexCount);    }        public void moveByFrame()    {        m_position.offset(m_myDirector * m_vByFrame, 0);        if (m_position.x > m_rightX)        {            m_position.x = m_rightX;            m_myDirector = DIRECTOR_LEFT;        }        else if (m_position.x < m_leftX)        {            m_position.x = m_leftX;            m_myDirector = DIRECTOR_RIGHT;        }        convert2GLpos();    }        public void setPosition(float x, float y)    {        m_position.set(x, y);        convert2GLpos();    }        public void offPosition(float dx, float dy)    {        m_position.offset(dx, dy);        convert2GLpos();    }        public void setRadius(float r)    {        m_radius = r;        double coef = 2.0 * Math.PI / (m_vertexCount - 2);        int i = 0;        for (i = 1; i < m_vertexCount; i++)        {            double rads = i * coef;                        m_vertices[i * POINT_SIZE] = (float)(m_vertices[0] + m_radius * Math.cos(rads));            m_vertices[i * POINT_SIZE + 1] = (float)(m_vertices[1] + m_radius * Math.sin(rads));        }        convert2GLpos();    }        private PointF m_position = new PointF();// 相對座標,在gl_surfaceview內的座標    private float m_leftX = 0;    private float m_rightX = 0;    private float m_radius;    private int m_vertexCount;    private Point m_parentWinSize = new Point();        private float m_vertices[] = null;    private int m_colors[] = null;        private FloatBuffer m_VertexBuffer = null;    private IntBuffer m_ColorBuffer = null;        private Random m_rand = new Random(System.currentTimeMillis());    private final static int DIRECTOR_LEFT = -1;    private final static int DIRECTOR_RIGHT = 1;    private int m_myDirector = DIRECTOR_LEFT;    private final static float VELOCITY_DEFAULT = 1;    private float m_vByFrame = VELOCITY_DEFAULT;        private final static float RADIUS_DEFAULT = 100;    private final static int VERTEX_COUNT_DEFAULT = 45;// > 5    private final static int POINT_SIZE = 2;    private final static int COLOR_SIZE = 4;// r, g, b, a    private final static int CENTER_COLOR = Color.argb(0x00, 0x00, 0x00, 0x00);    private final static int EDGE_COLOR = Color.argb(0xFF, 0x00, 0x00, 0x00);    }

參考:

1.android3D物體的碰撞——正方體的碰撞http://www.2cto.com/kf/201110/109245.html

2.使GLSurfaceview透明 可見背景圖片 http://blog.csdn.net/cc_lq/article/details/6629659

http://blog.sina.com.cn/s/blog_7705f5140100rive.html

http://topic.csdn.net/u/20110215/16/c2849359-b07e-424f-bf0d-db0506b69002.html

總結:

1.基本不會openGL,所以弄起來都是一知半解,頭好大,需要好好學學openGL了。

2.一開始我是仿照cocos2d-x的代碼寫的Android代碼,狗屁不通呀,就是顯示不出來,還各種崩。

3.glSurfaceView透明參考的是使GLSurfaceview透明 可見背景圖片:主要3句話

mGLSurfaceView.setZOrderOnTop(true);mGLSurfaceView.setEGLConfigChooser(8,8,8,8,16,0);mGLSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);

mGLSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);要在setRender之前加上,有木有啊有木有,坑死爹了

4.color的問題:

glClearColor參數都是float呀,就是0~1之間的數,r g b a 的順序

glColorPointer

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.