OpenGL ES纹理贴图

来源:互联网 发布:php接口文档 编辑:程序博客网 时间:2024/04/25 20:19

转载自:http://seya.iteye.com/blog/532525

OpenGL可以把纹理映射到指定的图形的表面上。简单一点的,就是给平面映射纹理,比如一个四边形,一个长方体的6个面,都可以指定位图作为纹理映射到各个面上。 

关于将一个位图作为纹理映射到某个或者多个面上,可以学习Jeff Molofee的OpenGL系列教程。 

对于指定的多个纹理,要根据自己的需要映射到不同的面上,需要对位图创建一个数组,用来存储位图的名称,然后在初始化OpenGL的时候,可以读取这些位图,然后生成多个纹理存储到一个纹理数组中,接着就可以指定绘制的某个面,对该指定的面进行纹理映射。 

下面,在的Jeff Molofee教程的第六课的基础上,实现对6个面分别进行不同的纹理映射。 

准备工作就是制作6幅不同的位图,如图所示: 


关键代码及其说明如下。 

创建全局纹理数组 

GLuint texture[6];   // 创建一个全局的纹理数组,用来存储将位图转换之后得到的纹理,对应于立方体的6个面 


加载位图文件 

加载位图,也就是把位图读取到内存空间,实现纹理的创建,加载位图的函数说明一下: 

AUX_RGBImageRec *LoadBMP(char *Filename)    // 根据位图文件的名称进行加载 

FILE *File=NULL;         // 文件指针 

if (!Filename)          // 如果没有指定位图文件名称就返回NULL 

   return NULL;         


File=fopen(Filename,"r");       // 根据指定的位图文件名称,打开该位图文件 

if (File)           // 如果位图文件存在 

   fclose(File);         // 因为只是需要判断问题是否存在,而不需要对位图文件进行写操作,所以关闭位图文件 
   return auxDIBImageLoad(Filename);    // 其实,只需要一个真正存在的位图文件的名称,实现加载位图文件,并返回一个指针 


return NULL;          // 位图文件加载失败就返回NULL 


上面实现加载位图的函数中,AUX_RGBImageRec是glaux.h中定义的类型,该类型的定义如下所示: 

/* 
** RGB Image Structure 
*/ 

typedef struct _AUX_RGBImageRec { 
    GLint sizeX, sizeY; 
    unsigned char *data; 
} AUX_RGBImageRec; 

首先,AUX_RGBImageRec类型是一个RGB图像结构类型。该结构定义了三个成员: 

sizeX —— 图像的宽度; 
sizeY —— 图像的高度; 
data; —— 图形所包含的数据,其实也就是该图形在内存中的像素数据的一个指针。 

AUX_RGBImageRec类型的变量描述了一幅图像的特征。 

上述函数中,调用了glaux.h库文件中的auxDIBImageLoad函数,其实它是一个宏,函数原型为auxRGBImageLoadW(LPCWSTR)或者auxRGBImageLoadA(LPCSTR),可以在该库文件中找到它的定义,如下所示: 

/* AUX_RGBImageRec * APIENTRY auxRGBImageLoad(LPCTSTR); */ 
#ifdef UNICODE 
#define auxRGBImageLoad auxRGBImageLoadW 
#else 
#define auxRGBImageLoad auxRGBImageLoadA 
#endif 
AUX_RGBImageRec * APIENTRY auxRGBImageLoadA(LPCSTR); 
AUX_RGBImageRec * APIENTRY auxRGBImageLoadW(LPCWSTR); 

#ifdef UNICODE 
#define auxDIBImageLoad auxDIBImageLoadW 
#else 
#define auxDIBImageLoad auxDIBImageLoadA 
#endif 
AUX_RGBImageRec * APIENTRY auxDIBImageLoadA(LPCSTR); 
AUX_RGBImageRec * APIENTRY auxDIBImageLoadW(LPCWSTR); 

宏auxDIBImageLoad实现的功能就是:根据指定的位图名称,将该位图的信息加载到内存中,以便用来创建成为纹理。 

创建纹理并加载纹理 

用于创建并加载纹理的函数为LoadGLTextures,实现如下所示: 

int LoadGLTextures()         // 根据加载的位图创建纹理 

int Status=FALSE;         // 指示纹理创建是否成功的标志 

AUX_RGBImageRec *TextureImage[6];     // 创建一个纹理图像数组,这里指定数组大小为6 

memset(TextureImage,0,sizeof(void *)*6);           // 初始化纹理图像数组,为其分配内存 

char *pictures[] = { // 创建一个位图名称数组,对应6幅位图 
   "Data/No1.bmp", 
   "Data/No2.bmp", 
   "Data/No3.bmp", 
   "Data/No4.bmp", 
   "Data/No5.bmp", 
   "Data/No6.bmp" 
}; 
for(int i=0; i<6; i++) // 遍历位图名称数组,根据位图名称分别生成 

   if (TextureImage[i]=LoadBMP(pictures[i])) // 加载位图i成功,修改状态标志变量Status为TRUE 
   { 
    Status=TRUE;        

   glGenTextures(1, &texture[i]);     // 为第i个位图创建纹理 
   glBindTexture(GL_TEXTURE_2D, texture[i]); // 将生成的纹理的名称绑定到指定的纹理上 
   glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[i]->sizeX, TextureImage[i]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[i]->data); 
   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); 
   } 

   if (TextureImage[i])         // 释放位图数组占用的内存空间 
   { 
    if (TextureImage[i]->data)       
    { 
     free(TextureImage[i]->data);    
    } 

    free(TextureImage[i]);        
   } 

return Status;          // 创建纹理并加载,返回成功或者失败的标志Status 


上述函数是创建和加载纹理的核心实现。 

1、glGenTextures函数 

其中,调用了glGenTextures函数,查看MSDN可以看到,声明如下所示: 

void glGenTextures( 
GLsizei n,          
GLuint * textures   
); 

函数参数的含义: 

n —— 生成的纹理的名称的个数; 

textures —— 生成的纹理名称所存储位置的指针,也就是一个纹理数组的内存地址,或者说是数组首元素的内存地址。 

函数被调用,会生成一系列纹理的名字,并存储到指定的数组中。 

2、glBindTexture函数 

glBindTexture函数实现了将调用glGenTextures函数生成的纹理的名字绑定到对应的目标纹理上。该函数的声明如下所示: 

void glBindTexture( 
GLenum target,   
GLuint texture   
); 

函数参数的含义: 

target —— 纹理被绑定的目标,它只能取值GL_TEXTURE_1D或者GL_TEXTURE_2D; 

texture —— 纹理的名称,并且,该纹理的名称在当前的应用中不能被再次使用。 

3、glTexImage2D函数 

调用glTexImage2D函数,用来指定二维纹理图像。该函数的声明如下所示: 

void glTexImage2D( 
GLenum target,        
GLint level,          
GLint components,     
GLsizei width,        
GLsizei height,       
GLint border,         
GLenum format,        
GLenum type,          
const GLvoid *pixels 
); 

函数参数的含义: 

target —— 指定目标纹理,必须为GL_TEXTURE_2D; 

level —— 指定图像级别的编号,0表示基本图像,其它可以参考MSDN; 

components —— 纹理中颜色组件的编号,可是是1或2或3或4; 

width —— 纹理图像的宽度; 

height —— 纹理图像的高度; 

border —— 纹理图像的边框宽度,必须是0或1; 

format —— 指定像素数据的格式,一共有9个取值:GL_COLOR_INDEX、GL_RED、GL_GREEN、GL_BLUE、GL_ALPHA、GL_RGB、GL_RGBA、GL_BGR_EXT、GL_BGRA_EXT、GL_LUMINANCE、GL_LUMINANCE_ALPHA ,具体含义可以参考MSDN; 

type —— 像素数据的数据类型,取值可以为GL_UNSIGNED_BYTE, GL_BYTE, GL_BITMAP, GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, GL_INT, and GL_FLOAT; 

pixels —— 内存中像素数据的指针。 

4、glTexParameteri函数 

glTexParameteri函数或者glTexParameterf函数用来设置纹理参数,声明如下所示: 

void glTexParameterf( 
GLenum target, 
GLenum pname, 
GLfloat param 
); 

void glTexParameteri( 
GLenum target, 
GLenum pname, 
GLint param    
); 

函数参数的含义: 

target —— 目标纹理,必须为GL_TEXTURE_1D或GL_TEXTURE_2D; 

pname —— 用来设置纹理映射过程中像素映射的问题等,取值可以为:GL_TEXTURE_MIN_FILTER、GL_TEXTURE_MAG_FILTER、GL_TEXTURE_WRAP_S、GL_TEXTURE_WRAP_T,详细含义可以查看MSDN; 

param —— 实际上就是pname的值,可以参考MSDN。 

另外,该类函数还有两个: 

void glTexParameterfv( 
GLenum target,         
GLenum pname,          
const GLfloat *params 
); 

void glTexParameteriv( 
GLenum target,       
GLenum pname,        
const GLint *params 
); 

上述程序中调用如下: 

    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); 

功能就是实现线形滤波的功能,当纹理映射到图形表面以后,如果因为其它条件的设置导致纹理不能更好地显示的时候,进行过滤,按照指定的方式进行显示,可能会过滤掉显示不正常的纹理像素。 

纹理映射过程 

纹理映射的过程是在DrawGLScene函数中实现的,也就是在绘制图形的过程中,直接进行我呢里映射,或者称为,为指定的平面贴纹理,DrawGLScene函数实现如下所示: 

int DrawGLScene(GLvoid)         

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
glLoadIdentity();         
glTranslatef(0.0f,0.0f,-5.0f); 

glRotatef(xrot,1.0f,0.0f,0.0f); 
glRotatef(yrot,0.0f,1.0f,0.0f); 
glRotatef(zrot,0.0f,0.0f,1.0f); 


// Front Face 
glBindTexture(GL_TEXTURE_2D, texture[0]); //   选择第一个纹理texture[0],进行贴纹理 
glBegin(GL_QUADS); 
   glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); 
   glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); 
   glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); 
   glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); 
glEnd(); 

// Back Face 
glBindTexture(GL_TEXTURE_2D, texture[1]); //   选择第二个纹理texture[1],进行贴纹理 
glBegin(GL_QUADS); 
   glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); 
   glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); 
   glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); 
   glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); 
glEnd(); 

// Top Face 
glBindTexture(GL_TEXTURE_2D, texture[2]); //   选择第三个纹理texture[2],进行贴纹理 
glBegin(GL_QUADS); 
   glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); 
   glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); 
   glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f); 
   glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); 
glEnd(); 

// Bottom Face 
glBindTexture(GL_TEXTURE_2D, texture[3]); //   选择第四个纹理texture[3],进行贴纹理 
glBegin(GL_QUADS); 
   glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); 
   glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f); 
   glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); 
   glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); 
glEnd(); 

// Right face 
glBindTexture(GL_TEXTURE_2D, texture[4]); //   选择第五个纹理texture[4],进行贴纹理 
glBegin(GL_QUADS); 
   glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); 
   glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); 
   glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); 
   glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); 
glEnd(); 

// Left Face 
glBindTexture(GL_TEXTURE_2D, texture[5]); //   选择第六个纹理texture[5],进行贴纹理 
glBegin(GL_QUADS); 
   glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); 
   glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); 
   glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); 
   glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); 
glEnd(); 

xrot+=0.3f; 
yrot+=0.2f; 
zrot+=0.4f; 
return TRUE;          


因为,通过前面的过程,已经将位图加载并创建和加载纹理成功,纹理数组已经存在于内存之中,调用上述函数实现纹理映射,即,从内存中取出指定的纹理,将其映射到立方体的指定的面上。 

上述函数中调用了glTexCoord2f函数,设置纹理坐标,该函数的声明如下所示: 

void glTexCoord2f( 
GLfloat s, 
GLfloat t 
); 

glTexCoord2f 的第一个参数是X坐标,当s=0.0f 时是纹理的左侧,s=0.5f 时是纹理的中点,s=1.0f 时是纹理的右侧。 glTexCoord2f 的第二个参数是Y坐标,t=0.0f 是纹理的底部,t=0.5f 是纹理的中点, t=1.0f 是纹理的顶部。 

上述函数在为前面那个面映射纹理的时候调用如下: 

   // Front Face 
glBindTexture(GL_TEXTURE_2D, texture[0]); 
glBegin(GL_QUADS); 
   glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); 
   glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); 
   glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); 
   glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); 
glEnd(); 

其中: 

glTexCoord2f(0.0f, 0.0f);表示将纹理texture[0]的左下角坐标(0.0f, 0.0f)映射到立方体前面那个面的顶点(-1.0f, -1.0f, 1.0)上; 

glTexCoord2f(1.0f, 0.0f);表示将纹理texture[0]的右下角坐标(1.0f, 0.0f)映射到立方体前面那个面的顶点(1.0f, -1.0f, 1.0f)上; 

glTexCoord2f(1.0f, 1.0f);表示将纹理texture[0]的右上角坐标(1.0f, 1.0f)映射到立方体前面那个面的顶点(1.0f, 1.0f, 1.0f)上; 

glTexCoord2f(0.0f, 1.0f);表示将纹理texture[0]的左上角坐标(0.0f, 1.0f)映射到立方体前面那个面的顶点(-1.0f, 1.0f, 1.0f)上。 

这样,纹理texture[0]就被映射到了立方体前面那个面上。 

纹理映射结果 

为了使立方体能够运动起来,对立方体进行累的旋转变换,而且,定义了三个全局变量: 

GLfloat xrot;    // 沿着x旋转的变量 
GLfloat yrot;    // 沿着y旋转的变量 
GLfloat zrot;    // 沿着z旋转的变量 

初始化都为0,然后,在每次调用DrawGLScene函数的时候,改变x、y、z的分量值,在DrawGLScene函数中如下所示: 

xrot+=0.3f; 
yrot+=0.2f; 
zrot+=0.4f; 

在DrawGLScene函数中还要执行旋转变换: 

glRotatef(xrot,1.0f,0.0f,0.0f); 
glRotatef(yrot,0.0f,1.0f,0.0f); 
glRotatef(zrot,0.0f,0.0f,1.0f); 

////////////////////////////////////////////////////////////////////// 
今天纠结于怎么在一个图上画多个图形,分别贴上纹理,看完了上面的文章,恍然大悟。改改代码,总算成功了。 
在android中的实现代码如下, 
首先在onSurfaceCreate()的时候,要先把这些图像载入进来,读取到内存中,给它们分配textureID. 
public void onSurfaceCreated(GL10 gl, EGLConfig config) { 
        /* 
         * By default, OpenGL enables features that improve quality 
         * but reduce performance. One might want to tweak that 
         * especially on software renderer. 
         */ 
        glDisable(GL_DITHER); 

        /* 
         * Some one-time OpenGL initialization can be made here 
         * probably based on features of this particular context 
         */ 
        glHint(GL_PERSPECTIVE_CORRECTION_HINT, 
                GL_FASTEST); 

        glClearColor(.5f, .5f, .5f, 1); 
        glShadeModel(GL_SMOOTH); 
        glEnable(GL_DEPTH_TEST); 
        glEnable(GL_TEXTURE_2D); 

        /* 
         * Create our texture. This has to be done each time the 
         * surface is created. 
         */ 

        int[] textures = new int[2]; 
//这里是给textures这个数组中的每一个id,创建一个对应的纹理。第一个参数是1. 
        glGenTextures(1, textures, 0); 


        mTextureID = textures[0]; 
        textureID2 = textures[1]; 
        for(int i=0;i<textures.length;i++){ 
//之前已经创建好了纹理,这一步可以想象为有一个隐藏的局部变量a,我们把这个变量a指向之前在内存中分配好的一个纹理textures[i]. 
        glBindTexture(GL_TEXTURE_2D, textures[i]); 
            
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 
                    GL_NEAREST); 
            glTexParameterf(GL_TEXTURE_2D, 
                    GL_TEXTURE_MAG_FILTER, 
                    GL_LINEAR); 

            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, 
                    GL_CLAMP_TO_EDGE); 
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 
                    GL_CLAMP_TO_EDGE); 

            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 
                    GL_REPLACE); 
//读取图像文件 
            InputStream is; 
            if(i == 0){ 
            is = mContext.getResources().openRawResource(R.drawable.robot); 
            }else{ 
            is = mContext.getResources() 
                .openRawResource(R.drawable.yellow); 
            } 
                    
            Bitmap bitmap; 
            try { 
                bitmap = BitmapFactory.decodeStream(is); 
            } finally { 
                try { 
                    is.close(); 
                } catch(IOException e) { 
                    // Ignore. 
                } 
            } 
            //这里就用到了之前所说的那个隐藏的变量a, 
            //把bitmap写到a所指向的那个texture里面。 
            GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0); 
            bitmap.recycle(); 
        } 
        
    } 

存好之后,要使用如下: 
    public void onDrawFrame(GL10 gl) { 
        /* 
         * By default, OpenGL enables features that improve quality 
         * but reduce performance. One might want to tweak that 
         * especially on software renderer. 
         */ 
        glDisable(GL_DITHER); 

        glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 
                GL_MODULATE); 

        /* 
         * Usually, the first thing one might want to do is to clear 
         * the screen. The most efficient way of doing this is to use 
         * glClear(). 
         */ 

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

        /* 
         * Now we're ready to draw some 3D objects 
         */ 

        glMatrixMode(GL_MODELVIEW); 
        glLoadIdentity(); 

        GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f); 

        glEnableClientState(GL_VERTEX_ARRAY); 
        glEnableClientState(GL_TEXTURE_COORD_ARRAY); 

        glActiveTexture(GL_TEXTURE0); 
//隐藏局部变量a,指向一个texture.之前是指到那块内存,然后写进去 
//这里是拿出来用的。 
        glBindTexture(GL_TEXTURE_2D, mTextureID); 
        
        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, 
                GL_REPEAT); 
        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 
                GL_REPEAT); 

        /*long time = SystemClock.uptimeMillis() % 4000L; 
        float angle = 0.090f * ((int) time); 

        glRotatef(angle, 0, 0, 1.0f); 
*/ 
        rectangle.draw(gl);//这里用texture1作为纹理。 
//绑定texture2,作为纹理。 
        glBindTexture(GL_TEXTURE_2D, textureID2); 
        tri.draw(gl); 
    } 

rectangle的draw()和trig的draw()方法是一样的: 
public void draw(GL10 gl) { 
            glFrontFace(GL_CCW); 
            glVertexPointer(3, GL_FLOAT, 0, mFVertexBuffer);//指定轮廓 
            glEnable(GL_TEXTURE_2D); 
            glTexCoordPointer(2, GL_FLOAT, 0, mTexBuffer);//指定纹理位置 
            glDrawElements(GL_TRIANGLE_STRIP, VERTS, 
                    GL_UNSIGNED_SHORT, mIndexBuffer);//画图 
        } 

在使用GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);的时候,可以不调用glBindTexture(),把图像载入到当前默认的一个texture里面,后面draw()的时候也不必去glBindTexture()。但这只能载入一个图像,多个的话就不行了,必须指定texture,每个图像绑定到一个texture上面。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 大人户口迁走小孩户口怎么办 网银转账处理中怎么办 教育部学籍在线验证报告有错怎么办 验证码连续输入三次错误怎么办 交通运输监察大队截车了怎么办 平安安康续保没成功怎么办 危险品经营许可证到期了怎么办 郑万350渝万怎么办 厂里饭堂的饭好难吃怎么办 学校的食堂饭菜不好不卫生怎么办 亲戚借钱我真没有怎么办 榴莲肉酸了吃了怎么办 亲戚赖在家里住怎么办 食堂饭菜味道差该怎么办 被监视居住公安打电话睡着了怎么办 鱼缺氧浮上水面怎么办 车载低音炮有电流声怎么办 925纯银变黑了怎么办 银子放久了变黑怎么办 高铁票网上售空怎么办 高铁票出票失败怎么办 高铁票名字打错怎么办 高铁票姓名错了怎么办 高铁票弄丢了怎么办 用过的车票丢了怎么办 高铁票被水洗了怎么办 沈阳地铁卡丢了怎么办 火车票没写检票口怎么办 吃鸡听的脚步声距离太近怎么办 检票时车票丢了怎么办 高铁出站没检票怎么办 高铁来不及取票怎么办 被发现假的增值税发票怎么办 高铁票身份证验证失败怎么办 网上订的火车票查不到怎么办 已经参加工作想学个本科证怎么办 火车晚点耽误下一趟列车怎么办 门外装监控没有预留电线怎么办 框架柱主筋柱顶预留长度不够怎么办 遇到很嚣张的人怎么办 在地板砖上铺木地板卧室门怎么办