OpenGL ES 地球月亮渲染案例

思維導圖

長截圖 2019-03-25 下午04.58.39.jpg

處理ArrayBuffer封裝

創(chuàng)建頂點緩存數(shù)組

// 此方法在當前的OpenGL ES上下文中創(chuàng)建一個頂點屬性數(shù)組緩沖區(qū),用于調(diào)用此方法的線程.
- (id)initWithAttribStride:(GLsizeiptr)aStride
   numberOfVertices:(GLsizei)count
   bytes:(const GLvoid *)dataPtr
   usage:(GLenum)usage;
{
   NSParameterAssert(0 < aStride);
   NSAssert((0 < count && NULL != dataPtr) ||
      (0 == count && NULL == dataPtr),
      @"data must not be NULL or count > 0");
      
   if(nil != (self = [super init]))
   {
      stride = aStride;
      bufferSizeBytes = stride * count;
      // 第一步
      glGenBuffers(1,
         &name);
      // 第二步
      glBindBuffer(GL_ARRAY_BUFFER,
         self.name);
       
      // 第三步
      glBufferData(
         GL_ARRAY_BUFFER,  // 初始化緩存區(qū)的內(nèi)容
         bufferSizeBytes,  // 要復制的字節(jié)數(shù)
         dataPtr,          // 要復制的字節(jié)地址
         usage);           //GPU內(nèi)存中的緩存
         
      NSAssert(0 != name, @"Failed to generate name");
   }
   
   return self;
}   

分配頂點數(shù)據(jù),準備繪制

// 當應用程序希望使用緩沖區(qū)呈現(xiàn)任何幾何圖形時枢贿,必須準備一個頂點屬性數(shù)組緩沖區(qū)。當你的應用程序準備一個緩沖區(qū)時,一些OpenGL ES狀態(tài)被改變橱赠,允許綁定緩沖區(qū)和配置指針。
- (void)prepareToDrawWithAttrib:(GLuint)index
   numberOfCoordinates:(GLint)count
   attribOffset:(GLsizeiptr)offset
   shouldEnable:(BOOL)shouldEnable
{
   NSParameterAssert((0 < count) && (count < 4));
   NSParameterAssert(offset < self.stride);
   NSAssert(0 != name, @"Invalid name");

   glBindBuffer(GL_ARRAY_BUFFER,
      self.name);

   if(shouldEnable)
   {
       glEnableVertexAttribArray(index);
   }

   glVertexAttribPointer( 
      index,            
      count,            
      GL_FLOAT,         
      GL_FALSE,         
      self.stride,      
      NULL + offset);
    
#ifdef DEBUG
   {
      GLenum error = glGetError();
      if(GL_NO_ERROR != error)
      {
         NSLog(@"GL Error: 0x%x", error);
      }
   }
#endif
}

繪制

// 提交由模式標識的繪圖命令箫津,并指示OpenGL ES從準備好的緩沖區(qū)中的頂點開始狭姨,從先前準備好的緩沖區(qū)中使用計數(shù)頂點。
+ (void)drawPreparedArraysWithMode:(GLenum)mode
   startVertexIndex:(GLint)first
   numberOfVertices:(GLsizei)count;
{
   glDrawArrays(mode, first, count);
}

重新緩存頂點數(shù)組

// 此方法加載由接收器存儲的數(shù)據(jù)
- (void)reinitWithAttribStride:(GLsizeiptr)aStride
   numberOfVertices:(GLsizei)count
   bytes:(const GLvoid *)dataPtr;
{
   NSParameterAssert(0 < aStride);
   NSParameterAssert(0 < count);
   NSParameterAssert(NULL != dataPtr);
   NSAssert(0 != name, @"Invalid name");

   self.stride = aStride;
   self.bufferSizeBytes = aStride * count;
   
    // 第二步
   glBindBuffer(GL_ARRAY_BUFFER,
      self.name);
    // 第三步
   glBufferData(
      GL_ARRAY_BUFFER,  
      bufferSizeBytes,  
      dataPtr,
      GL_DYNAMIC_DRAW); 
}

ViewDidLoad

新建opengles上下文及GLKView配置

//1.新建OpenGL ES 上下文
    self.mContext = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES2];
    
    //2.獲取GLKView
    GLKView *view = (GLKView *)self.view;
    view.context = self.mContext;
    view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
    view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
    
    [EAGLContext setCurrentContext:self.mContext];

配置baseEffect光照信息

//創(chuàng)建GLKBaseEffect 只能有3個光照苏遥、2個紋理
self.baseEffect = [[GLKBaseEffect alloc]init];

-(void)configureLight
{
    
    //1.是否開啟light0光照
    self.baseEffect.light0.enabled = GL_TRUE;
   
    /*
     union _GLKVector4
     {
     struct { float x, y, z, w; };
     struct { float r, g, b, a; };
     struct { float s, t, p, q; };
     float v[4];
     } __attribute__((aligned(16)));
     typedef union _GLKVector4 GLKVector4;
     
     union共用體
     有3個結(jié)構(gòu)體饼拍,
     比如表示頂點坐標的x,y,z,w
     比如表示顏色的,RGBA;
     表示紋理的stpq
     
     */
    //2.設(shè)置漫射光顏色
    self.baseEffect.light0.diffuseColor = GLKVector4Make(
                                                         1.0f,//Red
                                                         1.0f,//Green
                                                         1.0f,//Blue
                                                         1.0f);//Alpha
    /*
     The position of the light in world coordinates.
      世界坐標中的光的位置田炭。
     If the w component of the position is 0.0, the light is calculated using the directional light formula. The x, y, and z components of the vector specify the direction the light shines. The light is assumed to be infinitely far away; attenuation and spotlight properties are ignored.
     如果位置的w分量為0师抄,則使用定向光公式計算光。向量的x教硫、y和z分量指定光的方向叨吮。光被認為是無限遠的,衰減和聚光燈屬性被忽略栋豫。
     If the w component of the position is a non-zero value, the coordinates specify the position of the light in homogenous coordinates, and the light is either calculated as a point light or a spotlight, depending on the value of the spotCutoff property.
    如果該位置的W組件是一個非零的值挤安,指定的坐標的光在齊次坐標的位置,和光是一個點光源和聚光燈計算丧鸯,根據(jù)不同的spotcutoff屬性的值
     The default value is [0.0, 0.0, 1.0, 0.0].
     默認值[0.0f,0.0f,1.0f,0.0f];
     */
    
    self.baseEffect.light0.position = GLKVector4Make(
                                                     1.0f, //x
                                                     0.0f, //y
                                                     0.8f, //z
                                                     0.0f);//w
    
    //光的環(huán)境部分
    self.baseEffect.light0.ambientColor = GLKVector4Make(
                                                         0.2f,//Red
                                                         0.2f,//Green
                                                         0.2f,//Blue
                                                         1.0f);//Alpha
    
}

設(shè)置模型矩陣,投影矩陣

//獲取屏幕縱橫比
    GLfloat aspectRatio = self.view.bounds.size.width / self.view.bounds.size.height;
    
    //4.創(chuàng)建投影矩陣 -> 透視投影
    self.baseEffect.transform.projectionMatrix = GLKMatrix4MakeOrtho(-1.0 * aspectRatio, 1.0 * aspectRatio, -1.0, 1.0, 1.0, 120.0f);
    
    //5.設(shè)置模型矩陣 -5.0f表示往屏幕內(nèi)移動-5.0f距離
    self.baseEffect.transform.modelviewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, -5.0f);

處理頂點數(shù)據(jù)

-(void)bufferData
{
    //1蛤铜、GLKMatrixStackCreate()創(chuàng)建一個新的空矩陣
    self.modelViewMatrixStack = GLKMatrixStackCreate(kCFAllocatorDefault);
    
    //2、為將要緩存區(qū)數(shù)據(jù)開辟空間
    //sphereVerts 在sphere.h文件中存在
    /*
     參數(shù)1:數(shù)據(jù)大小 3個GLFloat類型丛肢,x,y,z
     參數(shù)2:有多少個數(shù)據(jù)围肥,count
     參數(shù)3:數(shù)據(jù)大小
     參數(shù)4:用途 GL_STATIC_DRAW,
     */
    //頂點數(shù)據(jù)緩存蜂怎,頂點數(shù)據(jù)從sphere.h文件的sphereVerts數(shù)組中獲取頂點數(shù)據(jù)x,y,z
    self.vertexPositionBuffer = [[AGLKVertexAttribArrayBuffer alloc]initWithAttribStride:(3 * sizeof(GLfloat)) numberOfVertices:sizeof(sphereVerts)/(3 * sizeof(GLfloat)) bytes:sphereVerts usage:GL_STATIC_DRAW];
    
    //法線穆刻,光照坐標 sphereNormals數(shù)組 x,y,z
    self.vertexNormalBuffer = [[AGLKVertexAttribArrayBuffer alloc]initWithAttribStride:(3 * sizeof(GLfloat)) numberOfVertices:sizeof(sphereNormals)/(3 * sizeof(GLfloat)) bytes:sphereNormals usage:GL_STATIC_DRAW];
    
    //紋理坐標 sphereTexCoords數(shù)組 x,y
    self.vertextTextureCoordBuffer = [[AGLKVertexAttribArrayBuffer alloc]initWithAttribStride:(2 * sizeof(GLfloat)) numberOfVertices:sizeof(sphereTexCoords)/ (2 * sizeof(GLfloat)) bytes:sphereTexCoords usage:GL_STATIC_DRAW];
    
    
    //3.獲取地球紋理
    CGImageRef earthImageRef = [UIImage imageNamed:@"Earth512x256.jpg"].CGImage;

    //控制圖像加載方式的選項
    NSDictionary *earthOptions = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],GLKTextureLoaderOriginBottomLeft, nil];
    
    //將紋理圖片加載到紋理數(shù)據(jù)對象earchTextureInfo中
    /*
     參數(shù)1:加載的紋理圖片
     參數(shù)2:控制圖像加載的方式的選項-字典
     參數(shù)3:錯誤信息
     */
    self.earchTextureInfo = [GLKTextureLoader textureWithCGImage:earthImageRef options:earthOptions error:NULL];
    
    //4.獲取月亮紋理
    CGImageRef moonImageRef = [UIImage imageNamed:@"Moon256x128"].CGImage;
    
    NSDictionary *moonOptions = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],GLKTextureLoaderOriginBottomLeft, nil];
    
    self.moomTextureInfo = [GLKTextureLoader textureWithCGImage:moonImageRef options:moonOptions error:NULL];
    
    //矩陣堆
    //用所提供的矩陣替換最頂層矩陣,將self.baseEffect.transform.modelviewMatrix,替換self.modelViewMatrixStack
    GLKMatrixStackLoadMatrix4(self.modelViewMatrixStack, self.baseEffect.transform.modelviewMatrix);
        
    //初始化在軌道上月球位置
    self.moonRotationAngleDegress = -20.0f;
    
        
}

渲染場景

#pragma mark - drawRect
//渲染場景
-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    //設(shè)置清屏顏色
    glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
    
    //清空顏色緩存區(qū)和深度緩存區(qū)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    //地球旋轉(zhuǎn)角度
    _earthRotationAngleDegress += 360.0f/60.0f;
    //月球旋轉(zhuǎn)角度
    _moonRotationAngleDegress += (360.0f/60.0f)/SceneDaysPerMoonOrbit;
    
    //2、準備繪制
    /*
     其實就是把數(shù)據(jù)傳遞過去杠步,然后指定讀取方式
     參數(shù)1:數(shù)據(jù)是做什么用的
     參數(shù)2:數(shù)據(jù)讀取個數(shù)
     參數(shù)3:數(shù)據(jù)讀取索引
     參數(shù)4:是否調(diào)用glEnableVertexAttribArray
     
     著色器能否讀取到數(shù)據(jù)氢伟,由是否啟用了對應的屬性決定榜轿,這就是glEnableVertexAttribArray的功能,允許頂點著色器讀取GPU(服務器端)數(shù)據(jù)朵锣。

     
     默認情況下谬盐,出于性能考慮,所有頂點著色器的屬性(Attribute)變量都是關(guān)閉的诚些,意味著數(shù)據(jù)在著色器端是不可見的飞傀,哪怕數(shù)據(jù)已經(jīng)上傳到GPU,由glEnableVertexAttribArray啟用指定屬性诬烹,才可在頂點著色器中訪問逐頂點的屬性數(shù)據(jù)砸烦。glVertexAttribPointer或VBO只是建立CPU和GPU之間的邏輯連接,從而實現(xiàn)了CPU數(shù)據(jù)上傳至GPU绞吁。但是幢痘,數(shù)據(jù)在GPU端是否可見,即家破,著色器能否讀取到數(shù)據(jù)雪隧,由是否啟用了對應的屬性決定,這就是glEnableVertexAttribArray的功能员舵,允許頂點著色器讀取GPU(服務器端)數(shù)據(jù)。
     
     那么藕畔,glEnableVertexAttribArray應該在glVertexAttribPointer之前還是之后調(diào)用马僻?答案是都可以,只要在繪圖調(diào)用(glDraw*系列函數(shù))前調(diào)用即可注服。
     */
    [self.vertexPositionBuffer prepareToDrawWithAttrib:GLKVertexAttribPosition numberOfCoordinates:3 attribOffset:0 shouldEnable:YES];
    [self.vertexNormalBuffer prepareToDrawWithAttrib:GLKVertexAttribNormal numberOfCoordinates:3 attribOffset:0 shouldEnable:YES];
    [self.vertextTextureCoordBuffer prepareToDrawWithAttrib:GLKVertexAttribTexCoord0 numberOfCoordinates:2 attribOffset:0 shouldEnable:YES];
    
    //3.開始繪制
    [self drawEarth];
    [self drawMoon];
    
}

繪制地球

-(void)drawEarth
{
    //獲取紋理的name韭邓、target
    self.baseEffect.texture2d0.name = self.earchTextureInfo.name;
    self.baseEffect.texture2d0.target = self.earchTextureInfo.target;
    
    /*
     current matrix:
     1.000000 0.000000 0.000000 0.000000
     0.000000 1.000000 0.000000 0.000000
     0.000000 0.000000 1.000000 0.000000
     0.000000 0.000000 -5.000000 1.000000
     
     為什么?因為你在viewDidLoad中設(shè)置的
     //5.設(shè)置模型矩形 -5.0f表示往屏幕內(nèi)移動-5.0f距離
     self.baseEffect.transform.modelviewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, -5.0f);
     */
    
    //將當前的modelViewMatrixStack 壓棧
    GLKMatrixStackPush(self.modelViewMatrixStack);
    
    //在指定的軸上旋轉(zhuǎn)最上面的矩陣溶弟。
    GLKMatrixStackRotate(self.modelViewMatrixStack, GLKMathDegreesToRadians(SceneEarthAxialTiltDeg), 1.0f, 0.0f, 0.0f);
    
  
     /*
     current matrix:
     1.000000 0.000000 0.000000 0.000000
     0.000000 0.917060 0.398749 0.000000
     0.000000 -0.398749 0.917060 0.000000
     0.000000 0.000000 -5.000000 1.000000
    
     為什么女淑?
      將矩陣與圍繞X旋轉(zhuǎn)的旋轉(zhuǎn)矩陣相乘,即可得上述結(jié)果
     */
    self.baseEffect.transform.modelviewMatrix = GLKMatrixStackGetMatrix4(self.modelViewMatrixStack);
    
    //準備繪制
    [self.baseEffect prepareToDraw];
    
    //調(diào)用AGLKVertexAttribArrayBuffer辜御,繪制圖形
    /*
     參數(shù)1:繪制的方式鸭你,三角形
     參數(shù)2:繪制數(shù)據(jù)讀取的索引
     參數(shù)3:繪制數(shù)據(jù)的大小
     */
    
    [AGLKVertexAttribArrayBuffer drawPreparedArraysWithMode:GL_TRIANGLES startVertexIndex:0 numberOfVertices:sphereNumVerts];
    
    //繪制完畢,則出棧
    /*
     current matrix:
     0.994522 0.041681 -0.095859 0.000000
     0.000000 0.917060 0.398749 0.000000
     0.104528 -0.396565 0.912036 0.000000
     0.000000 0.000000 -5.000000 1.000000
     */
    GLKMatrixStackPop(self.modelViewMatrixStack);
   
    /*
     current matrix:
     1.000000 0.000000 0.000000 0.000000
     0.000000 1.000000 0.000000 0.000000
     0.000000 0.000000 1.000000 0.000000
     0.000000 0.000000 -5.000000 1.000000
     */
    self.baseEffect.transform.modelviewMatrix = GLKMatrixStackGetMatrix4(self.modelViewMatrixStack);
    
}

繪制月球

-(void)drawMoon
{
    //獲取紋理的name擒权、target
    self.baseEffect.texture2d0.name = self.moomTextureInfo.name;
    self.baseEffect.texture2d0.target = self.moomTextureInfo.target;
    
    //壓棧
    GLKMatrixStackPush(self.modelViewMatrixStack);
    
    //圍繞Y軸旋轉(zhuǎn)moonRotationAngleDegress角度
    //自轉(zhuǎn)
    GLKMatrixStackRotate(self.modelViewMatrixStack, GLKMathDegreesToRadians(self.moonRotationAngleDegress), 0.0f, 1.0f, 0.0f);
  
    //平移 -月球距離地球的距離
    GLKMatrixStackTranslate(self.modelViewMatrixStack, 0.0f, 0.0f, SceneMoonDistanceFromEarth);
    
    //縮放袱巨,把月球縮放
    GLKMatrixStackScale(self.modelViewMatrixStack, SceneMoonRadiusFractionOfEarth, SceneMoonRadiusFractionOfEarth, SceneMoonRadiusFractionOfEarth);
    
    //旋轉(zhuǎn) 圍繞Y軸旋轉(zhuǎn)
    GLKMatrixStackRotate(self.modelViewMatrixStack, GLKMathDegreesToRadians(self.moonRotationAngleDegress), 0.0f, 1.0f, 0.0f);
    self.baseEffect.transform.modelviewMatrix = GLKMatrixStackGetMatrix4(self.modelViewMatrixStack);
    
    [self.baseEffect prepareToDraw];
    
    [AGLKVertexAttribArrayBuffer drawPreparedArraysWithMode:GL_TRIANGLES startVertexIndex:0 numberOfVertices:sphereNumVerts];
    
    GLKMatrixStackPop(self.modelViewMatrixStack);
    
    self.baseEffect.transform.modelviewMatrix = GLKMatrixStackGetMatrix4(self.modelViewMatrixStack);
}

切換投影方法

#pragma mark -Switch Click
//切換正投影效果或透視投影效果
- (IBAction)switchClick:(UISwitch *)sender {
    
    GLfloat aspect = self.view.bounds.size.width / self.view.bounds.size.height;
    
    if ([sender isOn]) {
    
        //正投影
        self.baseEffect.transform.projectionMatrix = GLKMatrix4MakeFrustum(-1.0 * aspect, 1.0 * aspect, -1.0, 1.0, 2.0, 120.0);
        
    }else
    {
        //透視投影
        self.baseEffect.transform.projectionMatrix = GLKMatrix4MakeOrtho(-1.0 * aspect, 1.0 * aspect, -1.0, 1.0, 2.0, 120.0);
    }
    
}

效果圖

12.gif
13.gif
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市碳抄,隨后出現(xiàn)的幾起案子愉老,更是在濱河造成了極大的恐慌,老刑警劉巖剖效,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嫉入,死亡現(xiàn)場離奇詭異焰盗,居然都是意外死亡,警方通過查閱死者的電腦和手機咒林,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門熬拒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人映九,你說我怎么就攤上這事梦湘。” “怎么了件甥?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵捌议,是天一觀的道長。 經(jīng)常有香客問我引有,道長瓣颅,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任譬正,我火速辦了婚禮宫补,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘曾我。我一直安慰自己粉怕,他們只是感情好,可當我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布抒巢。 她就那樣靜靜地躺著贫贝,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蛉谜。 梳的紋絲不亂的頭發(fā)上稚晚,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天,我揣著相機與錄音型诚,去河邊找鬼客燕。 笑死,一個胖子當著我的面吹牛狰贯,可吹牛的內(nèi)容都是我干的也搓。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼暮现,長吁一口氣:“原來是場噩夢啊……” “哼还绘!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起栖袋,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤拍顷,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后塘幅,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體昔案,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡尿贫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了踏揣。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片庆亡。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖捞稿,靈堂內(nèi)的尸體忽然破棺而出又谋,到底是詐尸還是另有隱情,我是刑警寧澤娱局,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布彰亥,位于F島的核電站,受9級特大地震影響衰齐,放射性物質(zhì)發(fā)生泄漏任斋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一耻涛、第九天 我趴在偏房一處隱蔽的房頂上張望废酷。 院中可真熱鬧,春花似錦抹缕、人聲如沸澈蟆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽丰介。三九已至,卻和暖如春鉴分,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背带膀。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工志珍, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人垛叨。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓伦糯,卻偏偏與公主長得像,于是被迫代替她去往敵國和親嗽元。 傳聞我的和親對象是個殘疾皇子敛纲,可洞房花燭夜當晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容