当前位置: 首页 > news >正文

京东导购网站开发平台网站建设网站

京东导购网站开发,平台网站建设网站,学网站开发有用么,网络建设公司起名1 前言 3D 模型的常用格式主要有 obj、fbx、gltf 等#xff0c;Filament 中的 filamesh.exe 工具可以将 obj、fbx 格式转换为 filamesh 格式#xff0c;然后再加载显示。对于 gltf 格式模型#xff0c;可以通过 ModelViewer 加载显示#xff0c;这不在本文的讨论范围内。 1…1 前言 3D 模型的常用格式主要有 obj、fbx、gltf 等Filament 中的 filamesh.exe 工具可以将 obj、fbx 格式转换为 filamesh 格式然后再加载显示。对于 gltf 格式模型可以通过 ModelViewer 加载显示这不在本文的讨论范围内。 1filamesh 简介 filamesh 工具的官方介绍如下。 filamesh is a tool to convert meshes into an optimized binary formatCaution! filamesh was designed to operate on trusted inputs. To minimize the risk of triggering memory corruption vulnerabilities, please make sure that the files passed to filamesh come from a trusted source, or run filamesh in a sandboxed environment.Usage:filamesh [options] source mesh destination fileSupported mesh formats:FBX, OBJInput meshes must have texture coordinates.Options:--help, -hprint this message--licensePrint copyright and license information--interleaved, -iinterleaves mesh attributes--compress, -cenable compression--ignore-uv1, -gIgnore the second set of UV coordinates 注意原始 obj、fbx 模型一定要包含纹理坐标否在会转换失败。 以下是一个简单的 filamesh 工具的使用案例。 filamesh cube.obj cube.filamesh 2obj 模型 obj 模型主要由 v顶点坐标、vt纹理坐标、vn法线向量、f三角面或四角面的顶点索引序列组成如下是一个三角形的 obj 文件。 # 三角形模型# 顶点位置 v 1.0 1.0 -1.0 # V1 v 1.0 -1.0 -1.0 # V2 v 1.0 1.0 1.0 # V3# 纹理坐标 vt 0.0 0.0 # VT1 vt 1.0 0.0 # VT2 vt 1.0 1.0 # VT3 vt 0.0 1.0 # VT4# 法线 vn 0.0 1.0 0.0 # VN1# 面v/vt/vn f 1/1/1 2/2/1 3/3/1 对于非设计类人员也可以使用记事本按照以上格式编辑一些简单的模型然后再拖拽到 Unity或 Blender、Maya、3DMax 等软件中进行预览。 3推荐阅读 读者如果对 Filament 不太熟悉请回顾以下内容。 Filament环境搭建绘制三角形绘制矩形绘制圆形绘制立方体纹理贴图立方体贴图6张图 2 立方体贴图 本文项目结构如下完整代码资源 → Filament加载obj和fbx模型。 2.1 基础类 为方便读者将注意力聚焦在 Filament 的输入上轻松配置复杂的环境依赖逻辑笔者仿照 OpenGL ES 的写法抽出了 FLSurfaceView、BaseModel、Mesh、MaterialUtils 和 MeshUtils 类。FLSurfaceView 与 GLSurfaceView 的功能类似承载了渲染环境配置BaseModel 用于管理模型的网格和材质Mesh 用于管理模型的顶点属性MaterialUtils 和 MeshUtils 中分别提供了一些材质和网格相关的工具。 build.gradle ... android {...aaptOptions { // 在应用程序打包过程中不压缩的文件noCompress filamat, ktx} }dependencies {implementation fileTree(dir: ../libs, include: [*.aar])... } 说明在项目根目录下的 libs 目录中需要放入以下 aar 文件它们源自Filament环境搭建中编译生成的 aar。 FLSurfaceView.java package com.zhyan8.loadmodel.filament.base;import android.content.Context; import android.graphics.Point; import android.view.Choreographer; import android.view.Surface; import android.view.SurfaceView;import com.google.android.filament.Camera; import com.google.android.filament.Engine; import com.google.android.filament.EntityManager; import com.google.android.filament.Filament; import com.google.android.filament.Renderer; import com.google.android.filament.Scene; import com.google.android.filament.Skybox; import com.google.android.filament.SwapChain; import com.google.android.filament.View; import com.google.android.filament.Viewport; import com.google.android.filament.android.DisplayHelper; import com.google.android.filament.android.FilamentHelper; import com.google.android.filament.android.UiHelper;import java.util.ArrayList;/*** Filament中待渲染的SurfaceView* 功能可以类比OpenGL ES中的GLSurfaceView* 用于创建Filament的渲染环境*/ public class FLSurfaceView extends SurfaceView {public static int RENDERMODE_WHEN_DIRTY 0; // 用户请求渲染才渲染一帧public static int RENDERMODE_CONTINUOUSLY 1; // 持续渲染protected int mRenderMode RENDERMODE_CONTINUOUSLY; // 渲染模式protected Choreographer mChoreographer; // 消息控制protected DisplayHelper mDisplayHelper; // 管理Display(可以监听分辨率或刷新率的变化)protected UiHelper mUiHelper; // 管理SurfaceView、TextureView、SurfaceHolderprotected Engine mEngine; // 引擎(跟踪用户创建的资源, 管理渲染线程和硬件渲染器)protected Renderer mRenderer; // 渲染器(用于操作系统窗口, 生成绘制命令, 管理帧延时)protected Scene mScene; // 场景(管理渲染对象、灯光)protected View mView; // 存储渲染数据(View是Renderer操作的对象)protected Camera mCamera; // 相机(视角管理)protected Point mDesiredSize; // 渲染分辨率protected float[] mSkyboxColor; // 背景颜色protected SwapChain mSwapChain; // 操作系统的本地可渲染表面(native renderable surface, 通常是一个window或view)protected FrameCallback mFrameCallback new FrameCallback(); // 帧回调protected ArrayListRenderCallback mRenderCallbacks; // 每一帧渲染前的回调(一般用于处理模型变换、相机变换等)static {Filament.init();}public FLSurfaceView(Context context) {super(context);mChoreographer Choreographer.getInstance();mDisplayHelper new DisplayHelper(context);mRenderCallbacks new ArrayList();}public void init() { // 初始化setupSurfaceView();setupFilament();setupView();setupScene();}public void setRenderMode(int renderMode) { // 设置渲染模式mRenderMode renderMode;}public void addRenderCallback(RenderCallback renderCallback) { // 添加渲染回调if (renderCallback ! null) {mRenderCallbacks.add(renderCallback);}}public void requestRender() { // 请求渲染mChoreographer.postFrameCallback(mFrameCallback);}public void onResume() { // 恢复mChoreographer.postFrameCallback(mFrameCallback);}public void onPause() { // 暂停mChoreographer.removeFrameCallback(mFrameCallback);}public void onDestroy() { // 销毁Filament环境mChoreographer.removeFrameCallback(mFrameCallback);mRenderCallbacks.clear();mUiHelper.detach();mEngine.destroyRenderer(mRenderer);mEngine.destroyView(mView);mEngine.destroyScene(mScene);mEngine.destroyCameraComponent(mCamera.getEntity());EntityManager entityManager EntityManager.get();entityManager.destroy(mCamera.getEntity());mEngine.destroy();}protected void setupScene() { // 设置Scene参数}protected void onResized(int width, int height) { // Surface尺寸变化时回调double zoom 1;double aspect (double) width / (double) height;mCamera.setProjection(Camera.Projection.ORTHO,-aspect * zoom, aspect * zoom, -zoom, zoom, 0, 1000);}private void setupSurfaceView() { // 设置SurfaceViewmUiHelper new UiHelper(UiHelper.ContextErrorPolicy.DONT_CHECK);mUiHelper.setRenderCallback(new SurfaceCallback());if (mDesiredSize ! null) {mUiHelper.setDesiredSize(mDesiredSize.x, mDesiredSize.y);}mUiHelper.attachTo(this);}private void setupFilament() { // 设置Filament参数mEngine Engine.create();// mEngine (new Engine.Builder()).featureLevel(Engine.FeatureLevel.FEATURE_LEVEL_0).build();mRenderer mEngine.createRenderer();mScene mEngine.createScene();mView mEngine.createView();mCamera mEngine.createCamera(mEngine.getEntityManager().create());}private void setupView() { // 设置View参数float[] color mSkyboxColor ! null ? mSkyboxColor : new float[] {0, 0, 0, 1};Skybox skybox (new Skybox.Builder()).color(color).build(mEngine);mScene.setSkybox(skybox);if (mEngine.getActiveFeatureLevel() Engine.FeatureLevel.FEATURE_LEVEL_0) {mView.setPostProcessingEnabled(false); // FEATURE_LEVEL_0不支持post-processing}mView.setCamera(mCamera);mView.setScene(mScene);View.DynamicResolutionOptions options new View.DynamicResolutionOptions();options.enabled true;mView.setDynamicResolutionOptions(options);}/*** 帧回调*/private class FrameCallback implements Choreographer.FrameCallback {Overridepublic void doFrame(long frameTimeNanos) { // 渲染每帧数据if (mRenderMode RENDERMODE_CONTINUOUSLY) {mChoreographer.postFrameCallback(this); // 请求下一帧}mRenderCallbacks.forEach(callback - callback.onCall());if (mUiHelper.isReadyToRender()) {if (mRenderer.beginFrame(mSwapChain, frameTimeNanos)) {mRenderer.render(mView);mRenderer.endFrame();}}}}/*** Surface回调*/private class SurfaceCallback implements UiHelper.RendererCallback {Overridepublic void onNativeWindowChanged(Surface surface) { // Native窗口改变时回调if (mSwapChain ! null) {mEngine.destroySwapChain(mSwapChain);}long flags mUiHelper.getSwapChainFlags();if (mEngine.getActiveFeatureLevel() Engine.FeatureLevel.FEATURE_LEVEL_0) {if (SwapChain.isSRGBSwapChainSupported(mEngine)) {flags flags | SwapChain.CONFIG_SRGB_COLORSPACE;}}mSwapChain mEngine.createSwapChain(surface, flags);mDisplayHelper.attach(mRenderer, getDisplay());}Overridepublic void onDetachedFromSurface() { // 解绑Surface时回调mDisplayHelper.detach();if (mSwapChain ! null) {mEngine.destroySwapChain(mSwapChain);mEngine.flushAndWait();mSwapChain null;}}Overridepublic void onResized(int width, int height) { // Surface尺寸变化时回调mView.setViewport(new Viewport(0, 0, width, height));FilamentHelper.synchronizePendingFrames(mEngine);FLSurfaceView.this.onResized(width, height);}}/*** 每一帧渲染前的回调* 一般用于处理模型变换、相机变换等*/public interface RenderCallback {void onCall();} } BaseModel.java package com.zhyan8.loadmodel.filament.base;import android.content.Context;import com.google.android.filament.Engine; import com.google.android.filament.EntityManager; import com.google.android.filament.Material; import com.google.android.filament.MaterialInstance; import com.google.android.filament.RenderableManager; import com.google.android.filament.RenderableManager.PrimitiveType; import com.google.android.filament.Texture; import com.google.android.filament.TransformManager; import com.zhyan8.loadmodel.filament.utils.MaterialUtils; import com.zhyan8.loadmodel.filament.base.Mesh.Part;import java.util.HashMap; import java.util.List; import java.util.Map;/*** 模型基类* 管理模型的网格、材质、渲染id*/ public class BaseModel {private static String TAG BaseModel;protected Context mContext; // 上下文protected Engine mEngine; // Filament引擎protected TransformManager mTransformManager; // 模型变换管理器protected Mesh mMesh; // 模型网格protected Material[] mMaterials; // 模型材质protected MaterialInstance[] mMaterialInstances; // 模型材质实例protected MapString, MaterialInstance mMaterialMap new HashMap(); // 材质名-材质protected Texture[] mTextures; // 纹理protected int mRenderable; // 渲染idprotected int mTransformComponent; // 模型变换组件的idprotected FLSurfaceView.RenderCallback mRenderCallback; // 每一帧渲染前的回调(一般用于处理模型变换、相机变换等)public BaseModel(Context context, Engine engine) {mContext context;mEngine engine;mTransformManager mEngine.getTransformManager();}public int getRenderable() { // 获取渲染idreturn mRenderable;}public FLSurfaceView.RenderCallback getRenderCallback() { // 获取渲染回调return mRenderCallback;}public void destroy() { // 销毁模型mMaterialMap.clear();mEngine.destroyEntity(mRenderable);if (mMesh ! null) {mMesh.destroy();}if (mTextures ! null) {for (int i 0; i mTextures.length; i) {mEngine.destroyTexture(mTextures[i]);}}if (mMaterialInstances ! null) {for (int i 0; i mMaterialInstances.length; i) {mEngine.destroyMaterialInstance(mMaterialInstances[i]);}}if (mMaterials ! null) {for (int i 0; i mMaterials.length; i) {mEngine.destroyMaterial(mMaterials[i]);}}EntityManager entityManager EntityManager.get();entityManager.destroy(mRenderable);}protected int getRenderable(PrimitiveType primitiveType) { // 获取渲染idint renderable EntityManager.get().create();ListPart parts mMesh.getParts();ListString materialNames mMesh.getMaterialNames();RenderableManager.Builder builder new RenderableManager.Builder(parts.size()).boundingBox(mMesh.getBox());for (int i 0; i parts.size(); i) {Part part parts.get(i);builder.geometry(i, primitiveType, mMesh.getVertexBuffer(), mMesh.getIndexBuffer(),part.offset, part.minIndex, part.maxIndex, part.indexCount);MaterialInstance material getMaterialInstance(materialNames, part.materialID);builder.material(i, material);}builder.build(mEngine, renderable);return renderable;}protected Material[] loadMaterials(String materialPath) { // 加载材质Material material MaterialUtils.loadMaterial(mContext, mEngine, materialPath);if (material ! null) {return new Material[] {material};}return null;}protected Material[] loadMaterials(String[] materialPaths) { // 加载材质Material[] materials new Material[materialPaths.length];for (int i 0; i materials.length; i) {materials[i] MaterialUtils.loadMaterial(mContext, mEngine, materialPaths[i]);}return materials;}protected MaterialInstance[] getMaterialInstance(Material[] materials) { // 获取材质实例MaterialInstance[] materialInstances new MaterialInstance[materials.length];for (int i 0; i materials.length; i) {materialInstances[i] materials[i].createInstance();}return materialInstances;}protected MaterialInstance[] getMaterialInstance(Material material, int count) { // 获取材质实例MaterialInstance[] materialInstances new MaterialInstance[count];for (int i 0; i count; i) {materialInstances[i] material.createInstance();}return materialInstances;}private MaterialInstance getMaterialInstance(ListString materialNames, int materialID) { // 获取材质MaterialInstance material null;if (materialNames ! null materialNames.size() materialID materialID 0) {String name materialNames.get(materialID);if (mMaterialMap.containsKey(name)) {material mMaterialMap.get(name);}}if (material null mMaterialMap.containsKey(DefaultMaterial)) {material mMaterialMap.get(DefaultMaterial);}return material;} } Mesh.java package com.zhyan8.loadmodel.filament.base;import com.google.android.filament.Box; import com.google.android.filament.Engine; import com.google.android.filament.IndexBuffer; import com.google.android.filament.VertexBuffer; import com.google.android.filament.VertexBuffer.AttributeType; import com.google.android.filament.VertexBuffer.VertexAttribute;import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.List;/*** 网格* 用于管理模型的顶点属性和顶点索引*/ public class Mesh {private Engine mEngine; // Filament引擎private VertexBuffer mVertexBuffer; // 顶点属性缓存private IndexBuffer mIndexBuffer; // 顶点索引缓存private ListPart mParts; // 子网格信息private Box mBox; // 渲染区域private ListString mMaterialNames; // 材质名public Mesh(Engine engine) {mEngine engine;}public Mesh(Engine engine, float[] vertices, short[] indices, ListPart parts, Box box, ListString materialNames) {mEngine engine;setVertices(vertices);setIndices(indices);setParts(parts, indices.length);setBox(box);mMaterialNames materialNames;}public Mesh(Engine engine, VertexBuffer vrtexBuffer, IndexBuffer indexBuffer, ListPart parts, Box box, ListString materialNames) {mEngine engine;mVertexBuffer vrtexBuffer;mIndexBuffer indexBuffer;mParts parts;setBox(box);mMaterialNames materialNames;}public Mesh(Engine engine, VertexPosCol[] vertices, short[] indices, ListPart parts, Box box, ListString materialNames) {mEngine engine;setVertices(vertices);setIndices(indices);setParts(parts, indices.length);setBox(box);mMaterialNames materialNames;}public Mesh(Engine engine, VertexPosUV[] vertices, short[] indices, ListPart parts, Box box, ListString materialNames) {mEngine engine;setVertices(vertices);setIndices(indices);setParts(parts, indices.length);setBox(box);mMaterialNames materialNames;}public void setVertices(float[] vertices) { // 设置顶点属性mVertexBuffer getVertexBuffer(vertices);}public void setVertices(VertexPosCol[] vertices) { // 设置顶点属性mVertexBuffer getVertexBuffer(vertices);}public void setVertices(VertexPosUV[] vertices) { // 设置顶点属性mVertexBuffer getVertexBuffer(vertices);}public void setIndices(short[] indices) { // 设置顶点索引mIndexBuffer getIndexBuffer(indices);}public void setParts(ListPart parts, int count) { // 设置顶点索引if (parts null || parts.size() 0) {mParts new ArrayList();mParts.add(new Part(0, count, 0, count - 1));} else {mParts parts;}}public void setBox(Box box) { // 渲染区域if (box null) {mBox new Box(0, 0, 0, 1, 1, 1);} else {mBox box;}}public VertexBuffer getVertexBuffer() { // 获取顶点属性缓存return mVertexBuffer;}public IndexBuffer getIndexBuffer() { // 获取顶点索引缓存return mIndexBuffer;}public ListPart getParts() { // 获取顶点索引缓存return mParts;}public Box getBox() {return mBox;}public ListString getMaterialNames() {return mMaterialNames;}public void destroy() {mEngine.destroyVertexBuffer(mVertexBuffer);mEngine.destroyIndexBuffer(mIndexBuffer);if (mParts ! null) {mParts.clear();}if (mMaterialNames ! null) {mMaterialNames.clear();}}private VertexBuffer getVertexBuffer(float[] values) { // 获取顶点属性缓存ByteBuffer vertexData getByteBuffer(values);int vertexCount values.length / 3;int vertexSize Float.BYTES * 3;VertexBuffer vertexBuffer new VertexBuffer.Builder().bufferCount(1).vertexCount(vertexCount).attribute(VertexAttribute.POSITION, 0, AttributeType.FLOAT3, 0, vertexSize).build(mEngine);vertexBuffer.setBufferAt(mEngine, 0, vertexData);return vertexBuffer;}private VertexBuffer getVertexBuffer(VertexPosCol[] values) { // 获取顶点属性缓存ByteBuffer vertexData getByteBuffer(values);int vertexCount values.length;int vertexSize VertexPosCol.BYTES;VertexBuffer vertexBuffer new VertexBuffer.Builder().bufferCount(1).vertexCount(vertexCount).attribute(VertexAttribute.POSITION, 0, AttributeType.FLOAT3, 0, vertexSize).attribute(VertexAttribute.COLOR, 0, AttributeType.UBYTE4, 3 * Float.BYTES, vertexSize).normalized(VertexAttribute.COLOR).build(mEngine);vertexBuffer.setBufferAt(mEngine, 0, vertexData);return vertexBuffer;}private VertexBuffer getVertexBuffer(VertexPosUV[] values) { // 获取顶点属性缓存ByteBuffer vertexData getByteBuffer(values);int vertexCount values.length;int vertexSize VertexPosUV.BYTES;VertexBuffer vertexBuffer new VertexBuffer.Builder().bufferCount(1).vertexCount(vertexCount).attribute(VertexAttribute.POSITION, 0, AttributeType.FLOAT3, 0, vertexSize).attribute(VertexAttribute.UV0, 0, AttributeType.FLOAT2, 3 * Float.BYTES, vertexSize).build(mEngine);vertexBuffer.setBufferAt(mEngine, 0, vertexData);return vertexBuffer;}private IndexBuffer getIndexBuffer(short[] values) { // 获取顶点索引缓存ByteBuffer indexData getByteBuffer(values);int indexCount values.length;IndexBuffer indexBuffer new IndexBuffer.Builder().indexCount(indexCount).bufferType(IndexBuffer.Builder.IndexType.USHORT).build(mEngine);indexBuffer.setBuffer(mEngine, indexData);return indexBuffer;}private ByteBuffer getByteBuffer(float[] values) { // float数组转换为ByteBufferByteBuffer byteBuffer ByteBuffer.allocate(values.length * Float.BYTES);byteBuffer.order(ByteOrder.nativeOrder());for (int i 0; i values.length; i) {byteBuffer.putFloat(values[i]);}byteBuffer.flip();return byteBuffer;}private ByteBuffer getByteBuffer(short[] values) { // short数组转换为ByteBufferByteBuffer byteBuffer ByteBuffer.allocate(values.length * Short.BYTES);byteBuffer.order(ByteOrder.nativeOrder());for (int i 0; i values.length; i) {byteBuffer.putShort(values[i]);}byteBuffer.flip();return byteBuffer;}private ByteBuffer getByteBuffer(VertexPosCol[] values) { // VertexPosCol数组转换为ByteBufferByteBuffer byteBuffer ByteBuffer.allocate(values.length * VertexPosCol.BYTES);byteBuffer.order(ByteOrder.nativeOrder());for (int i 0; i values.length; i) {values[i].put(byteBuffer);}byteBuffer.flip();return byteBuffer;}private ByteBuffer getByteBuffer(VertexPosUV[] values) { // VertexPosUV数组转换为ByteBufferByteBuffer byteBuffer ByteBuffer.allocate(values.length * VertexPosUV.BYTES);byteBuffer.order(ByteOrder.nativeOrder());for (int i 0; i values.length; i) {values[i].put(byteBuffer);}byteBuffer.flip();return byteBuffer;}/*** 子网格信息*/public static class Part {public int offset 0;public int indexCount 0;public int minIndex 0;public int maxIndex 0;public int materialID -1;public Box aabb new Box();public Part() {}public Part(int offset, int indexCount, int minIndex, int maxIndex) {this.offset offset;this.indexCount indexCount;this.minIndex minIndex;this.maxIndex maxIndex;}public Part(int offset, int indexCount, int minIndex, int maxIndex, int materialID, Box aabb) {this.offset offset;this.indexCount indexCount;this.minIndex minIndex;this.maxIndex maxIndex;this.materialID materialID;this.aabb aabb;}}/*** 顶点数据(位置颜色)* 包含顶点位置和颜色*/public static class VertexPosCol {public static int BYTES 16;public float x;public float y;public float z;public int color;public VertexPosCol() {}public VertexPosCol(float x, float y, float z, int color) {this.x x;this.y y;this.z z;this.color color;}public ByteBuffer put(ByteBuffer buffer) { // VertexPosCol转换为ByteBufferbuffer.putFloat(x);buffer.putFloat(y);buffer.putFloat(z);buffer.putInt(color);return buffer;}}/*** 顶点数据(位置纹理坐标)* 包含顶点位置和纹理坐标*/public static class VertexPosUV {public static int BYTES 20;public float x;public float y;public float z;public float u;public float v;public VertexPosUV() {}public VertexPosUV(float x, float y, float z, float u, float v) {this.x x;this.y y;this.z z;this.u u;this.v v;}public ByteBuffer put(ByteBuffer buffer) { // VertexPosUV转换为ByteBufferbuffer.putFloat(x);buffer.putFloat(y);buffer.putFloat(z);buffer.putFloat(u);buffer.putFloat(v);return buffer;}} } MaterialUtils.java package com.zhyan8.loadmodel.filament.utils;import android.content.Context; import android.content.res.AssetFileDescriptor; import android.os.Handler; import android.os.Looper; import android.util.Log;import com.google.android.filament.Engine; import com.google.android.filament.Material;import java.io.FileInputStream; import java.io.IOException; import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel;/*** 材质工具类*/ public class MaterialUtils {private static String TAG MaterialUtils;public static Material loadMaterial(Context context, Engine engine, String materialPath) { // 加载材质Buffer buffer readUncompressedAsset(context, materialPath);if (buffer ! null) {Material material (new Material.Builder()).payload(buffer, buffer.remaining()).build(engine);material.compile(Material.CompilerPriorityQueue.HIGH,Material.UserVariantFilterBit.ALL,new Handler(Looper.getMainLooper()),() - Log.i(TAG, Material material.getName() compiled.));engine.flush();return material;}return null;}private static Buffer readUncompressedAsset(Context context, String assetPath) { // 加载资源ByteBuffer dist null;try {AssetFileDescriptor fd context.getAssets().openFd(assetPath);try(FileInputStream fis fd.createInputStream()) {dist ByteBuffer.allocate((int) fd.getLength());try (ReadableByteChannel src Channels.newChannel(fis)) {src.read(dist);}}} catch (IOException e) {e.printStackTrace();}if (dist ! null) {return dist.rewind();}return null;} } MeshUtils.java package com.zhyan8.loadmodel.filament.utils;import android.content.Context; import android.util.Log;import com.google.android.filament.Box; import com.google.android.filament.Engine; import com.google.android.filament.IndexBuffer; import com.google.android.filament.VertexBuffer; import com.google.android.filament.VertexBuffer.AttributeType; import com.zhyan8.loadmodel.filament.base.Mesh; import com.zhyan8.loadmodel.filament.base.Mesh.Part;import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List;/*** 材质工具类*/ public class MeshUtils {private static final String FILAMESH_FILE_IDENTIFIER FILAMESH;private static final long HEADER_FLAG_SNORM16_UV 0x2L;private static final long MAX_UINT32 4294967295L;public static Mesh loadMesh(Context context, Engine engine, String meshPath) {try (InputStream inputStream context.getAssets().open(meshPath)) {Header header readHeader(inputStream);ReadableByteChannel channel Channels.newChannel(inputStream);ByteBuffer vertexBufferData readSizedData(channel, header.verticesSizeInBytes);ByteBuffer indexBufferData readSizedData(channel, header.indicesSizeInBytes);ListPart parts readParts(header, inputStream);ListString materialNames readMaterials(inputStream);VertexBuffer vertexBuffer createVertexBuffer(engine, header, vertexBufferData);IndexBuffer indexBuffer createIndexBuffer(engine, header, indexBufferData);return new Mesh(engine, vertexBuffer, indexBuffer, parts, header.aabb, materialNames);} catch (IOException e) {e.printStackTrace();}return null;}private static Header readHeader(InputStream input) { // 读取文件头信息Header header new Header();if (!readMagicNumber(input)) {Log.e(Filament, Invalid filamesh file.);return header;}header.versionNumber readUIntLE(input);header.parts readUIntLE(input);header.aabb new Box(readFloat32LE(input), readFloat32LE(input), readFloat32LE(input),readFloat32LE(input), readFloat32LE(input), readFloat32LE(input));header.flags readUIntLE(input);header.posOffset readUIntLE(input);header.positionStride readUIntLE(input);header.tangentOffset readUIntLE(input);header.tangentStride readUIntLE(input);header.colorOffset readUIntLE(input);header.colorStride readUIntLE(input);header.uv0Offset readUIntLE(input);header.uv0Stride readUIntLE(input);header.uv1Offset readUIntLE(input);header.uv1Stride readUIntLE(input);header.totalVertices readUIntLE(input);header.verticesSizeInBytes readUIntLE(input);header.indices16Bit readUIntLE(input);header.totalIndices readUIntLE(input);header.indicesSizeInBytes readUIntLE(input);header.valid true;return header;}private static ByteBuffer readSizedData(ReadableByteChannel channel, int sizeInBytes) { // 读取模型顶点数据ByteBuffer buffer ByteBuffer.allocateDirect(sizeInBytes);buffer.order(ByteOrder.LITTLE_ENDIAN);try {channel.read(buffer);} catch (IOException e) {e.printStackTrace();}buffer.flip();return buffer;}private static ListPart readParts(Header header, InputStream input) { // 读取子网格属性ListPart parts new ArrayList(header.parts);for (int i 0; i header.parts; i) {Part p new Part();p.offset readUIntLE(input);p.indexCount readUIntLE(input);p.minIndex readUIntLE(input);p.maxIndex readUIntLE(input);p.materialID readUIntLE(input);float minX readFloat32LE(input);float minY readFloat32LE(input);float minZ readFloat32LE(input);float maxX readFloat32LE(input);float maxY readFloat32LE(input);float maxZ readFloat32LE(input);p.aabb new Box(minX, minY, minZ, maxX, maxY, maxZ);parts.add(p);}return parts;}private static boolean readMagicNumber(InputStream input) { // 读取魔法数字, 用于判断是否是有效的filamesh文件byte[] temp new byte[FILAMESH_FILE_IDENTIFIER.length()];int bytesRead 0;try {bytesRead input.read(temp);} catch (IOException e) {throw new RuntimeException(e);}if (bytesRead ! FILAMESH_FILE_IDENTIFIER.length()) {return false;}String tempS new String(temp, Charset.forName(UTF-8));return tempS.equals(FILAMESH_FILE_IDENTIFIER);}private static ListString readMaterials(InputStream input) { // 读取材质int numMaterials readUIntLE(input);ListString materials new ArrayList(numMaterials);for (int i 0; i numMaterials; i) {int dataLength readUIntLE(input);byte[] data new byte[dataLength];try {input.read(data);} catch (IOException e) {e.printStackTrace();}try {input.skip(1);} catch (IOException e) {e.printStackTrace();}materials.add(new String(data, Charset.forName(UTF-8)));}return materials;}private static IndexBuffer createIndexBuffer(Engine engine, Header header, ByteBuffer data) { // 创建顶点索引缓冲IndexBuffer.Builder.IndexType indexType (header.indices16Bit ! 0) ?IndexBuffer.Builder.IndexType.USHORT : IndexBuffer.Builder.IndexType.UINT;IndexBuffer buffer new IndexBuffer.Builder().bufferType(indexType).indexCount(header.totalIndices).build(engine);buffer.setBuffer(engine, data);return buffer;}private static VertexBuffer createVertexBuffer(Engine engine, Header header, ByteBuffer data) { // 创建顶点属性缓冲AttributeType uvType uvType(header);VertexBuffer.Builder vertexBufferBuilder new VertexBuffer.Builder().bufferCount(1).vertexCount(header.totalVertices).normalized(VertexBuffer.VertexAttribute.COLOR).normalized(VertexBuffer.VertexAttribute.TANGENTS).attribute(VertexBuffer.VertexAttribute.POSITION, 0, VertexBuffer.AttributeType.HALF4, header.posOffset, header.positionStride).attribute(VertexBuffer.VertexAttribute.TANGENTS, 0, AttributeType.SHORT4, header.tangentOffset, header.tangentStride).attribute(VertexBuffer.VertexAttribute.COLOR, 0, AttributeType.UBYTE4, header.colorOffset, header.colorStride).attribute(VertexBuffer.VertexAttribute.UV0, 0, uvType, header.uv0Offset, header.uv0Stride);if (header.uv1Offset ! MAX_UINT32 header.uv1Stride ! MAX_UINT32) {vertexBufferBuilder.attribute(VertexBuffer.VertexAttribute.UV1, 0, uvType, header.uv1Offset, header.uv1Stride).normalized(VertexBuffer.VertexAttribute.UV1, true);}VertexBuffer buffer vertexBufferBuilder.build(engine);buffer.setBufferAt(engine, 0, data);return buffer;}private static AttributeType uvType(Header header) { // UV坐标的精度类型if ((header.flags HEADER_FLAG_SNORM16_UV) ! 0L) {return AttributeType.SHORT2;}return AttributeType.HALF2;}private static int readIntLE(InputStream input) { // 获取输入流中Little Endian格式的整数try {return (input.read() 0xff) |((input.read() 0xff) 8) |((input.read() 0xff) 16) |((input.read() 0xff) 24);} catch (IOException e) {e.printStackTrace();}return 0;}private static int readUIntLE(InputStream input) { // 获取输入流中Little Endian格式的无符号整数return (int) (readIntLE(input) 0xFFFFFFFFL);}private static float readFloat32LE(InputStream input) { // 获取输入流中Little Endian格式的浮点数byte[] bytes new byte[4];try {input.read(bytes, 0, 4);} catch (IOException e) {e.printStackTrace();}return ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getFloat();} }/*** 网格文件头*/ class Header {boolean valid false;int versionNumber 0;int parts 0;Box aabb new Box();int flags 0;int posOffset 0;int positionStride 0;int tangentOffset 0;int tangentStride 0;int colorOffset 0;int colorStride 0;int uv0Offset 0;int uv0Stride 0;int uv1Offset 0;int uv1Stride 0;int totalVertices 0;int verticesSizeInBytes 0;int indices16Bit 0;int totalIndices 0;int indicesSizeInBytes 0; } 2.2 业务类 MainActivity.java package com.zhyan8.loadmodel;import android.os.Bundle;import androidx.appcompat.app.AppCompatActivity;import com.zhyan8.loadmodel.filament.base.FLSurfaceView;public class MainActivity extends AppCompatActivity {private FLSurfaceView mFLSurfaceView;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mFLSurfaceView new MyFLSurfaceView(this);setContentView(mFLSurfaceView);mFLSurfaceView.init();mFLSurfaceView.setRenderMode(FLSurfaceView.RENDERMODE_CONTINUOUSLY);}Overridepublic void onResume() {super.onResume();mFLSurfaceView.onResume();}Overridepublic void onPause() {super.onPause();mFLSurfaceView.onPause();}Overridepublic void onDestroy() {super.onDestroy();mFLSurfaceView.onDestroy();} } MyFLSurfaceView.java package com.zhyan8.loadmodel;import android.content.Context;import com.google.android.filament.Camera; import com.zhyan8.loadmodel.filament.base.BaseModel; import com.zhyan8.loadmodel.filament.base.FLSurfaceView;public class MyFLSurfaceView extends FLSurfaceView {private BaseModel mMyModel;public MyFLSurfaceView(Context context) {super(context);}public void init() {mSkyboxColor new float[] {0.35f, 0.35f, 0.35f, 1};super.init();}Overridepublic void onDestroy() {mMyModel.destroy();super.onDestroy();}Overrideprotected void setupScene() { // 设置Scene参数mMyModel new MyModel(getContext(), mEngine);mScene.addEntity(mMyModel.getRenderable());addRenderCallback(mMyModel.getRenderCallback());}Overrideprotected void onResized(int width, int height) {double aspect (double) width / (double) height;mCamera.setProjection(45.0, aspect, 0.1, 1000.0, Camera.Fov.VERTICAL);float[] eye new float[] {1.5f, 1f, 7.5f}; // cube//float[] eye new float[] {1.5f, 1f, 500f}; // spider_bot//float[] eye new float[] {1.5f, 1f, 10f}; // shader_ballfloat[] center new float[] {0, 0, 0};float[] up new float[] {0, 1, 0};mCamera.lookAt(eye[0], eye[1], eye[2],center[0], center[1], center[2], up[0], up[1], up[2]);} } MyModel.java package com.zhyan8.loadmodel;import android.content.Context; import android.opengl.Matrix;import com.google.android.filament.Engine; import com.google.android.filament.MaterialInstance; import com.google.android.filament.RenderableManager.PrimitiveType; import com.zhyan8.loadmodel.filament.base.BaseModel; import com.zhyan8.loadmodel.filament.utils.MeshUtils;public class MyModel extends BaseModel {private String mMaterialPath materials/normal_light.filamat;private String mMeshPath models/cube.filamesh;//private String mMeshPath models/spider_bot.filamesh;//private String mMeshPath models/shader_ball.filamesh;private float[] mModelMatrix; // 模型变换矩阵private float[] mRotateAxis; // 旋转轴private float mRotateAgree 0; // 旋转角度public MyModel(Context context, Engine engine) {super(context, engine);init();}private void init() {mMaterials loadMaterials(mMaterialPath);mMaterialInstances getMaterialInstance(mMaterials);mMaterialMap.put(DefaultMaterial, mMaterialInstances[0]);mMesh MeshUtils.loadMesh(mContext, mEngine, mMeshPath);mRenderable getRenderable(PrimitiveType.TRIANGLES);mTransformComponent mTransformManager.getInstance(mRenderable);mRenderCallback () - renderCallback();mModelMatrix new float[16];mRotateAxis new float[] { 0.5f, 1f, 1f };}private void renderCallback() {mRotateAgree (mRotateAgree 1) % 360;mRotateAxis[0] mRotateAgree / 180f - 1;mRotateAxis[1] (float) Math.sin(mRotateAgree / 180f * Math.PI * 0.7f);mRotateAxis[2] (float) Math.cos(mRotateAgree / 180f * Math.PI * 0.5f);Matrix.setRotateM(mModelMatrix, 0, mRotateAgree, mRotateAxis[0], mRotateAxis[1], mRotateAxis[2]);mTransformManager.setTransform(mTransformComponent, mModelMatrix);} } normal_light.mat material {name : custom_light,shadingModel : unlit, // 禁用所有lighting// 顶点着色器入参MaterialVertexInputs中需要的顶点属性requires : [tangents] }fragment {void material(inout MaterialInputs material) {prepareMaterial(material); // 在方法返回前必须回调该函数vec3 normal normalize(getWorldNormalVector()); // 法线向量if (normal.x 0.0) {normal.x -normal.x / 2.0;}if (normal.y 0.0) {normal.y -normal.y / 2.0;}if (normal.z 0.0) {normal.z -normal.z / 2.0;}material.baseColor vec4(normal, 1.0);} } 说明 normal_light 材质使用模型的法线信息给模型表面着色。 cube.obj # 正方体模型# 顶点位置 v 1.0 1.0 -1.0 # V1 v 1.0 -1.0 -1.0 # V2 v 1.0 1.0 1.0 # V3 v 1.0 -1.0 1.0 # V4 v -1.0 1.0 -1.0 # V5 v -1.0 -1.0 -1.0 # V6 v -1.0 1.0 1.0 # V7 v -1.0 -1.0 1.0 # V8# 纹理坐标 vt 0.0 0.0 # VT1 vt 1.0 0.0 # VT2 vt 1.0 1.0 # VT3 vt 0.0 1.0 # VT4# 法线 vn 0.0 1.0 0.0 # VN1 (上面法线) vn 0.0 0.0 1.0 # VN2 (背面法线) vn -1.0 0.0 0.0 # VN3 (左面法线) vn 0.0 -1.0 0.0 # VN4 (下面法线) vn 1.0 0.0 0.0 # VN5 (右面法线) vn 0.0 0.0 -1.0 # VN6 (前面法线)# 面v/vt/vn f 1/1/1 5/2/1 7/3/1 f 1/1/1 7/3/1 3/4/1 f 4/1/2 3/2/2 7/3/2 f 4/1/2 7/3/2 8/4/2 f 8/1/3 7/2/3 5/3/3 f 8/1/3 5/3/3 6/4/3 f 6/1/4 2/2/4 4/3/4 f 6/1/4 4/3/4 8/4/4 f 2/1/5 1/2/5 3/3/5 f 2/1/5 3/3/5 4/4/5 f 6/1/6 5/2/6 1/3/6 f 6/1/6 1/3/6 2/4/6 transform.bat echo off setlocal enabledelayedexpansionecho transform materials set srcMatDir../src/main/raw/materials set distMatDir../src/main/assets/materialsfor %%f in (%srcMatDir%\*.mat) do (set matfile%%~nfmatc -p mobile -a opengl -o !matfile!.filamat %%fmove !matfile!.filamat %distMatDir%\!matfile!.filamat )echo transform mesh set srcMeshDir../src/main/raw/models set distMeshDir../src/main/assets/modelsfor %%f in (%srcMeshDir%\*.obj %srcMeshDir%\*.fbx) do (set meshfile%%~nffilamesh %%f !meshfile!.filameshmove !meshfile!.filamesh %distMeshDir%\!meshfile!.filamesh )echo Processing complete. pause 说明需要将 matc.exe 文件、filamesh.exe 文件与 transform.bat 文件放在同一个目录下面matc.exe 和 filamesh.exe 源自Filament环境搭建中编译生成的 exe 文件。双击 transform.bat 文件会自动将 /src/main/raw/materials 下面的所有 mat 文件全部转换为 filamat 文件并移到 /src/main/assets/materials/ 目录下面同时自动将 /src/main/raw/models下面的所有 obj 或 fbx 文件全部转换为 filamesh 文件并移到 /src/main/assets/models/ 目录下面。 加载 cube 模型运行效果如下。 加载 spider_bot 模型运行效果如下。  加载 shader_ball 模型运行效果如下。
http://www.w-s-a.com/news/806552/

相关文章:

  • 网站设计制作售价多少钱制作图片的软件是
  • 网站验证码目录简单带数据库的网站模版
  • 制作网站用c#做前台网站建设专题的意义
  • 广西建设职业技术学院教育网站牡丹区建设局网站
  • 网站后台怎么用ftp打开上海外贸进出口有限公司
  • 淘宝建设网站的意义大学生做那个视频网站
  • 如何提高你的网站的粘性建设银行流水网站
  • 微信h5在哪个网站做泰州专业网站制作公司
  • 现在.net做网站的多吗建设工程造价网
  • pc访问手机网站跳转违法网站开发人员
  • 网站前端做报名框wordpress 启动慢
  • 沈阳做网站客户多吗前端可以做网站吗
  • 网站设计规划书新媒体营销策略分析
  • dw个人网站主页怎么做天津工程信息建设网
  • 顺义做网站的公司网站页面设计基础教程
  • 安阳哪个公司做网站好企业没有做网站有的坏处
  • 网站开发有必要用php框架wordpress分页导航代码
  • wordpress建站seo鞍山制作网站哪家好
  • 网站空间流量查询上海门户网站制作
  • 网站开发技术是什么专业会的加强普法网站和普法网络集群建设
  • 上海建筑网站seo 推广
  • 乌兰察布做网站公司爱站网关键词挖掘工具站长工具
  • 白银网站建设白银申请网站空间怎么做
  • 免费炫酷网站模板网站建设需要用到什么软件有哪些
  • 电商网站开发 文献综述大型网站建设企业
  • 如何在建设部网站补录项目单仁牛商
  • 社保网站上做减员一直不审核软件程序开发
  • 网站友情链接购买天元建设集团有限公司资质
  • 南山商城网站建设哪家技术好株洲seo网站优化软件
  • 服务类网站建设18款禁用网站app直播