Flutter图形渲染插件glew的使用

发布于 1周前 作者 phonegap100 来自 Flutter

Flutter图形渲染插件glew的使用

需求

  • ffi ^2.1.2

注意事项

  • Windows 64位系统

示例

在本示例中,我们将展示如何使用 glewglfw3 在 Flutter 中实现一个简单的图形渲染。

作者

  • yamahara

示例代码

// https://github.com/JoeyDeVries/LearnOpenGL/blob/master/src/1.getting_started/2.1.hello_triangle/hello_triangle.cpp
import 'dart:ffi';
import 'package:glew/glew.dart';
import 'package:glfw3/glfw3.dart';

// 设置屏幕宽度和高度
const gScrWidth = 800;
const gScrHeight = 600;

// 顶点着色器源码
final gVertexShaderSource = '#version 330 core'
    '\n'
    'layout (location = 0) in vec3 aPos;'
    '\n'
    'void main()'
    '\n'
    '{'
    '\n'
    '    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);'
    '\n'
    '}';

// 片段着色器源码
final gFragmentShaderSource = '#version 330 core'
    '\n'
    'out vec4 FragColor;'
    '\n'
    'void main()'
    '\n'
    '{'
    '\n'
    '    FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);'
    '\n'
    '}';

int main() {
  // 初始化并配置GLFW
  // ------------------------------
  if (glfwInit() != GLFW_TRUE) {
    return -1;
  }
  glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
  glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  // 对于苹果系统
  glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

  // 创建GLFW窗口
  // --------------------
  var window =
      glfwCreateWindow(gScrWidth, gScrHeight, 'LearnOpenGL', nullptr, nullptr);
  if (window == nullptr) {
    print('Failed to create GLFW window');
    glfwTerminate();
    return -1;
  }
  glfwMakeContextCurrent(window);
  glfwSetFramebufferSizeCallback(
      window, Pointer.fromFunction(framebufferSizeCallback));

  // 加载所有OpenGL函数指针
  // ---------------------------------------
  gladLoadGLLoader(glfwGetProcAddress);

  // 构建并编译着色器程序
  // ------------------------------------
  // 顶点着色器
  var vertexShader = glCreateShader(GL_VERTEX_SHADER);
  gldtShaderSource(vertexShader, gVertexShaderSource);
  glCompileShader(vertexShader);
  if (gldtGetShaderiv(vertexShader, GL_COMPILE_STATUS) != GLFW_TRUE) {
    print('ERROR::SHADER::VERTEX::COMPILATION_FAILED');
    var bufSize = gldtGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH);
    if (bufSize > 1) {
      print(gldtGetShaderInfoLog(vertexShader, bufSize));
    }
  }

  // 片段着色器
  var fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
  gldtShaderSource(fragmentShader, gFragmentShaderSource);
  glCompileShader(fragmentShader);
  if (gldtGetShaderiv(fragmentShader, GL_COMPILE_STATUS) != GLFW_TRUE) {
    print('ERROR::SHADER::FRAGMENT::COMPILATION_FAILED');
    var bufSize = gldtGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH);
    if (bufSize > 1) {
      print(gldtGetShaderInfoLog(fragmentShader, bufSize));
    }
  }

  // 链接着色器
  var shaderProgram = glCreateProgram();
  glAttachShader(shaderProgram, vertexShader);
  glAttachShader(shaderProgram, fragmentShader);
  glLinkProgram(shaderProgram);
  // 检查链接错误
  if (gldtGetProgramiv(shaderProgram, GL_LINK_STATUS) != GL_TRUE) {
    print('ERROR::SHADER::PROGRAM::LINKING_FAILED');
    var bufSize = gldtGetProgramiv(shaderProgram, GL_INFO_LOG_LENGTH);
    if (bufSize > 1) {
      print(gldtGetProgramInfoLog(shaderProgram, bufSize));
    }
  }
  glDeleteShader(vertexShader);
  glDeleteShader(fragmentShader);

  // 设置顶点数据
  // ------------------------------------------------------------------
  var vertices = [
    -0.5, -0.5, 0.0, // 左下角
    0.5, -0.5, 0.0, // 右下角
    0.0, 0.5, 0.0, // 顶点
  ];

  var vao = gldtGenVertexArrays(1)[0];
  var vbo = gldtGenBuffers(1)[0];

  // 绑定顶点数组对象,设置顶点缓冲区并配置顶点属性
  glBindVertexArray(vao);
  glBindBuffer(GL_ARRAY_BUFFER, vbo);
  gldtBufferFloat(GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW);
  gldtVertexAttribPointer(
      0, 3, GL_FLOAT, GL_FALSE, 3 * sizeOf<Float>(), 0 * sizeOf<Float>());
  glEnableVertexAttribArray(0);

  // 解绑顶点缓冲区
  glBindBuffer(GL_ARRAY_BUFFER, 0);

  // 渲染循环
  // -----------
  while (glfwWindowShouldClose(window) == GLFW_FALSE) {
    // 处理输入
    processInput(window);

    // 渲染
    glClearColor(0.2, 0.3, 0.3, 1);
    glClear(GL_COLOR_BUFFER_BIT);

    // 使用着色器程序
    glUseProgram(shaderProgram);

    // 绑定顶点数组对象
    glBindVertexArray(vao);
    glDrawArrays(GL_TRIANGLES, 0, 3);

    // 交换缓冲区并处理IO事件
    glfwSwapBuffers(window);
    glfwPollEvents();
  }

  // 清理资源
  gldtDeleteVertexArrays([vao]);
  gldtDeleteBuffers([vbo]);
  glDeleteProgram(shaderProgram);

  // 终止GLFW
  glfwTerminate();

  return 0;
}

// 处理所有输入
void processInput(Pointer<GLFWwindow> window) {
  if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
    glfwSetWindowShouldClose(window, GLFW_TRUE);
  }
}

// 当窗口大小改变时调用此回调函数
void framebufferSizeCallback(
    Pointer<GLFWwindow> window, int width, int height) {
  glViewport(0, 0, width, height);
}

更多关于Flutter图形渲染插件glew的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter图形渲染插件glew的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中,直接使用GLEW(OpenGL Extension Wrangler Library)进行图形渲染并不是一个常见的做法,因为Flutter本身是基于Dart语言开发的,而GLEW是用于C/C++环境下OpenGL扩展加载的库。然而,如果你希望在Flutter应用中集成OpenGL渲染,你可以通过Flutter的Platform Channels与原生代码(如Android的Java/Kotlin或iOS的Swift/Objective-C)进行交互,并在原生代码中使用OpenGL和GLEW。

以下是一个简化的示例,展示了如何在Flutter中通过Platform Channels调用原生代码进行OpenGL渲染。由于GLEW的使用主要集中在OpenGL扩展的加载上,下面的示例将重点放在设置Platform Channels和OpenGL上下文上,而不是GLEW的具体使用(因为GLEW的使用与平台相关,且通常隐藏在OpenGL初始化和渲染代码中)。

1. 设置Flutter项目

首先,创建一个新的Flutter项目(如果你还没有的话):

flutter create flutter_glew_example
cd flutter_glew_example

2. 创建Platform Channel

lib目录下,修改main.dart文件以设置Platform Channel:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  static const platform = MethodChannel('com.example.flutter_glew_example/channel');

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Flutter GLEW Example'),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: _setupOpenGL,
            child: Text('Setup OpenGL'),
          ),
        ),
      ),
    );
  }

  Future<void> _setupOpenGL() async {
    try {
      final result = await platform.invokeMethod('setupOpenGL');
      print('OpenGL setup result: ${result}');
    } on PlatformException catch (e) {
      print("Failed to invoke: '${e.message}'.");
    }
  }
}

3. 实现原生代码

Android

android/app/src/main/java/com/example/flutter_glew_example/目录下,修改MainActivity.java以处理Platform Channel调用:

package com.example.flutter_glew_example;

import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.MethodChannel;

public class MainActivity extends FlutterActivity {
    private static final String CHANNEL = "com.example.flutter_glew_example/channel";

    @Override
    public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
        super.configureFlutterEngine(flutterEngine);
        new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
                .setMethodCallHandler(
                        (call, result) -> {
                            if (call.method.equals("setupOpenGL")) {
                                setupOpenGL();
                                result.success("OpenGL setup complete");
                            } else {
                                result.notImplemented();
                            }
                        }
                );
    }

    private void setupOpenGL() {
        // Create and set a GLSurfaceView
        GLSurfaceView glSurfaceView = new GLSurfaceView(this);
        glSurfaceView.setEGLContextClientVersion(2); // OpenGL ES 2.0
        glSurfaceView.setRenderer(new MyGLRenderer());

        // Set the GLSurfaceView as the content view of the activity
        setContentView(glSurfaceView);
    }

    // Define a simple OpenGL renderer
    private static class MyGLRenderer implements GLSurfaceView.Renderer {
        @Override
        public void onSurfaceCreated(javax.microedition.khronos.opengles.GL10 gl, javax.microedition.khronos.egl.EGLConfig config) {
            // Initialize OpenGL here (e.g., load shaders, set up buffers)
            // GLEW would be used here if we were in a pure OpenGL/C++ environment
        }

        @Override
        public void onSurfaceChanged(javax.microedition.khronos.opengles.GL10 gl, int width, int height) {
            // Handle size changes here
        }

        @Override
        public void onDrawFrame(javax.microedition.khronos.opengles.GL10 gl) {
            // Render the frame here
        }
    }
}

iOS

ios/Runner/目录下,修改AppDelegate.swift以处理Platform Channel调用(注意,iOS上设置OpenGL上下文通常涉及更复杂的UIKit和OpenGL ES集成):

import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    
    let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
    let channel = FlutterMethodChannel(name: "com.example.flutter_glew_example/channel", binaryMessenger: controller)
    
    channel.setMethodCallHandler({
      (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
      if call.method == "setupOpenGL" {
        setupOpenGL()
        result(Success("OpenGL setup complete"))
      } else {
        result(FlutterMethodNotImplemented)
      }
    })
    
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
  
  func setupOpenGL() {
    // Setting up OpenGL context on iOS is more complex and typically involves
    // creating a CAEAGLLayer and integrating it with a UIView.
    // GLEW usage would occur within the OpenGL rendering loop in Objective-C/Swift.
    
    // Placeholder: You would initialize your OpenGL context and renderer here.
    print("OpenGL setup placeholder on iOS")
  }
}

4. 运行项目

现在,你可以运行Flutter项目,并在点击按钮时通过Platform Channel调用原生代码来设置OpenGL上下文。请注意,上面的代码示例并没有实际展示GLEW的使用,因为GLEW主要用于C/C++中的OpenGL扩展加载,而在Flutter的原生集成中,你通常会在OpenGL的初始化代码中直接处理所需的OpenGL函数和扩展。

如果你确实需要在Flutter项目中使用GLEW,你可能需要创建一个原生的C/C++模块,通过Dart FFI(外部函数接口)或直接通过Platform Channels与Flutter进行通信。然而,这通常不是Flutter开发的常规做法,因为Flutter提供了丰富的UI和渲染库,可以直接在Dart代码中使用。

回到顶部