色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

您好,歡迎來(lái)電子發(fā)燒友網(wǎng)! ,新用戶?[免費(fèi)注冊(cè)]

您的位置:電子發(fā)燒友網(wǎng)>源碼下載>通訊/手機(jī)編程>

學(xué)習(xí)OpenGL ES模擬真實(shí)平面鏡的反射制造逼真3D效果

大小:0.3 MB 人氣: 2017-09-25 需要積分:1

前言

在基于CubeMap的反射效果一文中,介紹到如何使用CubeMap讓物體反射環(huán)境的光,從而制造逼真的3D效果。本文將介紹另一種反射效果的制作,模擬真實(shí)平面鏡的反射。反射效果是實(shí)時(shí)的,而且可以反射任何3D模型。下面是一張比較丑的效果圖,例子里面設(shè)置的燈光比較暗,導(dǎo)出gif后效果不好,最好還是下載例子自己運(yùn)行看的比較清楚。

原理

我將使用高中關(guān)于鏡面反射的物理知識(shí)來(lái)作為實(shí)現(xiàn)鏡面效果的理論基石。下面是2D下的關(guān)于鏡面反射的一張圖。

學(xué)習(xí)OpenGL ES模擬真實(shí)平面鏡的反射制造逼真3D效果

鏡子上顯示的圖像,可以看做鏡像過(guò)去的另一個(gè)人所看到的的情景。使用OpenGL的術(shù)語(yǔ)來(lái)說(shuō)就是把攝像機(jī)以鏡子所在的平面做鏡像,得到的鏡像攝像機(jī)所觀察到的世界,就是鏡面上應(yīng)該顯示的內(nèi)容。基本原理雖然很簡(jiǎn)單,但實(shí)現(xiàn)過(guò)程中也會(huì)遇到諸多問(wèn)題。比如如何把鏡像攝像機(jī)的渲染結(jié)果貼到鏡面上,鏡像攝像機(jī)被其他物體遮擋該如何處理。

寫(xiě)代碼之前

本文代碼依然延續(xù)學(xué)習(xí)OpenGL ES的項(xiàng)目代碼,任何之前已經(jīng)介紹的代碼將不再介紹。所以你真的想看懂本文的話,至少對(duì)OpenGL和本系列Demo項(xiàng)目有基本的了解。

封裝攝像機(jī)

之前的代碼中一直使用GLK的方法生成觀察矩陣,這次我對(duì)攝像機(jī)進(jìn)行了封裝,主要是為了更方便的進(jìn)行鏡像。攝像機(jī)的類(lèi)是Camera。主要功能是生成攝像機(jī)和鏡像攝像機(jī)。攝像機(jī)使用向前的向量forward,向上的向量up和位置position管理自身信息。鏡像時(shí)將這三個(gè)變量分別求解出鏡像值即可。求解向量的鏡像主要使用了向量的反射公式,具體大家可以看代碼。這里就不詳細(xì)解釋了。

@interface?Camera?:?NSObject@property?(assign,?nonatomic)?GLKVector3?forward;@property?(assign,?nonatomic)?GLKVector3?up;@property?(assign,?nonatomic)?GLKVector3?position;-?(void)setupCameraWithEye:(GLKVector3)eye?lookAt:(GLKVector3)lookAt?up:(GLKVector3)up;-?(void)mirrorTo:(Camera?*)targetCamera?plane:(GLKVector4)plane;-?(GLKMatrix4)cameraMatrix;@end

在鏡像方法- (void)mirrorTo:(Camera *)targetCamera plane:(GLKVector4)plane;中,使用GLKVector4表示平面,x,y,z表示法線,w表示在法線上移動(dòng)的位移。

渲染鏡像攝像機(jī)內(nèi)容

想要把鏡像攝像機(jī)的內(nèi)容渲染到鏡面的平面上,我們需要建立一個(gè)新的Framebuffer,并且綁定一個(gè)紋理到它的顏色附件中。這樣就可以把鏡像攝像機(jī)的內(nèi)容渲染到紋理了。如果你看過(guò)渲染到紋理這一篇文章,下面的代碼你就會(huì)感覺(jué)很熟悉。

-?(void)createTextureFramebuffer:(CGSize)framebufferSize?{????????glGenFramebuffers(1,?&mirrorFramebuffer);????glBindFramebuffer(GL_FRAMEBUFFER,?mirrorFramebuffer);????????//?生成顏色緩沖區(qū)的紋理對(duì)象并綁定到framebuffer上????glGenTextures(1,?&mirrorTexture);????glBindTexture(GL_TEXTURE_2D,?mirrorTexture);????glTexImage2D(GL_TEXTURE_2D,?0,?GL_RGBA,?framebufferSize.width,?framebufferSize.height,?0,?GL_RGBA,?GL_UNSIGNED_BYTE,?NULL);????glTexParameteri(GL_TEXTURE_2D,?GL_TEXTURE_WRAP_S,?GL_CLAMP_TO_EDGE);????glTexParameteri(GL_TEXTURE_2D,?GL_TEXTURE_WRAP_T,?GL_CLAMP_TO_EDGE);????glTexParameteri(GL_TEXTURE_2D,?GL_TEXTURE_MAG_FILTER,?GL_LINEAR);????glTexParameteri(GL_TEXTURE_2D,?GL_TEXTURE_MIN_FILTER,?GL_LINEAR);????glFramebufferTexture2D(GL_FRAMEBUFFER,?GL_COLOR_ATTACHMENT0,?GL_TEXTURE_2D,?mirrorTexture,?0);????????//?下面這段代碼不使用紋理作為深度緩沖區(qū)。????GLuint?depthBufferID;????glGenRenderbuffers(1,?&depthBufferID);????glBindRenderbuffer(GL_RENDERBUFFER,?depthBufferID);????glRenderbufferStorage(GL_RENDERBUFFER,?GL_DEPTH_COMPONENT16,?framebufferSize.width,?framebufferSize.height);????glFramebufferRenderbuffer(GL_FRAMEBUFFER,?GL_DEPTH_ATTACHMENT,?GL_RENDERBUFFER,?depthBufferID);????GLenum?status?=?glCheckFramebufferStatus(GL_FRAMEBUFFER);????if?(status?!=?GL_FRAMEBUFFER_COMPLETE)?{????????//?framebuffer生成失敗????}????glBindFramebuffer(GL_FRAMEBUFFER,?0);}

接著我們?cè)阡秩局鲌?chǎng)景之前,把場(chǎng)景渲染到鏡像專(zhuān)用的Framebuffer中。為了渲染鏡像中觀察者看到的景象,我將當(dāng)前的觀察矩陣設(shè)置為鏡像攝像機(jī)mirrorCamera的觀察矩陣,并且設(shè)置了新的Viewport匹配當(dāng)前的Framebuffer大小,同時(shí)也設(shè)置了新的投影矩陣mirrorProjectionMatrix匹配新的Framebuffer的比例。至于GL_CLIP_DISTANCE0_APPLE裁剪平面相關(guān)的代碼,我們后面再介紹。

-?(void)glkView:(GLKView?*)view?drawInRect:(CGRect)rect?{????self.projectionMatrix?=?self.mirrorProjectionMatrix;????self.cameraMatrix?=?[self.mirrorCamera?cameraMatrix];????glBindFramebuffer(GL_FRAMEBUFFER,?mirrorFramebuffer);????glViewport(0,?0,?1024,?1024);????glClearColor(0.7,?0.7,?0.9,?1);????glClear(GL_COLOR_BUFFER_BIT?|?GL_DEPTH_BUFFER_BIT);????self.clipplaneEnable?=?YES;????self.clipplane?=?GLKVector4Make(0,?0,?1,?0);????glEnable(GL_CLIP_DISTANCE0_APPLE);????[self?drawObjects];????????glDisable(GL_CLIP_DISTANCE0_APPLE);????self.clipplaneEnable?=?NO;????self.projectionMatrix?=?self.viewProjectionMatrix;????self.cameraMatrix?=?[self.mainCamera?cameraMatrix];????[view?bindDrawable];????glClearColor(0.7,?0.7,?0.7,?1);????glClear(GL_COLOR_BUFFER_BIT?|?GL_DEPTH_BUFFER_BIT);????[self?drawObjects];????[self?drawMirror];}

Mirror模型的渲染

Mirror繼承于Plane,繪制一個(gè)四邊形,目前并沒(méi)有實(shí)現(xiàn)任何獨(dú)特的代碼,主要用于后期將鏡面相關(guān)的邏輯移入其中。現(xiàn)在將它看做一個(gè)普通的四邊形即可,在渲染它時(shí),使用了特別編寫(xiě)的Shader frag_mirror.glsl。

precision?highp?float;varying?vec2?fragUV;varying?vec3?fragPosition;uniform?mat4?mirrorPVMatrix;uniform?mat4?modelMatrix;uniform?sampler2D?diffuseMap;void?main(void)?{????vec4?positionInWordCoord?=?mirrorPVMatrix?*?modelMatrix?*?vec4(fragPosition,?1.0);????positionInWordCoord?=?positionInWordCoord?/?positionInWordCoord.w;????positionInWordCoord?=?(positionInWordCoord?+?1.0)?*?0.5;????gl_FragColor?=?texture2D(diffuseMap,?positionInWordCoord.st);}

使用頂點(diǎn)位置最終投影到屏幕的坐標(biāo),計(jì)算UV,從鏡像攝像機(jī)渲染出的紋理上采樣。這個(gè)手法我們?cè)谕队凹y理中有介紹到,相當(dāng)于把鏡像攝像機(jī)看到的內(nèi)容按照鏡像攝像機(jī)的VP矩陣投影到鏡面的平面上。

我們?cè)谥鲌?chǎng)景渲染時(shí)才渲染鏡面模型。并且開(kāi)啟了GL_CULL_FACE,因?yàn)樽尫疵嬖阡秩緯r(shí)使用另一個(gè)法線進(jìn)行鏡像計(jì)算比較繁瑣而且沒(méi)有必要。在渲染過(guò)程中傳入鏡像攝像機(jī)和鏡像投影的矩陣相乘結(jié)果mirrorPVMatrix,以及頂點(diǎn)著色器需要的projectionMatrix和cameraMatrix,用來(lái)參與常規(guī)頂點(diǎn)著色流程。

-?(void)drawMirror?{????glEnable(GL_CULL_FACE);????[self.mirror.context?active];????[self.mirror.context?setUniformMatrix4fv:@“projectionMatrix”?value:self.projectionMatrix];????[self.mirror.context?setUniformMatrix4fv:@“mirrorPVMatrix”?value:?GLKMatrix4Multiply(self.mirrorProjectionMatrix,?[self.mirrorCamera?cameraMatrix])];????[self.mirror.context?setUniformMatrix4fv:@“cameraMatrix”?value:?self.cameraMatrix];????[self.mirror?draw:self.mirror.context];????glDisable(GL_CULL_FACE);}

裁剪平面

在前面我們提到過(guò)一個(gè)問(wèn)題,如果鏡像攝像機(jī)被遮擋應(yīng)該怎么辦。glEnable(GL_CLIP_DISTANCE0_APPLE);就是解決方案。裁剪平面在OpenGL中是直接支持的,但在OpenGL ES中需要使用蘋(píng)果的擴(kuò)展,所以GL_CLIP_DISTANCE0_APPLE后面有個(gè)APPLE。我們將平面以Vector4的表達(dá)方式傳入Vertex Shader中,最終系統(tǒng)會(huì)將觀察點(diǎn)到平面之間的點(diǎn)都忽略掉。這里我寫(xiě)死了0,0,1,0這個(gè)平面,當(dāng)然你也可以動(dòng)態(tài)獲取mirror模型的平面法線,使用normalMatrix和0,0,1,0相乘。

self.clipplaneEnable?=?YES;self.clipplane?=?GLKVector4Make(0,?0,?1,?0);glEnable(GL_CLIP_DISTANCE0_APPLE);

在Vertex Shader中需要添加如下代碼。

if?(clipplaneEnabled)?{????gl_ClipDistance[0]?=?dot((modelMatrix?*?position).xyz,?clipplane.xyz)?+?clipplane.w;}

總結(jié)

本文使用了渲染到紋理,紋理投影,裁剪平面等技術(shù)實(shí)現(xiàn)了鏡面效果。同時(shí)也涉及到了不少向量的計(jì)算,算是比較考驗(yàn)對(duì)OpenGL ES的熟練度,讀者可以看完例子之后自己嘗試去實(shí)現(xiàn)這個(gè)效果,了解一下自己對(duì)OpenGL ES的熟練程度。

非常好我支持^.^

(0) 0%

不好我反對(duì)

(0) 0%

      發(fā)表評(píng)論

      用戶評(píng)論
      評(píng)價(jià):好評(píng)中評(píng)差評(píng)

      發(fā)表評(píng)論,獲取積分! 請(qǐng)遵守相關(guān)規(guī)定!

      ?
      主站蜘蛛池模板: 男男女女爽爽爽视频免费| 乳色吐息在线观看全集免费观看| 福利社影院| 国产成人精品视频频| 久青草影院| 亚洲haose在线观看| 被强J高H纯肉公交车啊| 久久欧洲视频| 小泽玛丽av无码观看| 不卡无线在一二三区| 老色哥网站| 亚洲一卡二卡三卡四卡无卡麻豆| xiao77唯美清纯| 国产精品99久久久久久AV| 蜜桃传媒一区二区亚洲AV| 亚洲精品久久YY5099| 儿子你得太大了慢点插| 欧美gay老头互吃| 中文字幕不卡在线高清| 国产亚洲精品久久孕妇呦呦你懂| 日本强好片久久久久久AAA| 2022精品福利在线小视频| 禁室培欲在线视频免费观看| 午夜福利电影| 高清一区二区亚洲欧美日韩| 欧洲美女高清一级毛片| 涩涩涩涩爱网站| xxxxhdvideos动漫| 嫩草成人影院| 91桃色污无限免费看| 久久久久亚洲| 四虎国产精品永久一区高清| WWW亚洲精品久久久无码| 男人J进入女人P免费狂躁| 中文字幕亚洲无限码| 久久精品国产亚洲AV未满十八| 亚洲刺激视频| 国产午夜视频| 小短文H啪纯肉公交车| 国产精品青青青高清在线密亚| 我要色色网|