应用办公生活信息教育商业
投稿投诉
商业财经
汽车智能
教育国际
房产环球
信息数码
热点科技
生活手机
晨报新闻
办公软件
科学动态
应用生物
体育时事

一看就懂的OpenGLES教程临摹画手的浪漫之纹理映射(实践

  通过阅读本文,你将获得以下收获:
  1。如何将Bitmap传到Native层处理
  2。如何使用代码实现纹理映射
  3。通过纹理映射实现一些有趣的效果上篇回顾
  上一篇一看就懂的OpenGLES教程临摹画手的浪漫之纹理映射(理论篇)已经详细叙述了纹理的概念以及纹理映射到图元上的原理,都是纯理论,略显枯燥。
  今天就将理论付诸实践,一起来看看具体代码如何实现纹理映射。
  最后再利用纹理映射来实现一些有意思的效果,绝对不能错过
  代码实战如何将图片传入Native层
  上一篇一看就懂的OpenGLES教程临摹画手的浪漫之纹理映射(理论篇)主页有已经说过,纹理就是携带图片信息的容器,所以这里首先要获取到图片的信息(不然还纹理映射个毛线),在android的Java层,获取位图的方式可谓妇孺皆知:Bitmapbitmap((BitmapDrawable)getResources()。getDrawable(R。drawable。liyingai))。getBitmap();
  因为我们OpenGL代码是在Native层的,那么怎么将Bitmap传给Native层处理呢?其实直接传入即可,在C层用jobject接收(如果对于ndk还不太熟悉可以看下我之前写的入门文章:初探ndk的世界(一)),然后ndk已经提供了对应的jnigraphics库来处理Bitmap相关操作,它可以直接操作Bitmap的像素。
  使用之前,先要在CmakeList中链接jnigraphics库:targetlinklibraries(Specifiesthetargetlibrary。nativelibGLESv3EGLandroidjnigraphics操作Bitmap的库LinksthetargetlibrarytotheloglibraryincludedintheNDK。{loglib})
  Java层创建绘制纹理的Native方法:publicnativevoiddrawTexture(Bitmapbitmap,Objectsurface);
  在Native层对应的方法如下:JavacomexampleopenglstudydemoYuvPlayerdrawTexture(JNIEnvenv,jobjectthiz,jobjectbitmap,jobjectsurface)
  注意到在这里Bitmap对象已经是jobject类型。
  首先用jnigraphics库的AndroidBitmapgetInfo方法获取Bitmap对象的相关信息:Givenajavabitmapobject,filloutthe{linkAndroidBitmapInfo}structforit。Ifthecallfails,theinfoparameterwillbeignored。intAndroidBitmapgetInfo(JNIEnvenv,jobjectjbitmap,AndroidBitmapInfoinfo);
  第一个参数就是JNIEnv指针,第二个参数为Bimtap对象,第三个为结构体AndroidBitmapInfo的指针。
  AndroidBitmapInfo为何物呢?其实,它就类似一个水桶,在函数执行完就将数据舀出来,也就是获取到的信息会存放在AndroidBitmapInfo的结构体中,对于图片来说,最常见的信息莫过于宽高、像素格式等:Bitmapinfo,seeAndroidBitmapgetInfo()。typedefstruct{Thebitmapwidthinpixels。uint32twidth;Thebitmapheightinpixels。uint32theight;Thenumberofbyteperrow。uint32tstride;Thebitmappixelformat。See{linkAndroidBitmapFormat}int32tformat;Bitfieldcontaininginformationaboutthebitmap。pTwobitsareusedtoencodealpha。Use{linkANDROIDBITMAPFLAGSALPHAMASK}and{linkANDROIDBITMAPFLAGSALPHASHIFT}toretrievethem。pOnebitisusedtoencodewhethertheBitmapusestheHARDWAREConfig。Use{linkANDROIDBITMAPFLAGSISHARDWARE}toknow。pTheseflagswereintroducedinAPIlevel30。uint32tflags;}AndroidBitmapInfo;
  执行AndroidBitmapgetInfo方法的返回值会是以下几种情况,成功返回为0。AndroidBitmapfunctionsresultcode。enum{Operationwassuccessful。ANDROIDBITMAPRESULTSUCCESS0,Badparameter。ANDROIDBITMAPRESULTBADPARAMETER1,JNIexceptionoccured。ANDROIDBITMAPRESULTJNIEXCEPTION2,Allocationfailed。ANDROIDBITMAPRESULTALLOCATIONFAILED3,};
  一旦返回为0,那么恭喜你,已经成功拿到了Bitmap基本信息。
  C音视频学习资料免费获取方法:关注音视频开发T哥,点击链接即可免费获取2023年最新C音视频开发进阶独家免费学习大礼包!
  但是光拿到Bitmap的基本信息还是不够的,还记得上一篇一看就懂的OpenGLES教程临摹画手的浪漫之纹理映射(理论篇)提到纹理映射原理的时候说过:
  遍历图形中所有的片段,依次通过片段所在的位置坐标定位到其对应在纹理中的纹素,再获取到对应的颜色。
  我们知道一张2D图片,其实就是一个二维数组,按照一定的格式,每若干个数组元素其实就是代表一个纹素,所以要拿到对应的纹素,首先要拿到图片的像素二维数组。
  所幸的事,jnigraphics库的AndroidBitmaplockPixels已经帮我们做好这件事了:Givenajavabitmapobject,attempttolockthepixeladdress。LockingwillensurethatthememoryforthepixelswillnotmoveuntiltheunlockPixelscall,andensurethat,ifthepixelshadbeenpreviouslypurged,theywillhavebeenrestored。Ifthiscallsucceeds,itmustbebalancedbyacalltoAndroidBitmapunlockPixels,afterwhichtimetheaddressofthepixelsshouldnolongerbeused。Ifthissucceeds,addrPtrwillbesettothepixeladdress。Ifthecallfails,addrPtrwillbeignored。intAndroidBitmaplockPixels(JNIEnvenv,jobjectjbitmap,voidaddrPtr);
  前两个参数不言而喻,最后一个参数就是指向Bitmap像素二维数组的二级指针(如果对于二级指针不太理解,可以看下我之前的博文:漫谈C语言指针(三)),简单来说,该方法的作用就是通过一个二级指针指向传过来的Bitmap的像素数组。
  注意这个方法的名字带有lock,即它会锁一些东西。锁什么呢?通过方法的注释可知,会锁住像素数据的内存,直到AndroidBitmapunlockPixels方法调用才解锁。
  关于如何处理Bitmap纹素就先看到这,至于拿到的像素数据二级指针要怎么用等会再解答,我们再看看其他的纹理映射逻辑先。
  添加纹理坐标
  上一篇一看就懂的OpenGLES教程临摹画手的浪漫之纹理映射(理论篇)已经提及过纹理坐标的概念:
  所以这里我们需要指定纹理坐标,这里指定坐标的意义是指定需要进行纹理映射的那一部分纹理的顶点的坐标点,比如还是下面这张图,就是指定了左边需要映射的三角形的三个顶点在整个纹理中的坐标:
  为了简单,我们这里先映射整张图吧:floatvertices〔〕{图元顶点坐标纹理坐标0。5f,0。5f,0。0f,1。0f,1。0f,topright0。5f,0。5f,0。0f,1。0f,0。0f,bottomright0。5f,0。5f,0。0f,0。0f,0。0f,bottomleft0。5f,0。5f,0。0f,0。0f,1。0ftopleft};
  这里的纹理坐标就是指定了整张图片四个顶点。(当然,也可以指定只采样图片的一部分,后面会演示)
  然后依然像一看就懂的OpenGLES教程缓冲对象优化程序(二)一样使用VBO,VAO,EBO优化程序:unsignedintindices〔〕{0,1,3,firsttriangle1,2,3secondtriangle};unsignedintVBO,VAO,EBO;glGenVertexArrays(1,VAO);glGenBuffers(1,VBO);glGenBuffers(1,EBO);glBindVertexArray(VAO);glBindBuffer(GLARRAYBUFFER,VBO);glBufferData(GLARRAYBUFFER,sizeof(vertices),vertices,GLSTATICDRAW);glBindBuffer(GLELEMENTARRAYBUFFER,EBO);glBufferData(GLELEMENTARRAYBUFFER,sizeof(indices),indices,GLSTATICDRAW);复制代码着色器逻辑
  既然添加了纹理坐标了,根据经验和直觉,着色器是不是就要添加一个变量去接收纹理坐标了呢?
  没错,这是毋庸置疑的
  顶点着色器:version300eslayout(location0)invec4aPosition;新增的接收纹理坐标的变量layout(location1)invec2aTexCoord;纹理坐标输出给片段着色器使用outvec2TexCoord;voidmain(){直接把传入的坐标值作为传入渲染管线。glPosition是OpenGL内置的glPositionaPosition;纹理坐标传给片段着色器TexCoordaTexCoord;};
  这里要新增一个接收纹理坐标的变量aTexCoord,不过,因为采样这个任务还是交给了片段着色器来完成,毕竟着色还是片段着色器要干的活,所以最终还是提供给片段着色器使用,所以又用输出变量TexCoord送了出去。
  片段着色器:version300esprecisionmediumpfloat;新增的接收纹理坐标的变量invec2TexCoord;outvec4FragColor;传入的纹理uniformsampler2DourTexture;voidmain(){texture方法执行具体的采样FragColortexture(ourTexture,TexCoord);};
  这里用同名的TexCoord去接收顶点着色器传过来的纹理坐标。
  这里开始出现了一个陌生的新变量类型:sampler2D,看下官网的定义:
  AsamplerisasetofGLSLvariabletypes。Variablesofoneofthesamplertypesmustbeuniformsorasfunctionparameters。Eachsamplerinaprogramrepresentsasingletextureofaparticulartexturetype。Thetypeofthesamplercorrespondstothetypeofthetexturethatcanbeusedbythatsampler。
  可见它就是代表一个纹理对象,这里sampler2D中的2D代表的就是2D纹理。
  但是说它代表一个纹理对象其实是不准确的,更准确的是代表一个纹理单元,通过纹理单元去绑定一个纹理对象,从而间接绑定纹理对象。
  它只能被uniform修饰或者作为方法参数,这里被uniform修饰也就代表了一帧图像内,这个纹理单元是不会变的,即对应的纹理的图片是不变的。
  再看看main函数里面唯一的宠儿:FragColortexture(ourTexture,TexCoord);
  它就是传说中重中之重的采样函数了,具体来说就是获取到传入的具体纹理坐标值TexCoord在ourTexture对应的纹理上的纹素的颜色(当然由于不同的过滤模式会导致具体采样颜色的细节不同)。
  你可能会问,这里的TexCoord具体的坐标值是多少呢?如果这样问,那你可能8成没看过我之前讲过光栅化插值这个骚操作的博文:一看就懂的OpenGLES教程这或许是你遇过最难画的三角形(五),如果看过就知道,在这里,你传入顶点着色器的纹理坐标的那几个值,已经经过光栅化等的处理,把它通过几何关系转化为对应的一个坐标值了。
  这么一想,是不是整个流程都非常通畅了呢?
  纹理对象配置
  所以这里我们先通过AndroidBitmapgetInfo方法获取Bitmap基本信息:存储Bitmap基本信息的结构体AndroidBitmapInfobmpInfo;if(AndroidBitmapgetInfo(env,bitmap,bmpInfo)0){LOGD(AndroidBitmapgetInfo()failed!);return;}
  然后获取Bitmap像素数组的指针:voidbmpPixels;AndroidBitmaplockPixels(env,bitmap,bmpPixels);
  此时(Bitmap像素数组的指针bmpPixels)枪在手跟我走
  接下来就是配置纹理对象了。
  配置什么呢?还记得上一篇博文讲的纹理环绕和纹理过滤么?不记得的话直接回去看看这篇博文先吧。
  前面讲过纹理对象就是一个OpenGLObject,所以它的用法和其他的OpenGLObject是非常相似的,以下是纹理对象的结构图:
  Diagramofthecontentsofatextureobject
  可以看出,纹理对象由纹理数据存储区采样参数纹理参数构成。
  根据之前博文一看就懂的OpenGLES教程缓冲对象优化程序(一)写的,使用一个OpenGLObject的几部曲:
  创建对象绑定对象处理相关操作逻辑解绑对象销毁对象
  纹理对象也是如此。纹理idunsignedinttexture1;创建纹理glGenTextures(1,texture1);绑定纹理glBindTexture(GLTEXTURE2D,texture1);
  绑定纹理,开始具体的采样参数配置(当然不配置也有默认配置,一般最好配置一下为好):纹理环绕配置横坐标环绕配置glTexParameteri(GLTEXTURE2D,GLTEXTUREWRAPS,GLREPEAT);settexturewrappingtoGLREPEAT(defaultwrappingmethod)纵坐标环绕配置glTexParameteri(GLTEXTURE2D,GLTEXTUREWRAPT,GLREPEAT);纹理过滤配置settexturefilteringparameters(配置纹理过滤)纹理分辨率大于图元分辨率,即纹理需要被缩小的过滤配置glTexParameteri(GLTEXTURE2D,GLTEXTUREMINFILTER,GLNEAREST);纹理分辨率小于图元分辨率,即纹理需要被放大的过滤配置glTexParameteri(GLTEXTURE2D,GLTEXTUREMAGFILTER,GLLINEAR);
  纹理对象的配置是通过glTexParameteri函数实现的:
  voidglTexParameteri(
  GLenumtarget,
  GLenumpname,
  GLintparam);
  target是指定绑定的纹理目标,必须为GLTEXTURE1D,GLTEXTURE1DARRAY,GLTEXTURE2D,GLTEXTURE2DARRAY,GLTEXTURE2DMULTISAMPLE,GLTEXTURE2DMULTISAMPLEARRAY,GLTEXTURE3D,GLTEXTURECUBEMAP,GLTEXTURECUBEMAPARRAY,o,GLTEXTURERECTANGLE中的一种。我们映射的是普通的2D纹理,所以使用GLTEXTURE2D。
  pname为需要配置具体配置种类。
  param为具体的配置的值。
  首先是纹理环绕配置,这里通过首先是纹理环绕配置,这里指定的配置种类为GLTEXTUREWRAPS和GLTEXTUREWRAPT分别表示在s和t轴方向的采样环绕配置。GLREPEAT表示超过范围重复出现。
  s和t轴是什么?看下上篇文章这个熟悉的表示纹理坐标图估计你就懂了
  然后是纹理过滤配置:纹理分辨率大于图元分辨率,即纹理需要被缩小的过滤配置glTexParameteri(GLTEXTURE2D,GLTEXTUREMINFILTER,GLNEAREST);纹理分辨率小于图元分辨率,即纹理需要被放大的过滤配置glTexParameteri(GLTEXTURE2D,GLTEXTUREMAGFILTER,GLLINEAR);
  GLTEXTUREMINFILTER和GLTEXTUREMAGFILTER分别代表纹理被缩小和放大的场景。上一篇文章一看就懂的OpenGLES教程临摹画手的浪漫之纹理映射(理论篇)已经提到过,当进行采样的时候,纹理的纹素和图元的片段往往不是一样多的(简单理解就是图元面积和纹理图片的面积不一样大),这也就导致了,当纹理映射的时候,我们要做类似将纹理的几个顶点拉伸或者收缩到和图元顶点贴合在一起的时候,纹理会被放大或者缩小,于是就需要在纹理被放大和缩小2种情况下分别进行采样过滤的配置。
  接下来,也就是最重要的一步,那就是将前一步获取到的图片数据传给纹理对象:glTexImage2D(GLTEXTURE2D,0,GLRGBA,bmpInfo。width,bmpInfo。height,0,GLRGBA,GLUNSIGNEDBYTE,bmpPixels);
  看起来有点眼熟的bmpPixels正是前一步获取到的图片像素数组的指针。
  glTexImage2D方法的声明为:
  voidglTexImage2D(GLenumtarget,GLintlevel,GLintinternalformat,GLsizeiwidth,GLsizeiheight,GLintborder,GLenumformat,GLenumtype,constvoiddata);
  target:依然代表纹理目标。
  level:这里指的是mipmap的层级,mipmap还没讲到,这里我们暂时只传0。
  internalformat:表示纹理存储在GPU中的颜色格式。包括BaseInternalFormats、SizedInternalFormats、CompressedInternalFormats。
  最常见的BaseInternalFormats有以下格式:
  BaseInternalFormat
  RGBA,DepthandStencilValues
  InternalComponents
  GLDEPTHCOMPONENT
  Depth
  D
  GLDEPTHSTENCIL
  Depth,Stencil
  D,S
  GLRED
  Red
  R
  GLRG
  Red,Green
  R,G
  GLRGB
  Red,Green,Blue
  R,G,B
  GLRGBA
  Red,Green,Blue,Alpha
  R,G,B,A
  width和height:分别表示纹理图片的宽度和高度,一般要求至少有1024个纹素。
  border:这个据说是历史遗留的一个参数,现在固定传0就好。
  format:表示传入的纹理像素数据的颜色格式(注意和internalformat的区别)。比如:GLRED、GLRG、GLRGB,GLBGR、GLRGBA,GLBGRA。
  type:表示传入的纹理像素数据数组的元素的数据类型,比如GLUNSIGNEDBYTE,GLBYTE,GLUNSIGNEDSHORT,GLSHORT,GLUNSIGNEDINT,GLINT,GLHALFFLOAT,GLFLOAT等等。
  data:这就是传入的纹理像素数据的指针了。
  还是那句话,OpenGL为了强大的功能性,牺牲了使用的方便性,导致它就像一个憨憨,需要把传入的数据的细枝末节非常唠叨地告诉它,它才知道怎么去解析传入的数据。
  这里我们按如下参数来传:glTexImage2D(GLTEXTURE2D,0,GLRGBA,bmpInfo。width,bmpInfo。height,0,GLRGBA,GLUNSIGNEDBYTE,bmpPixels);
  首先映射的是2D纹理,所以target传GLTEXTURE2D。然后通过AndroidBitmaplockPixels方法得到的像素数据格式为RGBA,所以internalformat和format都传GLRGBA。接下来尺寸数据传从bmpInfo获取的宽高数据,这里像素数据的每个通道由8位组成,即范围为0255,所以对应的格式为GLUNSIGNEDBYTE。
  然后又是熟悉的解析顶点属性数组数据,分别传入顶点和纹理坐标数据(如果还不清楚具体是怎么解析的,请看系列的前面几篇博文):顶点坐标glVertexAttribPointer(0,3,GLFLOAT,GLFALSE,5sizeof(float),(void)0);glEnableVertexAttribArray(0);纹理坐标glVertexAttribPointer(1,2,GLFLOAT,GLFALSE,5sizeof(float),(void)(3sizeof(float)));glEnableVertexAttribArray(1);
  为了增强大家的学习效果,这次纹理映射的图片就依旧用经典的女神图。
  运行看下效果:
  额,图片怎么上下颠倒了
  这是Android平台的OpenGLes一个扎根多年的历史大坑,不要问我出现的原因,我只知道,在Android平台的OpenGLes,纹理坐标的原点是在左上角点(即一般一般情况下(0。0,1。0)点),而不是常见的左下角点,导致我们直接使用传入的纹理坐标会发生上下沿y轴0。5的直线发生镜面翻转。
  在Android平台的OpenGLes,真正的纹理坐标如下图红色文字所示:
  所以,这里顶点着色器传给片段着色器的纹理坐标我们需要做一点调整:version300eslayout(location0)invec4aPosition;layout(location1)invec2aTexCoord;outvec2TexCoord;voidmain(){glPositionaPosition;纹理坐标要经过上下翻转再传给片段着色器TexCoordvec2(aTexCoord。x,1。0aTexCoord。y);;};
  再运行一下:
  完美!
  聪明的你可能又觉察到一丝不对劲了
  片段着色器中表示纹理(纹理单元)的变量ourTexture我们都没传,咋就能够采样了呢?
  原因很简单:OpenGL内部帮我们传了。
  如果当前的渲染只需要一个纹理单元的情况下,OpenGL会默认我们使用的是第一个纹理单元,即GLTEXTURE0。所以片段着色器声明的sampler2D对象就会默认赋值为0,0则代表和GLTEXTURE0的纹理关联。
  而在客户端程序中,我们也并没有制定创建的纹理是属于哪个纹理单元的,所以默认也为第一个纹理单元,即GLTEXTURE0,所以对该纹理对象的所有操作,都默认为针对即GLTEXTURE0对应的纹理单元,所以我们的数据其实是默认和片段着色器的ourTexture变量关联上的。实现多图层混叠
  刚才实现的是单个纹理单元的渲染,接下来,我要做一件有趣的事情,就是将石原美里和李英爱的图片混合在一起:
  惊不惊喜
  首先新增一个纹理对象并配置参数和纹理数据:glGenTextures(1,texture2);glBindTexture(GLTEXTURE2D,texture2);setthetexturewrappingparametersglTexParameteri(GLTEXTURE2D,GLTEXTUREWRAPS,GLREPEAT);settexturewrappingtoGLREPEAT(defaultwrappingmethod)glTexParameteri(GLTEXTURE2D,GLTEXTUREWRAPT,GLREPEAT);settexturefilteringparametersglTexParameteri(GLTEXTURE2D,GLTEXTUREMINFILTER,GLNEAREST);glTexParameteri(GLTEXTURE2D,GLTEXTUREMAGFILTER,GLLINEAR);glTexImage2D(GLTEXTURE2D,0,GLRGBA,bmpInfo1。width,bmpInfo1。height,0,GLRGBA,GLUNSIGNEDBYTE,bmpPixels1);AndroidBitmapunlockPixels(env,bitmap1);
  上面刚说的我想就不用在这里重复了吧。
  这里要增加的步骤是,因为现在是需要2个纹理单元了,所以我们需要手动对纹理单元进行赋值:对着色器中的纹理单元变量进行赋值glUniform1i(glGetUniformLocation(program,ourTexture),0);glUniform1i(glGetUniformLocation(program,ourTexture1),1);
  关于Uniform变量的设置在一看就懂的OpenGLES教程这或许是你遇过最难画的三角形(五)已经提及,这里就不赘述了。
  分别对片段着色器中的ourTexture和ourTexture1变量赋值0和1,分别表示GLTEXTURE0和GLTEXTURE1纹理单元一一对应。
  然后将纹理单元和纹理对象进行绑定:将纹理单元和纹理对象进行绑定激活纹理单元,下面的绑定就会和当前激活的纹理单元关联上glActiveTexture(GLTEXTURE0);glBindTexture(GLTEXTURE2D,texture1);glActiveTexture(GLTEXTURE1);glBindTexture(GLTEXTURE2D,texture2);
  先使用glActiveTexture方法激活纹理单元,然后根据OpenGL的规则,接下来执行的glBindTexture对应的纹理对象就会和这个激活的纹理单元关联上。
  这样子,便完成了纹理对象texture1和着色器中的变量ourTexture、纹理对象texture2和着色器中的变量ourTexture1的绑定。(不得不说这个绑定真绕)
  片段着色器变成:version300esprecisionmediumpfloat;invec2TexCoord;outvec4FragColor;传入的纹理uniformsampler2DourTexture;新增纹理单元uniformsampler2DourTexture1;voidmain(){对2个纹理进行混合FragColormix(texture(ourTexture,TexCoord),texture(ourTexture1,TexCoord),0。5);};
  mix为OpenGL内置的函数,表示对2个数进行按比例混合叠加,这里就是对当前片段从2纹理采样得到的颜色值进行按照0。5的比例混合。
  运行看下:
  是不是有点电影转场内味了?是不是妙不可言
  总结
  本文主要从代码实践角度详细(盲猜可能网上没有比这个更详细的嘻嘻)讲解为如何进行纹理映射,最后通过将2个纹理进行混合,实现了一个挺有意思的效果。当然不仅仅是混合,这里就可以充分发挥想象力,去干一些灰常有趣的事情,这就是下一篇文章的内容,即开始玩一些奇技淫巧了。
  项目代码
  openglesstudydemo(不断更新中)参考
  纹理TextureSampler(GLSL)作者:半岛铁盒里的猫链接:https:juejin。cnpost7155040552353234951
  来源:稀土掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  在开发的路上你不是一个人,欢迎加入C音视频开发交流群链接大家庭讨论交流!

黑龙江游记之一百一十鸡西篇密山32022年8月1日8点30分到达兴凯湖。兴凯湖,唐代称为湄沱湖,以盛产湄沱之鲫驰名,又因湖形如月琴,故金代有北琴海之称,清代改为兴凯湖,为淡水湖。兴凯湖原为中国内湖……日本大学新研究对智能手机上瘾导致儿童大脑停止发育不得不说,很多沉迷游戏的孩子成绩会更差,这已经成为大多数家长的共识。浪费时间、分散精力、不愿意学习等原因,大家普遍认可。最近看到一个研究新闻,结果是停止大脑发育,真的吓到……法国航空4590号班机空难真相法国航空4590号班机空难(法语:Vol4590AirFrance)又称为协和客机空难。发生在2000年7月25日,法国航空一架原定由法国巴黎夏尔戴高乐国际机场飞往美国纽约甘迺……碾压广东上海!CBA最大黑马狂升第3,新打法正式冲击辽浙!本赛季的CBA常规赛第16轮比赛正在如火如荼地进行中,在北京首钢队与吉林队之间有一场备受瞩目的恶战。经过了四节的角逐,北京队在利夫、范子铭、曾凡博等人的帮助下以13493击败了……诗有鹏举兄文有踏遍青山,足矣!码农邵明告别这一年踏遍青山告别这一年这一年,我们终于知道,阳是无法隔断的,无论你用了什么办法,最后你还是要阳。这一年,我们终于知道,其实阳了也没有什么可怕,关键在于你……女性这3处毛发旺盛,会获得什么好处?建议女性多了解下导语:其实我们身上的毛发包含很多种,比如鼻毛、头发、眉毛、汗毛、腋毛等,这些毛发都属于一个女性朋友们而言,体毛比较旺盛,可以说是非常烦人的事。特别是在一些炎热的季节,需要……预算1500左右,给父母用,主要是刷视频和微信,高性价比手机预算1500左右,给父母用,主要就是刷视频和微信,期望能多用几年?刷视频和微信,期望能多用几年,这种的要求就对应一定要大内存。大内存才是王道,有了大内存,父母才不会动不动……公司上市前离职,进入大厂转型产品经理,毕业8年我为何这么折腾Hi大家好,我是可米同学,是善知岛英语的创建者之一。〔碰拳〕个人选择之路进入互联网教育公司,深度参与付费用户100万的核心课程项目;公司规模达到3000人,即……2023年换新机不糊涂,一加11华为P60三星S23都很猛农历新年离我们越来越近了,很多小伙伴除了做年度总结外,也会寻思着换新手头上的东西,比如智能手机,让卡顿不再伴随新的一年。而目前手机市场也依旧是新机不断,也有很多新旗舰的预热消息……为什么华为路由器无法识别槽位板卡?最近遇到一个问题,华为路由器在插入板卡后,该板卡指示灯不亮。一、路由器下电后检查板卡是否完全插入槽位,确定板卡已经插入槽位。二、加电再次查看板卡,发现指示灯依然不亮……许家印今年是关键年,恒大一定能偿还各种债务化解风险,一定能涅1月1日晚间,恒大集团董事局主席许家印在公司内部发出了一封《致全体恒大人的一封家书》。许家印总结了恒大集团2022年全年的表现,称2022年恒大地产732个保交楼项目全面……win10也能用安卓子系统!附安装教程,仅2步即可搞定微软公司在Windows11发布之初就开始给用户画饼,微软表示Win11系统将会提供WSA服务。WSA服务就是一个可以在PC上运行的Android应用的安卓子系统,它的全……
旅行记皖南行(2),皖南川藏线的路与寺院的兴衰时间:2020年11月27日皖南行第一天早晨7点启程,朋友执意把我送到皖南川藏线入口,用他的话说:让我看着你的背影潇洒的前行。于是锁上店门,两人各骑辆自行车出发了,……国青队员赛后与现场球迷一起庆祝干掉韩国队!我们要去世青赛!直播吧3月10日讯据记者马德兴报道,国青在U20亚洲杯小组出线后,有队员与现场球迷一起庆祝时发出了要去世青赛的豪言。11战平吉尔吉斯斯坦的比赛结束时,当在替补席上的球员们……周末,扬州茱萸湾迎来春游潮春天是扬州最明媚的季节,春风和煦、繁花似锦。今天是周末,不少市民、游客结伴而行,感受扬州的盎然春意,尽享周末美好时光。上午,茱萸湾景区里,前来游玩赏春、看小动物的市民游客熙熙攘……iPhone15Pro将配备索尼LiDAR传感器或有助于延长这段时间以来,外界关于新一代的iPhone15系列的爆料越来越密集,不出意外的话该系列将继续推出包含iPhone15、iPhone15Plus、iPhone15Pro和iPho……再回1时代!2月份CPI同比涨幅回落明显中新网3月9日电(中新财经记者谢艺观)9日,国家统计局公布2月份全国居民消费价格(CPI)数据。受上年同期对比基数较高等因素影响,2月份CPI同比上涨1。0,再回1时代。……WOT丨免费翻牌抽奖140换全局这不比氪金箱子香多了?本文首发于微信公众号坦克零距离,文章转载权限坦克空间站UP为个人专栏文章作者,非官方人员,在头条同步更新文章开箱子上瘾啊?各位车长老爷们大家好啊,我是阿纳贝尔……开宾馆记录怎么才能查到(了解4种查询技巧)开宾馆记录怎么才能查到1、如果起诉以后可以申请法院查询开房记录,其实就是在本地,是否退房都有记录,有时过错方可能会写下或保证书。如家会员卡。宾馆开房备案或者查询有关问题,……怀疑老婆出轨怎么查聊天记录(了解4种查询策略)怀疑老婆出轨怎么查聊天记录1、所以在这里给大家所准备的就是有关于怎么查老婆和别人开过房这方面的相关的情况介绍,老婆出轨怎么查用软件查微信聊天记录。在这里为的要安排,看看他……广州早茶的正确打开方式广州是一个充满活力的城市,其繁华和喧嚣的城市风景吸引着来自世界各地的游客和商人。然而,广州的人们仍然保留了一种悠闲和惬意的生活方式,这种生活方式表现在许多方面,其中最重要的是早……黑客教你定位找人(了解10种查询方式)黑客教你定位找人1、他破解了一款手机聊天程序的位置信息防护系统,聊天室等网上渠道销售,您可以听取与他人进行的所有谈话。只需要您只需要简单3步。我也不知道以为为什么要这样做……棒球夹克火了,可你还不知道穿哪件?我们必须得承认,当一件单品在市场上存在的时间足够久的时候,它总会形成一股潮流,例如作为美式校园文化产物的棒球夹克,以往被视为平常老套的运动服,却在这两年再度翻红,成为流行文化的……政府工作报告六大看点今年政府工作报告,从政策目标到政策实施力度的表述均偏温和5左右的经济增长目标,3的预算赤字率,3。8万亿新增专项债规模以及精准有力的货币政策。稳健的经济目标背后体现了政府对经济……
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网