Я работаю над приложением Android с openglES 3.0 и хочу создать систему загрузчика obj и отобразить 3D-модель с его текстурой.Мой код правильно отображает трехмерную сетку без текстуры.Если я попытаюсь добавить текстуру, она отобразит текстуру, а некоторая часть текстуры будет пустыми треугольниками.
Пример:
моя сетка с текстурой
мой файл объектной сетки
мой файл текстуры png
Не могу найти, в чем проблема.
Мой фрагментный шейдер
precision mediump float;
uniform vec4 vColor;
uniform sampler2D uTexture;
varying vec2 oTexCoordinate;
void main() {
gl_FragColor = texture2D(uTexture, oTexCoordinate);
//gl_FragColor = vec4(1, 0.5, 0, 1.0);
}
Мой вершинный шейдер
attribute vec4 position;
uniform mat4 matrix;
attribute vec2 vTexCoordinate;
varying vec2 oTexCoordinate;
void main() {
oTexCoordinate = vTexCoordinate;
gl_Position = matrix * position;
}
Заранее спасибо.
Обновление:
Спасибо.
Я изменил свой код, чтобы он соответствовал вашей идее, я активировал выборку лица и добавил буфер для обычного, сейчас я его не использую.Я поставил свой новый код ниже.Но проблема не полностью решена, см. Рисунок ниже.
Я думаю, что мне нужно передать нормальную информацию шейдерам, но я неуверен, как это сделать правильно, или если это решение.
public class MeshLoader {
private int program;
private List<String> facesVertexList;
private List<String> facesTextureList;
private List<String> facesNormalList;
private List<String> verticesList;
private List<String> textureList;
private List<String> normalList;
private FloatBuffer verticesBuffer;
private FloatBuffer verticesBufferTemp;
private FloatBuffer facesVertexBuffer;
private FloatBuffer facesTextureBuffer;
private FloatBuffer facesNormalBuffer;
private FloatBuffer textureBuffer;
private FloatBuffer textureBufferTemp;
private FloatBuffer normalBuffer;
private FloatBuffer normalBufferTemp;
private Context contextMeshLoader;
final int[] textureHandle = new int[1];
public MeshLoader(Context context) {
contextMeshLoader = context;
textureList = new LinkedList<>();
verticesList = new LinkedList<>();
normalList = new LinkedList<>();
facesVertexList = new LinkedList<>();
facesTextureList = new LinkedList<>();
facesNormalList = new LinkedList<>();
openObjFile(0);
String vertexShaderCode = "";
try{
InputStream vertexShaderStream = context.getResources().openRawResource(R.raw.vertex_shader);
vertexShaderCode = IOUtils.toString(vertexShaderStream, Charset.defaultCharset());
vertexShaderStream.close();
}
catch (Exception e){
Log.e("MeshReaderActivity", "Error reading vertex shader", e);
}
String fragmentShaderCode = "";
try{
InputStream fragmentShaderStream = context.getResources().openRawResource(R.raw.fragment_shader);
fragmentShaderCode = IOUtils.toString(fragmentShaderStream, Charset.defaultCharset());
fragmentShaderStream.close();
}
catch(Exception e){
Log.e("MeshReaderActivity", "Error reading fragment shader", e);
}
int vertexShader = GLES30.glCreateShader(GLES30.GL_VERTEX_SHADER);
GLES30.glShaderSource(vertexShader, vertexShaderCode);
int fragmentShader = GLES30.glCreateShader(GLES30.GL_FRAGMENT_SHADER);
GLES30.glShaderSource(fragmentShader, fragmentShaderCode);
GLES30.glCompileShader(vertexShader);
GLES30.glCompileShader(fragmentShader);
program = GLES30.glCreateProgram();
GLES30.glAttachShader(program, vertexShader);
GLES30.glAttachShader(program, fragmentShader);
GLES30.glLinkProgram(program);
GLES30.glUseProgram(program);
}
public void openObjFile(int value)
{
InputStream is;
value = 0;
if(value == 0)
is = contextMeshLoader.getResources().openRawResource(R.raw.objface);
else
is = contextMeshLoader.getResources().openRawResource(R.raw.objship);
if(verticesBufferTemp != null)
verticesBufferTemp.clear();
if(facesVertexBuffer != null)
facesVertexBuffer.clear();
if(textureBuffer != null)
textureBuffer.clear();
if(verticesList != null)
verticesList.clear();
if(facesVertexList != null)
facesVertexList.clear();
if(textureList != null)
textureList.clear();
try{
byte[] buffer = new byte[is.available()];
is.read(buffer);
String data = new String(buffer);
parseData(data);
ByteBuffer buffer2 = ByteBuffer.allocateDirect(facesVertexList.size() * 3 * 4);
buffer2.order(ByteOrder.nativeOrder());
facesVertexBuffer = buffer2.asFloatBuffer();
ByteBuffer buffer3 = ByteBuffer.allocateDirect(facesTextureList.size() * 3 * 4);
buffer3.order(ByteOrder.nativeOrder());
facesTextureBuffer = buffer3.asFloatBuffer();
ByteBuffer buffer6 = ByteBuffer.allocateDirect(facesTextureList.size() * 3 * 4);
buffer6.order(ByteOrder.nativeOrder());
facesNormalBuffer = buffer6.asFloatBuffer();
for(String face: facesVertexList) {
String vertexIndices[] = face.split("\\s+");
float vertex1 = Float.parseFloat(vertexIndices[1]);
float vertex2 = Float.parseFloat(vertexIndices[2]);
float vertex3 = Float.parseFloat(vertexIndices[3]);
facesVertexBuffer.put((vertex1 - 1));
facesVertexBuffer.put((vertex2 - 1));
facesVertexBuffer.put((vertex3 - 1));
}
facesVertexBuffer.position(0);
for(String texture: facesTextureList){
String textureIndice[] = texture.split("\\s+");
float texture1 = Float.parseFloat(textureIndice[1]);
float texture2 = Float.parseFloat(textureIndice[2]);
float texture3 = Float.parseFloat(textureIndice[3]);
facesTextureBuffer.put((texture1 - 1));
facesTextureBuffer.put((texture2 - 1));
facesTextureBuffer.put((texture3 - 1));
}
facesTextureBuffer.position(0);
for(String normal: facesNormalList) {
String normalIndice[] = normal.split("\\s+");
float normal1 = Float.parseFloat(normalIndice[1]);
float normal2 = Float.parseFloat(normalIndice[2]);
float normal3 = Float.parseFloat(normalIndice[3]);
facesNormalBuffer.put((normal1 - 1));
facesNormalBuffer.put((normal2 - 1));
facesNormalBuffer.put((normal3 - 1));
}
facesNormalBuffer.position(0);
ByteBuffer buffer1 = ByteBuffer.allocateDirect(verticesList.size() * 3 * 4);
buffer1.order(ByteOrder.nativeOrder());
verticesBufferTemp = buffer1.asFloatBuffer();
ByteBuffer buffer5 = ByteBuffer.allocateDirect(textureList.size() * 2 * 4);
buffer5.order(ByteOrder.nativeOrder());
textureBufferTemp = buffer5.asFloatBuffer();
ByteBuffer buffer7 = ByteBuffer.allocateDirect(textureList.size() * 3 * 4);
buffer7.order(ByteOrder.nativeOrder());
normalBufferTemp = buffer7.asFloatBuffer();
for(String vertex: verticesList) {
String coords[] = vertex.split("\\s+");
float x = Float.parseFloat(coords[1]);
float y = Float.parseFloat(coords[2]);
float z = Float.parseFloat(coords[3]);
verticesBufferTemp.put(x);
verticesBufferTemp.put(y);
verticesBufferTemp.put(z);
}
verticesBufferTemp.position(0);
for (String texture:textureList)
{
String textureIndices[] = texture.split("\\s+");
float texture1 = Float.parseFloat(textureIndices[1]);
float texture2 = Float.parseFloat(textureIndices[2]);
textureBufferTemp.put(texture1);
textureBufferTemp.put(texture2);
}
textureBufferTemp.position(0);
for (String normal:normalList)
{
String normalIndices[] = normal.split("\\s+");
float normal1 = Float.parseFloat(normalIndices[1]);
float normal2 = Float.parseFloat(normalIndices[2]);
normalBufferTemp.put(normal1);
normalBufferTemp.put(normal2);
}
normalBufferTemp.position(0);
System.out.println("size remaining " + facesVertexBuffer.remaining());
ByteBuffer bufferV = ByteBuffer.allocateDirect(facesVertexBuffer.remaining() * 3 * 4);
bufferV.order(ByteOrder.nativeOrder());
verticesBuffer = bufferV.asFloatBuffer();
ByteBuffer bufferT = ByteBuffer.allocateDirect(facesVertexBuffer.remaining() * 2 * 4);
bufferT.order(ByteOrder.nativeOrder());
textureBuffer = bufferT.asFloatBuffer();
ByteBuffer bufferN = ByteBuffer.allocateDirect(facesVertexBuffer.remaining() * 3 * 4);
bufferN.order(ByteOrder.nativeOrder());
normalBuffer = bufferN.asFloatBuffer();
int size = facesVertexBuffer.remaining();
for(int i = 0; i < size;i++)
{
int faceVertex = Math.round(facesVertexBuffer.get(i)) ;
int faceTexture = Math.round(facesTextureBuffer.get(i));
int faceNormal = Math.round(facesNormalBuffer.get(i));
float x = verticesBufferTemp.get((faceVertex)*3);
float y = verticesBufferTemp.get(((faceVertex)*3)+1);
float z = verticesBufferTemp.get(((faceVertex)*3)+2);
verticesBuffer.put( i*3, x);
verticesBuffer.put( (i*3)+1, y);
verticesBuffer.put( (i*3)+2, z);
float u = textureBufferTemp.get((faceTexture)*2);
float v = -textureBufferTemp.get(((faceTexture)*2)+1);
textureBuffer.put( i*2, u);
textureBuffer.put( (i*2)+1, v);
float xn = normalBufferTemp.get((faceNormal*3));
float yn = normalBufferTemp.get((faceNormal*3)+1);
float zn = normalBufferTemp.get((faceNormal*3)+2);
normalBuffer.put(i*3,xn);
normalBuffer.put((i*3)+1,yn);
normalBuffer.put((i*3)+2,zn);
}
verticesBuffer.position(0);
textureBuffer.position(0);
normalBuffer.position(0);
is.close();
loadTexture();
}
catch (Exception e) {
Log.e("MeshReaderActivity", "Error reading objfile", e);
}
}
public void parseData(String dataToParse)
{
Log.i("parse data method", "parse data method");
String[] data = dataToParse.split("\n");
for (int i = 0;i < data.length;i++)
{
String line = data[i];
if(line.startsWith("v "))
{
// Add vertex line to list of vertices
verticesList.add(line);
}
else if(line.startsWith("vt "))
{
textureList.add(line);
}
else if(line.startsWith("vn "))
{
normalList.add(line);
}
else if(line.startsWith("f "))
{
// Add face line to faces list
triangulate(line);
}
}
}
public void triangulate(String lineToTriangulate)
{
String lineSplit[] = lineToTriangulate.split("\\s+");
if(lineSplit.length > 4)
{
String line1="";
String line2="";
if (lineToTriangulate.contains("/"))
{
line1 = lineSplit[0] + " " + lineSplit[1].split("/")[0] + " " + lineSplit[2].split("/")[0] + " " + lineSplit[3].split("/")[0];
line2 = lineSplit[0] + " " + lineSplit[1].split("/")[0] + " " + lineSplit[2].split("/")[0] + " " + lineSplit[4].split("/")[0];
}
else
{
line1 = lineSplit[0] + " " + lineSplit[1] + " " + lineSplit[2] + " " + lineSplit[3];
line2 = lineSplit[0] + " " + lineSplit[1] + " " + lineSplit[2] + " " + lineSplit[4];
}
facesVertexList.add(line1);
facesVertexList.add(line2);
}
else
{
if(lineToTriangulate.contains("/"))
{
String[] splitElement1 = lineSplit[1].split("/");
String[] splitElement2 = lineSplit[2].split("/");
String[] splitElement3 = lineSplit[3].split("/");
String line = lineSplit[0] + " " + splitElement1[0] + " " + splitElement2[0] + " " + splitElement3[0];
facesVertexList.add(line);
line = lineSplit[0] + " " + splitElement1[1] + " " + splitElement2[1] + " " + splitElement3[1];
facesTextureList.add(line);
line = lineSplit[0] + " " + splitElement1[2] + " " + splitElement2[2] + " " + splitElement3[2];
facesNormalList.add(line);
}
else
{
facesVertexList.add(lineToTriangulate);
}
}
}
public void draw(float scratch[],float zoom){
int position = GLES30.glGetAttribLocation(program, "position");
GLES30.glEnableVertexAttribArray(position);
GLES30.glVertexAttribPointer(position, 3, GLES30.GL_FLOAT, false, 3 * 4, verticesBuffer);
int mTextureUniformHandle = GLES30.glGetUniformLocation(program, "uTexture");
int mTextureCoordinateHandle = GLES30.glGetAttribLocation(program, "vTexCoordinate");
GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
GLES30.glUniform1i(mTextureUniformHandle, 0);
GLES30.glEnableVertexAttribArray(mTextureCoordinateHandle);
GLES30.glVertexAttribPointer(mTextureCoordinateHandle, 2, GLES30.GL_FLOAT, false, 2*4, textureBuffer);
int normalHandle = GLES30.glGetAttribLocation(program,"normal");
GLES30.glEnableVertexAttribArray(normalHandle);
GLES30.glVertexAttribPointer(normalHandle,3,GLES30.GL_FLOAT,false,3*4,normalBuffer);
float[] projectionMatrix = new float[16];
float[] viewMatrix = new float[16];
float[] productMatrix = new float[16];
Matrix.frustumM(projectionMatrix, 0,
-1, 1,
-1, 1,
1, 11);
Matrix.setLookAtM(viewMatrix, 0,
0, 0, zoom,
0, 0, 0,
0, 1, 0);
Matrix.multiplyMM(productMatrix, 0,
projectionMatrix, 0,
viewMatrix, 0);
float[] finalMatrix = new float[16];
Matrix.multiplyMM(finalMatrix, 0,
productMatrix, 0,
scratch, 0);
Matrix.rotateM(finalMatrix, 0, 180, 0.0f, 1.0f, 0.0f);
int matrix = GLES30.glGetUniformLocation(program, "matrix");
GLES30.glUniform1i(matrix,0);
//GLES30.glUniformMatrix4fv(matrix, 1, false, productMatrix, 0);
GLES30.glUniformMatrix4fv(matrix, 1, false, finalMatrix, 0);
int size = facesVertexBuffer.remaining();
GLES30.glEnable(GLES30.GL_CULL_FACE);
GLES30.glCullFace(GLES30.GL_BACK);
GLES30.glDrawArrays(GLES30.GL_TRIANGLES,0,size);
GLES30.glDisableVertexAttribArray(position);
GLES30.glDisableVertexAttribArray(mTextureCoordinateHandle);
}
public void loadTexture()
{
GLES30.glGenTextures(1, textureHandle,0);
if (textureHandle[0] == 0)
{
throw new RuntimeException("Error generating texture name.");
}
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = true; // No pre-scaling
Bitmap bitmap = BitmapFactory.decodeResource(contextMeshLoader.getResources(), R.raw.pngface, options);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureHandle[0]);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
GLUtils.texImage2D(GLES30.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
}
}
Еще раз спасибо.
Обновление
Для поплавка это была ошибкакопировать вставить.Для моей проблемы отображения я нашел решение.Мне просто нужно добавить метод onDrawFrame.
GLES30.glEnable(GLES30.GL_DEPTH_TEST);
Теперь, моя сетка и его текстура отображаются правильно.
Спасибо за вашу помощь.