OpenGL ES for iOS - 4

繪制到其他渲染目的地

Framebuffer對象是渲染命令的目標(biāo)。當(dāng)您創(chuàng)建一個(gè)framebuffer對象時(shí),您可以精確控制其存儲(chǔ)的顏色,深度和模板數(shù)據(jù)。您可以通過將圖像附加到幀緩沖區(qū)來提供此存儲(chǔ),如圖4-1所示。最常見的圖像附件是一個(gè)renderbuffer對象。您還可以將OpenGL ES紋理附加到幀緩沖區(qū)的顏色附加點(diǎn),這意味著任何繪圖命令都將呈現(xiàn)到紋理中。之后,紋理可以作為未來渲染命令的輸入。您還可以在單??個(gè)渲染上下文中創(chuàng)建多個(gè)幀緩沖區(qū)對象。您可以這樣做,以便您可以在多個(gè)幀緩沖區(qū)之間共享相同的渲染管道和OpenGL ES資源。


4-1.png

所有這些方法都需要手動(dòng)創(chuàng)建framebuffer和renderbuffer對象來存儲(chǔ)來自O(shè)penGL ES上下文的渲染結(jié)果,以及編寫附加代碼以將其內(nèi)容顯示在屏幕上,如果需要,運(yùn)行動(dòng)畫循環(huán)

創(chuàng)建一個(gè)Framebuffer對象

根據(jù)您的應(yīng)用程序要執(zhí)行的任務(wù),您的應(yīng)用程序會(huì)配置不同的對象以附加到framebuffer對象。在大多數(shù)情況下,配置幀緩沖區(qū)的區(qū)別在于什么對象附加到framebuffer對象的顏色附著點(diǎn)

  • 要使用幀緩沖區(qū)進(jìn)行屏幕外圖像處理,請附加一個(gè)renderbuffer。請參閱創(chuàng)建Offscreen Framebuffer對象。
  • 要使用幀緩沖圖像作為后續(xù)渲染步驟的輸入,請附加紋理。請參閱使用Framebuffer對象渲染到紋理。
  • 要在Core Animation圖層組合中使用framebuffer,請使用特殊的Core Animation感知renderbuffer。請參閱渲染到核心動(dòng)畫層。
創(chuàng)建非屏幕幀緩沖對象

用于屏幕外渲染的幀緩沖區(qū)將其所有附件分配為OpenGL ES渲染緩沖區(qū)。以下代碼分配帶有顏色和深度附件的framebuffer對象。

  1. 創(chuàng)建幀緩沖區(qū)并綁定它。
GLuint framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
  1. 創(chuàng)建一個(gè)彩色渲染緩沖區(qū),為其分配存儲(chǔ)空間,并將其附加到framebuffer的顏色附著點(diǎn)。
GLuint colorRenderbuffer;
glGenRenderbuffers(1, &colorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer);
  1. 創(chuàng)建一個(gè)深度或深度/模板renderbuffer,為其分配存儲(chǔ),并將其附加到framebuffer的深度附件點(diǎn)。
GLuint depthRenderbuffer;
glGenRenderbuffers(1, &depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
  1. 測試framebuffer的完整性。只有當(dāng)幀緩沖區(qū)的配置更改時(shí),才需要執(zhí)行此測試。
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER) ;
if(status != GL_FRAMEBUFFER_COMPLETE) {
    NSLog(@"failed to make complete framebuffer object %x", status);
}

繪制到屏幕外的renderbuffer后,可以將其內(nèi)容返回給CPU,以便使用glReadPixels函數(shù)進(jìn)一步處理

使用Framebuffer對象渲染到紋理

創(chuàng)建此幀緩沖區(qū)的代碼與屏幕外的示例幾乎相同,但是現(xiàn)在將分配紋理并附加到顏色附加點(diǎn)

  • 創(chuàng)建framebuffer對象(使用與創(chuàng)建Offscreen Framebuffer對象相同的過程)。
  • 創(chuàng)建目標(biāo)紋理,并將其附加到framebuffer的顏色附件點(diǎn)。
// create the texture
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,  width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
  • 分配并附加深度緩沖區(qū)(如前所述)。
  • 測試framebuffer的完整性(如前所述)。

盡管此示例假定您要渲染為顏色紋理,但其他選項(xiàng)也是可能的。例如,使用OES_depth_texture擴(kuò)展,您可以將紋理附加到深度附件點(diǎn),以將場景中的深度信息存儲(chǔ)到紋理中。您可以使用此深度信息來計(jì)算最終渲染場景中的陰影。

渲染到核心動(dòng)畫層

核心動(dòng)畫是iOS上圖形渲染和動(dòng)畫的核心基礎(chǔ)設(shè)施。您可以使用主持使用不同iOS子系統(tǒng)(如UIKit,Quartz 2D和OpenGL ES)呈現(xiàn)的內(nèi)容的圖層來構(gòu)成應(yīng)用的用戶界面或其他視覺顯示。 OpenGL ES通過CAEAGLLayer類連接到Core Animation,這是一種特殊類型的Core Animation層,其內(nèi)容來自O(shè)penGL ES renderbuffer。 Core Animation將renderbuffer的內(nèi)容與其他圖層復(fù)合,并在屏幕上顯示生成的圖像。


4-2.png

CAEAGLLayer通過提供兩個(gè)關(guān)鍵功能向OpenGL ES提供此支持。首先,它為renderbuffer分配共享存儲(chǔ)。其次,它將渲染緩沖區(qū)呈現(xiàn)給Core Animation,將該圖層的以前內(nèi)容替換為renderbuffer中的數(shù)據(jù)。該模型的優(yōu)點(diǎn)在于,只有當(dāng)渲染的圖像發(fā)生變化時(shí),核心動(dòng)畫層的內(nèi)容不需要在每個(gè)幀中繪制。
注意:GLKView類會(huì)自動(dòng)執(zhí)行以下步驟,因此當(dāng)您要在視圖的內(nèi)容層中使用OpenGL ES進(jìn)行繪圖時(shí),應(yīng)使用它

為OpenGL ES渲染使用Core Animation層

  1. 創(chuàng)建CAEAGLLayer對象并配置其屬性。
    為獲得最佳性能,請將圖層的不透明屬性的值設(shè)置為YES??吹阶⒁夂诵膭?dòng)畫合成性能??蛇x地,通過為CAEAGLLayer對象的drawableProperties屬性分配一個(gè)新的值字典來配置渲染表面的表面屬性。您可以指定renderbuffer的像素格式,并指定在將它們發(fā)送到Core Animation之后,renderbuffer的內(nèi)容是否被丟棄。有關(guān)允許密鑰的列表,請參閱EAGLDrawable Protocol Reference。
  2. 分配OpenGL ES上下文并使其成為當(dāng)前上下文。請參閱配置OpenGL ES上下文。
  3. 創(chuàng)建framebuffer對象(如上面的創(chuàng)建Offscreen Framebuffer對象)。
  4. 創(chuàng)建一個(gè)顏色renderbuffer,通過調(diào)用上下文的renderbufferStorage:fromDrawable:method分配其存儲(chǔ),并傳遞層對象作為參數(shù)。寬度,高度和像素格式取自層,用于為renderbuffer分配存儲(chǔ)空間
GLuint colorRenderbuffer;
glGenRenderbuffers(1, &colorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
[myContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:myEAGLLayer];
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer);

注意:當(dāng)核心動(dòng)畫層的界限或?qū)傩愿臅r(shí),應(yīng)用程序應(yīng)重新分配renderbuffer的存儲(chǔ)空間。如果不重新分配renderbuffers,renderbuffer大小將不匹配圖層的大小;在這種情況下,Core Animation可以縮放圖像的內(nèi)容以適應(yīng)圖層。

  1. 檢索顏色renderbuffer的高度和寬度。
GLint width;
GLint height;
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);

在前面的例子中,renderbuffers的寬度和高度被明確地提供給緩沖區(qū)的分配存儲(chǔ)。這里,代碼在分配存儲(chǔ)后從顏色renderbuffer中檢索寬度和高度。您的應(yīng)用程序執(zhí)行此操作是因?yàn)轭伾玶enderbuffer的實(shí)際尺寸是根據(jù)圖層的邊界和比例因子計(jì)算的。附加到幀緩沖區(qū)的其他渲染緩沖區(qū)必須具有相同的尺寸。除了使用高度和寬度來分配深度緩沖區(qū)之外,還可以使用它們來分配OpenGL ES視口,并幫助確定應(yīng)用程序紋理和模型所需的詳細(xì)程度。請參閱支持高分辨率顯示器。

  1. 分配并附加深度緩沖區(qū)(如前所述)。
  2. 測試framebuffer的完整性(如前所述)。
  3. 將CAEAGLLayer對象添加到Core Animation層次結(jié)構(gòu),將其傳遞給可見層的addSublayer:方法。

繪制到Framebuffer對象

現(xiàn)在你有一個(gè)framebuffer對象,你需要填寫它。本節(jié)介紹渲染新幀并將其呈現(xiàn)給用戶所需的步驟。渲染到紋理或屏幕外框架緩沖區(qū)的作用類似,僅在應(yīng)用程序使用最終幀時(shí)有所不同。

按需渲染或動(dòng)畫循環(huán)

當(dāng)渲染到Core Animation層時(shí),您必須選擇何時(shí)繪制OpenGL ES內(nèi)容,就像使用GLKit視圖和視圖控制器進(jìn)行繪制時(shí)一樣。如果渲染到屏幕外的幀緩沖區(qū)或紋理,則繪制每當(dāng)適用于使用這些幀緩沖區(qū)的情況時(shí)。

對于按需繪圖,實(shí)現(xiàn)自己的方法來繪制和呈現(xiàn)您的renderbuffer,并且每當(dāng)您要顯示新內(nèi)容時(shí)調(diào)用它。

要使用動(dòng)畫循環(huán)繪制,請使用CADisplayLink對象。顯示鏈接是Core Animation提供的一種定時(shí)器,可讓您將繪圖同步到畫面的刷新率。清單4-1顯示了如何檢索顯示視圖的屏幕,使用該屏幕創(chuàng)建新的顯示鏈接對象,并將顯示鏈接對象添加到運(yùn)行循環(huán)。
注意:GLKViewController類可自動(dòng)使用CADisplayLink對象來動(dòng)畫化GLKView內(nèi)容。僅當(dāng)您需要超出GLKit框架提供的行為時(shí)才直接使用CADisplayLink類。

Listing4-1

displayLink = [myView.window.screen displayLinkWithTarget:self selector:@selector(drawFrame)];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

在drawFrame方法的實(shí)現(xiàn)之內(nèi),讀取顯示鏈接的timestamp屬性以獲取要渲染的下一個(gè)幀的時(shí)間戳。它可以使用該值來計(jì)算下一幀中的對象的位置。

通常,每次屏幕刷新時(shí)觸發(fā)顯示鏈接對象;該值通常為60 Hz,但可能會(huì)因不同的設(shè)備而異。大多數(shù)應(yīng)用程序不需要每秒更新屏幕60次。您可以將顯示鏈接的frameInterval屬性設(shè)置為在調(diào)用方法之前執(zhí)行的實(shí)際幀數(shù)。例如,如果幀間隔設(shè)置為3,則您的應(yīng)用程序每三幀調(diào)用一次,或大約每秒20幀。
重要提示:為獲得最佳效果,請選擇應(yīng)用程序可以始終如一地實(shí)現(xiàn)的幀率平滑,一致的幀速率產(chǎn)生比不規(guī)則變化的幀速率更愉快的用戶體驗(yàn)。

渲染視頻幀
圖4-3顯示了OpenGL ES應(yīng)用程序在iOS上呈現(xiàn)和呈現(xiàn)視頻幀
的步驟。這些步驟包括提高應(yīng)用程序性能的許多提示


4-3.png

清除緩沖區(qū)

在每幀的開始,擦除所有幀緩沖附件的內(nèi)容,其中不需要前一幀的內(nèi)容來繪制下一幀。調(diào)用glClear函數(shù),將所有緩沖區(qū)的位掩碼傳遞給清除,如清單4-2所示。
Listing4-2

glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

對OpenGL ES使用glClear“提示”,可以丟棄renderbuffer或紋理的現(xiàn)有內(nèi)容,避免將以前的內(nèi)容加載到內(nèi)存中的昂貴的操作。

準(zhǔn)備資源并執(zhí)行繪圖命令

這兩個(gè)步驟包括您在設(shè)計(jì)應(yīng)用程序架構(gòu)時(shí)所做的大多數(shù)關(guān)鍵決策。首先,您決定要向用戶顯示什么,并配置相應(yīng)的OpenGL ES對象(如頂點(diǎn)緩沖區(qū)對象,紋理,著色器程序及其輸入變量)以上傳到GPU。接下來,您提交繪圖通知,告訴GPU如何使用這些資源來渲染幀。

OpenGL ES設(shè)計(jì)指南中更詳細(xì)地介紹了渲染器設(shè)計(jì)。現(xiàn)在,要注意的最重要的性能優(yōu)化是,只有在渲染新幀時(shí)才能更快地修改OpenGL ES對象。雖然您的應(yīng)用程序可以在修改對象和提交繪圖命令之間交替(如圖4-3中的虛線所示),它的運(yùn)行速度更快,如果它每幀只執(zhí)行一次

執(zhí)行繪圖命令

此步驟將使用您在上一步中準(zhǔn)備的對象,并提交繪圖命令以使用它們。在OpenGL ES設(shè)計(jì)指南中詳細(xì)介紹了將此部分渲染代碼設(shè)計(jì)為高效運(yùn)行。現(xiàn)在,要注意的最重要的性能優(yōu)化是,如果在開始渲染新幀時(shí)僅修改OpenGL ES對象,則應(yīng)用程序運(yùn)行速度更快。雖然您的應(yīng)用程序可以在修改對象和提交繪圖命令之間交替(如虛線所示),但如果它只執(zhí)行一次,則運(yùn)行速度更快。

解決多重采樣

如果您的應(yīng)用程序使用多重采樣來提高圖像質(zhì)量,則應(yīng)用程序必須在呈現(xiàn)給用戶之前解析像素。多采樣在使用多采樣來提高圖像質(zhì)量方面有詳細(xì)的介紹。

丟棄不需要的Renderbuffers

丟棄操作是一種性能提示,它告訴OpenGL ES,不再需要一個(gè)或多個(gè)渲染緩沖區(qū)的內(nèi)容。通過暗示OpenGL ES,您不需要renderbuffer的內(nèi)容,緩沖區(qū)中的數(shù)據(jù)可以被丟棄,并且可以避免更新這些緩沖區(qū)內(nèi)容的昂貴任務(wù)。

在渲染循環(huán)的這個(gè)階段,您的應(yīng)用程序已經(jīng)提交了框架的所有繪圖命令。當(dāng)您的應(yīng)用程序需要彩色renderbuffer顯示到屏幕時(shí),它可能不需要深度緩沖區(qū)的內(nèi)容。清單4-3放棄了深度緩沖區(qū)的內(nèi)容。
Listing4-3

const GLenum discards[]  = {GL_DEPTH_ATTACHMENT};
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glDiscardFramebufferEXT(GL_FRAMEBUFFER,1,discards);

注意:glDiscardFramebufferEXT函數(shù)由OpenGL ES 1.1和2.0的EXT_discard_framebuffer擴(kuò)展提供。在OpenGL ES 3.0上下文中,使用glInvalidateFramebuffer函數(shù)。

將結(jié)果呈現(xiàn)給核心動(dòng)畫

在此步驟中,顏色渲染緩沖區(qū)保存完成的框架,因此您需要做的就是將其呈現(xiàn)給用戶。清單4-4將renderbuffer綁定到上下文并呈現(xiàn)它。這將導(dǎo)致完成的框架被交給核心動(dòng)畫。
Listing4-4

glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER];

默認(rèn)情況下,您必須假定在應(yīng)用程序呈現(xiàn)renderbuffer后,renderbuffer的內(nèi)容將被丟棄。這意味著,每當(dāng)您的應(yīng)用程序呈現(xiàn)幀時(shí),它必須在渲染新幀時(shí)完全重新創(chuàng)建幀的內(nèi)容。由于這個(gè)原因,上面的代碼總是擦除顏色緩沖區(qū)。

如果您的應(yīng)用程序要保留幀之間的顏色renderbuffer的內(nèi)容,請將kEAGLDrawablePropertyRetainedBacking密鑰添加到CAEAGLLayer對象的drawableProperties屬性中存儲(chǔ)的字典中,并從較早的glClear函數(shù)調(diào)用中刪除GL_COLOR_BUFFER_BIT常量。保留的支持可能需要iOS才能分配額外的內(nèi)存來保留緩沖區(qū)的內(nèi)容,這可能會(huì)降低應(yīng)用程序的性能。

使用多重采樣來提高圖像質(zhì)量

多采樣是一種抗鋸齒形式,可以在大多數(shù)3D應(yīng)用程序中平滑鋸齒狀邊緣并提高圖像質(zhì)量。 OpenGL ES 3.0包括多采樣作為核心規(guī)范的一部分,iOS通過APPLE_framebuffer_multisample擴(kuò)展在OpenGL ES 1.1和2.0中提供。多采樣使用更多的內(nèi)存和片段處理時(shí)間來渲染圖像,但它可以以比使用其他方法更低的性能成本來提高圖像質(zhì)量。

圖4-4顯示了多采樣如何工作。而不是創(chuàng)建一個(gè)framebuffer對象,您的應(yīng)用程序創(chuàng)建兩個(gè)。多重采樣緩沖區(qū)包含渲染內(nèi)容所需的所有附件(通常為彩色和深度緩沖區(qū))。解析緩沖區(qū)僅包含向用戶顯示渲染圖像所必需的附件(通常為彩色渲染緩沖區(qū),但可能是紋理),使用“創(chuàng)建幀緩沖區(qū)對象”中的相應(yīng)過程創(chuàng)建。多重采樣渲染緩沖區(qū)使用與解析幀緩沖區(qū)相同的維度進(jìn)行分配,但每個(gè)包含一個(gè)附加參數(shù),該參數(shù)指定為每個(gè)像素存儲(chǔ)的采樣數(shù)。您的應(yīng)用程序?qū)⑵渌袖秩緢?zhí)行到多重采樣緩沖區(qū),然后通過將這些樣本解析為解析緩沖區(qū)來生成最終的抗鋸齒圖像。


4-4.png

清單4-5顯示了創(chuàng)建多采樣緩沖區(qū)的代碼。此代碼使用先前創(chuàng)建的緩沖區(qū)的寬度和高度。它調(diào)用glRenderbufferStorageMultisampleAPPLE函數(shù)為renderbuffer創(chuàng)建多采樣存儲(chǔ)。
Listing4-5

glGenFramebuffers(1, &sampleFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, sampleFramebuffer);
 
glGenRenderbuffers(1, &sampleColorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, sampleColorRenderbuffer);
glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_RGBA8_OES, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, sampleColorRenderbuffer);
 
glGenRenderbuffers(1, &sampleDepthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, sampleDepthRenderbuffer);
glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, sampleDepthRenderbuffer);
 
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
    NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));

以下是修改渲染代碼以支持多采樣的步驟:

  1. 在清除緩沖區(qū)步驟中,清除多重采樣幀緩沖區(qū)的內(nèi)容。
glBindFramebuffer(GL_FRAMEBUFFER, sampleFramebuffer);
glViewport(0, 0, framebufferWidth, framebufferHeight);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  1. 提交繪圖命令后,將內(nèi)容從多重采樣緩沖區(qū)解析為解析緩沖區(qū)。為每個(gè)像素存儲(chǔ)的樣本被合并到解析緩沖區(qū)中的單個(gè)樣本中。
glBindFramebuffer(GL_DRAW_FRAMEBUFFER_APPLE, resolveFrameBuffer);
glBindFramebuffer(GL_READ_FRAMEBUFFER_APPLE, sampleFramebuffer);
glResolveMultisampleFramebufferAPPLE();
  1. 在“丟棄”步驟中,可以丟棄附加到多重采樣幀緩沖區(qū)的兩個(gè)renderbuffer。這是因?yàn)槟?jì)劃呈現(xiàn)的內(nèi)容存儲(chǔ)在解析幀緩沖區(qū)中。
const GLenum discards[]  = {GL_COLOR_ATTACHMENT0,GL_DEPTH_ATTACHMENT};
glDiscardFramebufferEXT(GL_READ_FRAMEBUFFER_APPLE,2,discards);
  1. 在當(dāng)前結(jié)果步驟中,您將呈現(xiàn)附加到解析幀緩沖區(qū)的顏色renderbuffer。
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER];

多次采樣不是免費(fèi)的;需要額外的內(nèi)存來存儲(chǔ)附加樣本,并將樣本解析為解析幀緩沖區(qū)需要時(shí)間。如果您向應(yīng)用程序添加多重采樣,請始終測試應(yīng)用程序的性能,以確保其仍然可以接受。
注意:上述代碼假定為OpenGL ES 1.1或2.0上下文。多采樣是OpenGL ES 3.0 API核心的一部分,但功能不同。詳見規(guī)范。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容