This question already has answers here:
How to read the content of a file to a string in C?
(12 answers)
Closed 5 years ago.
I'm writing a OpenGL with NDK example.
My shader code in main.c:
const char vShaderStr[] =
"#version 300 es \n"
"uniform mat4 u_mvpMatrix; \n"
"layout(location = 0) in vec4 a_position; \n"
"layout(location = 1) in vec4 a_color; \n"
"out vec4 v_color; \n"
"void main() \n"
"{ \n"
" v_color = a_color; \n"
" gl_Position = u_mvpMatrix * a_position; \n"
"} \n";
const char fShaderStr[] =
"#version 300 es \n"
"precision mediump float; \n"
"in vec4 v_color; \n"
"layout(location = 0) out vec4 outColor; \n"
"void main() \n"
"{ \n"
" outColor = v_color; \n"
"} \n";
userData->programObject = esLoadProgram ( vShaderStr, fShaderStr );
I had tried this snippet to convert(I also change the way of create shader in main.c), but failed:
I want use extern shader file by reading them in main.c .
How can I convert it?
You'd do it the same way that you'd load any other file:
char * get_file_contents(char const* file_name) {
FILE * file = fopen("vert.glsl", "r");
fseek(file, 0, SEEK_END);
size_t size = ftell(file);
rewind(file);
char * str = malloc(size);
fread(str, 1, size, file);
fclose(file);
return str;
}
int main() {
/*...*/
char const* vShaderStr = get_file_contents("vert.glsl");
char const* fShaderStr = get_file_contents("frag.glsl");
userData->programObject = esLoadProgram ( vShaderStr, fShaderStr );
free(vShaderStr);
free(fShaderStr);
/*...*/
}
I only program in C++, so I'm not going to try to add error handling to this code. This should be enough for you to get a start, though.
Related
I am a freshman with OpenGL. I try to find the solution to my problem. I have recorded a video with alpha mask. The top part of video RGB and bottom is alpha. As I understand need to change my shaders, but I don`t understand how to do this.
Vertex shader
private static final String vertexShaderCode =
"attribute vec4 vPosition;" +
"attribute vec4 vTexCoordinate;" +
"uniform mat4 textureTransform;" +
"varying vec2 v_TexCoordinate;" +
"void main() {" +
" v_TexCoordinate = (textureTransform * vTexCoordinate).xy;" +
" gl_Position = vPosition;" +
"}";
Fragment shader
private static final String fragmentShaderCode =
"#extension GL_OES_EGL_image_external : require\n" +
"precision mediump float;" +
"uniform samplerExternalOES texture;" +
"varying vec2 v_TexCoordinate;" +
"void main () {" +
" vec4 color = texture2D(texture, v_TexCoordinate);" +
" gl_FragColor = color;" +
"}";
To skip fragments you can use the discard keyword in the fragment shader.
You have to do 2 look ups to the texture. The first one in the upper half, to get the RGB color channels and the 2nd one in the lower half to get the mask from the red color channel:
vec2 c_uv = vec2(texture.x, texture.y*0.5);
vec4 color = texture2D(c_uv, v_TexCoordinate);
vec2 m_uv = vec2(texture.x, 0.5 + texture.y*0.5);
float mask = texture2D(m_uv, v_TexCoordinate).r;
The fragment shader may look like this:
#extension GL_OES_EGL_image_external : require
precision mediump float;
uniform samplerExternalOES texture;
varying vec2 v_TexCoordinate;
void main () {
vec2 m_uv = vec2(v_TexCoordinate.x, 0.5 + v_TexCoordinate.y*0.5);
float mask = texture2D(texture, m_uv).r;
if ( mask < 0.5 )
discard;
vec2 c_uv = vec2(v_TexCoordinate.x, v_TexCoordinate.y*0.5);
vec4 color = texture2D(texture, c_uv);
gl_FragColor = color;
}
I'm having mpvMatrix (mvpMatrix is calculated as model * view * projection using Matrix.multiply()) and passing it to shader and it's ok.
Now i'd like to move multiplication from CPU to GPU (from Matrix.multiply to shader).
If i'm trying to pass model, view and projection martrix separately and multiply them in shader i see nothing.
I'm sure matrix are not null and have real values (as if i multiply them on CPU instead of GPU it's ok), matrix uniform index are >= 0 (they are found in shader). What can be wrong?
Shaders:
private final String vertexShader =
"uniform mat4 u_mMatrix; \n" // Матрица модели
+ "uniform mat4 u_vMatrix; \n" // Матрица модели
+ "uniform mat4 u_pMatrix; \n" // Матрица модели
+ "attribute vec4 a_Position; \n" // Информация о положении вершин.
+ "attribute vec2 a_TexCoordinate; \n" // Per-vertex texture coordinate information we will pass in.
+ "varying vec2 v_TexCoordinate; \n" // This will be passed into the fragment shader.
+ "void main() \n" // Начало программы вершинного шейдера.
+ "{ \n"
+ " v_TexCoordinate = a_TexCoordinate; \n"
+ " mat4 mvMatrix = u_mMatrix * u_vMatrix;"
+ " mat4 mvpMatrix = mvMatrix * u_pMatrix;"
+ " gl_Position = mvpMatrix \n" // gl_Position специальные переменные используемые для хранения конечного положения.
+ " * a_Position; \n" // Умножаем вершины на матрицу для получения конечного положения
+ "} \n"; // в нормированных координатах экрана.
private final String fragmentShader =
"precision mediump float; \n" // Устанавливаем по умолчанию среднюю точность для переменных. Максимальная точность в фрагментном шейдере не нужна.
+ "uniform sampler2D u_Texture; \n" // The input texture.
+ "varying vec2 v_TexCoordinate; \n" // Interpolated texture coordinate per fragment.
+ "void main() \n" // Точка входа для фрагментного шейдера.
+ "{ \n"
+ " gl_FragColor = texture2D(u_Texture, v_TexCoordinate); \n" // Передаем значения цветов.
+ "}";
Binding:
mMatrixHandle = GLES20.glGetUniformLocation(programHandle, "u_mMatrix"); // = 0
vMatrixHandle = GLES20.glGetUniformLocation(programHandle, "u_vMatrix"); // = 2
pMatrixHandle = GLES20.glGetUniformLocation(programHandle, "u_pMatrix"); // = 3
Drawing:
GLES20.glUniformMatrix4fv(mMatrixHandle, 1, false, modelMatrix, 0);
GLES20.glUniformMatrix4fv(vMatrixHandle, 1, false, viewMatrix, 0);
GLES20.glUniformMatrix4fv(pMatrixHandle, 1, false, projectionMatrix, 0);
Actually my matrix multiplication order in shader was wrong, the correct order is:
gl_Position = u_pMatrix * u_mMatrix * u_vMatrix * a_Position;
so the correct shader source is:
private final String vertexShader =
"uniform mat4 u_mMatrix; \n" // Матрица модели
+ "uniform mat4 u_vMatrix; \n" // Матрица модели
+ "uniform mat4 u_pMatrix; \n" // Матрица модели
+ "attribute vec4 a_Position; \n" // Информация о положении вершин.
+ "attribute vec2 a_TexCoordinate; \n" // Per-vertex texture coordinate information we will pass in.
+ "varying vec2 v_TexCoordinate; \n" // This will be passed into the fragment shader.
+ "void main() \n" // Начало программы вершинного шейдера.
+ "{ \n"
+ " v_TexCoordinate = a_TexCoordinate; \n"
+ " gl_Position = u_pMatrix * u_mMatrix * u_vMatrix \n" // gl_Position специальные переменные используемые для хранения конечного положения.
+ " * a_Position; \n" // Умножаем вершины на матрицу для получения конечного положения
+ "} \n"; // в нормированных координатах экрана.
I am doing yuv to rgb conversion using opengl shaders. But its only show green and pink colors. I am using ffmpeg to decode movie. I am beginner in this, so have no idea how to solve it. ffmpeg give me three buffers of yuv. I am directly assigning these buffers to three textures.
Here are shaders I am using.
static const char* VERTEX_SHADER =
"attribute vec4 vPosition; \n"
"attribute vec2 a_texCoord; \n"
"varying vec2 tc; \n"
"uniform mat4 u_mvpMat; \n"
"void main() \n"
"{ \n"
" gl_Position = u_mvpMat * vPosition; \n"
" tc = a_texCoord; \n"
"} \n";
static const char* YUV_FRAG_SHADER =
"#ifdef GL_ES \n"
"precision highp float; \n"
"#endif \n"
"varying vec2 tc; \n"
"uniform sampler2D TextureY; \n"
"uniform sampler2D TextureU; \n"
"uniform sampler2D TextureV; \n"
"uniform float imageWidth; \n"
"uniform float imageHeight; \n"
"void main(void) \n"
"{ \n"
"float nx, ny; \n"
"vec3 yuv; \n"
"vec3 rgb; \n"
"nx = tc.x; \n"
"ny = tc.y; \n"
"yuv.x = texture2D(TextureY, tc).r; \n"
"yuv.y = texture2D(TextureU, vec2(nx/2.0, ny/2.0)).r - 0.5; \n"
"yuv.z = texture2D(TextureV, vec2(nx/2.0, ny/2.0)).r - 0.5; \n"
// Using BT.709 which is the standard for HDTV
"rgb = mat3( 1, 1, 1, \n"
"0, -0.18732, 1.8556, \n"
"1.57481, -0.46813, 0)*yuv;\n"
// BT.601, which is the standard for SDTV is provided as a reference
//"rgb = mat3( 1, 1, 1, \n"
// "0, -0.34413, 1.772, \n"
// "1.402, -0.71414, 0) * yuv; \n"
"gl_FragColor = vec4(rgb, 1.0); \n"
"} \n";
Output:
What wrong am I doing? Please help me out with this.
Thank You.
UPDATE:
While debugging ffmpeg decoding, I found that ffmpeg decoder give PIX_FMT_YUV420P output format. Do I have to make some tweaks to get correct image colors?
I'm not sure about this transformation:
"rgb = mat3( 1, 1, 1, \n"
"0, -0.18732, 1.8556, \n"
"1.57481, -0.46813, 0)*yuv;\n"
In refreshing my memory on matrix * vector operations in GLSL using this page as reference, I think you either need to transpose the coefficient matrix, or move yuv to the front of the operation, i.e., yuv * mat3(...). Performing the operation as mat3(...) * yuv means:
r = y * 1 + u * 1 + v * 1
g = y * 0 + u * -0.18732 + v * 1.8556
b = y * 1.57481 + u * -0.46813 + v * 0
And these conversions are very incorrect.
As another reference, here's a small, complete, sample GLSL shader program that converts YUV -> RGB that may be of some guidance: http://www.fourcc.org/source/YUV420P-OpenGL-GLSLang.c
How can I pass a float value to fragment shader ?
This is my code on android:
int aUseTexture = GLES20.glGetAttribLocation(program, "uUseTexture");
GLES20.glUniform1f(aUseTexture, 1.0f);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
Here is my shader:
String verticesShader =
"uniform mat4 uScreen;\n" +
"attribute vec2 aPosition;\n" +
"attribute vec3 aColor;\n" +
"attribute vec2 aTexPos; \n" +
"varying vec2 vTexPos; \n" +
"varying vec3 vColor;\n" +
"void main() {\n" +
" vTexPos = aTexPos; \n" +
" gl_Position = uScreen * vec4(aPosition.xy, 0.0, 1.0);\n" +
" vColor = aColor;\n" +
"}";
// Our fragment shader. Just return vColor.
// If you look at this source and just said 'WTF?', remember
// that all the attributes are defined in the VERTEX shader and
// all the 'varying' vars are considered OUTPUT of vertex shader
// and INPUT of the fragment shader. Here we just use the color
// we received and add a alpha value of 1.
String fragmentShader =
"uniform float uUseTexture; \n" +
"uniform sampler2D uTexture;\n" +
"precision mediump float;\n"+
"varying vec2 vTexPos; \n" +
"varying vec3 vColor;\n" +
"void main(void)\n" +
"{\n" +
" if ( uUseTexture != 1.0 ) \n" +
" gl_FragColor = vec4(vColor.xyz, 1); \n" +
" else \n" +
" gl_FragColor = texture2D(uTexture, vTexPos); \n" +
//" gl_FragColor = vec4(vColor.xyz, 1);\n" +
"}";
You can see the if statement in the fragment shader , that is the one i tried to check if i pass in 1.0 it should do texture else use color.
You are probably using the wrong function call for "uniform variable". Try glGetUniformLocation() as follow:
int aUseTexture = GLES20.glGetUniformLocation(program, "uUseTexture");
Also, the floating point testing (uUseTexture != 1.0) may not be always reliable all the time. You may want to use an integer type.
As far as I know you have to pass the value through the vertex shader before it can get to the fragment shader. e.g. add "uniform float uUseTexture_in; \n" and "varying float uUseTexture; \n" at the top of the vertex shader, in the main function add "uUseTexture = uUseTexture_in;". And your shader should work
How can I draw a pixel(2D view)for Android using OpenGlEs?
It is simple when we use for drawing
draw(Canvas canvas)
{
...
}
So using it we draw
canvas.drawPoint(i, j, paint);
But in OpenGlEs I still haven't got any function like it.
Please reply
Thank in Advance
GLES20Renderer.programLight = GLES20.glCreateProgram();
int vertexShaderLight = GLES20Renderer.loadShader(GLES20.GL_VERTEX_SHADER, GLES20Renderer.vertexShaderCodeLight);
int fragmentShaderLight = GLES20Renderer.loadShader(GLES20.GL_FRAGMENT_SHADER, GLES20Renderer.fragmentShaderCodeLight);
GLES20.glAttachShader(GLES20Renderer.programLight, vertexShaderLight);
GLES20.glAttachShader(GLES20Renderer.programLight, fragmentShaderLight);
GLES20.glLinkProgram(GLES20Renderer.programLight);
uPLocationLight = GLES20.glGetUniformLocation(GLES20Renderer.programLight, "uP");
uVPositionLocationLight = GLES20.glGetUniformLocation(GLES20Renderer.programLight, "uVPosition");
GLES20.glUseProgram(GLES20Renderer.programLight);
GLES20.glUniform4f(uVPositionLocationLight, LightPosInEyeSpace[0], LightPosInEyeSpace[1], LightPosInEyeSpace[2], LightPosInEyeSpace[3]);
GLES20.glUniformMatrix4fv(uPLocationLight, 1, false, ProjectionMatrix, 0);
GLES20.glDrawArrays(GLES20.GL_POINTS, 0, 1);
private static final String vertexShaderCodeLight =
"uniform vec4 uVPosition; \n"
+ "uniform mat4 uP; \n"
+ "void main(){ \n"
+ " gl_PointSize = 15.0; \n"
+ " gl_Position = uP * uVPosition; \n"
+ "} \n";
private static final String fragmentShaderCodeLight =
"#ifdef GL_FRAGMENT_PRECISION_HIGH \n"
+ "precision highp float; \n"
+ "#else \n"
+ "precision mediump float; \n"
+ "#endif \n"
+ "void main(){ \n"
+ " gl_FragColor = vec4(1.0,1.0,1.0,1.0); \n"
+ "} \n";
glDrawElements(GL_POINTS, 0, num_points, point_array);
You can also use glDrawArrays if you use glVertexPointer first.
Use glPointParameter, glPointSize, and glColor to modify the appearance of the points. Using glPointSizePointer lets you specify an array of point sizes, which is handy for particle effects.