I am working on a augment reality project with ar-core and OpenGL. I have an issue while rendering objects in OpenGL, the transparency is not applying to the particular texture. I am rendering the texture for the 3d object from mtl using an obj loader library.
The rendered 3D object should look like this:
But my 3D object looks like this:
The transparency at the head of the object is missing.
My mtl file is: # Blender MTL File: 'Bacteriophage_new.blend' # Material Count: 7
newmtl Material_008_001
Ns 94.117647
Ka 1.000000 1.000000 1.000000
Kd 0.640000 0.640000 0.640000
Ks 0.125000 0.125000 0.125000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
map_Kd Green.png.001.png
newmtl Material_010_001
Ns 94.117647
Ka 1.000000 1.000000 1.000000
Kd 0.640000 0.640000 0.640000
Ks 0.125000 0.125000 0.125000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
map_Kd Green.png.004.png
newmtl Material_011_001
Ns 94.117647
Ka 1.000000 1.000000 1.000000
Kd 0.640000 0.640000 0.640000
Ks 0.125000 0.125000 0.125000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
map_Kd pink.jpg.002.jpg
newmtl Material_012_001
Ns 94.117647
Ka 1.000000 1.000000 1.000000
Kd 0.640000 0.640000 0.640000
Ks 0.125000 0.125000 0.125000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
map_Kd blue.png.002.png
newmtl Material_013_001
Ns 94.117647
Ka 1.000000 1.000000 1.000000
Kd 0.640000 0.640000 0.640000
Ks 0.125000 0.125000 0.125000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
map_Kd dark.png.002.png
newmtl Material_014_001
Ns 94.117647
Ka 1.000000 1.000000 1.000000
Kd 0.640000 0.640000 0.640000
Ks 0.125000 0.125000 0.125000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
map_Kd Green.png.004.png
newmtl Material_015_001
Ns 94.117647
Ka 1.000000 1.000000 1.000000
Kd 0.640000 0.640000 0.640000
Ks 0.125000 0.125000 0.125000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 0.800000
illum 2
map_Kd Green.png.004.png
My Main Actity class:
In OnSurfaceCreated preparing objects for draw by calling createOnGlThread Method:
renderObject.createOnGlThread(HelloArActivity.this,str + ".obj", str + ".png",ObjPath);
In OnDrawFrame Method draw a object by calling draw method
renderObject.draw(viewmtx,projmtx,lightIntensity,mAnchorMatrix,scaleFactor);
RenderObject class:
package com.google.ar.core.examples.java.helloar.rendering;
import android.content.Context;
import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import de.javagl.obj.Mtl;
import de.javagl.obj.MtlReader;
import de.javagl.obj.Obj;
import de.javagl.obj.ObjReader;
import de.javagl.obj.ObjSplitting;
import de.javagl.obj.ObjUtils;
public class RenderObject
{
private static final String TAG =
RenderObject.class.getSimpleName();
private final List<ObjectRenderer> materialGroupObjectRenderers;
public RenderObject()
{
this.materialGroupObjectRenderers = new ArrayList<>();
}
public void createOnGlThread(Context context, String objAssetName,
String defaultTextureFileName,String ObjPath) throws IOException
{
// Read the obj file.
Log.d("ObjPathPlus",ObjPath+objAssetName);
try {
InputStream objInputStream = context.getAssets().open(ObjPath + objAssetName);
Log.d("GetInputStream",""+objInputStream);
Obj obj = ObjReader.read(objInputStream);
/ Obj renderableObj = ObjUtils.convertToRenderable(obj);
// When there are no material groups, then just render the object
// using the default texture
Log.d("HowManyVertices", "" + renderableObj.getNumVertices());
Log.d("GetTMatG", "" + renderableObj.getNumMaterialGroups());
if (renderableObj.getNumMaterialGroups() == 0) {
createRenderers(context, renderableObj, defaultTextureFileName);
} else {
// Otherwise, create one renderer for each material
createMaterialBasedRenderers(context, renderableObj,
defaultTextureFileName,ObjPath);
}
}catch (Exception e)
{
Log.d("GetPatheE",""+e.toString());
}
}
private void createRenderers(Context context, Obj obj,
String textureFileName) throws IOException
{
if (obj.getNumVertices() <= 65000)
{
createRenderer(context, obj, textureFileName);
}
else
{
Log.d("ObjectVertextG","Greater");
// If there are more than 65k vertices, then the object has to be
// split into multiple parts, each having at most 65k vertices
List<Obj> objParts = ObjSplitting.splitByMaxNumVertices(obj, 65000);
for (int j = 0; j < objParts.size(); j++)
{
Obj objPart = objParts.get(j);
createRenderer(context, objPart, textureFileName);
}
}
}
private void createMaterialBasedRenderers(Context context, Obj obj,
String defaultTextureFileName,String ObjPath) throws IOException
{
List<String> mtlFileNames = obj.getMtlFileNames();
List<Mtl> allMtls = new ArrayList<>();
for (String mtlFileName : mtlFileNames)
{
InputStream mtlInputStream = context.getAssets().open(ObjPath+mtlFileName);
List<Mtl> mtls = MtlReader.read(mtlInputStream);
allMtls.addAll(mtls);
}
// Obtain the material groups from the OBJ, and create renderers for
// each of them
Map<String, Obj> materialGroupObjs =
ObjSplitting.splitByMaterialGroups(obj);
for (Map.Entry<String, Obj> entry : materialGroupObjs.entrySet())
{
String materialName = entry.getKey();
String textureFileName = findTextureFileName(materialName, allMtls,
defaultTextureFileName);
Log.d("GtTexture",textureFileName);
Obj materialGroupObj = entry.getValue();
createRenderers(context, materialGroupObj, ObjPath+textureFileName);
}
}
private String findTextureFileName(String materialName,
Iterable<? extends Mtl> mtls, String defaultTextureFileName)
{
for (Mtl mtl : mtls)
{
if (Objects.equals(materialName, mtl.getName()))
{
if(mtl.getName().equals("Material_015_001"))
{
Log.d("GetDissolve",""+mtl.getD());
}
Log.d("ObjectsARe",materialName+"="+mtl.getName());
return mtl.getMapKd();
}
}
return defaultTextureFileName;
}
private void createRenderer(Context context, Obj obj,
String textureFileName) throws IOException
{
Log.i(TAG, "Rendering part with " + obj.getNumVertices()
+ " vertices and " + textureFileName);
ObjectRenderer objectRenderer = new ObjectRenderer();
objectRenderer.createOnGlThread(context, obj, textureFileName);
materialGroupObjectRenderers.add(objectRenderer);
}
/**
* Draws the model.
*
* @param cameraView A 4x4 view matrix, in column-major order.
* @param cameraPerspective A 4x4 projection matrix, in column-major order.
* @param lightIntensity Illumination intensity. Combined with diffuse and
* specular material properties.
*/
public void draw(float[] cameraView, float[] cameraPerspective,
float lightIntensity,float[] AnchorMatrix,float scalfactor)
{
Log.d("ObjRenSize",""+materialGroupObjectRenderers.size()+"And ScaleFactor"+"="+scalfactor);
for (ObjectRenderer renderer : materialGroupObjectRenderers)
{
renderer.updateModelMatrix(AnchorMatrix,scalfactor);
renderer.draw(cameraView, cameraPerspective, lightIntensity);
}
// ObjectRenderer objectRenderer=new ObjectRenderer();
// objectRenderer.updateModelMatrix(AnchorMatrix,scalfactor);
}
}
ObjectRenderer class:
package com.google.ar.core.examples.java.helloar.rendering;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLES30;
import android.opengl.GLUtils;
import android.opengl.Matrix;
import android.util.Log;
import com.google.ar.core.examples.java.helloar.R;
import com.google.ar.core.examples.java.helloar.TGAReader;
import de.javagl.obj.Mtl;
import de.javagl.obj.MtlReader;
import de.javagl.obj.Obj;
import de.javagl.obj.ObjData;
import de.javagl.obj.ObjFace;
import de.javagl.obj.ObjGroup;
import de.javagl.obj.ObjReader;
import de.javagl.obj.ObjSplitting;
import de.javagl.obj.ObjUtils;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import java.util.List;
public class ObjectRenderer {
private static final String TAG = ObjectRenderer.class.getSimpleName();
public enum BlendMode {
Shadow,
Grid
}
private static final int COORDS_PER_VERTEX = 3;
private static final float[] LIGHT_DIRECTION = new float[] { 0.250f, 0.866f, 0.433f, 0.0f };
private float[] mViewLightDirection = new float[4];
private int mVertexBufferId;
private int mVerticesBaseAddress;
private int mTexCoordsBaseAddress;
private int mNormalsBaseAddress;
private int mIndexBufferId;
private int mIndexCount;
private int mProgram;
private int[] mTextures = new int[1];
private int mModelViewUniform;
private int mModelViewProjectionUniform;
private int mPositionAttribute;
private int mNormalAttribute;
private int mTexCoordAttribute;
private int mTextureUniform;
private int mLightingParametersUniform;
private int mMaterialParametersUniform;
private BlendMode mBlendMode = null;
private float mAmbient = 0.3f;
private float mDiffuse = 1.0f;
private float mSpecular = 1.0f;
private float mSpecularPower = 6.0f;
private int[] vectorArrayObjectIds;
private String OBJ_PATH;
private Obj mObj;
public ObjectRenderer() {
}
public ObjectRenderer(String ObjPath)
{
OBJ_PATH=ObjPath;
}
public void createOnGlThread(Context context, Obj obj,
String diffuseTextureAssetName) throws IOException {
Log.d("TextureAssName",diffuseTextureAssetName);
Bitmap textureBitmap = BitmapFactory.decodeStream(
context.getAssets().open(diffuseTextureAssetName));
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glGenTextures(mTextures.length, mTextures, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextures[0]);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR_MIPMAP_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, textureBitmap, 0);
GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
textureBitmap.recycle();
ShaderUtil.checkGLError(TAG, "Texture loading");
IntBuffer wideIndices = ObjData.getFaceVertexIndices(obj, 3);
FloatBuffer vertices = ObjData.getVertices(obj);
FloatBuffer texCoords = ObjData.getTexCoords(obj, 2);
FloatBuffer normals = ObjData.getNormals(obj);
ShortBuffer indices = ByteBuffer.allocateDirect(2 * wideIndices.limit())
.order(ByteOrder.nativeOrder()).asShortBuffer();
while (wideIndices.hasRemaining()) {
indices.put((short) wideIndices.get());
}
indices.rewind();
int[] buffers = new int[2];
GLES20.glGenBuffers(2, buffers, 0);
mVertexBufferId = buffers[0];
mIndexBufferId = buffers[1];
mVerticesBaseAddress = 0;
mTexCoordsBaseAddress = mVerticesBaseAddress + 4 * vertices.limit();
mNormalsBaseAddress = mTexCoordsBaseAddress + 4 * texCoords.limit();
final int totalBytes = mNormalsBaseAddress + 4 * normals.limit();
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVertexBufferId);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, totalBytes, null, GLES20.GL_STATIC_DRAW);
GLES20.glBufferSubData(
GLES20.GL_ARRAY_BUFFER, mVerticesBaseAddress, 4 * vertices.limit(), vertices);
GLES20.glBufferSubData(
GLES20.GL_ARRAY_BUFFER, mTexCoordsBaseAddress, 4 * texCoords.limit(), texCoords);
GLES20.glBufferSubData(
GLES20.GL_ARRAY_BUFFER, mNormalsBaseAddress, 4 * normals.limit(), normals);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mIndexBufferId);
mIndexCount = indices.limit();
GLES20.glBufferData(
GLES20.GL_ELEMENT_ARRAY_BUFFER, 2 * mIndexCount, indices, GLES20.GL_STATIC_DRAW);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
ShaderUtil.checkGLError(TAG, "OBJ buffer load");
final int vertexShader = ShaderUtil.loadGLShader(TAG, context,
GLES20.GL_VERTEX_SHADER, R.raw.object_vertex);
final int fragmentShader = ShaderUtil.loadGLShader(TAG, context,
GLES20.GL_FRAGMENT_SHADER, R.raw.object_fragment);
mProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(mProgram, vertexShader);
GLES20.glAttachShader(mProgram, fragmentShader);
GLES20.glLinkProgram(mProgram);
GLES20.glUseProgram(mProgram);
ShaderUtil.checkGLError(TAG, "Program creation");
mModelViewUniform = GLES20.glGetUniformLocation(mProgram, "u_ModelView");
mModelViewProjectionUniform =
GLES20.glGetUniformLocation(mProgram, "u_ModelViewProjection");
mPositionAttribute = GLES20.glGetAttribLocation(mProgram, "a_Position");
mNormalAttribute = GLES20.glGetAttribLocation(mProgram, "a_Normal");
mTexCoordAttribute = GLES20.glGetAttribLocation(mProgram, "a_TexCoord");
mTextureUniform = GLES20.glGetUniformLocation(mProgram, "u_Texture");
mLightingParametersUniform = GLES20.glGetUniformLocation(mProgram, "u_LightingParameters");
mMaterialParametersUniform = GLES20.glGetUniformLocation(mProgram, "u_MaterialParameters");
ShaderUtil.checkGLError(TAG, "Program parameters");
Matrix.setIdentityM(mModelMatrix, 0);
}
// }
public void setBlendMode(BlendMode blendMode) {
mBlendMode = blendMode;
}
public void updateModelMatrix(float[] modelMatrix, float scaleFactor) {
float[] scaleMatrix = new float[16];
Matrix.setIdentityM(scaleMatrix, 0);
scaleMatrix[0] = scaleFactor;
scaleMatrix[5] = scaleFactor;
scaleMatrix[10] = scaleFactor;
Matrix.multiplyMM(mModelMatrix, 0, modelMatrix, 0, scaleMatrix, 0);
}
public void setMaterialProperties(
float ambient, float diffuse, float specular, float specularPower) {
mAmbient = ambient;
mDiffuse = diffuse;
mSpecular = specular;
mSpecularPower = specularPower;
}
public void draw(float[] cameraView, float[] cameraPerspective, float lightIntensity) {
ShaderUtil.checkGLError(TAG, "Before draw");
// Build the ModelView and ModelViewProjection matrices
// for calculating object position and light.
Matrix.multiplyMM(mModelViewMatrix, 0, cameraView, 0, mModelMatrix, 0);
Matrix.multiplyMM(mModelViewProjectionMatrix, 0, cameraPerspective, 0, mModelViewMatrix, 0);
GLES20.glUseProgram(mProgram);
// Set the lighting environment properties.
Matrix.multiplyMV(mViewLightDirection, 0, mModelViewMatrix, 0, LIGHT_DIRECTION, 0);
normalizeVec3(mViewLightDirection);
GLES20.glUniform4f(mLightingParametersUniform,
mViewLightDirection[0], mViewLightDirection[1], mViewLightDirection[2], lightIntensity);
// Set the object material properties.
GLES20.glUniform4f(mMaterialParametersUniform, mAmbient, mDiffuse, mSpecular,
mSpecularPower);
// Attach the object texture.
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextures[0]);
GLES20.glUniform1i(mTextureUniform, 0);
// Set the vertex attributes.
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVertexBufferId);
GLES20.glVertexAttribPointer(
mPositionAttribute, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, mVerticesBaseAddress);
GLES20.glVertexAttribPointer(
mNormalAttribute, 3, GLES20.GL_FLOAT, false, 0, mNormalsBaseAddress);
GLES20.glVertexAttribPointer(
mTexCoordAttribute, 2, GLES20.GL_FLOAT, false, 0, mTexCoordsBaseAddress);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
// Set the ModelViewProjection matrix in the shader.
GLES20.glUniformMatrix4fv(
mModelViewUniform, 1, false, mModelViewMatrix, 0);
GLES20.glUniformMatrix4fv(
mModelViewProjectionUniform, 1, false, mModelViewProjectionMatrix, 0);
// Enable vertex arrays
GLES20.glEnableVertexAttribArray(mPositionAttribute);
GLES20.glEnableVertexAttribArray(mNormalAttribute);
GLES20.glEnableVertexAttribArray(mTexCoordAttribute);
if (mBlendMode != null) {
GLES20.glDepthMask(false);
GLES20.glEnable(GLES20.GL_BLEND);
switch (mBlendMode) {
case Shadow:
// Multiplicative blending function for Shadow.
GLES20.glBlendFunc(GLES20.GL_ZERO, GLES20.GL_ONE_MINUS_SRC_ALPHA);
break;
case Grid:
// Grid, additive blending function.
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
break;
}
}
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mIndexBufferId);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, mIndexCount, GLES20.GL_UNSIGNED_SHORT, 0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
if (mBlendMode != null) {
GLES20.glDisable(GLES20.GL_BLEND);
GLES20.glDepthMask(true);
}
// Disable vertex arrays
GLES20.glDisableVertexAttribArray(mPositionAttribute);
GLES20.glDisableVertexAttribArray(mNormalAttribute);
GLES20.glDisableVertexAttribArray(mTexCoordAttribute);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
ShaderUtil.checkGLError(TAG, "After draw");
}
private static void normalizeVec3(float[] v) {
float reciprocalLength = 1.0f / (float) Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
v[0] *= reciprocalLength;
v[1] *= reciprocalLength;
v[2] *= reciprocalLength;
}
}
object_fragment.shader
precision mediump float;
uniform sampler2D u_Texture;
uniform vec4 u_LightingParameters;
uniform vec4 u_MaterialParameters;
varying vec3 v_ViewPosition;
varying vec3 v_ViewNormal;
varying vec2 v_TexCoord;
void main() {
// We support approximate sRGB gamma.
const float kGamma = 0.4545454;
const float kInverseGamma = 2.2;
// Unpack lighting and material parameters for better naming.
vec3 viewLightDirection = u_LightingParameters.xyz;
float lightIntensity = u_LightingParameters.w;
float materialAmbient = u_MaterialParameters.x;
float materialDiffuse = u_MaterialParameters.y;
float materialSpecular = u_MaterialParameters.z;
float materialSpecularPower = u_MaterialParameters.w;
// Normalize varying parameters, because they are linearly interpolated in the vertex shader.
vec3 viewFragmentDirection = normalize(v_ViewPosition);
vec3 viewNormal = normalize(v_ViewNormal);
// Apply inverse SRGB gamma to the texture before making lighting calculations.
// Flip the y-texture coordinate to address the texture from top-left.
vec4 objectColor = texture2D(u_Texture, vec2(v_TexCoord.x, 1.0 - v_TexCoord.y));
objectColor.rgb = pow(objectColor.rgb, vec3(kInverseGamma));
// Ambient light is unaffected by the light intensity.
float ambient = materialAmbient;
// Approximate a hemisphere light (not a harsh directional light).
float diffuse = lightIntensity * materialDiffuse *
0.5 * (dot(viewNormal, viewLightDirection) + 1.0);
// Compute specular light.
vec3 reflectedLightDirection = reflect(viewLightDirection, viewNormal);
float specularStrength = max(0.0, dot(viewFragmentDirection, reflectedLightDirection));
float specular = lightIntensity * materialSpecular *
pow(specularStrength, materialSpecularPower);
// Apply SRGB gamma before writing the fragment color.
gl_FragColor.a = objectColor.a;
gl_FragColor.rgb = pow(objectColor.rgb * (ambient + diffuse) + specular, vec3(kGamma));
}
object_vertex.shader
uniform mat4 u_ModelView;
uniform mat4 u_ModelViewProjection;
attribute vec4 a_Position;
attribute vec3 a_Normal;
attribute vec2 a_TexCoord;
varying vec3 v_ViewPosition;
varying vec3 v_ViewNormal;
varying vec2 v_TexCoord;
void main() {
v_ViewPosition = (u_ModelView * a_Position).xyz;
v_ViewNormal = normalize((u_ModelView * vec4(a_Normal, 0.0)).xyz);
v_TexCoord = a_TexCoord;
gl_Position = u_ModelViewProjection * a_Position;
}
Please help me to solve this issue