나는 안드로이드 플랫폼에서 OpenGL 삼각형에 텍스처 매핑을 적용하는 올바른 방법을 이해하려고합니다. 이상한 동작을 발견했습니다 : 텍스처 매핑이 정점을 지정하는 순서에 영향을받는 것 같습니다.안드로이드 OpenGL 텍스처 매핑은 어떻게 정점 순서의 영향을 받습니까?
여기에 구체적인 문제가 있습니다. 이 그림에서 당신은 질감, 삼각형 원하는 매핑을 볼 수 있습니다 (미안, 단일 링크에 2 개 개의 이미지를 결합했다)
실제 질감의 그림은 2 × 2 PNG입니다.
코드는 기본적으로 렌더러와 모델의 두 클래스로 세분됩니다.
[...]
public void onSurfaceCreated(GL10 gl, EGLConfig config)
{
glDisable(GL_DITHER);
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, lightAmbientBuffer);
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, lightDiffuseBuffer);
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, lightPositionBuffer);
gl.glEnable(GL10.GL_LIGHT0);
gl.glShadeModel(GL10.GL_SMOOTH);
gl.glClearColor(0.0f, 0.5f, 0.5f, 1f);
// per rimuovere superfici nascoste
gl.glClearDepthf(1.0f);
gl.glEnable(GL10.GL_DEPTH_TEST);
gl.glDepthFunc(GL10.GL_LEQUAL);
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
// caricamento texture
glEnable(GL_TEXTURE_2D);
int[] textures = new int[1];
gl.glGenTextures(1, textures, 0);
textureId = textures[0];
gl.glBindTexture(GL_TEXTURE_2D, textureId);
gl.glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gl.glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl.glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
for (Drawable m : models) { // the models are kept in a Vector
if (m.getTextureLoader() != null)
m.getTextureLoader().load(gl);
}
}
:
- 이것은 OpenGL을 초기화입니다
렌더러 (여기 내가 아직 완전히 이해하지 않았다 많은 일들이있다, 난 그냥 예에서이 코드를 채택
그리고 여기 프레임 렌더링 기능 (실제 드로잉은 m.draw (gl) 호출에서 완료됩니다) :
public void onDrawFrame(GL10 gl)
{
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
GL_MODULATE);
// Clear Screen And Depth Buffer
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
gl.glEnable(GL10.GL_LIGHTING);
gl.glTranslatef(0.0f, -1.2f, -z); // just a little translation in order to see the complete drawing
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureId);
gl.glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gl.GL_CLAMP_TO_EDGE);
gl.glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gl.GL_CLAMP_TO_EDGE);
for (Drawable m : models) {
m.draw(gl);
}
gl.glLoadIdentity();
}
마침내 여기
public class OneTriangle implements Drawable {
Context context;
FloatBuffer textureMappingBuffer;
FloatBuffer vertexBuffer;
ShortBuffer facesIdxBuffer;
public OneTriangle(Context context) {
this.context = context;
float[] v = {
-2, 2, 0, //A
2, 2, 0,//B
-2, -2, 0 };//C
//correct
/*
short[] idx = {0,1,2};
float[] vt ={
0,0,//red
1,0,//green
0,1};//yellow
*/
//wrong
short[] idx = {1,2,0};
float[] vt ={
1,0,//green
0,1,//yellow
0,0//red
};
{
ByteBuffer vBuf = ByteBuffer.allocateDirect(v.length * Float.SIZE/8);
vBuf.order(ByteOrder.nativeOrder());
vertexBuffer = vBuf.asFloatBuffer();
vertexBuffer.put(v);
vertexBuffer.position(0);
}
{
ByteBuffer fBuf = ByteBuffer.allocateDirect(idx.length * Short.SIZE/8);
fBuf.order(ByteOrder.nativeOrder());
facesIdxBuffer = fBuf.asShortBuffer();
facesIdxBuffer.put(idx);
facesIdxBuffer.position(0);
}
{
ByteBuffer vBuf = ByteBuffer.allocateDirect(vt.length * Float.SIZE/8);
vBuf.order(ByteOrder.nativeOrder());
textureMappingBuffer = vBuf.asFloatBuffer();
textureMappingBuffer.put(vt);
textureMappingBuffer.position(0);
}
}
public void draw(GL10 gl)
{
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertexBuffer);
glTexCoordPointer(2, GL_FLOAT, 0, textureMappingBuffer);
glDrawElements(GL_TRIANGLES, facesIdxBuffer.capacity(), GL_UNSIGNED_SHORT, facesIdxBuffer);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
public TextureLoader getTextureLoader()
{
return new AssetTextureLoader(context, "tetraedro.png");
}
}
프로젝트에서 "자산"폴더에서 텍스처 파일을로드 AssetTextureLoader 클래스는, (의 청소 :
- 모델 여기
는 모델 클래스 지루한 예외 처리 코드) :
public class AssetTextureLoader implements TextureLoader {
private Context context;
private String filename;
public AssetTextureLoader(Context context, String filename) {
this.context = context;
this.filename = filename;
}
public void load(GL10 gl)
{
InputStream is;
is = context.getResources().getAssets().open(filename);
Bitmap bitmap = BitmapFactory.decodeStream(is);
is.close();
Log.d("texture loader", "internal format:" + GLUtils.getInternalFormat(bitmap)+", type: "+GLUtils.getType(bitmap));
GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
}
}
OneTriangle 클래스에서 볼 수 있듯이 A-B-C 순서의 꼭짓점과 빨강 - 녹색 - 노란색 순서의 매핑을 기본적으로 나열하는 주석 처리 된 "올바른"초기화가 있습니다. 이 코드는 올바른 텍스처 매핑을 생성합니다.
그렇다면 단순히 "잘못된"섹션의 정점 순서를 변경하려고했습니다 : B-C-A 및 녹색 - 노란색 - 빨간색. A가 항상 빨간색으로 매핑되고, B가 녹색으로 매핑되고 C가 노란색으로 매핑되므로 정확한 출력을 얻을 것으로 기대됩니다. 하지만 대신 완전히 다른 결과를 얻습니다.
을 (전에 이미지의 두 번째 부분 참조)하지만 더있다 : 여기
당신은이 개 출력을 볼 수 있습니다! 이 방식으로 모델 초기화를 다시 변경하면 :
//should be wrong but is correct
short[] idx = {1,0,2};
float[] vt ={
0,0,//red
1,0,//green
0,1};//yellow
.. 올바른 매핑을 얻을 수 있습니다! 사실, 나는 idx 배열에 대한 임의의 순서를 선택할 수 있으며 그것은 중요하지 않습니다. 한 vt 배열이 특정 r-g-y 순서에있는 한 올바른 이미지를 얻습니다.
왜 opengl이 내게 적대적입니까?
매우 긴 게시물에 대해 유감이지만 실수가 있으면 구현의 어느 곳에 나 숨길 수 있습니다.
대단히 감사합니다. 코드를 다시 작성해야했지만 지금은 완벽하게 작동합니다! – hariseldon78