unity.生成表示地图信息的二维数组_Unity3D 中生成任意形状3D Texture amp; 体积云...
3d 贴图一般在 Houdini等软件生成,毕竟需要其他软件支持,导入导出预览效率和制作效率都不高 (Houdini也不便宜....别问就是穷...)
Unity中只见到过一些3D噪音图的生成,本文提供一个任意物体(Mesh)的生成3dTexture方法,水平有限如果高见不胜赐教
知乎视频www.zhihu.com
基本流程
1.物体shader 使用VFACE 判断模正反 给予不同的颜色
2.shader 中调整裁剪clip的值,对模型进行切片,并使用相机将每片拍下来保存为Texture2D 数组
3.将保存的Texture2D数组 生成为Texture3D
4.将生成完的Texture3D 重新载入另一个shader进行模糊,再次切片 合成导出,(3D贴图的模糊需要采集 前后左右上下,因为是一个3维的,如果你想深入了解 可以参考这篇 Nvdia 的Fast Third-Order Texture Filtering )
效果图
创建的速度比较理想,128 分辨率以内的都可以在1秒内创建完成
首先是切片的shader ,使用VFACE 判断正反,内白外黑
Shader "sliceSahder"
{Properties{_facadeColor("FacadeColor", Color) = (1,1,1,1)_backColor("BackColor", Color) = (1,1,1,1)_height("Height", Range(-1,1)) = 0.0}SubShader{Tags{"DisableBatching" = "True""Queue" = "Transparent""RenderType" = "Transparent"}Pass{Tags {"RenderType" = "Opaque" "Queue" = "Geometry"}Zwrite OnCull Off AlphaToMask On //改善AlphaTest抗锯齿CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;};struct v2f{float4 vertex : SV_POSITION;float3 worldPos : TEXCOORD0;};float _height;float4 _backColor, _facadeColor;float4 _SliceObjectPos;v2f vert(appdata v){v2f o = (v2f)0;o.vertex = UnityObjectToClipPos(v.vertex);float3 wPos = mul(unity_ObjectToWorld, v.vertex.xyz);//_SliceObjectPos是模型的世界空间位置,我们要控制切片范围在box内o.worldPos = wPos + _SliceObjectPos .xyz;return o;}float4 frag(v2f i, fixed facing : VFACE) : SV_Target{float4 heightResult = step(i.worldPos.y + _height,0);float4 facade = heightResult * _facadeColor;float4 back = heightResult * _backColor;float4 finalColor = 0;if (facing > 0){finalColor = facade;}else{finalColor = back;}clip(finalColor.a - 0.5);return finalColor;}ENDCG}}
}
我们控制 _height的值就可以控制 切片的高度
忘记说一下,我们首先需要创建一个切片区域,先画一个1立方米的盒子
controlBox.cs
private void OnDrawGizmos(){Gizmos.color = boxColor * new Color(0.5f, 0.5f, 0.5f, 0.5f);Gizmos.DrawWireCube(transform.position, transform.localScale);}
下面是 controlBoxEditor.cs 中的内容
创建一个摄像机与这个Box 匹配,注意要让摄像机背景为黑色
public Camera CreateCamera(){controlBox controlFun = (controlBox)target;if (controlGameObject != null){return xRayCamera;}else{controlGameObject = new GameObject("SliceCam");controlGameObject.transform.SetParent(controlFun.transform);controlGameObject.hideFlags = HideFlags.DontSave;Vector3 LocalScale = controlFun.transform.localScale;float CamPos = LocalScale.y / 2;//保正相机在box 顶部向下看controlGameObject.transform.position = controlFun.transform.position + new Vector3(0, CamPos, 0);controlGameObject.transform.localEulerAngles = new Vector3(90, 0, 0);xRayCamera = controlGameObject.AddComponent<Camera>();xRayCamera.clearFlags = CameraClearFlags.SolidColor;xRayCamera.backgroundColor = Color.black;//背景要设置黑色xRayCamera.orthographic = true;xRayCamera.orthographicSize = CamPos;xRayCamera.nearClipPlane = 0;//box最顶面xRayCamera.farClipPlane = LocalScale.y;//box最底面xRayCamera.enabled = true;xRayCamera.renderingPath = RenderingPath.Forward;int maskLayer = 1 << 31;//设置一个专用层xRayCamera.cullingMask = maskLayer;return xRayCamera;}}
这时相机中的效果就是这样
下一步就是在循环中一张张的渲染所有切片保存到Texture2D数组备用
float RamapValue(float original, float oldMinVal, float oldMaxVal, float newMinVal, float newMaxVal){float calculate = (original - oldMinVal) * (newMaxVal - newMinVal) / (oldMaxVal - oldMinVal) + newMinVal;return calculate;}private void CreateTextureArray(bool Blur){controlBox controlFun = (controlBox)target;int sliceCount = controlFun.SliceCountLayer;Texture3DArray = new Texture2D[sliceCount];for (int i = 0; i < sliceCount; i++){serializedObject.Update();//如果是Editor的类一定要加这个,否则不刷新//使用 Alpha8 减少贴图大小RenderTexture xRayLayer = new RenderTexture(sliceCount, sliceCount, 24, RenderTextureFormat.R8);// 重映射值,如设置128层,shader中(-0.5,0.5) 那么每层步进 0.007813 float setLayer = RamapValue(i, 0, sliceCount(128), controlFun.MinMax.x(-0.5), controlFun.MinMax.y(0.5));if (Blur){controlFun.BlurMaterial.SetTexture("_VolumeTex", BuildTexture3D);controlFun.BlurMaterial.SetFloat("_offset", setLayer);}else{controlFun.SliceMaterial.SetFloat("_height", setLayer);//设置每层偏移参数}xRayCamera.targetTexture = xRayLayer;xRayCamera.Render();Texture2D texture2D = new Texture2D(sliceCount, sliceCount, TextureFormat.R8, false);RenderTexture.active = xRayLayer;texture2D.ReadPixels(new Rect(0, 0, sliceCount, sliceCount), 0, 0);texture2D.Apply();Texture3DArray[i] = texture2D;//这时也可以保存每层出来看一下//bytes = texture2D.EncodeToPNG();//File.WriteAllBytes("Assets/Texture3DTemp/My3DTexture" + i + ".png", bytes);serializedObject.ApplyModifiedProperties();}//AssetDatabase.ImportAsset("Assets/Texture3DTemp");}
然后就可以创建3D 贴图了 (如果模糊的话这里要走两遍)
public void Create3DTexture(bool blur, bool save){CreateCamera();CreateTextureArray(blur);int width = Texture3DArray[0].width;int height = Texture3DArray[0].height;int depth = Texture3DArray.Length;BuildTexture3D = new Texture3D(width, height, depth, TextureFormat.R8, true);var color3d = new Color[width * height * depth];int idx = 0;for (int z = depth-1; z >= 0; z--) //反向读取 写入3D贴图{UIProgressBar(true, blur, (int)RamapValue(z, depth,0,0, depth));//进度条显示Texture2D loadedtexture = Texture3DArray[z];for (int y = 0; y < height; ++y){for (int x = 0; x < width; ++x, ++idx){color3d[idx] = loadedtexture.GetPixel(x, y);}}}UIProgressBar(false, blur);BuildTexture3D.SetPixels(color3d);BuildTexture3D.Apply();if (save)// 如果进行模糊,第一遍不用保存到硬盘{AssetDatabase.CreateAsset(BuildTexture3D, "Assets/My3DTexture.asset");DestroyImmediate(controlGameObject);Texture3DArray = null;BuildTexture3D = null;xRayCamera = null;controlGameObject = null;}}
下面是3D 贴图模糊时使用的shader
Shader "Unlit/sliceBlurShader"
{Properties{_clearColor("ClearColor",Color) = (1,1,1,1)_VolumeTex("VolumeTex",3D) = "black"{}_offset("Offset", float) = 0_stepSize("StepSize",range(0,2)) = 1_transparency("Transparency",float) = 1_opacityCorrection ("OpacityCorrection",float) = 1}SubShader{Tags { "RenderType"="Transparent" }Pass{ZWrite OffBlend One OneMinusSrcAlphaCull OffCGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 posW : TEXCOORD1;float4 vertex : SV_POSITION;};Texture3D<float4> _VolumeTex;SamplerState sampler_VolumeTex;float _offset;float _stepSize;float _opacityCorrection;float4 _clearColor;float _transparency;v2f vert (appdata v){v2f o;o.vertex = UnityObjectToClipPos(float4(v.vertex.xyz, 1.0));o.uv = v.uv;o.posW = mul(unity_ObjectToWorld, float4(v.vertex.xyz, 1.0));return o;}fixed4 frag(v2f i) : SV_Target{ float3 tex3DUvw = float3(i.posW.x,i.posW.y + _offset,i.posW.z );float colorSample = 0;float colAcc = 0;float dx = 0.5;//偏移UVfloat3 vTAR = float3(dx, dx, dx) * _stepSize;float3 vTAL = float3(dx, dx, -dx) * _stepSize;float3 vTPR = float3(dx, -dx, dx) * _stepSize;float3 vTPL = float3(dx, -dx, -dx) * _stepSize;float3 vBAR = float3(-dx, dx, dx) * _stepSize;float3 vBAL = float3(-dx, dx, -dx) * _stepSize;float3 vBPR = float3(-dx, -dx, dx) * _stepSize;float3 vBPL = float3(-dx, -dx, -dx) * _stepSize;//利用mipmap 代替downSamplefor (int mipLevel = 0; mipLevel <5; mipLevel++){colorSample += _VolumeTex.SampleLevel(sampler_VolumeTex, tex3DUvw + vTAR, mipLevel);colorSample += _VolumeTex.SampleLevel(sampler_VolumeTex, tex3DUvw + vTAL, mipLevel);colorSample += _VolumeTex.SampleLevel(sampler_VolumeTex, tex3DUvw + vTPR, mipLevel);colorSample += _VolumeTex.SampleLevel(sampler_VolumeTex, tex3DUvw + vTPL, mipLevel);colorSample += _VolumeTex.SampleLevel(sampler_VolumeTex, tex3DUvw + vBAR, mipLevel);colorSample += _VolumeTex.SampleLevel(sampler_VolumeTex, tex3DUvw + vBAL, mipLevel);colorSample += _VolumeTex.SampleLevel(sampler_VolumeTex, tex3DUvw + vBPR, mipLevel);colorSample += _VolumeTex.SampleLevel(sampler_VolumeTex, tex3DUvw + vBPL, mipLevel);colorSample *= 0.125;colAcc = (1.0 - colAcc.r) * colorSample + colAcc;}return saturate(pow(colAcc.r * _transparency, _opacityCorrection));}ENDCG}}
}
无模糊和有模糊对比,模糊后边缘的衰减可以添加细节噪音 更柔和
顺便说下,不使用RayMarch 也是可以简单的预览3D贴图的 上面的效果就是使用下列代码创建的
using UnityEngine;public class LoadTexture3D : MonoBehaviour
{public Material sliceMaterial;//使用模糊shader 创建一个材质球指引到这public int textureLength = 64;private MeshRenderer[] meshRenders;private GameObject gameObject;private GameObject planeObject;void Start(){meshRenders = new MeshRenderer[textureLength - 1];gameObject = GameObject.CreatePrimitive(PrimitiveType.Quad);gameObject.GetComponent<MeshRenderer>().sharedMaterial = sliceMaterial;gameObject.transform.position = transform.position;gameObject.transform.SetParent(transform);gameObject.transform.rotation = Quaternion.Euler(90, 0, 0);for (int i = 0; i < textureLength - 1; i++){Vector3 pos = new Vector3(transform.position.x, transform.position.y + i * (1f / textureLength) - 0.5f, transform.position.z );planeObject = Instantiate(gameObject);planeObject.transform.position = pos;planeObject.transform.SetParent(transform);meshRenders[i] = planeObject.GetComponent<MeshRenderer>();}sliceMaterial.SetFloat("_offset", 0);}}
体积云渲染相关可以看这篇
面向搜索引擎编程:RayMarching实时体积云渲染入门(上)zhuanlan.zhihu.com
参考 https://gamedev.stackexchange.com/questions/26649/glsl-one-pass-gaussian-blur
unity.生成表示地图信息的二维数组_Unity3D 中生成任意形状3D Texture amp; 体积云...相关推荐
- php 二维数组根据键值合并二维数组_php数组根据某键值,把相同键值的合并最终生成一个新的二维数组...
匿名用户 1级 2013-12-29 回答 php数组根据某一个键值,把相同键值的合并生成一个新的二维数组 源数据: $infos = array( array( 'a' => 36, 'b' ...
- python创建一个n*m的二维数组_Python中创建二维数组
Python中创建二维数组 二维数组 二维数组本质上是以数组作为数组元素的数组,即"数组的数组",类型说明符 数组名[常量表达式][常量表达式].二维数组又称为矩阵,行列数相等的矩 ...
- Java黑皮书课后题第8章:*8.31(几何:交点)编写一个方法,返回两条直线的交点。四个点存放在4*2的二维数组points中。编写一个程序,提示用户输入4个点,并显示交点
*8.31(几何:交点)编写一个方法,返回两条直线的交点.四个点存放在4*2的二维数组points中.编写一个程序,提示用户输入4个点,并显示交点 题目 题目描述 破题 代码 本题运行实例 题目 题目 ...
- python构建二维数组_Python中创建二维数组
二维数组 二维数组本质上是以数组作为数组元素的数组,即"数组的数组",类型说明符 数组名[常量表达式][常量表达式].二维数组又称为矩阵,行列数相等的矩阵称为方阵.对称矩阵a[i] ...
- 将一个数组a的行和列的元素互换,存到另一个二维数组b中
将一个数组a的行和列的元素互换,存到另一个二维数组b中 #include<stdio.h> int main() { int a[2][3]={{1,2,3},{4,5,6}}; int ...
- c语言二维数组a中,a,a[0],a[0][0]的值与值的类型
c语言二维数组中的一些表达式的值与意义的问题 前两天写代码的时候遇到一些关于数组的问题,进而对二维数组进行了一些深入的思考.想到了一个有意思的问题. 在二维数组a中,&a,&a[0], ...
- php循环构建二维数组,php循环生成二维数组
程序中定义了二维数组arr,arr有3行4列共12个元素,程序中采用for循环语句的嵌套来计算数组中各个元素的和,并将结果保存在sum变量中,最后打印输出结果. public ...... 1. 从数 ...
- python list二维数组_python中的二维数组和lamda
原博文 2016-11-16 15:15 − python列表推导式 list=[[0 for i in xrange(3)] for j in xrange(4)] 二维数组 g=lambda x, ...
- js二维数组arr中表示读取第i行第j列的是:_c++ c语言 数组与字符串
c语法7 - 数组与字符串 概述 定义:把具有相同类型的若干变量按有序形式组织起来称为数组. C语言数组属于构造数据类型.一个数组可以分解为多个数组元素,这些数组元素可以是基本数据类型或是构造类型.因 ...
最新文章
- CSS Grid 网格布局全解析
- RHEL5 RHEL6升级GCC
- UVA 1613 K-Graph Oddity K度图着色 (构造)
- java8 java9 接口 interface
- Windows Phone 7中用好Silverlig“.NET研究”ht开发利器
- 直面PHP微服务架构挑战
- 数据结构-在O(1)时间删除链表节点
- 对ObjectMapper的理解及延伸
- 微软开发无人店技术叫阵Amazon Go,以后沃尔玛也能拿了就走?
- weblogic domain的安装与配置
- java double 初始化_java语言程序员之正确的初始化
- NRF52840开发注意
- 【力扣面试】面试题 04.02. 最小高度树(就是创建二叉平衡树)
- Java、JSP房产中介房屋信息管理系统
- STM32单片机bootloader扫盲
- 浏览器主页被hao123劫持之解决方案
- 联想计算机设置恢复出厂,联想电脑恢复出厂设置还原系统攻略
- 读《多头自注意力层和卷积层的关系》笔记
- php处理小米广告平台API上报方案对接(主要是APP下载)
- C# 淘宝商品微信返利助手开发-(二)返利助手开放文档以及帐号申请地址