十四、混合

第一部分 概念:

1) 引入

OpenGL ES 混合本质上是将 2 个片元的颜色进行调和,产生一个新的颜色。OpenGL ES 混合发生在片元通过各项测试之后,准备进入帧缓冲区的片元和原有的片元按照特定比例加权计算出最终片元的颜色值,不再是新(源)片元直接覆盖缓冲区中的(目标)片元。

在这里插入图片描述

2)应用

启用 OpenGL ES 混合使用 需要在绘画前启动glEnable(GL_BLEND);

然后通过 void glBlendFunc(GLenum sfactor, GLenum dfactor); 设置混合的方式,其中 sfactor 表示源因子,dfactor 表示目标因子。

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// GL_SRC_ALPHA 表示源因子取值为源颜色的 alpha
// GL_ONE_MINUS_SRC_ALPHA 表示目标因子取值为 1- alpha(源颜色的 alpha)

// 操作符默认为 GL_FUNC_ADD ,即加权相加。
// 混合公式变成了 源颜色向量 × alpha + 目标颜色向量 × (1- alpha)

在这里插入图片描述

默认的操作符是加号,我们也可以通过void glBlendEquation(GLenum mode)接口来自定义设置。

GL_FUNC_ADD:默认的,彼此元素相加

GL_FUNC_SUBTRACT:彼此元素相减

GL_FUNC_REVERSE_SUBTRACT:彼此元素相减,但顺序相反

GL_MIN:混合结果的 4 个通道值分别取 2 元素中 4 个通道较小的值

GL_MAX:混合结果的 4 个通道值分别取 2 元素中 4 个通道较大的值

glBlendFuncSeperate为 RGB 和 alpha 通道各自设置不同的混合因子

//对 RGB 和 Alpha 分别设置 BLEND 函数

void glBlendFuncSeparate(GLenum srcRGB,GLenum dstRGB,GLenum srcAlpha,GLenum dstAlpha);

glBlendFuncSeperate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,GL_ONE, GL_ZERO);
上面就表示
混合结果颜色 RGB 向量 = 源颜色 RGB 向量 × alpha + 目标颜色 RGB 向量 × (1- alpha);
混合结果颜色 alpha = 源颜色 alpha × 1 + 目标颜色 alpha × 0;

这个也是默认为+号,但是可以通过glBlendEquationSeparate为 RGB 和 alpha 通道各自设置不同操作符。void glBlendEquationSeparate(GLenum modeRGB,GLenum modeAlpha);

另外需要格外注意的是,开启混合和深度测试绘制透明物体时,需要遵循物体距观察者(Camera)的距离,由远到近开始绘制,这样可以避免由于深度测试开启后(在透明物体后面)丢弃片元造成的奇怪现象。

第二部分 实践:

1)java部分

java部分在绘制部分都是跟之前一致的,只是因为混合使用到了图片的RGBA中A的维度,需要将32位的png图片在java端转换为具体的RGBA数据传递到JNI去。

NativeImpl.java

public class NativeImpl {
	。。。。
	//多出这个native接口
	public static native void native_SetImageDataWithIndex(int index, int width,int height, byte[] byteArray);
}

MyGLSurfaceView.java

public class MyGLSurfaceView extends GLSurfaceView implements ScaleGestureDetector.OnScaleGestureListener{
	 public MyGLSurfaceView(Context context) {
	 	...
	 	
	 	//开始的时候就把内容主动传递到
	 	loadRGBAImage(R.drawable.board_texture,0);
        loadRGBAImage(R.drawable.floor,1);
        loadRGBAImage(R.drawable.window,2);
	 }
	private Bitmap loadRGBAImage(int resId, int index) {
        InputStream is = this.getResources().openRawResource(resId);
        Bitmap bitmap;
        try {
            bitmap = BitmapFactory.decodeStream(is);
            if (bitmap != null) {
                int bytes = bitmap.getByteCount();
                ByteBuffer buf = ByteBuffer.allocate(bytes);
                bitmap.copyPixelsToBuffer(buf);
                byte[] byteArray = buf.array();
                renderer.setImageDataWithIndex(index, bitmap.getWidth(), bitmap.getHeight(), byteArray);
            }
        }
        finally
        {
            try
            {
                is.close();
            }
            catch(IOException e)
            {
                e.printStackTrace();
            }
        }
        return bitmap;
    }
    
    
    ...
    
    private class MyRenderer implements Renderer {
    	...
    	public void setImageDataWithIndex(int index, int width, int height, byte[] bytes) {
            NativeImpl.native_SetImageDataWithIndex(index, width, height, bytes);
        }
    }
}

2)C++部分

NativeGL.cpp

多出
std::vector<struct ImageTyep> vcImage;
/*
 * Class:     com_example_nineblending_native_SetImageDataWithIndex
 * Method:    native_SetImageDataWithIndex
 * Signature: (III[B)V
 */
JNIEXPORT void JNICALL native_SetImageDataWithIndex(JNIEnv *env, jobject instance, jint index, jint width, jint height, jbyteArray byteArray)
{
	struct ImageTyep itype;
	int len = env->GetArrayLength (byteArray);
	uint8_t* buf = new uint8_t[len];
	env->GetByteArrayRegion(byteArray, 0, len, reinterpret_cast<jbyte*>(buf));
	itype.data = buf;
	itype.width =width;
	itype.height = height;
	vcImage.push_back(itype);
	LOGD("native_SetImageDataWithIndex  width=%d height =  height", width, height);
	//env->DeleteLocalRef(byteArray);
}

Blending.h

//
// Created by CreatWall_zhouwen on 2023/5/15.
//

#ifndef NINEBLENDING_BLENDING_H
#define NINEBLENDING_BLENDING_H
#include <GLES3/gl3.h>
#include <detail/type_mat.hpp>
#include <detail/type_mat4x4.hpp>
#include <vector>
#include <map>
#include "Const.h"
#define MATH_PI 3.1415926535897932384626433832802
#define RENDER_IMG_NUM 3
class Blending {
public:
    Blending();
    ~Blending();
    void CreateProgram(const char *ver, const char *frag);
    void Draw();
    void getTexturedata(std::vector<struct ImageTyep> vcImagetemp);
    static Blending* GetInstance();
    static void DestroyInstance();
    void UpdateTransformMatrix(float rotateX, float rotateY, float scaleX, float scaleY);
    void UpdateMatrix(glm::mat4 &mvpMatrix, int angleXRotate, int angleYRotate, float scale, glm::vec3 transVec3, float ratio);
    void OnSurfaceChanged(int width, int height);
private:
    GLuint program;
    GLuint vertexShaderHandle;
    GLuint fragShaderHandle;

    GLuint m_TextureIds[RENDER_IMG_NUM];
    GLint m_SamplerLoc;
    GLint m_MVPMatLoc;

    GLuint m_VaoIds[3];
    GLuint m_VboIds[3];
    std::vector<struct ImageTyep> m_vcImage;
    glm::mat4 m_MVPMatrix;

    std::vector<glm::vec3> windowsTrans;
    std::map<GLfloat, glm::vec3> sorted;

    int m_AngleX;
    int m_AngleY;
    int Srceenwidth;
    int Srceenheight;
};


#endif //NINEBLENDING_BLENDING_H

Blending.cpp

//
// Created by CreatWall_zhouwen on 2023/5/15.
//

#include "Blending.h"
#include "Util.h"
#include "GLUtil.h"
#include <gtc/matrix_transform.hpp>
Blending* m_pContext = nullptr;
#define TAG "DRAWTEXTURE"
GLfloat boxVertices[] = {
      //position            //texture coord
      -0.5f, -0.5f, -0.5f,   0.0f, 0.0f,
      0.5f, -0.5f, -0.5f,   1.0f, 0.0f,
      0.5f,  0.5f, -0.5f,   1.0f, 1.0f,
      0.5f,  0.5f, -0.5f,   1.0f, 1.0f,
      -0.5f,  0.5f, -0.5f,   0.0f, 1.0f,
      -0.5f, -0.5f, -0.5f,   0.0f, 0.0f,

      -0.5f, -0.5f, 0.5f,    0.0f, 0.0f,
      0.5f, -0.5f, 0.5f,    1.0f, 0.0f,
      0.5f,  0.5f, 0.5f,    1.0f, 1.0f,
      0.5f,  0.5f, 0.5f,    1.0f, 1.0f,
      -0.5f,  0.5f, 0.5f,    0.0f, 1.0f,
      -0.5f, -0.5f, 0.5f,    0.0f, 0.0f,

      -0.5f,  0.5f,  0.5f,   1.0f, 0.0f,
      -0.5f,  0.5f, -0.5f,   1.0f, 1.0f,
      -0.5f, -0.5f, -0.5f,   0.0f, 1.0f,
      -0.5f, -0.5f, -0.5f,   0.0f, 1.0f,
      -0.5f, -0.5f,  0.5f,   0.0f, 0.0f,
      -0.5f,  0.5f,  0.5f,   1.0f, 0.0f,

      0.5f,  0.5f,  0.5f,   1.0f, 0.0f,
      0.5f,  0.5f, -0.5f,   1.0f, 1.0f,
      0.5f, -0.5f, -0.5f,   0.0f, 1.0f,
      0.5f, -0.5f, -0.5f,   0.0f, 1.0f,
      0.5f, -0.5f,  0.5f,   0.0f, 0.0f,
      0.5f,  0.5f,  0.5f,   1.0f, 0.0f,

      -0.5f, -0.5f, -0.5f,   0.0f, 1.0f,
      0.5f, -0.5f, -0.5f,   1.0f, 1.0f,
      0.5f, -0.5f,  0.5f,   1.0f, 0.0f,
      0.5f, -0.5f,  0.5f,   1.0f, 0.0f,
      -0.5f, -0.5f,  0.5f,   0.0f, 0.0f,
      -0.5f, -0.5f, -0.5f,   0.0f, 1.0f,

      -0.5f, 0.5f, -0.5f,    0.0f, 1.0f,
      0.5f, 0.5f, -0.5f,    1.0f, 1.0f,
      0.5f, 0.5f,  0.5f,    1.0f, 0.0f,
      0.5f, 0.5f,  0.5f,    1.0f, 0.0f,
      -0.5f, 0.5f,  0.5f,    0.0f, 0.0f,
      -0.5f, 0.5f, -0.5f,    0.0f, 1.0f,
};

GLfloat flatVertices[] = {
      5.0f, -0.5f,  5.0f,  2.0f,  0.0f,
      -5.0f, -0.5f,  5.0f,  0.0f,  0.0f,
      -5.0f, -0.5f, -5.0f,  0.0f,  2.0f,

      5.0f, -0.5f,  5.0f,  2.0f,  0.0f,
      -5.0f, -0.5f, -5.0f,  0.0f,  2.0f,
      5.0f, -0.5f, -5.0f,  2.0f,  2.0f
};

GLfloat windowVertices[] = {
      0.0f,  0.5f,  0.0f,  0.0f,  0.0f,
      0.0f, -0.5f,  0.0f,  0.0f,  1.0f,
      1.0f, -0.5f,  0.0f,  1.0f,  1.0f,

      0.0f,  0.5f,  0.0f,  0.0f,  0.0f,
      1.0f, -0.5f,  0.0f,  1.0f,  1.0f,
      1.0f,  0.5f,  0.0f,  1.0f,  0.0f
};

Blending::Blending() {
    m_SamplerLoc = GL_NONE;
   m_MVPMatLoc = GL_NONE;

   m_AngleX = 0;
   m_AngleY = 0;
   Srceenwidth =  1080;
   Srceenheight = 2115;
}

Blending::~Blending() {

}

void Blending::CreateProgram(const char *ver, const char *frag) {
   LOGD("CreateProgram Enter");
   // 编译链接用于离屏渲染的着色器程序
   program = CreateGLProgram(ver, frag, vertexShaderHandle, fragShaderHandle);
   if (program == GL_NONE)
   {
      LOGD("FBOSample::Init m_ProgramObj == GL_NONE");
      return;
   }
   LOGD("CreateGLProgram Success");
   m_SamplerLoc = glGetUniformLocation(program, "s_TextureMap");
   m_MVPMatLoc = glGetUniformLocation(program, "u_MVPMatrix");
   //创建VBO
   glGenBuffers(3, m_VboIds);
   glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[0]);
   glBufferData(GL_ARRAY_BUFFER, sizeof(boxVertices), boxVertices, GL_STATIC_DRAW);

   glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[1]);
   glBufferData(GL_ARRAY_BUFFER, sizeof(flatVertices), flatVertices, GL_STATIC_DRAW);

   glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[2]);
   glBufferData(GL_ARRAY_BUFFER, sizeof(windowVertices), windowVertices, GL_STATIC_DRAW);

   //创建VAO并绑定VBO
   glGenVertexArrays(3, m_VaoIds);

   glBindVertexArray(m_VaoIds[0]);
   glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[0]);
   glEnableVertexAttribArray(0);
   glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (const void *) 0);
   glEnableVertexAttribArray(1);
   glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (const void *) (3* sizeof(GLfloat)));
   glBindBuffer(GL_ARRAY_BUFFER, GL_NONE);
   glBindVertexArray(GL_NONE);

   glBindVertexArray(m_VaoIds[1]);
   glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[1]);
   glEnableVertexAttribArray(0);
   glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (const void *) 0);
   glEnableVertexAttribArray(1);
   glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (const void *) (3* sizeof(GLfloat)));
   glBindBuffer(GL_ARRAY_BUFFER, GL_NONE);
   glBindVertexArray(GL_NONE);

   glBindVertexArray(m_VaoIds[2]);
   glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[2]);
   glEnableVertexAttribArray(0);
   glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (const void *) 0);
   glEnableVertexAttribArray(1);
   glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (const void *) (3* sizeof(GLfloat)));
   glBindBuffer(GL_ARRAY_BUFFER, GL_NONE);
   glBindVertexArray(GL_NONE);

   //创建纹理并绑定数据
   glGenTextures(RENDER_IMG_NUM, m_TextureIds);
   for (int i = 0; i < RENDER_IMG_NUM; ++i)
   {
      glActiveTexture(GL_TEXTURE0 + i);
      glBindTexture(GL_TEXTURE_2D, m_TextureIds[i]);
      glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
      glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_vcImage[i].width, m_vcImage[i].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_vcImage[i].data);
      LOGD("width = %d, height = %d",m_vcImage[i].width, m_vcImage[i].height);
      glBindTexture(GL_TEXTURE_2D, GL_NONE);
   }

    //布局参数
    windowsTrans.push_back(glm::vec3(-1.5f,  0.0f, -0.48f));
    windowsTrans.push_back(glm::vec3( 1.5f,  0.0f,  0.51f));
    windowsTrans.push_back(glm::vec3( 0.0f,  0.0f,  0.7f));
    windowsTrans.push_back(glm::vec3(-0.3f,  0.0f, -2.3f));
    windowsTrans.push_back(glm::vec3( 0.5f,  0.0f, -0.6f));
    for (GLuint i = 0; i < windowsTrans.size(); i++)
    {
        GLfloat distance = std::sqrt(std::pow(windowsTrans[i].x - 0.5f, 2.0f) + std::pow(windowsTrans[i].y - 1.0f, 2.0f) + std::pow(windowsTrans[i].z - 3.0f, 2.0f));
        sorted[distance] = windowsTrans[i];
    }
}

void Blending::Draw() {
   float ratio = (float)Srceenwidth / Srceenheight;
   glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
   glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   glEnable(GL_DEPTH_TEST);//开启深度测试
   glEnable(GL_BLEND);//开启混合
   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);//源颜色向量 × alpha + 目标颜色向量 × (1- alpha)

   glUseProgram(program);

   glBindVertexArray(m_VaoIds[0]);
   // Bind the RGBA map
   glActiveTexture(GL_TEXTURE0);
   glBindTexture(GL_TEXTURE_2D, m_TextureIds[0]);
   glUniform1i(m_SamplerLoc, 0);

   UpdateMatrix(m_MVPMatrix, 0, 0, 1.0,  glm::vec3(-1.0f, 0.0f, -1.0f), ratio);
   glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0][0]);
   glDrawArrays(GL_TRIANGLES, 0, 36);

   UpdateMatrix(m_MVPMatrix, 0, 0, 1.0,  glm::vec3(2.0f, 0.0f, 0.0f), ratio);
   glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0][0]);
   glDrawArrays(GL_TRIANGLES, 0, 36);

   glBindVertexArray(0);

   glBindVertexArray(m_VaoIds[1]);
   // Bind the RGBA map
   glActiveTexture(GL_TEXTURE0);
   glBindTexture(GL_TEXTURE_2D, m_TextureIds[1]);
   glUniform1i(m_SamplerLoc, 0);

   UpdateMatrix(m_MVPMatrix, 0, 0, 1.0, glm::vec3(0.0f,  0.0f,  0.0f), ratio);
   glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0][0]);
   glDrawArrays(GL_TRIANGLES, 0, 6);
   glBindVertexArray(0);

   glBindVertexArray(m_VaoIds[2]);
   // Bind the RGBA map
   glActiveTexture(GL_TEXTURE0);
   glBindTexture(GL_TEXTURE_2D, m_TextureIds[2]);
   glUniform1i(m_SamplerLoc, 0);

   for (auto it = sorted.rbegin(); it != sorted.rend(); ++it)
   {
      UpdateMatrix(m_MVPMatrix, 0, 0 , 1.0, it->second, ratio);
      glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0][0]);
      glDrawArrays(GL_TRIANGLES, 0, 6);
   }

   glBindVertexArray(0);

   glDisable(GL_DEPTH_TEST);
   glDisable(GL_BLEND);
}

void Blending::getTexturedata(std::vector<struct ImageTyep> vcImagetemp) {
   m_vcImage = vcImagetemp;
}

Blending *Blending::GetInstance() {
   if (m_pContext == nullptr)
   {
      m_pContext = new Blending();
   }
   return m_pContext;
}

void Blending::DestroyInstance() {
   if (m_pContext)
   {
      delete m_pContext;
      m_pContext = nullptr;
   }
}

void Blending::UpdateTransformMatrix(float rotateX, float rotateY, float scaleX, float scaleY) {
   m_AngleX = static_cast<int>(rotateX);
   m_AngleY = static_cast<int>(rotateY);
}

void Blending::UpdateMatrix(glm::mat4 &mvpMatrix, int angleXRotate, int angleYRotate, float scale,
                            glm::vec3 transVec3, float ratio) {
   LOGD("BlendingSample::UpdateMatrix angleX = %d, angleY = %d, ratio = %f", angleXRotate,
         angleYRotate, ratio);
   angleXRotate = angleXRotate % 360;
   angleYRotate = angleYRotate % 360;

   //转化为弧度角
   float radiansX = static_cast<float>(MATH_PI / 180.0f * angleXRotate);
   float radiansY = static_cast<float>(MATH_PI / 180.0f * angleYRotate);


   // Projection matrix
   //glm::mat4 Projection = glm::ortho(-ratio, ratio, -1.0f, 1.0f, 0.0f, 100.0f);
   //glm::mat4 Projection = glm::frustum(-ratio, ratio, -1.0f, 1.0f, 4.0f, 100.0f);
   glm::mat4 Projection = glm::perspective(45.0f, ratio, 0.1f, 100.f);

   // View matrix
   glm::mat4 View = glm::lookAt(
         glm::vec3(0.5, 1, 3), // Camera is at (0,0,1), in World Space
         glm::vec3(0, 0, 0), // and looks at the origin
         glm::vec3(0, 1, 0)  // Head is up (set to 0,-1,0 to look upside-down)
   );

   // Model matrix
   glm::mat4 Model = glm::mat4(1.0f);
   Model = glm::scale(Model, glm::vec3(scale, scale, scale));
   Model = glm::rotate(Model, radiansX, glm::vec3(1.0f, 0.0f, 0.0f));
   Model = glm::rotate(Model, radiansY, glm::vec3(0.0f, 1.0f, 0.0f));
   Model = glm::translate(Model, transVec3);

   mvpMatrix = Projection * View * Model;
}

void Blending::OnSurfaceChanged(int width, int height) {
   Srceenwidth = width;
   Srceenheight = height;
   LOGD("OnSurfaceChanged Srceenwidth = %d, Srceenheight = %d, ratio = %f", Srceenwidth,Srceenheight);
}

#

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值