I have a bitmap on my device(which is a 6x1 cubemap), which I want to render on all the faces of the cube
InputStream is = getContext().getResources().openRawResource(R.raw.photo);
Bitmap bitmap = BitmapFactory.decodeStream(is);
int bytes = bitmap.getByteCount();
ByteBuffer pixels = ByteBuffer.allocate(bytes);
bitmap.copyPixelsToBuffer(pixels);
Here is my vertex shader:
uniform mat4 uMVPMatrix;
uniform mat4 uSTMatrix;
attribute vec4 aPosition;
attribute vec4 aTextureCoord;
attribute vec4 aColor;
varying vec2 vTextureCoord;
varying vec4 vColor;
void main() {
gl_Position = uMVPMatrix * aPosition;
vTextureCoord = (uSTMatrix * aTextureCoord).xy;
vColor = aColor;
}
Here is my fragment shader:
precision mediump float;
varying vec2 vTextureCoord;
varying vec4 vColor;
uniform samplerCube sTexture;
void main() {
gl_FragColor = textureCube(sTexture, vec3(vTextureCoord, 1.0)) * vColor;
}
And here is what I am doing in my renderer in onSurfaceCreated():
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
int[] texIds = new int[1];
GLES20.glGenTextures(1, texIds, 0);
m360PhotoTextureId = texIds[0];
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(
GLES20.GL_TEXTURE_CUBE_MAP,
mTextureId);
for (int i = 0 ; i < 6 ; i++ ){
pixels.position(0);
GLES20.glTexImage2D(
GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
0,
GLES20.GL_RGBA,
1,
1,
0,
GLES20.GL_RGBA,
GLES20.GL_UNSIGNED_BYTE,
pixels);
}
GLES20.glTexParameteri(
GLES20.GL_TEXTURE_CUBE_MAP,
GLES20.GL_TEXTURE_MIN_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameteri(
GLES20.GL_TEXTURE_CUBE_MAP,
GLES20.GL_TEXTURE_MAG_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameteri(
GLES20.GL_TEXTURE_CUBE_MAP,
GLES20.GL_TEXTURE_WRAP_S,
GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(
GLES20.GL_TEXTURE_CUBE_MAP,
GLES20.GL_TEXTURE_WRAP_T,
GLES20.GL_CLAMP_TO_EDGE);
GLES20.glBindTexture(GLES20.GL_TEXTURE_CUBE_MAP, 0);
All I see is a black screen in my texture view, when I expect to see a photo(in the pixels) being rendered on all the faces of the cube.
Any pointers or help would be appreciated.
I tried:
Vertex shader:
uniform mat4 uMVPMatrix;
attribute vec4 aPosition;
varying vec3 vTextureCoord;
void main() {
gl_Position = uMVPMatrix * aPosition;
vTextureCoord = aPosition.xyz;
}
Fragment shader:
precision mediump float;
varying vec3 vTextureCoord;
uniform samplerCube sTexture;
void main() {
gl_FragColor = textureCube(sTexture, vTextureCoord);
}
But I get the same black screen.
A cubemap texture is a texture who's images represent the faces of a cube. The "texture coordinate" for a cubemap texture is the vector direction from the center of the cube which points to the color you want to use.
You are trying to use a regular old 2D texture coordinate, with a third component probably added to silence the compiler. You must provide directions, not 2D coordinates. You can generate them in the vertex shader from your position. But that requires knowing what space aPosition is, and you didn't tell me. So I can't show you how to do that.
Regardless, the vertex shader needs to be providing a 3D direction for the texture coordinate. It should either be generated or passed from a VS input.
Note that your program may have other problems. But this is the problem that can be deduced from your code.
Related
I am trying to create image filters like Instagram for my Android application. I am new to image processing and have just stumbled upon this term called color mapping. After many research, I tried to create my own filter using OpenGL using a lookup table (LUT). But upon adding the filter to a camera, Here is the result:
You can see that there is this weird blueish color at the edge of my thumb. It only happens on overexposed areas of the image.
Here is the fragment shader code:
#extension GL_OES_EGL_image_external : require
precision lowp float;
varying highp vec2 vTextureCoord;
uniform samplerExternalOES inputImage;
uniform sampler2D lookup;
void main() {
vec2 tiles = vec2(8.0);
vec2 tileSize = vec2(64.0);
vec4 texel = texture2D(inputImage, vTextureCoord);
float index = texel.b * (tiles.x * tiles.y - 1.0);
float index_min = min(62.0, floor(index));
float index_max = index_min + 1.0;
vec2 tileIndex_min;
tileIndex_min.y = floor(index_min / tiles.x);
tileIndex_min.x = floor(index_min - tileIndex_min.y * tiles.x);
vec2 tileIndex_max;
tileIndex_max.y = floor(index_max / tiles.x);
tileIndex_max.x = floor(index_max - tileIndex_max.y * tiles.x);
vec2 tileUV = mix(0.5/tileSize, (tileSize-0.5)/tileSize, texel.rg);
vec2 tableUV_1 = tileIndex_min / tiles + tileUV / tiles;
vec2 tableUV_2 = tileIndex_max / tiles + tileUV / tiles;
vec3 lookUpColor_1 = texture2D(lookup, tableUV_1).rgb;
vec3 lookUpColor_2 = texture2D(lookup, tableUV_2).rgb;
vec3 lookUpColor = mix(lookUpColor_1, lookUpColor_2, index-index_min);
gl_FragColor = vec4(lookUpColor, 1.0);
}
Here is the lookup table. This is a base lookup table. I tried editing the lookup tables and applying the filter but the result is same, irrespective of the table.
What is causing this issue? Can anyone show me how to create a simple fragment shader that maps color from lookup table to the current texture? Any help would be appreciated. Regards.
Here is the code for loading the textures:
public static int loadTexture(final Bitmap img) {
int[] textures = new int[1];
GLES20.glGenTextures(1, textures, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, img, 0);
return textures[0];
}
Not sure what color space or gamma your external sampler is using, but it looks like you are getting input values outside of the zero-to-one range, so the over exposed areas are jumping a LUT tile boundary.
As a diagnostic, clamp your inputs between zero and one, but this is rarely the right "proper fix" as the clipping in the colors will be obvious.
Something like this:
vec4 texel = texture2D(inputImage, vTextureCoord);
texel = min(texel, 1.0);
I am working on a project in which I am using GLES20 to render a texture. I used GLUtils.texImage2D() to draw 2d texture image from the bitmap.
What do I need to implement to make these changes:
Place the texture to the right corner of the screen instead of stretching it to the full screen.
Provide incremental rotation frame by frame to the texture.
Shaders
private final static String FRAGMENT_SHADER =
"precision mediump float;\n" +
"varying vec2 vTextureCoord;\n" +
"uniform lowp sampler2D sTexture;\n" +
"uniform lowp sampler2D oTexture;\n" +
"void main() {\n" +
" lowp vec4 textureColor = texture2D(sTexture, vTextureCoord);\n" +
" lowp vec4 textureColor2 = texture2D(oTexture, vTextureCoord);\n" +
" \n" +
" gl_FragColor = mix(textureColor, textureColor2, textureColor2.a);\n" +
"}\n";
protected static final String DEFAULT_VERTEX_SHADER =
"attribute highp vec4 aPosition;\n" +
"attribute highp vec4 aTextureCoord;\n" +
"varying highp vec2 vTextureCoord;\n" +
"void main() {\n" +
"gl_Position = aPosition;\n" +
"vTextureCoord = aTextureCoord.xy;\n" +
"}\n";
Texture Generation
int[] textures = new int[1];
#Override
public void setup() {
super.setup();// 1
GLES20.glGenTextures(1, textures, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
}
#Override
public void onDraw() {
if (bitmap == null) {
return;
}
int offsetDepthMapTextureUniform = getHandle("oTexture");
GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
if (bitmap != null && !bitmap.isRecycled()) {
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, bitmap, 0);
}
GLES20.glUniform1i(offsetDepthMapTextureUniform, 3);
// Recycle the bitmap, since its data has been loaded into OpenGL.
releaseBitmap();
}
UPDATED
I added the mMVPMatrix for the texture transformation as suggested by alexrnov. Both, camera feed and overlay texture are rotating now.
protected static final String VERTEX_SHADER ="attribute highp vec4 aPosition;\n" +
"uniform mat4 uMVPMatrix;\n" +
"attribute highp vec4 aTextureCoord;\n" +
"varying highp vec2 vTextureCoord;\n" +
"void main() {\n" +
"gl_Position = uMVPMatrix * aPosition;\n" +
"vTextureCoord = aTextureCoord.xy;\n" +
"}\n";
#Override
public void onDraw() {
....
Matrix.setIdentityM(mvpMatrix, 0);
Matrix.rotateM(mvpMatrix, 0, rotation, 0.0f, 0.0f, 1.0f);
rotation++;
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, getMVPMatrixAsFloatBuffer(mvpMatrix));
...
}
The project structure is quite complicated. I can't write all the code here. Please refer the Github Project
Maybe there is another way, but you can overlay the texture on the rectangle, and apply transformations (movement/rotate) to this rectangle:
Vertex shader:
#version 100
uniform mat4 u_mvpMatrix; // MVP-matrix for moving and rotating texture
attribute vec4 a_position; // data of vertices rectangle
attribute vec2 a_textureCoordinates;
varying vec2 v_textureCoordinates;
void main() {
v_textureCoordinates = a_textureCoordinates;
gl_Position = u_mvpMatrix * a_position;
}
Fragment shader:
#version 100
varying vec2 v_textureCoordinates;
uniform sampler2D s_texture;
void main() {
gl_FragColor = texture2D(s_texture, v_textureCoordinates);
}
Approximate Java-code:
private final int textureID;
...
textureID = loadTexture(R.raw.texture);
...
#Override
public void draw() {
GLES20.glUseProgram(programObject);
GLES20.glEnableVertexAttribArray(positionLink);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, VBO[0]);
GLES20.glVertexAttribPointer(positionLink, VERTEX_COMPONENT,
GLES20.GL_FLOAT, false, VERTEX_STRIDE, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
GLES20.glEnableVertexAttribArray(textureCoordinatesLink);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, VBO[1]);
GLES20.glVertexAttribPointer(textureCoordinatesLink, TEXTURE_COMPONENT,
GLES20.GL_FLOAT, false, TEXTURE_STRIDE, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureID);
GLES20.glUniform1i(samplerLink, 0);
GLES20.glUniformMatrix4fv(mvpMatrixLink, 1, false,
RectangleObject3D.getMVPMatrixAsFloatBuffer());
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, VBO[2]);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, NUMBER_INDICES,
GLES20.GL_UNSIGNED_INT, 0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
GLES20.glDisableVertexAttribArray(positionLink);
GLES20.glDisableVertexAttribArray(textureCoordinatesLink);
}
MVP-matrix:
import android.opengl.Matrix
protected val viewMatrix = FloatArray(16)
protected val projectionMatrix = FloatArray(16)
protected val modelMatrix = FloatArray(16)
protected val modelViewMatrix = FloatArray(16)
protected val mvpMatrix = FloatArray(16)
...
Matrix.setLookAtM(viewMatrix, 0, 0f, 0f, 0f,
0f, 0f, -4f, 0f, 1.0f, 0.0f) // camera
...
// parameters different for portrait and landscape orientation screen android
Matrix.frustumM(projectionMatrix, 0, left, right, bottom, top, near, far)
...
fun spotPosition() { // invoke on every frame
Matrix.setIdentityM(modelMatrix, 0)
Matrix.translateM(modelMatrix, 0, x, y, z) // move object
Matrix.rotateM(modelMatrix, 0, angleX, 0.0f, 1.0f, 0.0f) // rotate object
Matrix.scaleM(modelMatrix, 0, 4f, 4f, 4f) // scale object
Matrix.multiplyMM(modelViewMatrix, 0, viewMatrix, 0, modelMatrix, 0)
Matrix.multiplyMM(mvpMatrix, 0, projectionMatrix, 0, modelViewMatrix, 0)
}
fun getMVPMatrixAsFloatBuffer(): FloatBuffer = floatBuffer(mvpMatrix)
get FloatBuffer (essential in Java SDK):
public static FloatBuffer floatBuffer(float[] data) {
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(data.length * 4)
.order(ByteOrder.nativeOrder());
FloatBuffer returnBuffer = byteBuffer.asFloatBuffer();
returnBuffer.put(data).position(0);
return returnBuffer;
}
I've been trying to apply the filters I use in the android-gpuimage library in the Mediacodec surface context. So far I've succeeded in using the filters that only require one extra texture map. However, when I try to apply a filter that needs at least two, the result is an either blue-colored or rainbow-colored mess.
The following issue deals with the one that uses a texture lookup filter and an vignette filter.
The vertex shader I used is as follows:
uniform mat4 uMVPMatrix;
uniform mat4 textureTransform;
attribute vec4 vPosition;
attribute vec4 vTexCoordinate;
varying vec2 v_TexCoordinate;
void main() {
gl_Position = uMVPMatrix * vPosition;
v_TexCoordinate = (textureTransform * vTexCoordinate).xy;
}
The fragment shader I used is as follows:
#extension GL_OES_EGL_image_external : require
precision lowp float;
varying highp vec2 v_TexCoordinate;
uniform samplerExternalOES u_Texture; //MediaCodec decoder provided data
uniform sampler2D inputImageTexture2; //Amaro filter map
uniform sampler2D inputImageTexture3; //Common vignette map
void main()
{
vec3 texel = texture2D(u_Texture, v_TexCoordinate).rgb;
vec2 red = vec2(texel.r, 0.16666);
vec2 green = vec2(texel.g, 0.5);
vec2 blue = vec2(texel.b, 0.83333);
texel.rgb = vec3(
texture2D(inputImageTexture2, red).r,
texture2D(inputImageTexture2, green).g,
texture2D(inputImageTexture2, blue).b);
//After further research I found the problem is somewhere below
vec2 tc = (2.0 * v_TexCoordinate) - 1.0;
float d = dot(tc, tc);
vec2 lookup = vec2(d, texel.r);
texel.r = texture2D(inputImageTexture3, lookup).r;
lookup.y = texel.g;
texel.g = texture2D(inputImageTexture3, lookup).g;
lookup.y = texel.b;
texel.b = texture2D(inputImageTexture3, lookup).b;
//The problem is somewhere above
gl_FragColor = vec4(texel, 1.0);
}
The end result of that program looked like this:
Is this the result of a bad vignette map, or is it something to do with the vignette application part of the fragment shader?
EDIT:
The texture used for inputImageTexture2:
The texture used for inputImageTexture3:
Turns out the way I load my textures matters.
My current code for loading textures:
public int loadColormap(final Bitmap colormap) {
IntBuffer textureIntBuf = IntBuffer.allocate(1);
GLES20.glGenTextures(1, textureIntBuf);
int textureHandle = textureIntBuf.get();
//if (textures[2] != 0) {
if (textureHandle != 0) {
//GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[2]);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, colormap, 0);
}
//if (textures[2] == 0) {
if (textureHandle == 0) {
throw new RuntimeException("Error loading texture.");
}
//return textures[2];
return textureHandle;
}
The previous incarnation used the textures array, an array I use to load the data from MediaCodec and the watermark. For some reason if I use that instead of generating an IntBuffer for each texture, the textures used in the fragment shader get jumbled or something.
I am using libgdx to create a virtual trial room app. I am new to both Java and libgdx, so I might be wrong somewhere.
I plan to create a shader and a Mesh, and a texture is rendered on the Mesh(texture is a fabric of purple color with stripes). Then I plan to do affine transformation of very small triangles(shear, rotate, transform or translate) in the mesh to form a shirt(2D image) like below.
My idea is when the triangles transform, they take with them the part of texture with them, and the texture is modified.
Initially when I try to render the texture on the mesh, it shows a black screen instead of the purple fabric. My code:
public class MyAffineTransformation implements ApplicationListener {
Texture img;
String vertexShader;
String fragmentShader;
Mesh mesh;
ShaderProgram shader;
private float[] verts = new float[MAX_VERTS * NUM_COMPONENTS]; //Used to make triangles
private int idx = 0; //The index position
#Override
public void create() {
img = new Texture(Gdx.files.internal("fabric.jpg"));
img.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
img.setFilter(TextureFilter.Linear, TextureFilter.Linear);
mesh = new Mesh(true, 3, 3, new VertexAttribute(Usage.Position, POSITION_COMPONENTS, ShaderProgram.POSITION_ATTRIBUTE),
new VertexAttribute(Usage.TextureCoordinates, 2, ShaderProgram.TEXCOORD_ATTRIBUTE));
mesh.setVertices(new float[] { -0.5f, -0.5f, 0.5f, -0.5f, 0, 0.5f });
mesh.setIndices(new short[] { 0, 1, 2 });
//Shader - vertex and fragment shader are posted below
vertexShader = Gdx.files.internal("affine.vert").readString();
fragmentShader = Gdx.files.internal("affine.frag").readString();
shader = new ShaderProgram(vertexShader, fragmentShader);
}
#Override
public void render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
Gdx.graphics.getGL20().glEnable(GL20.GL_TEXTURE_2D);
img.bind();
mesh.render(shader, GL20.GL_TRIANGLES, 0, 3);
}
My Vertex Shader:
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord;
uniform mat4 u_projTrans;
varying vec4 v_color;
varying vec2 v_texCoords;
void main() {
v_texCoords = a_texCoord;
gl_Position = u_projTrans * a_position;
}
Fragment Shader:
#ifdef GL_ES
#define LOWP lowp
precision mediump float;
#else
#define LOWP
#endif
varying LOWP vec4 v_color;
varying vec2 v_texCoords;
uniform sampler2D u_texture;
void main()
{
gl_FragColor = v_color * texture2D(u_texture, v_texCoords);
}
It shows a black screen as of now. Please help me render texture on Mesh.
Also, when that happens, is it possible to do Affine transfotmation(rotation, translation, scaling, shearing etc) of small triangles in the mesh to form a 2D shirt. Please let me know if I am wrong somewhere.
I'm implementing skeletal animation in my android phone, and here is how I do it:
Calcualte all bone transformation matrices on the CPU side
Create a float texture to store these matrices (so this is done at the beginning of each frame). The codes look like below:
if(texID) {
glDeleteTextures(1, &texID);
texID = 0;
}
glGenTextures(1, &texID);
glBindTexture(GL_TEXTURE_2D, texID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_FLOAT, p);
In vertex shader, fetch matrix from this texture and apply to vertex position
This approach works fine in my Motorola Milestone XT-701 using a POWERVR GPU. But when I run it on a Qualcomm snapdragon (SE Xperia X10i and Google Nexus one), there are many triangles disappeared (looks randomly), so it seems the model is flickering.
I also tried to reduce the scene complexity by rendering only one animated model, and the flicker become less but still exists. Does anyone know what I may be doing wrong? Is this some kind of synchronization problem?
You can see the snapshots here (the first two pictures is correct, and the later two are wrong). The APK file of my grogram can be downloaded here. (it does not require any permission so don't worry)
Here is the vertex shader I used:
struct light {
lowp vec4 position; // light position for a point/spot light or
// normalized dir. for a directional light
lowp vec4 ambient_color;
lowp vec4 diffuse_color;
lowp vec4 specular_color;
lowp vec3 spot_direction;
lowp vec3 attenuation_factors;
lowp float spot_exponent;
lowp float spot_cutoff_angle;
bool compute_distance_attenuation;
};
struct material {
lowp vec4 ambient_color;
lowp vec4 diffuse_color;
lowp vec4 specular_color;
lowp vec4 emissive_color;
lowp float specular_exponent;
};
// uniforms used by the vertex shader
// uniform vec4 u_color;
uniform highp mat4 u_mvMatrix;
uniform highp mat4 u_projMatrix;
uniform bool u_enable_lighting;
uniform light u_light_state;
uniform material u_material_state;
uniform bool u_enable_texture;
uniform highp sampler2D s_jointTex; // use highp for float texture
// attributes input to the vertex shader
// attribute lowp vec4 a_color;
attribute highp vec3 a_position;
attribute lowp vec3 a_normal;
attribute mediump vec2 a_texCoord;
attribute highp float a_jointID;
// varying variables – input to the fragment shader
varying lowp vec4 v_front_color;
varying mediump vec2 v_texCoord;
vec2 mapTo2D(float idx)
{
vec2 st = vec2(idx + 0.5, 0.5);
return st / 256.0;
}
void main()
{
mat4 joint = mat4(1.0);
if(a_jointID >= 0.0)
{
float idx = a_jointID * 4.0;
joint = mat4( texture2D(s_jointTex, mapTo2D(idx)),
texture2D(s_jointTex, mapTo2D(idx+1.0)),
texture2D(s_jointTex, mapTo2D(idx+2.0)),
texture2D(s_jointTex, mapTo2D(idx+3.0)) );
gl_Position = (u_projMatrix * u_mvMatrix) * joint * vec4(a_position, 1.0); // hint compiler to extract uniform calculation
// v_front_color = vec4(1.0, 0.0, 0.0, 1.0);
}
else
{
gl_Position = (u_projMatrix * u_mvMatrix) * vec4(a_position, 1.0); // hint compiler to extract uniform calculation
// v_front_color = vec4(0.0, 1.0, 0.0, 1.0);
}
if(u_enable_lighting)
{
lowp vec4 computed_color = vec4(0.0);
vec3 normal = normalize( vec3(u_mvMatrix * joint * vec4(a_normal, 0.0) ) );
vec3 lightDir = normalize( vec3(u_mvMatrix * u_light_state.position) );
float NdotL = max(dot(normal, lightDir), 0.0);
computed_color += u_light_state.ambient_color * u_material_state.ambient_color + NdotL * u_light_state.diffuse_color * u_material_state.diffuse_color;
if(NdotL > 0.0) {
vec3 half_vec = normalize(lightDir + vec3(0.0, 0.0, 1.0)); // why?
float NdotHV = dot(normal, half_vec);
if(NdotHV > 0.0)
computed_color += u_light_state.specular_color * u_material_state.specular_color * pow(NdotHV, u_material_state.specular_exponent);
}
v_front_color = computed_color;
}
else
v_front_color = vec4(1.0, 1.0, 1.0, 1.0); // u_material_state.ambient_color; // TODO?
v_texCoord = a_texCoord;
}
Re-creating a texture each frame is not efficient. You can use the same texID and just call glTexImage* each frame.
Why don't you use 1D texture? It would remove a burden of tex-coord conversion to 2D.
Your joint matrix is 4x4, but you store it as 4 GL_RGBA vectors. This internal format does allow only [0,1] range, which is not appropriate for your task. Try using GL_RGBA_16f as internal format instead.