opengl画三角形的函数,opengl画三维图形
前面,我们已经在NDK层设置了EGL环境,并介绍了一些与着色器相关的理论知识。所以这一次,让我们用匹配的EGL画一个三角形。
在Opengl ES的世界里,再复杂的形状,都是由点、线或者三角形组成的。所以三角形的绘制在Opengl ES中非常重要,甚至比武林高手的内功还要重要。
Opengl ES中有很多坐标系。今天我们先来学习一些标准化的设备坐标。
标准化设备坐标(NDC),一旦你的顶点坐标在顶点着色器中被处理,它们就是标准化的设备坐标。
标准化设备坐标是x、y和z的值,都在-1.0和1.0之间。任何超出-1和1范围的坐标都将被丢弃/裁剪,不会显示在屏幕上。
如下图,在标准化的设备坐标中,假设有一个正方形的屏幕,那么屏幕的中心就是坐标的原点,左上角是坐标(-1,1),右下角是坐标(1,1)。
这里的代码需要解释亮点:
在后续的实战例子中,前面介绍的demo的代码经常被重用,所以如果是重用前的代码逻辑,为了节省篇幅,作者就不赘述了。演示中,为了简洁起见,没有将子线程打开为GL线程,这显然是错误的。在实际开发中,要打开子线程来操作Opengl。首先,为了后续使用的方便,我们分别在Java层和C中创建BaseOpengl的基类:
基础OpenGLJava公共类库OpenGL {//triangle公共静态final int draw _ type _ triangle=0;public long glNativePtr受保护的EGLHelper eglHelper受保护的int drawTypepublic base OpenGL(int drawType){ this . drawType=drawType;this . egl helper=new egl helper();} public void Surface created(Surface Surface){ eglhelper . Surface created(Surface);} public void surface changed(int width,int height){ egl helper . surface changed(width,height);} public void surface destroyed(){ egl helper . surface destroyed();} public void release(){ if(glnativetr!=0){ n_free(glNativePtr,drawType);glNativePtr=0;} } public void onGlDraw(){ if(glnativetr==0){ glnativetr=n _ GL _ native init(egl helper . native ptr,draw type);} if(glNativePtr!=0){ n _ onGlDraw(glnativetr,draw type);} }//Draw private native void n _ onraw(long ptr,int Draw type);受保护的native long n _ GL _ native init(long eglPtr,int drawType);private native void n _ free(long ptr,int drawType);}以下是C的BaseOpengl:
base OpenGL . H # ifndef NDK _ OpenGL _ LEARN _ base OpenGL _ H #定义NDK _ OpenGL _ LEARN _ base OpenGL _ H # include ./egl helper/egl helper . h # include gles 3/gl3 . h # include string class base OpenGL { public:egl helper * egl helper;闪烁程序{ 0 };public:base OpenGL();//析构函数必须是虚函数virtual ~ base OpenGL();//加载着色器并链接到程序void initgl program(STD:string ver,STD:string fragment);//绘制虚拟void onDraw()=0;};# endif//ndk _ opengles _ learn _ base OpenGL _ h注意,基类的析构函数必须是虚函数。为什么?如果不是虚函数,会导致析构不完全。具体原因请编程搜索引擎。
base OpenGL . CPP # include base OpenGL . h # include ./utils/shaderutils . h base OpenGL:base OpenGL(){ } void base OpenGL:initgl program(STD:string ver,STD:string fragment){ program=create program(ver . c _ str(),fragment . c _ str());} base OpenGL:~ base OpenGL(){ eglHelper=nullptr;如果(程序!=0){ glDeleteProgram(program);}}}然后用BaseOpengl定制一个SurfaceView,就是MyGLSurfaceView:
公共类MyGLSurfaceView扩展表面视图实现表面固定器.回调{ public base OpenGL base OpenGL private on draw listener on draw listener;公共MyGLSurfaceView(上下文上下文){ this(上下文,null);} public MyGLSurfaceView(Context Context,AttributeSet attrs){ super(Context,attrs);getHolder().添加回调(this);} public void set base OpenGL(base OpenGL base OpenGL){ this。base OpenGL=base OpenGL} public void setondrawlister(ondrawlister ondrawlister){ this。ondrawlister=ondrawlister} @覆盖创建的公共空表面(@非空表面持有者表面持有者){ if(null!=base OpenGL){ base OpenGL。创建的曲面(曲面固定器。get surface());} } @ Override public void surface changed(@ NonNull surface holder surface holder,int i,int w,int h) { if(null!=base OpenGL){ base OpenGL。表面改变(w,h);} if(null!=ondraw listener){ ondraw listener。ondraw frame();} } @ Override public void surface destroyed(@ NonNull surface holder surface holder){ if(null!=base OpenGL){ base OpenGL。表面销毁();} }公共接口OnDrawListener { void onDrawFrame();}}有了以上基类,既然我们的目标是绘制一个三角形,那么我们在爪哇层和C层再新建一个三角形计算机图形学的类吧,他们都继承三角形Opengl:
TriangleOpengl.javapublic类三角形Opengl扩展了base OpenGL {公共三角形OpenGL(){ super(base OpenGL .DRAW _ TYPE _ TRIANGLE);}}C三角形计算机图形学类,TriangleOpengl.h:
# ifndef NDK _ OpenGL es _ LEARN _ triangle OpenGL _ H #定义NDK _ OpenGL _ LEARN _三角形OpenGL _ H #包含BaseOpengl.h 类三角形OpenGL:public base OpenGL { public:triangle OpenGL();虚拟~三角形OpenGL();虚拟void onDraw();private:闪烁位置句柄{-1 };闪烁颜色句柄{-1 };};# endif//NDK _ OPENGLES _ LEARN _三角形OpenGL _ htriangle OpenGL。CPP:
# include 三角形OpenGL。h #包含./utils/Log.h//定点着色器vec4 aColor中的static const char * ver= # version 300 es \ n ;\n 在vec4位置;\ n out ve C4 vColor \ n void main(){ \ n vColor=a color;\ n GL _ Position=a Position \ n }//片元着色器static const char * fragment= # version 300 es \ n precision mediump float;vec4颜色中的\ n ";\ n out ve C4 frag color \ n void main(){ \ n frag color=vColor;\ n }//三角形三个顶点常数静态GLfloat顶点[]={ 0.0f,0.5f,-0.5f,-0.5f,0.5f,-0.5f };//rgba const static GL float COLOR _ ICES[]={ 0.0f,0.0f,1.0f,1.0f };三角形OpenGL:三角形OpenGL():base OpenGL(){ initgl程序(ver,fragment);position handle=glgetattributelocation(程序,一个位置);color handle=glgetattributelocation(program, aColor );LOGD(’程序:%d ,程序);LOGD(’位置句柄:%d ,位置句柄);LOGD(colorHandle:%d ,颜色句柄);}三角形OpenGL:~三角形OpenGL()除了{ } void三角形OpenGL:onDraw(){ LOGD(三角形OpenGL onDraw );glClearColor(0.0f,1.0f,0.0f,1.0f);GL清零(GL _ COLOR _ BUFFER _ BIT);葡萄糖程序(程序);/** *尺寸几个数字表示一个点,显示是两个数字表示一个点*正常化是否需要归一化,不用,这里已经归一化了*步幅步长,连续顶点之间的间隔,如果顶点直接是连续的,也可填0 */glvertexattributepointer(位置句柄,2,GL_FLOAT,GL_FALSE,0,顶点);//启用顶点数据glEnableVertexAttribArray(位置句柄);//这个不需要glEnableVertexAttribArray glvertexattrib 4 Fv(彩色手柄,COLOR _ ICES);glDrawArrays(GL_TRIANGLES,0,3);glUseProgram(0);//禁用顶点glDisableVertexAttribArray(位置句柄);if(nullptr!=egl helper){ egl helper-交换缓冲区();} LOGD(三角形OpenGL onDraw-end );}在前面的章节中我们介绍了着色器的创建、编译、链接等,但是缺少了具体使用方式,这里我们补充说明一下。
着色器的使用只要搞懂如何传递数据给着色器中变量。首先我们需要获取到着色器程序中的变量,然后赋值。
我们看上面的TriangleOpengl.cpp的构造函数:
triangle OpenGL:triangle OpenGL():base OpenGL(){ initgl program(ver,fragment);//获取aPosition变量position handle=glgetattributelocation(program, a position );//get acolor color handle=glgetattributelocation(program, acolor );LOGD(程序:%d ,程序);LOGD(位置句柄:%d ,位置句柄);LOGD(colorHandle:%d ,color handle);}从上面我们通过函数glGetAttribLocation获得了变量aPosition和aColor的句柄。我们在这里定义的位置和颜色是向量变量。如果定义统一变量,需要使用函数glGetUniformLocation来获取统一变量的句柄。
有了这些变量句柄,我们可以通过这些变量句柄将函数传递给着色器程序。具体可参考TriangleOpengl.cpp的onDraw函数
此外,如果变量是均匀变量,则参数通过一系列均匀形式传递.功能。
下面是对函数glVertexAttribPointer的stride参数的描述。一般不会用,传0就行。但是,如果需要提高性能,比如在同一个数组中传递顶点坐标和纹理/颜色坐标,就需要使用这个stride参数。目前顶点坐标数组是和其他数组分开的,可以暂时忽略。
调用活动中的测试结果:
公共类DrawTriangleActivity扩展了app compat activity { private triangle OpenGL mtriangleangl;@ Override protected void onCreate(Bundle savedInstanceState){ super . onCreate(savedInstanceState);setContentView(r . layout . activity _ draw _ triangle);MyGLSurfaceView glSurfaceView=findViewById(r . id . my _ GL _ surface _ view);mtriangleopgl=new triangle OpenGL();GL surface view . setbase OpenGL(mtriangleopgl);GL surface view . setondrawlister(新的MyGLSurfaceView。OnDrawListener(){ @ Override public void ondraw frame(){ mtriangleongl . ongldraw();} });} @覆盖受保护的void onDestroy() { if(null!=mtriangeopengl){ mtriangeopengl . release();} super . ondestroy();}}如果你运行它,看到一个蓝色的三角形,说明这个三角形画成功了!
要来源码就不要贴源码链接了。把它写在纸上太容易了,所以你知道你必须去做。这是常有的事。你看着就觉得很简单。实际上,你必须敲门。只有敲的过程中出了问题,然后你解决了,那才是你的。
在这个系列之后贴上整个项目的演示代码。
以前的笔记:EGL环境建设OpenglEs
OpenglEs的着色器
关注我,共同进步,生活不止编码!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。