OpenGL ES畫板

来源:https://www.cnblogs.com/lybSkill/archive/2018/12/10/10095696.html
-Advertisement-
Play Games

一、概述 利用自定義頂點和片元著色器渲染,並且設置圖片紋理顏色為畫筆顏色 二、核心代碼 三、效果圖 GitHub ...


一、概述

利用自定義頂點和片元著色器渲染,並且設置圖片紋理顏色為畫筆顏色

二、核心代碼

 

- (void)renderLineFromPoint:(CGPoint)start toPoint:(CGPoint)end
{
    //頂點緩存區
    static GLfloat *vertexBuffer = NULL;
    //頂點Max
    static NSUInteger vertexMax = 64;
    //頂點個數
    NSUInteger vertexCount = 0,count;
    CGFloat scale = self.contentScaleFactor;
    
    //點到像素轉換:乘以比例因數
    start.x *= scale;
    start.y *= scale;
    end.x *= scale;
    end.y *= scale;
    
    //開闢頂點緩存區
    if (vertexBuffer == NULL) {
        vertexBuffer = malloc(vertexMax*2*sizeof(GLfloat));
    }
    
    //求得兩點之間的距離
    float seq = sqrtf((end.x-start.x)*(end.x-start.x)+(end.y-start.y)*(end.y-start.y));
    /*向上取整:求得距離要產生多少個點
     kBrushPixelStep值越大,筆觸越細;值越小,筆觸越粗
     */
    NSInteger pointCount = ceil(seq/kBrushPixelStep);
    count = MAX(pointCount, 1);
    
    for (int i = 0; i < count; i++) {
        if (vertexCount == vertexMax) {
            //修改2倍增長
            vertexMax = 2*vertexMax;
            vertexBuffer = realloc(vertexBuffer, vertexMax*2*sizeof(GLfloat));
        }
        
        //計算兩個之間的距離有多少個點,並存儲在頂點緩存區中
        vertexBuffer[2*vertexCount+0] = start.x+(end.x-start.x)*((GLfloat)i/(GLfloat)count);
        vertexBuffer[2*vertexCount+1] = start.y+(end.y-start.y)*((GLfloat)i/(GLfloat)count);
        
        vertexCount++;
    }
    
    //綁定頂點數據
    glBindBuffer(GL_ARRAY_BUFFER, vboID);
    //將數據從CPU中複製到GPU中提供給OpenGL使用
    glBufferData(GL_ARRAY_BUFFER, vertexCount*2*sizeof(GLfloat), vertexBuffer, GL_DYNAMIC_DRAW);
    
    //啟用指定屬性
    glEnableVertexAttribArray(ATTRIB_VERTEX);
    //鏈接頂點屬性
    glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, GL_FALSE, 2*sizeof(GLfloat), 0);
    
    //使用數據匯流排:傳遞頂點數據到頂點著色器
    glUseProgram(program[PROGRAME_POINT].id);
    //繪製頂點:繪製模型、起始點、頂點個數
    glDrawArrays(GL_POINTS, 0, (int)vertexCount);
    //綁定渲染緩存區到特定標誌符上
    glBindRenderbuffer(GL_RENDERBUFFER, viewRenderBuffer);
    //開始渲染
    [context presentRenderbuffer:GL_RENDERBUFFER];
    
}

 

- (textureInfo_t)textureFromName:(NSString *)name
{
    CGImageRef brushImage;
    CGContextRef brushContext;
    GLubyte *brushData;
    size_t width, height;
    GLuint texID;
    textureInfo_t texture;
    
    brushImage = [UIImage imageNamed:name].CGImage;
    width = CGImageGetWidth(brushImage);
    height = CGImageGetHeight(brushImage);
    //開闢紋理圖片記憶體
    brushData = (GLubyte *)calloc(width*height*4, sizeof(GLubyte));
    
    /*創建點陣圖上下文
     參數:圖片記憶體地址、圖片寬、圖片高、像素組件位數(一般設置8),每一行所占比特數、顏色空間、顏色通道
     */
    brushContext = CGBitmapContextCreate(brushData, width, height, 8, width*4, CGImageGetColorSpace(brushImage), kCGImageAlphaPremultipliedLast);
    
    //繪圖
    CGContextDrawImage(brushContext, CGRectMake(0, 0, (CGFloat)width, (CGFloat)height), brushImage);
    //釋放上下文
    CGContextRelease(brushContext);
    
    //申請紋理標誌符
    glGenTextures(1, &texID);
    //綁定紋理
    glBindTexture(GL_TEXTURE_2D, texID);
    //設置紋理屬性:縮小濾波器、線性濾波器
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    /*生成2D紋理圖片
     參數:紋理目標、圖像級別(0為基本級別)、顏色組件(GL_RGBA、GL_ALPHA)、圖像寬、圖像高、邊框寬度(一般為0)、像素數據顏色格式、像素數據類型、記憶體中指向圖像數據指針
     */
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)width, (int)height, 0, GL_RGBA, GL_UNSIGNED_BYTE, brushData);
    
    free(brushData);
    
    //配置紋理屬性
    texture.id = texID;
    texture.width = (int)width;
    texture.height = (int)height;
    
    return texture;
}
- (void)setupShaders
{
    for (int i = 0; i < NUM_PROGRAMS; i++) {
        
        //讀取頂點著色器程式
        char *vsrc = readFile(pathForResource(program[i].vert));
        //讀取片元著色器程式
        char *fsrc = readFile(pathForResource(program[i].frag));
        NSString *vsrcStr = [[NSString alloc] initWithBytes:vsrc length:strlen(vsrc)-1 encoding:NSUTF8StringEncoding];
        NSString *fsrcStr = [[NSString alloc] initWithBytes:fsrc length:strlen(fsrc)-1 encoding:NSUTF8StringEncoding];
        NSLog(@"vsrcStr------%@", vsrcStr);
        NSLog(@"fsrcStr------%@", fsrcStr);
        
        GLsizei attribCt = 0;
        GLchar *attribUsed[NUM_ATTRIBS];
        GLint attrib[NUM_ATTRIBS];
        GLchar *attribName[NUM_ATTRIBS] = {
            "inVertex"
        };
        
        const char *uniformName[NUM_UNIFORMS] = {
            "MVP","pointSize","vertexColor", "texture"
        };
        
        for (int j = 0; j < NUM_ATTRIBS; j++) {
            if (strstr(vsrc, attribName[j])) {
                attrib[attribCt] = j;
                attribUsed[attribCt++] = attribName[j];
            }
        }
        
        //program處理:創建、鏈接、生成
        glueCreateProgram(vsrc, fsrc, attribCt, (const char **)&attribUsed[0], attrib, NUM_UNIFORMS, &uniformName[0], program[i].uniform, &program[i].id);
        
        free(vsrc);
        free(fsrc);
        
        if (i == PROGRAME_POINT) {
            glUseProgram(program[PROGRAME_POINT].id);
           //為當前程式指定uniform變數
            glUniform1i(program[PROGRAME_POINT].uniform[UNIFORM_TEXTURE], 0);
            
            //設置正射投影矩陣
            GLKMatrix4 projectionMatrix = GLKMatrix4MakeOrtho(0, backingWidth, 0, backingHeight, -1, 1);
            //創建模型視圖矩陣:單元矩陣
            GLKMatrix4 modelViewMatrix = GLKMatrix4Identity;
            //正射投影矩陣與模型視圖矩陣相乘,結果保存在MVPMatrix矩陣中
            GLKMatrix4 MVPMatrix = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix);
           
           /*為當前程式指定Uniform變數值
            參數:指明要更改的Uniform變數的位置、將要被修改的矩陣的數量、矩陣值被載入變數時是否要對舉證進行變換(如轉置)、將要用於更新uniform變數MVP的數組指針
            */
            glUniformMatrix4fv(program[PROGRAME_POINT].uniform[UNIFORM_MVP], 1, GL_FALSE, MVPMatrix.m);
           //為當前程式對象Uniform變數的pointSize賦值
            glUniform1f(program[PROGRAME_POINT].uniform[UNIFORM_POINT_SIZE], brushTexture.width/kBrushScale);
            //為當前程式對象Uniform變數頂點顏色賦值
            glUniform4fv(program[PROGRAME_POINT].uniform[UNIFORM_VERTEX_COLOR], 1, brushColor);
            
        }
    }
    
    glError();
}

三、效果圖

 

 

GitHub

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 尤其是在學習的過程, 也是天天和資料庫打交道, 難免會有腦子短路的時候, 比如root密碼忘記了, 你說怎麼辦~~~, 沒關係, 往下看 mysql提供了一種跳過用戶認證的配置, 參數, 你配置上這個參數後, 就可以不驗證直接登進資料庫.. 修改配置文件 以Linux為例, mysql的配置文件一般 ...
  • 現mysql中有一張表php_user表,表結構為: 表中數據有: 現在想查詢出來不同學生的語數外成績在一行顯示,那麼需要用到行轉列的用法, 一、行轉列 1、使用case...when....then 進行行轉列MAX(case when 條件 then 列內容 else 不匹配時顯示內容 end) ...
  • Mysql 多主一從數據備份 概述 對任何一個資料庫的操作都自動應用到另外一個資料庫,始終保持兩個資料庫中的數據一致。 這樣做有如下幾點好處: 1. 可以做災備,其中一個壞了可以切換到另一個。 2. 可以做負載均衡,可以將請求分攤到其中任何一臺上,提高網站吞吐量。 對於異地熱備,尤其適合災備。 My ...
  • 一,Xcode-->Preferences >Key Bindings. 參考資料:《Xcode實戰開發》 ...
  • 今天繼續學習flutter,覺得這個優秀的東西,許多方面還需要完善,作為一個後來者,要多向別人學習。俗話說,“學無先後,達者為師”。今天呢,我又重新把flutter_boss這個項目代碼 從頭到腳看了一遍,併進行重構。 廢話不多說,展示出來分享給大家。本項目源碼已上傳GitHub,文末給出地址。 一 ...
  • 今日需求,EditText內容為一串字元串,要求將用戶軟鍵盤輸入的小寫字母在輸入的時候自動轉為大寫字母,反之亦然。 效果如下: 第一次做該需求,原先想法: 對於afterTextChanged回調方法里,對輸入的字元串進行大小寫轉換,結果失敗,因為每次轉換之後實際就再次回調該方法導致死迴圈。 最後解 ...
  • 單例模式主要實現唯一實例,存活於整個程式範圍內,一般存儲用戶信息經常用到單例,比如用戶密碼,密碼在登錄界面用一次,在修改密碼界面用一次,而使用單例,就能保證密碼唯一實例。如果不用單例模式,init 兩個的實例的堆棧地址不一樣,所以存放的數據的位置也不一樣,當其中一個數據改變,另一個數據依然不變。單例 ...
  • Pxpay 個人收款開源項目:https://gitee.com/DaLianZhiYiKeJi/xpay 支付寶收款的幾種方式: 對於傳統方式.支付寶限制了一天二維碼的生成數量.在這之間簡直是好用得不要不要得.但是突然間支付寶爸爸說.你搞那麼多二維碼幹啥.還備註...一天給你20張夠不夠? 於是乎 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...