OpenGL ES 3.0(8) 워터마크가 있는 카메라 미리보기
이번에는 안드로이드에서 워터마크가 있는 카메라 미리보기 기능을 구현하기 위해 두 개의 무늬가 필요합니다. 하나는 카메라 미리보기, 하나는 워터마크를 표시하는 데 사용되고 정점 착색기는 다음과 같습니다.
#version 300 es
layout(location=0) in vec4 aPosition;
layout(location=1) in vec4 aCameraTexCoord;
layout(location=2) in vec4 aWatermarkTexCoord;
uniform mat4 mCameraMatrix;
uniform mat4 mWatermarkMatrix;
out vec2 vCameraTexCoord;
out vec2 vWatermarkTexCoord;
void main() {
vCameraTexCoord = (mCameraMatrix * aCameraTexCoord).xy;
vWatermarkTexCoord = (mWatermarkMatrix * aWatermarkTexCoord).xy;
gl_Position = aPosition;
}
세그먼트 셰이더는 두 텍스쳐의 중첩 방법을 염두에 두고 알파 값으로 판단하면 됩니다.
#version 300 es
#extension GL_OES_EGL_image_external_essl3 : require
precision highp float;
uniform samplerExternalOES sCameraTexture;
uniform sampler2D sWatermarkTexture;
in vec2 vCameraTexCoord;
in vec2 vWatermarkTexCoord;
layout(location=0) out vec4 fragColor;
void main() {
vec4 camera = texture(sCameraTexture, vCameraTexCoord);
vec4 watermark = texture(sWatermarkTexture, vWatermarkTexCoord);
//
float r = watermark.r + (1.0 - watermark.a) * camera.r;
float g = watermark.g + (1.0 - watermark.a) * camera.g;
float b = watermark.b + (1.0 - watermark.a) * camera.b;
fragColor = vec4(r, g, b, 1.0);
}
OpenGL 코드
먼저 교점 좌표, 텍스쳐 좌표 등을 설정합니다.
const static GLfloat VERTICES[] = {
-1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
1.0f, -1.0f
};
const static GLfloat CAMERA_COORDS[] = {
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f,
};
const static GLfloat WATERMARK_COORD[] = {
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
};
const static GLushort INDICES[] = {
0, 1, 2,
0, 2, 3
};
const static GLuint ATTRIB_POSITION = 0;
const static GLuint ATTRIB_CAMERA_COORD = 1;
const static GLuint ATTRIB_WATERMARK_COORD = 2;
const static GLuint VERTEX_POS_SIZE = 2;
const static GLuint CAMERA_COORD_SIZE = 2;
const static GLuint WATERMARK_COORD_SIZE = 2;
const static GLuint INDEX_NUMBER = 6;
다음으로 OpenGL 환경을 초기화하고 Camera 미리 보기를 열기 위해 sCameraTexture의 id를 자바 층에 되돌려줍니다.
int Watermark::init() {
if (!mEGLCore->buildContext(mWindow)) {
return -1;
}
std::string *vShader = readShaderFromAsset(mAssetManager, "watermark.vert");
std::string *fShader = readShaderFromAsset(mAssetManager, "watermark.frag");
mProgram = loadProgram(vShader->c_str(), fShader->c_str());
glGenTextures(1, &mTextureOes);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureOes);
glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
glGenTextures(1, &mTexture2D);
glBindTexture(GL_TEXTURE_2D, mTexture2D);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mWatermarkWidth, mWatermarkHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, mWatermarkPixel);
mCameraMatrixLoc = glGetUniformLocation(mProgram, "mCameraMatrix");
mWatermarkMatrixLoc = glGetUniformLocation(mProgram, "mWatermarkMatrix");
mCameraTextureLoc = glGetUniformLocation(mProgram, "sCameraTexture");
mWatermarkTextureLoc = glGetUniformLocation(mProgram, "sWatermarkTexture");
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
delete vShader;
delete fShader;
return mTextureOes;
}
마지막으로 그리면 됩니다.
void Watermark::draw(GLfloat *cameraMatrix, GLfloat *watermarkMatrix) {
glViewport(0, 0, mWidth, mHeight);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(mProgram);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureOes);
glUniform1i(mCameraTextureLoc, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, mTexture2D);
glUniform1i(mWatermarkTextureLoc, 1);
glUniformMatrix4fv(mCameraMatrixLoc, 1, GL_FALSE, cameraMatrix);
glUniformMatrix4fv(mWatermarkMatrixLoc, 1, GL_FALSE, watermarkMatrix);
glEnableVertexAttribArray(ATTRIB_POSITION);
glVertexAttribPointer(ATTRIB_POSITION, VERTEX_POS_SIZE, GL_FLOAT, GL_FALSE, 0, VERTICES);
glEnableVertexAttribArray(ATTRIB_CAMERA_COORD);
glVertexAttribPointer(ATTRIB_CAMERA_COORD, CAMERA_COORD_SIZE, GL_FLOAT, GL_FALSE, 0,
CAMERA_COORDS);
glEnableVertexAttribArray(ATTRIB_WATERMARK_COORD);
glVertexAttribPointer(ATTRIB_WATERMARK_COORD, WATERMARK_COORD_SIZE, GL_FLOAT, GL_FALSE, 0,
WATERMARK_COORD);
// glDrawArrays(GL_TRIANGLE_STRIP, 0, VERTEX_NUM);
glDrawElements(GL_TRIANGLES, INDEX_NUMBER, GL_UNSIGNED_SHORT, INDICES);
glDisableVertexAttribArray(ATTRIB_POSITION);
glDisableVertexAttribArray(ATTRIB_CAMERA_COORD);
glDisableVertexAttribArray(ATTRIB_WATERMARK_COORD);
glFlush();
mEGLCore->swapBuffer();
}
Java 코드
Java 코드는 간단합니다. UI는 SurfaceView 하나만 있으면 됩니다. Camera를 열면 OpenGL에서 되돌아오는 무늬 id를 Camera에 설정하면 미리 보기가 가능합니다.
private void initOpenGL(Surface surface, int width, int height, byte[] watermark,
int watermarkWidth, int watermarkHeight) {
mExecutor.execute(() -> {
int textureId = _init(surface, width, height, watermark, watermark.length,
watermarkWidth, watermarkHeight, getAssets());
if (textureId < 0) {
Log.e(TAG, "surfaceCreated init OpenGL ES failed!");
return;
}
mSurfaceTexture = new SurfaceTexture(textureId);
mSurfaceTexture.setOnFrameAvailableListener(surfaceTexture -> drawOpenGL());
try {
mCamera.setPreviewTexture(mSurfaceTexture);
mCamera.startPreview();
} catch (IOException e) {
Log.e(TAG, "onSurfaceCreated exception: " + e.getLocalizedMessage());
}
});
}
private void drawOpenGL() {
mExecutor.execute(() -> {
if (mSurfaceTexture != null) {
mSurfaceTexture.updateTexImage(); // OpenGL
mSurfaceTexture.getTransformMatrix(mCameraMatrix);
_draw(mCameraMatrix, mWatermarkMatrix);
}
});
}
private void releaseOpenGL() {
mExecutor.execute(() -> {
if (mSurfaceTexture != null) {
mSurfaceTexture.release();
mSurfaceTexture = null;
}
_release();
});
}
여기서 ""처음에 native 방법으로 시작해서 물자국에 대해서는 그림이 될 수 있다.
private void makeImageWatermark() {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher, options);
int byteCount = bitmap.getByteCount();
ByteBuffer buffer = ByteBuffer.allocate(byteCount);
bitmap.copyPixelsToBuffer(buffer);
buffer.position(0);
mWatermark = buffer.array();
mWatermarkWidth = bitmap.getWidth();
mWatermarkHeight = bitmap.getHeight();
bitmap.recycle();
Matrix.scaleM(mWatermarkMatrix, 0, 2.5f, 2.5f, 2.5f);
}
또는 문자일 수 있습니다.
private void makeTextWatermark(int width, int height) {
Bitmap textBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(textBitmap);
Paint paint = new Paint();
paint.setColor(Color.argb(255, 255, 0, 0));
paint.setTextSize(28);
paint.setAntiAlias(true);
paint.setTextAlign(Paint.Align.CENTER);
Rect rect = new Rect(0, 0, width, height);
Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();
//
int baseline = (rect.bottom + rect.top - fontMetrics.bottom - fontMetrics.top) / 2;
canvas.drawText(" : zouzhiheng", rect.centerX(), baseline, paint);
int capacity = width * height * 4;
ByteBuffer buffer = ByteBuffer.allocate(capacity);
textBitmap.copyPixelsToBuffer(buffer);
buffer.position(0);
mWatermark = buffer.array();
mWatermarkWidth = textBitmap.getWidth();
mWatermarkHeight = textBitmap.getHeight();
textBitmap.recycle();
Matrix.scaleM(mWatermarkMatrix, 0, 2f, 2f, 2f);
}
의문
마지막으로 몇 가지 이해하지 못한 문제가 있었다.
소스가 GitHub에 업로드되었으므로 이에 대한 자세한 지침이 필요합니다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.