【Filament】绘制圆形

1 前言

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

2 绘制圆形

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

2.1 自定义基类

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

        build.gradle

...
android {...aaptOptions { // 在应用程序打包过程中不压缩的文件noCompress 'filamat', 'ktx'}
}dependencies {implementation fileTree(dir: '../libs', include: ['*.aar'])...
}

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

        FLSurfaceView.java

package com.zhyan8.circle.filament;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;/** 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(); // 帧回调static {Filament.init();}public FLSurfaceView(Context context) {super(context);mChoreographer = Choreographer.getInstance();mDisplayHelper = new DisplayHelper(context);}public void init() { // 初始化setupSurfaceView();setupFilament();setupView();setupScene();}public void setRenderMode(int renderMode) { // 设置渲染模式mRenderMode = renderMode;}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);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);}/** 帧回调*/private class FrameCallback implements Choreographer.FrameCallback {@Overridepublic void doFrame(long frameTimeNanos) { // 渲染每帧数据if (mRenderMode == RENDERMODE_CONTINUOUSLY) {mChoreographer.postFrameCallback(this); // 请求下一帧}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);}}
}

        BaseModel.java

package com.zhyan8.circle.filament;import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;import com.google.android.filament.Box;
import com.google.android.filament.Engine;
import com.google.android.filament.EntityManager;
import com.google.android.filament.IndexBuffer;
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.VertexBuffer;
import com.google.android.filament.VertexBuffer.AttributeType;
import com.google.android.filament.VertexBuffer.VertexAttribute;import java.io.FileInputStream;
import java.io.IOException;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;/** 模型基类* 管理模型的材质、顶点属性、顶点索引、渲染id*/
public class BaseModel {private static String TAG = "BaseModel";protected AssetManager mAssetManager; // 资源管理器protected Engine mEngine; // Filament引擎protected Material mMaterial; // 模型材质protected MaterialInstance mMaterialInstance; // 模型材质实例protected VertexBuffer mVertexBuffer; // 顶点属性缓存protected IndexBuffer mIndexBuffer; // 顶点索引缓存protected int mRenderable; // 渲染idprotected Box mBox; // 渲染区域public BaseModel(AssetManager assetManager, Engine engine) {mAssetManager = assetManager;mEngine = engine;}public Material getMaterial() { // 获取材质return mMaterial;}public VertexBuffer getVertexBuffer() { // 获取顶点属性缓存return mVertexBuffer;}public IndexBuffer getIndexBuffer() { // 获取顶点索引缓存return mIndexBuffer;}public int getRenderable() { // 获取渲染idreturn mRenderable;}public void destroy() { // 销毁模型mEngine.destroyEntity(mRenderable);mEngine.destroyVertexBuffer(mVertexBuffer);mEngine.destroyIndexBuffer(mIndexBuffer);mEngine.destroyMaterialInstance(mMaterialInstance);mEngine.destroyMaterial(mMaterial);EntityManager entityManager = EntityManager.get();entityManager.destroy(mRenderable);}protected Material loadMaterial(String materialPath) { // 加载材质Buffer buffer = readUncompressedAsset(mAssetManager, materialPath);if (buffer != null) {Material material = (new Material.Builder()).payload(buffer, buffer.remaining()).build(mEngine);mMaterialInstance = material.createInstance();material.compile(Material.CompilerPriorityQueue.HIGH,Material.UserVariantFilterBit.ALL,new Handler(Looper.getMainLooper()),() -> Log.i(TAG, "Material " + material.getName() + " compiled."));mEngine.flush();return material;}return null;}protected 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;}protected VertexBuffer getVertexBuffer(Vertex[] values) { // 获取顶点属性缓存ByteBuffer vertexData = getByteBuffer(values);int vertexCount = values.length;int vertexSize = Vertex.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;}protected 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;}protected int getRenderable(PrimitiveType primitiveType, int vertexCount) { // 获取渲染idint renderable = EntityManager.get().create();new RenderableManager.Builder(1).boundingBox(mBox).geometry(0, primitiveType, mVertexBuffer, mIndexBuffer, 0, vertexCount).material(0, mMaterialInstance).build(mEngine, renderable);return renderable;}private Buffer readUncompressedAsset(AssetManager assetManager, String assetName) { // 加载资源ReadableByteChannel src = null;ByteBuffer dist = null;try {AssetFileDescriptor fd = assetManager.openFd(assetName);FileInputStream fis = fd.createInputStream();dist = ByteBuffer.allocate((int) fd.getLength());src = Channels.newChannel(fis);src.read(dist);} catch (IOException e) {Log.d(TAG, "readUncompressedAsset-catch, e=" + e);} finally {if (src != null) {try {src.close();} catch (IOException e) {Log.d(TAG, "readUncompressedAsset-finally, e=" + e);}}}if (dist != null) {return dist.rewind();}return null;}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(Vertex[] values) { // Vertex数组转换为ByteBufferByteBuffer byteBuffer = ByteBuffer.allocate(values.length * Vertex.BYTES);byteBuffer.order(ByteOrder.nativeOrder());for (int i = 0; i < values.length; i++) {values[i].put(byteBuffer);}byteBuffer.flip();return byteBuffer;}/** 顶点数据* 包含顶点位置和颜色*/public static class Vertex {public static int BYTES = 16;public float x;public float y;public float z;public int color;public Vertex() {}public Vertex(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) { // Vertex转换为ByteBufferbuffer.putFloat(x);buffer.putFloat(y);buffer.putFloat(z);buffer.putInt(color);return buffer;}}
}

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

        MainActivity.java

package com.zhyan8.circle;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;import com.zhyan8.circle.filament.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.circle;import android.content.Context;import com.google.android.filament.Camera;
import com.zhyan8.circle.filament.BaseModel;
import com.zhyan8.circle.filament.FLSurfaceView;public class MyFLSurfaceView extends FLSurfaceView {private BaseModel mMyModel;public MyFLSurfaceView(Context context) {super(context);}public void init() {mSkyboxColor = new float[] {0.965f, 0.941f, 0.887f, 1};super.init();}@Overridepublic void onDestroy() {mMyModel.destroy();super.onDestroy();}@Overrideprotected void setupScene() { // 设置Scene参数mMyModel = new Circle1(getContext().getAssets(), mEngine);mScene.addEntity(mMyModel.getRenderable());}@Overrideprotected void onResized(int width, int height) {double zoom = 1.5;double aspect = (double) width / (double) height;mCamera.setProjection(Camera.Projection.ORTHO,-aspect * zoom, aspect * zoom, -zoom, zoom, 0, 10);}
}

        Circle1.java

package com.zhyan8.circle;import android.content.res.AssetManager;import com.google.android.filament.Box;
import com.google.android.filament.Engine;
import com.google.android.filament.RenderableManager.PrimitiveType;
import com.zhyan8.circle.filament.BaseModel;public class Circle1 extends BaseModel {private String materialPath = "materials/circle1.filamat";private float[] mVertices;private short[] mIndex;public Circle1(AssetManager assetManager, Engine engine) {super(assetManager, engine);init();}private void init() {int num = 50;mVertices = getCircle(0, 0, 0.5f, num);mIndex = getIndices(num);mBox = new Box(0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.01f);mMaterial = loadMaterial(materialPath);mVertexBuffer = getVertexBuffer(mVertices);mIndexBuffer = getIndexBuffer(mIndex);mRenderable = getRenderable(PrimitiveType.TRIANGLES, mIndex.length);}private float[] getCircle(float centerX, float centerY, float radius, int num) {float unit = (float) (2 * Math.PI / num);float[] coords = new float[(num + 1) * 3];int index = 0;for (int i = 0; i < num; i++) {coords[index++] = (float)(centerX + radius * Math.cos(unit * i));coords[index++] = (float)(centerY + radius * Math.sin(unit * i));coords[index++] = 0;}coords[index++] = centerX;coords[index++] = centerY;coords[index] = 0;return coords;}private short[] getIndices(int num) {short[] indices = new short[num * 3];short centerIndex = (short) num;short index = 0;for (short i = 0; i < num - 1; i++) {indices[index++] = centerIndex;indices[index++] = i;indices[index++] = (short)(i + 1);}indices[index++] = centerIndex;indices[index++] = (short) (num - 1);indices[index] = 0;return indices;}
}

        circle1.mat

material {name : circle,// 禁用所有lightingshadingModel : unlit,featureLevel : 0
}fragment {vec3 sRGB_to_linear(vec3 color) { // gamma解码, 转换到线下空间color.x = pow(color.r, 2.2);color.y = pow(color.g, 2.2);color.z = pow(color.b, 2.2);return color;}void material(inout MaterialInputs material) {prepareMaterial(material); // 在方法返回前必须回调该函数vec3 color = vec3(0.455, 0.725, 1.0);color = sRGB_to_linear(color);material.baseColor = vec4(color, 1.0);}
}

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

        transform.bat

@echo off
setlocal enabledelayedexpansion
set "srcFolder=../src/main/materials"
set "distFolder=../src/main/assets/materials"for %%f in ("%srcFolder%\*.mat") do (set "matfile=%%~nf"matc -p mobile -a opengl -o "!matfile!.filamat" "%%f"move "!matfile!.filamat" "%distFolder%\!matfile!.filamat"
)echo Processing complete.
pause

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

        运行效果如下。

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

        MyFLSurfaceView.java

package com.zhyan8.circle;import android.content.Context;import com.google.android.filament.Camera;
import com.zhyan8.circle.filament.BaseModel;
import com.zhyan8.circle.filament.FLSurfaceView;public class MyFLSurfaceView extends FLSurfaceView {private BaseModel mMyModel;public MyFLSurfaceView(Context context) {super(context);}public void init() {mSkyboxColor = new float[] {0.965f, 0.941f, 0.887f, 1};super.init();}@Overridepublic void onDestroy() {mMyModel.destroy();super.onDestroy();}@Overrideprotected void setupScene() { // 设置Scene参数mMyModel = new Circle2(getContext().getAssets(), mEngine);mScene.addEntity(mMyModel.getRenderable());}@Overrideprotected void onResized(int width, int height) {double zoom = 1.5;double aspect = (double) width / (double) height;mCamera.setProjection(Camera.Projection.ORTHO,-aspect * zoom, aspect * zoom, -zoom, zoom, 0, 10);}
}

        Circle2.java

package com.zhyan8.circle;import android.content.res.AssetManager;import com.google.android.filament.Box;
import com.google.android.filament.Colors;
import com.google.android.filament.Engine;
import com.google.android.filament.RenderableManager.PrimitiveType;
import com.zhyan8.circle.filament.BaseModel;public class Circle2 extends BaseModel {private String materialPath = "materials/circle2.filamat";private float[] mVertices;private short[] mIndex;public Circle2(AssetManager assetManager, Engine engine) {super(assetManager, engine);init();}private void init() {int num = 50;mVertices = getCircle(0, 0, 0.5f, num);mIndex = getIndices(num);mBox = new Box(0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.01f);mMaterial = loadMaterial(materialPath);mMaterialInstance.setParameter("baseColor", Colors.RgbType.SRGB, 0.455f, 0.725f, 1.0f);mVertexBuffer = getVertexBuffer(mVertices);mIndexBuffer = getIndexBuffer(mIndex);mRenderable = getRenderable(PrimitiveType.TRIANGLES, mIndex.length);}private float[] getCircle(float centerX, float centerY, float radius, int num) {float unit = (float) (2 * Math.PI / num);float[] coords = new float[(num + 1) * 3];int index = 0;for (int i = 0; i < num; i++) {coords[index++] = (float)(centerX + radius * Math.cos(unit * i));coords[index++] = (float)(centerY + radius * Math.sin(unit * i));coords[index++] = 0;}coords[index++] = centerX;coords[index++] = centerY;coords[index] = 0;return coords;}private short[] getIndices(int num) {short[] indices = new short[num * 3];short centerIndex = (short) num;short index = 0;for (short i = 0; i < num - 1; i++) {indices[index++] = centerIndex;indices[index++] = i;indices[index++] = (short)(i + 1);}indices[index++] = centerIndex;indices[index++] = (short) (num - 1);indices[index] = 0;return indices;}
}

        circle2.mat

material {name : circle,// 禁用所有lightingshadingModel : unlit,featureLevel : 0,parameters : [{ // 颜色必须在线性空间中传递, 而不是sRGB空间type : float3,name : baseColor}]
}fragment {void material(inout MaterialInputs material) {prepareMaterial(material); // 在方法返回前必须回调该函数material.baseColor.rgb = materialParams.baseColor;}
}

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/239614.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RetinaNet:Focal Loss for Dense Object Detection(CVPR2018)

文章目录 Abstract北京发现问题并给出方法成果 IntroductionRelated WorkRobust 评估 Focal LossBalanced Cross EntropyFocal Loss DefinitionClass Imbalance and Model InitializationClass Imbalance and Two-stage Detectors RetinaNet DetectorExperimentsConclusion hh …

基于SpringBoot的桃花峪滑雪场租赁系统 JAVA简易版

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 游客服务2.2 雪场管理 三、数据库设计3.1 教练表3.2 教练聘请表3.3 押金规则表3.4 器材表3.5 滑雪场表3.7 售票表3.8 器材损坏表 四、系统展示五、核心代码5.1 查询教练5.2 教练聘请5.3 查询滑雪场5.4 滑雪场预定5.5 新…

WebAssembly 的魅力:高效、安全、跨平台(上)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

JUC并发编程 08——原子操作类

目录 一.原子更新基本类型类 实现原理 二.原子更新数组 三.原子更新引用类型 四.原子更新字段类 Java从JDK1.5开始提供了J.U.C下的atomic包&#xff0c;atomic包提供了一系列的操作简单&#xff0c;性能高效&#xff0c;并能保证线程安全的类去更新基本类型变量&#xff0…

WebAssembly 的魅力:高效、安全、跨平台(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

Unity中的导航系统

NavMesh(导航网格)是3D游戏世界中用于实现动态物体自动寻路的一种技术&#xff0c;将游戏中复杂的结构组织关系简化为带有一定信息的网格&#xff0c;在这些网格的基础上通过一系列的计算来实现自动寻路。导航时&#xff0c;只需要给导航物体挂载导航组建&#xff0c;导航物体便…

【Grafana】Grafana匿名访问以及与LDAP连接

上一篇文章利用Docker快速部署了Grafana用来展示Zabbix得监控数据&#xff0c;但还需要给用户去创建账号允许他们登录后才能看展示得数据&#xff0c;那有什么办法让非管理员更方便得去访问Grafana呢&#xff1f;下面介绍两个比较方便实现的&#xff1a; 在开始设置前&#xff…

显示器屏幕oled的性能、使用场景、维护

OLED显示器屏幕具有许多独特的性能和使用场景&#xff0c;以下是关于OLED显示器屏幕的性能、使用场景和维护的详细介绍&#xff1a; 一、性能 色彩鲜艳&#xff1a;OLED显示器屏幕能够呈现出更加鲜艳的色彩&#xff0c;色彩饱和度高&#xff0c;色彩还原性好&#xff0c;可以给…

SpringBoot+JaywayJsonPath实现Json数据的DSL(按照指定节点表达式解析json获取指定数据)

场景 若依前后端分离版手把手教你本地搭建环境并运行项目&#xff1a; 若依前后端分离版手把手教你本地搭建环境并运行项目_前后端分离项目本地运行-CSDN博客 在上面搭建SpringBoot项目的基础上&#xff0c;并且在项目中引入fastjson、hutool等所需依赖后。 Jayway JsonPat…

【【C++11特性篇】【强制/禁止 】生成默认函数的关键字default&delete(代码演示)

前言 大家好吖&#xff0c;欢迎来到 YY 滴C系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的《Linux》…

动物分类识别教程+分类释义+界面展示

1.项目简介 动物分类教程分类释义界面展示 动物分类是生物学中的一个基础知识&#xff0c;它是对动物进行分类、命名和描述的科学方法。本教程将向您介绍动物分类的基本原则和方法&#xff0c;并提供一些常见的动物分类释义。 动物分类的基本原则 动物分类根据动物的形态、…

vue3老项目如何引入vite

vue3老项目如何引入vite 安装 npm install vite vitejs/plugin-vue --save-dev Vite官方中文文档修改package.json文件 在 npm scripts 中使用 vite 执行文件 "scripts": {"serve": "vite","build": "vite build","pr…

听GPT 讲Rust源代码--src/tools(22)

File: rust/src/tools/tidy/src/lib.rs rust/src/tools/tidy/src/lib.rs是Rust编译器源代码中tidy工具的实现文件之一。tidy工具是Rust项目中的一项静态检查工具&#xff0c;用于确保代码质量和一致性。 tidy工具主要有以下几个作用&#xff1a; 格式化代码&#xff1a;tidy工具…

Rust报错:the msvc targets depend on the msvc linker but `link.exe` was not found

当我在我的 windows 电脑上安装 rust&#xff0c;然后用 cargo 新建了一个项目后&#xff0c;cargo run 会报错&#xff1a; error: linker link.exe not found| note: program not foundnote: the msvc targets depend on the msvc linker but link.exe was not foundnote: p…

css学习笔记6(盒子模型)

CSS盒子模型 五、CSS盒子模型1.CSS长度单位2.元素的显示模式3.总结各元素的显示模式4.修改元素显示模式5.盒子模型的组成6.盒子内容区&#xff08;content&#xff09;7.关于默认宽度8.盒子内边距&#xff08;padding&#xff09;9.盒子边框&#xff08;border&#xff09;10.盒…

Apache Flink 进阶教程(七):网络流控及反压剖析

目录 前言 网络流控的概念与背景 为什么需要网络流控 网络流控的实现&#xff1a;静态限速 网络流控的实现&#xff1a;动态反馈/自动反压 案例一&#xff1a;Storm 反压实现 案例二&#xff1a;Spark Streaming 反压实现 疑问&#xff1a;为什么 Flink&#xff08;bef…

基于Netty构建Websocket服务端

除了构建TCP和UDP服务器和客户端&#xff0c;Netty还可以用于构建WebSocket服务器。WebSocket是一种基于TCP协议的双向通信协议&#xff0c;可以在Web浏览器和Web服务器之间建立实时通信通道。下面是一个简单的示例&#xff0c;演示如何使用Netty构建一个WebSocket服务器。 项目…

深圳鼎信|输电线路防山火视频监控预警装置:森林火灾来袭,安全不留白!

受线路走廊制约和环保要求影响&#xff0c;输电线路大多建立在高山上&#xff0c;不仅可以减少地面障碍物和人类活动的干扰&#xff0c;还能提高线路的抗灾能力和可靠性。但同时也会面临其它的难题&#xff0c;例如森林火灾预防。今天&#xff0c;深圳鼎信智慧将从不同角度分析…

signaltap立即触发的错误解决方法

signaltap点下run analysis后没有等到触发条件满足就触发了&#xff0c;原因是触发方式设置错误&#xff0c;应修改触发方式&#xff1a; 将Trigger flow control 从State-based 改为Sequential。

trino-435版本windows下源码编译

一、源码下载地址 https://github.com/trinodb/trino/tags 二、编译环境及工具准备 1、maven &#xff08;1&#xff09;版本&#xff1a;3.6.3 &#xff08;2&#xff09;settings.xml配置 <?xml version"1.0" encoding"UTF-8"?> <settin…