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

【Unity3D】Jobs、Burst并行计算裁剪Texture3D物体

版本:Unity2019.4.0f1

PackageManager下载Burst插件(1.2.3版本)

利用如下代码,生成一个Texture3D资源,它只能脚本生成,是一个32*32*32的立方体,导出路径记得改下,不然报错。

using UnityEditor;
using UnityEngine;public class ExampleEditorScript
{[MenuItem("CreateExamples/3DTexture")]static void CreateTexture3D(){// 配置纹理int size = 32;TextureFormat format = TextureFormat.RGBA32;TextureWrapMode wrapMode = TextureWrapMode.Clamp;// 创建纹理并应用配置Texture3D texture = new Texture3D(size, size, size, format, false);texture.wrapMode = wrapMode;// 创建 3 维数组以存储颜色数据Color[] colors = new Color[size * size * size];// 填充数组,使纹理的 x、y 和 z 值映射为红色、蓝色和绿色float inverseResolution = 1.0f / (size - 1.0f);for (int z = 0; z < size; z++){int zOffset = z * size * size;for (int y = 0; y < size; y++){int yOffset = y * size;for (int x = 0; x < size; x++){colors[x + yOffset + zOffset] = new Color(x * inverseResolution,y * inverseResolution, z * inverseResolution, 1.0f);}}}// 将颜色值复制到纹理texture.SetPixels(colors);// 将更改应用到纹理,然后将更新的纹理上传到 GPUtexture.Apply();// 将纹理保存到 Unity 项目AssetDatabase.CreateAsset(texture, "Assets/JobsDemo/Example3DTexture.asset");}
}

场景上创建一个Cube和LineRenderer(注意Line的位置要设置到(0,0,0) 如下图 摄像机保持位置(0,1,-10))

新建一个材质球挂到Cube上,Shader代码如下:

Shader "Unlit/VolumeShader"
{Properties{_MainTex("Texture", 3D) = "white" {}_Alpha("Alpha", float) = 0.02_StepSize("Step Size", float) = 0.01}SubShader{Tags { "Queue" = "Transparent" "RenderType" = "Transparent" }Blend One OneMinusSrcAlphaLOD 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"// 最大光线追踪样本数#define MAX_STEP_COUNT 128// 允许的浮点数误差#define EPSILON 0.00001fstruct appdata{float4 vertex : POSITION;};struct v2f{float4 vertex : SV_POSITION;float3 objectVertex : TEXCOORD0;float3 vectorToSurface : TEXCOORD1;};sampler3D _MainTex;float4 _MainTex_ST;float _Alpha;float _StepSize;v2f vert(appdata v){v2f o;// 对象空间中的顶点将成为光线追踪的起点o.objectVertex = v.vertex;// 计算世界空间中从摄像机到顶点的矢量float3 worldVertex = mul(unity_ObjectToWorld, v.vertex).xyz;o.vectorToSurface = worldVertex - _WorldSpaceCameraPos;o.vertex = UnityObjectToClipPos(v.vertex);return o;}float4 BlendUnder(float4 color, float4 newColor){color.rgb += (1.0 - color.a) * newColor.a * newColor.rgb;color.a += (1.0 - color.a) * newColor.a;return color;}fixed4 frag(v2f i) : SV_Target{// 开始在对象的正面进行光线追踪float3 rayOrigin = i.objectVertex;// 使用摄像机到对象表面的矢量获取射线方向float3 rayDirection = mul(unity_WorldToObject, float4(normalize(i.vectorToSurface), 1));float4 color = float4(0, 0, 0, 0);float3 samplePosition = rayOrigin;// 穿过对象空间进行光线追踪for (int i = 0; i < MAX_STEP_COUNT; i++){// 仅在单位立方体边界内累积颜色if (max(abs(samplePosition.x), max(abs(samplePosition.y), abs(samplePosition.z))) < 0.5f + EPSILON){float4 sampledColor = tex3D(_MainTex, samplePosition + float3(0.5f, 0.5f, 0.5f));sampledColor.a *= _Alpha;color = BlendUnder(color, sampledColor);samplePosition += rayDirection * _StepSize;}}return color;}ENDCG}}
}

新建一个空物体Jobs,挂载脚本JobsTest.cs

using System;
using System.Collections;
using System.Collections.Generic;
using Unity.Burst;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using UnityEngine;public class JobsTest : MonoBehaviour
{private int width, height, depth;public LineRenderer lineRenderer;public GameObject cubeGo;private Transform cubeTrans;private Texture3D _Tex3D;private Color[] colors;private Color[] cacheColor;NativeArray<Color> nativeColors;NativeArray<ColorData> nativeColorDatas;MyJob myJob = new MyJob();private void Awake(){Material mat = cubeGo.GetComponent<MeshRenderer>().sharedMaterial;_Tex3D = (Texture3D)mat.GetTexture("_MainTex");width = _Tex3D.width;height = _Tex3D.height;depth = _Tex3D.depth;colors = _Tex3D.GetPixels();cacheColor = _Tex3D.GetPixels();cubeTrans = cubeGo.transform;Debug.Log(colors.Length);}private void OnEnable(){lineRenderer.positionCount = 1;_Tex3D.SetPixels(cacheColor);_Tex3D.Apply();nativeColors = new NativeArray<Color>(colors.Length, Allocator.Persistent);nativeColorDatas = new NativeArray<ColorData>(colors.Length, Allocator.Persistent);myJob.width = width;myJob.height = height;myJob.depth = depth;myJob.colors = nativeColors;myJob.colorDatas = nativeColorDatas;for (int z = 0; z < depth; z++){for (int y = 0; y < height; y++){for (int x = 0; x < width; x++){int i = z * (width * height) + y * width + x;nativeColors[i] = colors[i];ColorData colorData = new ColorData();colorData.x = x;colorData.y = y;colorData.z = z;nativeColorDatas[i] = colorData;}}}}private void OnDisable(){_Tex3D.SetPixels(cacheColor);_Tex3D.Apply();nativeColorDatas.Dispose();nativeColors.Dispose();}// Update is called once per framevoid Update(){if (Input.GetMouseButtonDown(0)){Vector3 screenPos = Input.mousePosition;screenPos.z = 1;lineRenderer.SetPosition(lineRenderer.positionCount - 1, Camera.main.ScreenToWorldPoint(screenPos));if (lineRenderer.positionCount == 3){Calculate();lineRenderer.positionCount = 1;}else{lineRenderer.positionCount++;}}else{if (lineRenderer.positionCount > 1){Vector3 screenPos = Input.mousePosition;screenPos.z = 1;lineRenderer.SetPosition(lineRenderer.positionCount - 1, Camera.main.ScreenToWorldPoint(screenPos));}}}private void Calculate(){float startTime = Time.realtimeSinceStartup;//模型坐标myJob.p1 = cubeTrans.InverseTransformPoint(lineRenderer.GetPosition(0));myJob.p2 = cubeTrans.InverseTransformPoint(lineRenderer.GetPosition(1));myJob.p3 = cubeTrans.InverseTransformPoint(lineRenderer.GetPosition(2));myJob.object2World = cubeTrans.localToWorldMatrix;myJob.world2Camera = Camera.main.worldToCameraMatrix;myJob.camera2Clip = Camera.main.projectionMatrix;JobHandle jobHandle = default;jobHandle = myJob.ScheduleParallel(colors.Length, 64, jobHandle);jobHandle.Complete();_Tex3D.SetPixels(nativeColors.ToArray());_Tex3D.Apply();Debug.Log((Time.realtimeSinceStartup - startTime) * 1000 + "ms");}
}[BurstCompile]
public struct MyJob : IJobFor
{//[NativeDisableContainerSafetyRestriction]public NativeArray<Color> colors;//[NativeDisableContainerSafetyRestriction] //发现jobs日志有 out of length报错可用此特性忽略public NativeArray<ColorData> colorDatas;public Vector3 p1, p2, p3;public int width, height, depth;public Matrix4x4 object2World;public Matrix4x4 world2Camera;public Matrix4x4 camera2Clip;public void Execute(int index){if (colors[index] == Color.clear){return;}Vector3 localPoint = new Vector3(colorDatas[index].x / (width * 1.0f), colorDatas[index].y / (height * 1.0f), colorDatas[index].z / (depth * 1.0f)) - (Vector3.one * 0.5f);Vector2 screenPoint = Local2Screen(localPoint);Vector2 screenP1 = Local2Screen(p1);Vector2 screenP2 = Local2Screen(p2);Vector2 screenP3 = Local2Screen(p3);bool isInside = IsPointInTriangle(screenPoint, screenP1, screenP2, screenP3);if (isInside){colors[index] = Color.clear;}}//2个二维向量行列式值,可理解为求出了2个二维向量构成的面的法线z值private float Cross(Vector2 a, Vector2 b, Vector2 p){return (b.x - a.x) * (p.y - a.y) - (b.y - a.y) * (p.x - a.x);}private bool IsPointInTriangle(Vector2 p, Vector2 a, Vector2 b, Vector2 c){float signOfTrig = Cross(a, b, c);float signOfAB = Cross(a, b, p);float signOfCA = Cross(c, a, p);float signOfBC = Cross(b, c, p);bool d1 = (signOfAB * signOfTrig > 0);bool d2 = (signOfCA * signOfTrig > 0);bool d3 = (signOfBC * signOfTrig > 0);return d1 && d2 && d3;//方法2://Vector3 pa = a - p;//Vector3 pb = b - p;//Vector3 pc = c - p;//分别进行3次,求其中2个向量构成的三角面的法线;//Vector3 pab = Vector3.Cross(pa, pb);//Vector3 pbc = Vector3.Cross(pb, pc);//Vector3 pca = Vector3.Cross(pc, pa);//分别进行3次,求其中2个法线构成的点积(夹角)>0代表两条法线方向相同//float z1 = Vector3.Dot(pab, pbc);//float z2 = Vector3.Dot(pab, pca);//float z3 = Vector3.Dot(pbc, pca);//若3条法线之间的朝向都是相同的,说明p点在<a,b,c>三角形内//return z1 > 0 && z2 > 0 && z3 > 0;            }private Vector2 Local2Screen(Vector3 localPos){Vector3 worldPos = object2World.MultiplyPoint(localPos);Vector3 cameraPos = world2Camera.MultiplyPoint(worldPos);Vector4 clipPos = camera2Clip * new Vector4(cameraPos.x, cameraPos.y, cameraPos.z, 1.0f);if (clipPos.w != 0){clipPos = clipPos / clipPos.w;}float screenX = (clipPos.x + 1) / 2f * 1920f;float screenY = (clipPos.y + 1) / 2f * 1080f;return new Vector2(screenX, screenY);}
}
public struct ColorData
{public float x, y, z;
}

项目资源:

耗时如下:

相关文章:

【Unity3D】Jobs、Burst并行计算裁剪Texture3D物体

版本&#xff1a;Unity2019.4.0f1 PackageManager下载Burst插件(1.2.3版本) 利用如下代码&#xff0c;生成一个Texture3D资源&#xff0c;它只能脚本生成&#xff0c;是一个32*32*32的立方体&#xff0c;导出路径记得改下&#xff0c;不然报错。 using UnityEditor; using Uni…...

Cesium材质——Material

简介&#xff1a; Cesium.Material对象的目的&#xff0c;就是生成一段名称为czm_getMaterial的函数&#xff08;示例代码如下&#xff09;&#xff0c; 这个czm_getMaterial函数&#xff0c;是shader代码&#xff0c;会被放到片元着色器中使用。 czm_material czm_getMater…...

Postman请求报错SSL证书验证问题

1.报错如下 2.解决报错...

终章:DevOps实践总结报告

DevOps实践总结报告 一、概述 1. 报告目的 本报告旨在总结DevOps实践中的关键领域、最佳实践和实施成果&#xff0c;包括需求管理、持续集成/持续部署、测试管理、安全管理和效能度量等方面。 2. 覆盖范围 #mermaid-svg-L0xFFzMbiDH1qhbl {font-family:"trebuchet ms&…...

解锁金融新纪元:内部知识库的深度挖掘与战略价值

在日新月异的金融行业中&#xff0c;信息的快速流通与精准决策成为了企业竞争力的核心。随着大数据、人工智能等技术的不断渗透&#xff0c;金融机构开始意识到&#xff0c;内部知识库的深度挖掘不仅是提升业务效率的关键&#xff0c;更是推动行业创新与转型的重要驱动力。本文…...

【c语言】一维数组与二维数组

数组 数组名代表的是数组在内存中的起始位置&#xff0c;即首元素的地址&#xff0c;而下表表示的则是该元素相对数组起始位置的偏移量 一维数组 1.定义 类型名 数组名[数组长度] int a[100]; //整型数组长度为101&#xff0c;数组名为a char b[100];//字符型数组长度为101&…...

Milvus×EasyAi:如何用java从零搭建人脸识别应用

如何从零搭建一个人脸识别应用&#xff1f;不妨试试原生Java人工智能算法&#xff1a;EasyAi Milvus 的组合拳。 本文将使用到的软件和工具包括&#xff1a; EasyAi&#xff1a;人脸特征向量提取Milvus&#xff1a;向量数据库用于高效存储和检索数据。 01. EasyAi&#xff1a;…...

Dockerfile 实战指南:解锁高效容器化开发

一、Dockerfile 简介 Dockerfile 是构建镜像的文本文件&#xff0c;通过一系列指令描述镜像构建过程&#xff0c;构建操作由 Docker daemon 进行&#xff0c;它会先验证语法&#xff0c;然后逐一运行指令&#xff0c;每次生成一个新的镜像层&#xff0c;直到构建出最终的镜像。…...

【每日学点鸿蒙知识】混淆配置、主线程处理大量数据、客户端拖拽效果、三方网站加载样式、List警告问题

1、HarmonyOS API升级之后缺少混淆配置文件&#xff1f; 可参考以下文档&#xff1a; 混淆配置&#xff1a;https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-build-obfuscation-V5 混淆规则&#xff1a;https://gitee.com/openharmony/arkcompiler_ets…...

ChatGPT-4助力学术论文提升文章逻辑、优化句式与扩充内容等应用技巧解析。附提示词案例

目录 1.扩写&#xff08;expansion/paraphrasing&#xff09; 2.优化&#xff08;optimization&#xff09; 3.缩写&#xff08;optimization&#xff09; 4.提取关键词&#xff08;keyword extraction&#xff09; 5.短语转换&#xff08;phrase transformation&#xff…...

Android TextView 添加图标并实现换行

图文混排。 binding.apply {val spannable = SpannableString(" " + "Kotlin 是 Android 官方推荐的编程语言。")val drawable: Drawable = ContextCompat.getDrawable(this@DemoMainXmlActivity,R.mipmap.ic_title_d)!!drawable.setBounds(0, 0, drawabl…...

matplotlib pyton 如何画柱状图,利用kimi,直接把图拉倒上面,让他生成

要绘制类似于您提供的图像的柱状图&#xff0c;您可以使用Python中的Matplotlib库&#xff0c;这是一个非常流行的绘图库。以下是一个简单的示例代码&#xff0c;展示如何使用Matplotlib来创建一个类似的柱状图&#xff1a; python import matplotlib.pyplot as plt import nu…...

如何保证mysql数据库到ES的数据一致性

1.同步双写方案 在代码中对数据库和ES进行双写操作&#xff0c;确保先更新数据后更新ES。 优点&#xff1a; 数据一致性&#xff1a;双写策略可以保证在MySql和Elasticsearch之间数据的强一致性&#xff0c;因为每次数据库的变更都会在Elasticsearch同步反映。实时性&#xf…...

安装MongoDB,环境配置

官网下载地址&#xff1a;MongoDB Shell Download | MongoDB 选择版本 安装 下载完成双击打开 点击mongodb-windows-x86_64-8.0.0-signed 选择安装地址 检查安装地址 安装成功 二.配置MongoDB数据库环境 1.找到安装好MongoDB的bin路径 复制bin路径 打开此电脑 -> 打开高级…...

家用无线路由器的 2.4GHz 和 5GHz

家中的无线路由器 WiFi 名称有两个&#xff0c;一个后面带有 “5G” 的标记&#xff0c;这让人产生疑问&#xff1a;“连接带‘5G’的 WiFi 是不是速度更快&#xff1f;” 实际上&#xff0c;这里的 “5G” 并不是移动通信中的 5G 网络&#xff0c;而是指路由器的工作频率为 5G…...

我的tensorboard

1.Tensorboard 2.Tensorboard的使用 导入tensorboard并创建SummaryWriter 添加标量数据 添加图片数据 直方图 模型可视化 3.代码使用 模型可视化 # 记录模型结构 dummy_input torch.randn(1, 3, 224, 224).to(device) # 根据你的模型输入尺寸调整 writer.add_graph(model…...

Quartz 相关线程

​ 我们在前面文章中说到过Quartz涉及到的线程&#xff0c;但是散落在几篇文章中&#xff0c;不好找。而Quartz涉及到的线程对于理解Quartz也比较重要&#xff0c;所以今天专门提取出来单独说一下。 Quartz中的主要线程&#xff1a; 任务调度线程QuartzSchedulerThread 任务执…...

【QED】爱丽丝与混沌的无尽海

文章目录 题目题目描述输入输出格式数据范围测试样例 思路代码复杂度分析时间复杂度空间复杂度 题目 题目链接&#x1f517; 题目描述 如图所示&#xff0c;爱丽丝在一个3x3的迷宫之中&#xff0c;每个方格中标有 1 − 9 1-9 1−9各不相同的数字&#xff0c;爱丽丝可以从一格…...

IO模型学习

背景知识 Socket 套接字。 客户端和服务端通信时&#xff0c;客户端需要数据出口&#xff0c;服务端需要数据入口&#xff0c;这两个出入口就是Socket。数据接收方新建socket后需要绑定ip和端口号&#xff0c;这样客户端才能链接上socket。连接的过程就是 三次握手 FD file …...

Doxygen 使用指南

Doxygen 是一个文档生成工具&#xff0c;可以从源代码中的注释生成高质量的文档&#xff0c;支持多种编程语言&#xff08;如 C/C、Python、Java 等&#xff09;。以下是 Doxygen 的基本使用方法。 1. 安装 Doxygen 1.1 下载 Doxygen 访问 Doxygen 官网。根据操作系统选择合适…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

VB.net复制Ntag213卡写入UID

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比

目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec&#xff1f; IPsec VPN 5.1 IPsec传输模式&#xff08;Transport Mode&#xff09; 5.2 IPsec隧道模式&#xff08;Tunne…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...