经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Java » 查看文章
【Filament】绘制圆形
来源:cnblogs  作者:little_fat_sheep  时间:2024/2/28 9:07:33  对本文有异议

1 前言

? Filament环境搭建中介绍了 Filament 的 Windows 和 Android 环境搭,绘制三角形中介绍了绘制纯色和彩色三角形,绘制矩形中介绍了绘制纯色和彩色矩形,本文将使用 Filament 绘制圆形。

2 绘制圆形

? 本文项目结构如下,完整代码资源 → Filament绘制圆形

img

2.1 自定义基类

? 为方便读者将注意力聚焦在 Filament 的输入上,轻松配置复杂的环境依赖逻辑,笔者仿照 OpenGL ES 的写法,抽出了 FLSurfaceView 和 BaseModel 类。FLSurfaceView 与 GLSurfaceView 的功能类似,承载了渲染环境配置;BaseModel 中提供了一些 VertexBuffer、IndexBuffer、Material、Renderable 相关的工具类,方便子类直接使用这些工具类。

? build.gradle

  1. ...
  2. android {
  3. ...
  4. aaptOptions { // 在应用程序打包过程中不压缩的文件
  5. noCompress 'filamat', 'ktx'
  6. }
  7. }
  8. dependencies {
  9. implementation fileTree(dir: '../libs', include: ['*.aar'])
  10. ...
  11. }

? 说明:在项目根目录下的 libs 目录中,需要放入以下 aar 文件,它们源自Filament环境搭建中编译生成的 aar。

img

? FLSurfaceView.java

  1. package com.zhyan8.circle.filament;
  2. import android.content.Context;
  3. import android.graphics.Point;
  4. import android.view.Choreographer;
  5. import android.view.Surface;
  6. import android.view.SurfaceView;
  7. import com.google.android.filament.Camera;
  8. import com.google.android.filament.Engine;
  9. import com.google.android.filament.EntityManager;
  10. import com.google.android.filament.Filament;
  11. import com.google.android.filament.Renderer;
  12. import com.google.android.filament.Scene;
  13. import com.google.android.filament.Skybox;
  14. import com.google.android.filament.SwapChain;
  15. import com.google.android.filament.View;
  16. import com.google.android.filament.Viewport;
  17. import com.google.android.filament.android.DisplayHelper;
  18. import com.google.android.filament.android.FilamentHelper;
  19. import com.google.android.filament.android.UiHelper;
  20. /*
  21. * Filament中待渲染的SurfaceView
  22. * 功能可以类比OpenGL ES中的GLSurfaceView
  23. * 用于创建Filament的渲染环境
  24. */
  25. public class FLSurfaceView extends SurfaceView {
  26. public static int RENDERMODE_WHEN_DIRTY = 0; // 用户请求渲染才渲染一帧
  27. public static int RENDERMODE_CONTINUOUSLY = 1; // 持续渲染
  28. protected int mRenderMode = RENDERMODE_CONTINUOUSLY; // 渲染模式
  29. protected Choreographer mChoreographer; // 消息控制
  30. protected DisplayHelper mDisplayHelper; // 管理Display(可以监听分辨率或刷新率的变化)
  31. protected UiHelper mUiHelper; // 管理SurfaceView、TextureView、SurfaceHolder
  32. protected Engine mEngine; // 引擎(跟踪用户创建的资源, 管理渲染线程和硬件渲染器)
  33. protected Renderer mRenderer; // 渲染器(用于操作系统窗口, 生成绘制命令, 管理帧延时)
  34. protected Scene mScene; // 场景(管理渲染对象、灯光)
  35. protected View mView; // 存储渲染数据(View是Renderer操作的对象)
  36. protected Camera mCamera; // 相机(视角管理)
  37. protected Point mDesiredSize; // 渲染分辨率
  38. protected float[] mSkyboxColor; // 背景颜色
  39. protected SwapChain mSwapChain; // 操作系统的本地可渲染表面(native renderable surface, 通常是一个window或view)
  40. protected FrameCallback mFrameCallback = new FrameCallback(); // 帧回调
  41. static {
  42. Filament.init();
  43. }
  44. public FLSurfaceView(Context context) {
  45. super(context);
  46. mChoreographer = Choreographer.getInstance();
  47. mDisplayHelper = new DisplayHelper(context);
  48. }
  49. public void init() { // 初始化
  50. setupSurfaceView();
  51. setupFilament();
  52. setupView();
  53. setupScene();
  54. }
  55. public void setRenderMode(int renderMode) { // 设置渲染模式
  56. mRenderMode = renderMode;
  57. }
  58. public void requestRender() { // 请求渲染
  59. mChoreographer.postFrameCallback(mFrameCallback);
  60. }
  61. public void onResume() { // 恢复
  62. mChoreographer.postFrameCallback(mFrameCallback);
  63. }
  64. public void onPause() { // 暂停
  65. mChoreographer.removeFrameCallback(mFrameCallback);
  66. }
  67. public void onDestroy() { // 销毁Filament环境
  68. mChoreographer.removeFrameCallback(mFrameCallback);
  69. mUiHelper.detach();
  70. mEngine.destroyRenderer(mRenderer);
  71. mEngine.destroyView(mView);
  72. mEngine.destroyScene(mScene);
  73. mEngine.destroyCameraComponent(mCamera.getEntity());
  74. EntityManager entityManager = EntityManager.get();
  75. entityManager.destroy(mCamera.getEntity());
  76. mEngine.destroy();
  77. }
  78. protected void setupScene() { // 设置Scene参数
  79. }
  80. protected void onResized(int width, int height) { // Surface尺寸变化时回调
  81. double zoom = 1;
  82. double aspect = (double) width / (double) height;
  83. mCamera.setProjection(Camera.Projection.ORTHO,
  84. -aspect * zoom, aspect * zoom, -zoom, zoom, 0, 1000);
  85. }
  86. private void setupSurfaceView() { // 设置SurfaceView
  87. mUiHelper = new UiHelper(UiHelper.ContextErrorPolicy.DONT_CHECK);
  88. mUiHelper.setRenderCallback(new SurfaceCallback());
  89. if (mDesiredSize != null) {
  90. mUiHelper.setDesiredSize(mDesiredSize.x, mDesiredSize.y);
  91. }
  92. mUiHelper.attachTo(this);
  93. }
  94. private void setupFilament() { // 设置Filament参数
  95. mEngine = Engine.create();
  96. // mEngine = (new Engine.Builder()).featureLevel(Engine.FeatureLevel.FEATURE_LEVEL_0).build();
  97. mRenderer = mEngine.createRenderer();
  98. mScene = mEngine.createScene();
  99. mView = mEngine.createView();
  100. mCamera = mEngine.createCamera(mEngine.getEntityManager().create());
  101. }
  102. private void setupView() { // 设置View参数
  103. float[] color = mSkyboxColor != null ? mSkyboxColor : new float[] {0, 0, 0, 1};
  104. Skybox skybox = (new Skybox.Builder()).color(color).build(mEngine);
  105. mScene.setSkybox(skybox);
  106. if (mEngine.getActiveFeatureLevel() == Engine.FeatureLevel.FEATURE_LEVEL_0) {
  107. mView.setPostProcessingEnabled(false); // FEATURE_LEVEL_0不支持post-processing
  108. }
  109. mView.setCamera(mCamera);
  110. mView.setScene(mScene);
  111. }
  112. /*
  113. * 帧回调
  114. */
  115. private class FrameCallback implements Choreographer.FrameCallback {
  116. @Override
  117. public void doFrame(long frameTimeNanos) { // 渲染每帧数据
  118. if (mRenderMode == RENDERMODE_CONTINUOUSLY) {
  119. mChoreographer.postFrameCallback(this); // 请求下一帧
  120. }
  121. if (mUiHelper.isReadyToRender()) {
  122. if (mRenderer.beginFrame(mSwapChain, frameTimeNanos)) {
  123. mRenderer.render(mView);
  124. mRenderer.endFrame();
  125. }
  126. }
  127. }
  128. }
  129. /*
  130. * Surface回调
  131. */
  132. private class SurfaceCallback implements UiHelper.RendererCallback {
  133. @Override
  134. public void onNativeWindowChanged(Surface surface) { // Native窗口改变时回调
  135. if (mSwapChain != null) {
  136. mEngine.destroySwapChain(mSwapChain);
  137. }
  138. long flags = mUiHelper.getSwapChainFlags();
  139. if (mEngine.getActiveFeatureLevel() == Engine.FeatureLevel.FEATURE_LEVEL_0) {
  140. if (SwapChain.isSRGBSwapChainSupported(mEngine)) {
  141. flags = flags | SwapChain.CONFIG_SRGB_COLORSPACE;
  142. }
  143. }
  144. mSwapChain = mEngine.createSwapChain(surface, flags);
  145. mDisplayHelper.attach(mRenderer, getDisplay());
  146. }
  147. @Override
  148. public void onDetachedFromSurface() { // 解绑Surface时回调
  149. mDisplayHelper.detach();
  150. if (mSwapChain != null) {
  151. mEngine.destroySwapChain(mSwapChain);
  152. mEngine.flushAndWait();
  153. mSwapChain = null;
  154. }
  155. }
  156. @Override
  157. public void onResized(int width, int height) { // Surface尺寸变化时回调
  158. mView.setViewport(new Viewport(0, 0, width, height));
  159. FilamentHelper.synchronizePendingFrames(mEngine);
  160. FLSurfaceView.this.onResized(width, height);
  161. }
  162. }
  163. }

? BaseModel.java

  1. package com.zhyan8.circle.filament;
  2. import android.content.res.AssetFileDescriptor;
  3. import android.content.res.AssetManager;
  4. import android.os.Handler;
  5. import android.os.Looper;
  6. import android.util.Log;
  7. import com.google.android.filament.Box;
  8. import com.google.android.filament.Engine;
  9. import com.google.android.filament.EntityManager;
  10. import com.google.android.filament.IndexBuffer;
  11. import com.google.android.filament.Material;
  12. import com.google.android.filament.MaterialInstance;
  13. import com.google.android.filament.RenderableManager;
  14. import com.google.android.filament.RenderableManager.PrimitiveType;
  15. import com.google.android.filament.VertexBuffer;
  16. import com.google.android.filament.VertexBuffer.AttributeType;
  17. import com.google.android.filament.VertexBuffer.VertexAttribute;
  18. import java.io.FileInputStream;
  19. import java.io.IOException;
  20. import java.nio.Buffer;
  21. import java.nio.ByteBuffer;
  22. import java.nio.ByteOrder;
  23. import java.nio.channels.Channels;
  24. import java.nio.channels.ReadableByteChannel;
  25. /*
  26. * 模型基类
  27. * 管理模型的材质、顶点属性、顶点索引、渲染id
  28. */
  29. public class BaseModel {
  30. private static String TAG = "BaseModel";
  31. protected AssetManager mAssetManager; // 资源管理器
  32. protected Engine mEngine; // Filament引擎
  33. protected Material mMaterial; // 模型材质
  34. protected MaterialInstance mMaterialInstance; // 模型材质实例
  35. protected VertexBuffer mVertexBuffer; // 顶点属性缓存
  36. protected IndexBuffer mIndexBuffer; // 顶点索引缓存
  37. protected int mRenderable; // 渲染id
  38. protected Box mBox; // 渲染区域
  39. public BaseModel(AssetManager assetManager, Engine engine) {
  40. mAssetManager = assetManager;
  41. mEngine = engine;
  42. }
  43. public Material getMaterial() { // 获取材质
  44. return mMaterial;
  45. }
  46. public VertexBuffer getVertexBuffer() { // 获取顶点属性缓存
  47. return mVertexBuffer;
  48. }
  49. public IndexBuffer getIndexBuffer() { // 获取顶点索引缓存
  50. return mIndexBuffer;
  51. }
  52. public int getRenderable() { // 获取渲染id
  53. return mRenderable;
  54. }
  55. public void destroy() { // 销毁模型
  56. mEngine.destroyEntity(mRenderable);
  57. mEngine.destroyVertexBuffer(mVertexBuffer);
  58. mEngine.destroyIndexBuffer(mIndexBuffer);
  59. mEngine.destroyMaterialInstance(mMaterialInstance);
  60. mEngine.destroyMaterial(mMaterial);
  61. EntityManager entityManager = EntityManager.get();
  62. entityManager.destroy(mRenderable);
  63. }
  64. protected Material loadMaterial(String materialPath) { // 加载材质
  65. Buffer buffer = readUncompressedAsset(mAssetManager, materialPath);
  66. if (buffer != null) {
  67. Material material = (new Material.Builder()).payload(buffer, buffer.remaining()).build(mEngine);
  68. mMaterialInstance = material.createInstance();
  69. material.compile(
  70. Material.CompilerPriorityQueue.HIGH,
  71. Material.UserVariantFilterBit.ALL,
  72. new Handler(Looper.getMainLooper()),
  73. () -> Log.i(TAG, "Material " + material.getName() + " compiled."));
  74. mEngine.flush();
  75. return material;
  76. }
  77. return null;
  78. }
  79. protected VertexBuffer getVertexBuffer(float[] values) { // 获取顶点属性缓存
  80. ByteBuffer vertexData = getByteBuffer(values);
  81. int vertexCount = values.length / 3;
  82. int vertexSize = Float.BYTES * 3;
  83. VertexBuffer vertexBuffer = new VertexBuffer.Builder()
  84. .bufferCount(1)
  85. .vertexCount(vertexCount)
  86. .attribute(VertexAttribute.POSITION, 0, AttributeType.FLOAT3, 0, vertexSize)
  87. .build(mEngine);
  88. vertexBuffer.setBufferAt(mEngine, 0, vertexData);
  89. return vertexBuffer;
  90. }
  91. protected VertexBuffer getVertexBuffer(Vertex[] values) { // 获取顶点属性缓存
  92. ByteBuffer vertexData = getByteBuffer(values);
  93. int vertexCount = values.length;
  94. int vertexSize = Vertex.BYTES;
  95. VertexBuffer vertexBuffer = new VertexBuffer.Builder()
  96. .bufferCount(1)
  97. .vertexCount(vertexCount)
  98. .attribute(VertexAttribute.POSITION, 0, AttributeType.FLOAT3, 0, vertexSize)
  99. .attribute(VertexAttribute.COLOR, 0, AttributeType.UBYTE4, 3 * Float.BYTES, vertexSize)
  100. .normalized(VertexAttribute.COLOR)
  101. .build(mEngine);
  102. vertexBuffer.setBufferAt(mEngine, 0, vertexData);
  103. return vertexBuffer;
  104. }
  105. protected IndexBuffer getIndexBuffer(short[] values) { // 获取顶点索引缓存
  106. ByteBuffer indexData = getByteBuffer(values);
  107. int indexCount = values.length;
  108. IndexBuffer indexBuffer = new IndexBuffer.Builder()
  109. .indexCount(indexCount)
  110. .bufferType(IndexBuffer.Builder.IndexType.USHORT)
  111. .build(mEngine);
  112. indexBuffer.setBuffer(mEngine, indexData);
  113. return indexBuffer;
  114. }
  115. protected int getRenderable(PrimitiveType primitiveType, int vertexCount) { // 获取渲染id
  116. int renderable = EntityManager.get().create();
  117. new RenderableManager.Builder(1)
  118. .boundingBox(mBox)
  119. .geometry(0, primitiveType, mVertexBuffer, mIndexBuffer, 0, vertexCount)
  120. .material(0, mMaterialInstance)
  121. .build(mEngine, renderable);
  122. return renderable;
  123. }
  124. private Buffer readUncompressedAsset(AssetManager assetManager, String assetPath) { // 加载资源
  125. ByteBuffer dist = null;
  126. try {
  127. AssetFileDescriptor fd = assetManager.openFd(assetPath);
  128. try(FileInputStream fis = fd.createInputStream()) {
  129. dist = ByteBuffer.allocate((int) fd.getLength());
  130. try (ReadableByteChannel src = Channels.newChannel(fis)) {
  131. src.read(dist);
  132. }
  133. }
  134. } catch (IOException e) {
  135. e.printStackTrace();
  136. }
  137. if (dist != null) {
  138. return dist.rewind();
  139. }
  140. return null;
  141. }
  142. private ByteBuffer getByteBuffer(float[] values) { // float数组转换为ByteBuffer
  143. ByteBuffer byteBuffer = ByteBuffer.allocate(values.length * Float.BYTES);
  144. byteBuffer.order(ByteOrder.nativeOrder());
  145. for (int i = 0; i < values.length; i++) {
  146. byteBuffer.putFloat(values[i]);
  147. }
  148. byteBuffer.flip();
  149. return byteBuffer;
  150. }
  151. private ByteBuffer getByteBuffer(short[] values) { // short数组转换为ByteBuffer
  152. ByteBuffer byteBuffer = ByteBuffer.allocate(values.length * Short.BYTES);
  153. byteBuffer.order(ByteOrder.nativeOrder());
  154. for (int i = 0; i < values.length; i++) {
  155. byteBuffer.putShort(values[i]);
  156. }
  157. byteBuffer.flip();
  158. return byteBuffer;
  159. }
  160. private ByteBuffer getByteBuffer(Vertex[] values) { // Vertex数组转换为ByteBuffer
  161. ByteBuffer byteBuffer = ByteBuffer.allocate(values.length * Vertex.BYTES);
  162. byteBuffer.order(ByteOrder.nativeOrder());
  163. for (int i = 0; i < values.length; i++) {
  164. values[i].put(byteBuffer);
  165. }
  166. byteBuffer.flip();
  167. return byteBuffer;
  168. }
  169. /*
  170. * 顶点数据
  171. * 包含顶点位置和颜色
  172. */
  173. public static class Vertex {
  174. public static int BYTES = 16;
  175. public float x;
  176. public float y;
  177. public float z;
  178. public int color;
  179. public Vertex() {}
  180. public Vertex(float x, float y, float z, int color) {
  181. this.x = x;
  182. this.y = y;
  183. this.z = z;
  184. this.color = color;
  185. }
  186. public ByteBuffer put(ByteBuffer buffer) { // Vertex转换为ByteBuffer
  187. buffer.putFloat(x);
  188. buffer.putFloat(y);
  189. buffer.putFloat(z);
  190. buffer.putInt(color);
  191. return buffer;
  192. }
  193. }
  194. }

2.2 绘制纯色圆形(固定材质颜色)

? MainActivity.java

  1. package com.zhyan8.circle;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.os.Bundle;
  4. import com.zhyan8.circle.filament.FLSurfaceView;
  5. public class MainActivity extends AppCompatActivity {
  6. private FLSurfaceView mFLSurfaceView;
  7. @Override
  8. protected void onCreate(Bundle savedInstanceState) {
  9. super.onCreate(savedInstanceState);
  10. mFLSurfaceView = new MyFLSurfaceView(this);
  11. setContentView(mFLSurfaceView);
  12. mFLSurfaceView.init();
  13. mFLSurfaceView.setRenderMode(FLSurfaceView.RENDERMODE_CONTINUOUSLY);
  14. }
  15. @Override
  16. public void onResume() {
  17. super.onResume();
  18. mFLSurfaceView.onResume();
  19. }
  20. @Override
  21. public void onPause() {
  22. super.onPause();
  23. mFLSurfaceView.onPause();
  24. }
  25. @Override
  26. public void onDestroy() {
  27. super.onDestroy();
  28. mFLSurfaceView.onDestroy();
  29. }
  30. }

? MyFLSurfaceView.java

  1. package com.zhyan8.circle;
  2. import android.content.Context;
  3. import com.google.android.filament.Camera;
  4. import com.zhyan8.circle.filament.BaseModel;
  5. import com.zhyan8.circle.filament.FLSurfaceView;
  6. public class MyFLSurfaceView extends FLSurfaceView {
  7. private BaseModel mMyModel;
  8. public MyFLSurfaceView(Context context) {
  9. super(context);
  10. }
  11. public void init() {
  12. mSkyboxColor = new float[] {0.965f, 0.941f, 0.887f, 1};
  13. super.init();
  14. }
  15. @Override
  16. public void onDestroy() {
  17. mMyModel.destroy();
  18. super.onDestroy();
  19. }
  20. @Override
  21. protected void setupScene() { // 设置Scene参数
  22. mMyModel = new Circle1(getContext().getAssets(), mEngine);
  23. mScene.addEntity(mMyModel.getRenderable());
  24. }
  25. @Override
  26. protected void onResized(int width, int height) {
  27. double zoom = 1.5;
  28. double aspect = (double) width / (double) height;
  29. mCamera.setProjection(Camera.Projection.ORTHO,
  30. -aspect * zoom, aspect * zoom, -zoom, zoom, 0, 10);
  31. }
  32. }

? Circle1.java

  1. package com.zhyan8.circle;
  2. import android.content.res.AssetManager;
  3. import com.google.android.filament.Box;
  4. import com.google.android.filament.Engine;
  5. import com.google.android.filament.RenderableManager.PrimitiveType;
  6. import com.zhyan8.circle.filament.BaseModel;
  7. public class Circle1 extends BaseModel {
  8. private String materialPath = "materials/circle1.filamat";
  9. private float[] mVertices;
  10. private short[] mIndex;
  11. public Circle1(AssetManager assetManager, Engine engine) {
  12. super(assetManager, engine);
  13. init();
  14. }
  15. private void init() {
  16. int num = 50;
  17. mVertices = getCircle(0, 0, 0.5f, num);
  18. mIndex = getIndices(num);
  19. mBox = new Box(0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.01f);
  20. mMaterial = loadMaterial(materialPath);
  21. mVertexBuffer = getVertexBuffer(mVertices);
  22. mIndexBuffer = getIndexBuffer(mIndex);
  23. mRenderable = getRenderable(PrimitiveType.TRIANGLES, mIndex.length);
  24. }
  25. private float[] getCircle(float centerX, float centerY, float radius, int num) {
  26. float unit = (float) (2 * Math.PI / num);
  27. float[] coords = new float[(num + 1) * 3];
  28. int index = 0;
  29. for (int i = 0; i < num; i++) {
  30. coords[index++] = (float)(centerX + radius * Math.cos(unit * i));
  31. coords[index++] = (float)(centerY + radius * Math.sin(unit * i));
  32. coords[index++] = 0;
  33. }
  34. coords[index++] = centerX;
  35. coords[index++] = centerY;
  36. coords[index] = 0;
  37. return coords;
  38. }
  39. private short[] getIndices(int num) {
  40. short[] indices = new short[num * 3];
  41. short centerIndex = (short) num;
  42. short index = 0;
  43. for (short i = 0; i < num - 1; i++) {
  44. indices[index++] = centerIndex;
  45. indices[index++] = i;
  46. indices[index++] = (short)(i + 1);
  47. }
  48. indices[index++] = centerIndex;
  49. indices[index++] = (short) (num - 1);
  50. indices[index] = 0;
  51. return indices;
  52. }
  53. }

? circle1.mat

  1. material {
  2. name : circle,
  3. // 禁用所有lighting
  4. shadingModel : unlit,
  5. featureLevel : 0
  6. }
  7. fragment {
  8. vec3 sRGB_to_linear(vec3 color) { // gamma解码, 转换到线下空间
  9. color.x = pow(color.r, 2.2);
  10. color.y = pow(color.g, 2.2);
  11. color.z = pow(color.b, 2.2);
  12. return color;
  13. }
  14. void material(inout MaterialInputs material) {
  15. prepareMaterial(material); // 在方法返回前必须回调该函数
  16. vec3 color = vec3(0.455, 0.725, 1.0);
  17. color = sRGB_to_linear(color);
  18. material.baseColor = vec4(color, 1.0);
  19. }
  20. }

? 说明:这里需要进行伽马解码处理,将颜色空间转换到线性空间中,否则显示的颜色将会偏亮,伽马编码原理详见 → 【Unity3D】伽马校正

? transform.bat

  1. @echo off
  2. setlocal enabledelayedexpansion
  3. set "srcFolder=../src/main/materials"
  4. set "distFolder=../src/main/assets/materials"
  5. for %%f in ("%srcFolder%\*.mat") do (
  6. set "matfile=%%~nf"
  7. matc -p mobile -a opengl -o "!matfile!.filamat" "%%f"
  8. move "!matfile!.filamat" "%distFolder%\!matfile!.filamat"
  9. )
  10. echo Processing complete.
  11. pause

? 说明:需要将 matc.exe 文件与 transform.bat 文件放在同一个目录下面,matc.exe 源自Filament环境搭建中编译生成的 exe 文件。双击 transform.bat 文件,会自动将 /src/main/materials/ 下面的所有 mat 文件全部转换为 filamat 文件,并移到 /src/main/assets/materials/ 目录下面。

? 运行效果如下。

img

2.3 绘制纯色圆形(传递材质颜色)

? MyFLSurfaceView.java

  1. package com.zhyan8.circle;
  2. import android.content.Context;
  3. import com.google.android.filament.Camera;
  4. import com.zhyan8.circle.filament.BaseModel;
  5. import com.zhyan8.circle.filament.FLSurfaceView;
  6. public class MyFLSurfaceView extends FLSurfaceView {
  7. private BaseModel mMyModel;
  8. public MyFLSurfaceView(Context context) {
  9. super(context);
  10. }
  11. public void init() {
  12. mSkyboxColor = new float[] {0.965f, 0.941f, 0.887f, 1};
  13. super.init();
  14. }
  15. @Override
  16. public void onDestroy() {
  17. mMyModel.destroy();
  18. super.onDestroy();
  19. }
  20. @Override
  21. protected void setupScene() { // 设置Scene参数
  22. mMyModel = new Circle2(getContext().getAssets(), mEngine);
  23. mScene.addEntity(mMyModel.getRenderable());
  24. }
  25. @Override
  26. protected void onResized(int width, int height) {
  27. double zoom = 1.5;
  28. double aspect = (double) width / (double) height;
  29. mCamera.setProjection(Camera.Projection.ORTHO,
  30. -aspect * zoom, aspect * zoom, -zoom, zoom, 0, 10);
  31. }
  32. }

? Circle2.java

  1. package com.zhyan8.circle;
  2. import android.content.res.AssetManager;
  3. import com.google.android.filament.Box;
  4. import com.google.android.filament.Colors;
  5. import com.google.android.filament.Engine;
  6. import com.google.android.filament.RenderableManager.PrimitiveType;
  7. import com.zhyan8.circle.filament.BaseModel;
  8. public class Circle2 extends BaseModel {
  9. private String materialPath = "materials/circle2.filamat";
  10. private float[] mVertices;
  11. private short[] mIndex;
  12. public Circle2(AssetManager assetManager, Engine engine) {
  13. super(assetManager, engine);
  14. init();
  15. }
  16. private void init() {
  17. int num = 50;
  18. mVertices = getCircle(0, 0, 0.5f, num);
  19. mIndex = getIndices(num);
  20. mBox = new Box(0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.01f);
  21. mMaterial = loadMaterial(materialPath);
  22. mMaterialInstance.setParameter("baseColor", Colors.RgbType.SRGB, 0.455f, 0.725f, 1.0f);
  23. mVertexBuffer = getVertexBuffer(mVertices);
  24. mIndexBuffer = getIndexBuffer(mIndex);
  25. mRenderable = getRenderable(PrimitiveType.TRIANGLES, mIndex.length);
  26. }
  27. private float[] getCircle(float centerX, float centerY, float radius, int num) {
  28. float unit = (float) (2 * Math.PI / num);
  29. float[] coords = new float[(num + 1) * 3];
  30. int index = 0;
  31. for (int i = 0; i < num; i++) {
  32. coords[index++] = (float)(centerX + radius * Math.cos(unit * i));
  33. coords[index++] = (float)(centerY + radius * Math.sin(unit * i));
  34. coords[index++] = 0;
  35. }
  36. coords[index++] = centerX;
  37. coords[index++] = centerY;
  38. coords[index] = 0;
  39. return coords;
  40. }
  41. private short[] getIndices(int num) {
  42. short[] indices = new short[num * 3];
  43. short centerIndex = (short) num;
  44. short index = 0;
  45. for (short i = 0; i < num - 1; i++) {
  46. indices[index++] = centerIndex;
  47. indices[index++] = i;
  48. indices[index++] = (short)(i + 1);
  49. }
  50. indices[index++] = centerIndex;
  51. indices[index++] = (short) (num - 1);
  52. indices[index] = 0;
  53. return indices;
  54. }
  55. }

? circle2.mat

  1. material {
  2. name : circle,
  3. // 禁用所有lighting
  4. shadingModel : unlit,
  5. featureLevel : 0,
  6. parameters : [
  7. { // 颜色必须在线性空间中传递, 而不是sRGB空间
  8. type : float3,
  9. name : baseColor
  10. }
  11. ]
  12. }
  13. fragment {
  14. void material(inout MaterialInputs material) {
  15. prepareMaterial(material); // 在方法返回前必须回调该函数
  16. material.baseColor.rgb = materialParams.baseColor;
  17. }
  18. }

? 运行效果如下,可以看到,与 2.2 节中进行伽马校正后的颜色是一样的。

img

? 声明:本文转自【Filament】绘制圆形

原文链接:https://www.cnblogs.com/zhyan8/p/18024345

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号