/// <summary> /// Sets the specified cull value to the object at results index /// </summary> /// <param name="value">Value</param> /// <param name="index">Results index</param> /// <param name="item">Object</param> private void SetCullValue(CullData value, int index, ICullable item, bool force) { if (!this.Objects.ContainsKey(item)) { this.Objects.Add(item, new List <CullData>(index + 1)); } var values = this.Objects[item]; if (values.Count <= index) { var valuesToAdd = new CullData[index - values.Count + 1]; values.AddRange(valuesToAdd); } if (force) { // Culled values stay untouched if (values[index].Culled) { values[index] = value; } } else { values[index] = value; } }
void AddBatch(int offset, int count, float3[] pos, quaternion[] rot, float3[] scale) { AABB localbound; localbound.Center = this._mesh.mesh.bounds.center; localbound.Extents = _mesh.mesh.bounds.extents; MaterialPropertyBlock block = new MaterialPropertyBlock(); var colors = new NativeArray <Vector4>(3, Allocator.Temp); colors[0] = (new Vector4(Color.red.r, Color.red.g, Color.red.b, Color.red.a)); colors[1] = (new Vector4(Color.yellow.r, Color.yellow.g, Color.yellow.b, Color.yellow.a)); colors[2] = (new Vector4(Color.blue.r, Color.blue.g, Color.blue.b, Color.blue.a)); block.SetVectorArray("_Color", colors.ToArray()); var batchIndex = _batchRendererGroup.AddBatch(_mesh.mesh, 0, _material, 0, ShadowCastingMode.On, true, false, new Bounds(Vector3.zero, 1000 * Vector3.one), count, null, null); // _batchRendererGroup.SetInstancingData(batchIndex,count,block); int colorArrayIndex = Shader.PropertyToID("_Color_Array"); float *nativePtr = null; var arr4 = _batchRendererGroup.GetBatchVectorArray(batchIndex, colorArrayIndex); nativePtr = (float *)arr4.GetUnsafePtr(); UnsafeUtility.MemCpy(nativePtr, (float *)colors.GetUnsafePtr(), UnsafeUtility.SizeOf <float4>() * count); // colors.Dispose(); var matrices = _batchRendererGroup.GetBatchMatrices(batchIndex); for (int i = 0; i < count; i++) { matrices[i] = float4x4.TRS(pos[i], rot[i], scale[i]); var aabb = AABB.Transform(matrices[i], localbound); _cullDatas[offset + i] = new CullData() { bound = aabb, position = pos[i], minDistance = 0, maxDistance = 100 }; } }
public void UpdateRectangles() { this.UpdateCullRect(); for (int n = 0, count = this.list.Count; n < count; ++n) { CullData data = this.list[n]; if (!data.IsEnabled || !data.Target) { continue; } data.Update(); } }
/// <summary> /// Performs cull test in the object list against the culling volume /// </summary> /// <param name="volume">Culling volume</param> /// <param name="index">Results index</param> /// <param name="objects">Objects list</param> /// <returns>Returns true if any object results inside the volume</returns> public bool Cull(ICullingVolume volume, int index, IEnumerable <ICullable> objects) { bool res = false; foreach (var item in objects) { var cull = item.Cull(volume, out float distance); var cullData = new CullData { Culled = cull, Distance = distance, }; this.SetCullValue(cullData, index, item, false); if (!cullData.Culled) { res = true; } } return(res); }
// NOTE: for performance! (duplicated code) public void UpdateVisibles() { Rect area = this.UpdateCullRect(); for (int n = 0, count = this.list.Count; n < count; ++n) { CullData data = this.list[n]; if (!data.IsEnabled) { continue; } if (!data.IsValid) { continue; } data.Update(); Rect rect = data.Rect; if (area.xMin < rect.xMax && area.xMax > rect.xMin && area.yMin < rect.yMax && area.yMax > rect.yMin) { if (!data.IsActivated) { data.SetActive(true); } } else { if (data.IsActivated) { data.SetActive(false); } } } }
private void AddBatch(Mesh mesh, Material mat, BatchParameters param, ref int cullOffset) { MaterialPropertyBlock matBlock = new MaterialPropertyBlock(); matBlock.SetVectorArray("_PerInstanceColor", param.Colors); var batchIndex = this.batchRendererGroup.AddBatch(mesh, 0, mat, 0, ShadowCastingMode.On, true, false, param.Bnd, param.InstanceCount, matBlock, null); var batchMatrices = this.batchRendererGroup.GetBatchMatrices(batchIndex); var pos = new float4(0, 0, 0, 1); for (int i = 0; i < param.InstanceCount; i++) { batchMatrices[i] = param.Matrices[i]; cullData[cullOffset + i] = new CullData() { extents = 0.5f * param.Bnd.size, position = math.mul(param.Matrices[i], pos).xyz, minDistance = 0, maxDistance = detailDistance, }; } cullOffset += param.InstanceCount; }
void UpdateData() { AABB localbound; localbound.Center = this._mesh.mesh.bounds.center; localbound.Extents = _mesh.mesh.bounds.extents; var pos = new float3[4]; var rot = new quaternion[4]; var scale = new float3[4]; for (int i = 0; i < 4; i++) { pos[i] = new float3(i * 2, updateIndex, 0); rot[i] = quaternion.identity; scale[i] = new float3(1, 1, 1); } _batchRendererGroup.SetInstancingData(updateIndex, 4, null); int colorArrayIndex = Shader.PropertyToID("_Color_Array"); float *nativePtr = null; var arr4 = _batchRendererGroup.GetBatchVectorArray(updateIndex, colorArrayIndex); nativePtr = (float *)arr4.GetUnsafePtr(); var colors = new NativeArray <Vector4>(4, Allocator.Temp); colors[1] = (new Vector4(Color.red.r, Color.red.g, Color.red.b, Color.red.a)); colors[2] = (new Vector4(Color.yellow.r, Color.yellow.g, Color.yellow.b, Color.yellow.a)); colors[0] = (new Vector4(Color.blue.r, Color.blue.g, Color.blue.b, Color.blue.a)); colors[3] = Color.cyan; UnsafeUtility.MemCpy(nativePtr, (float *)colors.GetUnsafePtr(), UnsafeUtility.SizeOf <float4>() * 4); var matrices = _batchRendererGroup.GetBatchMatrices(updateIndex); NativeMultiHashMapIterator <int> it; CullData cullData; bool has = _cullDic.TryGetFirstValue(updateIndex, out cullData, out it); for (int i = 0; i < 4; i++) { matrices[i] = float4x4.TRS(pos[i], rot[i], scale[i]); var aabb = AABB.Transform(matrices[i], localbound); if (i > 0) { has = _cullDic.TryGetNextValue(out cullData, ref it); } if (!has) { _cullDic.Add(updateIndex, new CullData() { bound = aabb, position = pos[i], minDistance = 0, maxDistance = 10 }); } else { cullData = new CullData() { bound = aabb, position = pos[i], minDistance = 0, maxDistance = 10 }; } } updateIndex++; }
private void AddBatch(int offset, int count, float3[] pos, quaternion[] rot, float3[] scale) { var localBound = mesh.bounds; var block = new MaterialPropertyBlock(); var colors = new List <Vector4>(count); for (int i = 0; i < count; i++) { colors.Add(new Vector4(Random.value, Random.value, Random.value, Random.value)); } // 因为srp batcher buffer的关系 instance buffer 会混乱 // block.SetVectorArray(BaseColor_ID, colors); //下面的Bounds是需要组合过的 var batchIndex = batchRendererGroup.AddBatch( mesh, 0, material, 0, ShadowCastingMode.On, true, false, new Bounds(Vector3.zero, 1000 * Vector3.one), count, block, null ); var matrices = batchRendererGroup.GetBatchMatrices(batchIndex); for (int i = 0; i < count; i++) { float4x4 tempMatrix = float4x4.TRS(pos[i], rot[i], scale[i]); Bounds aabb = OtherUtils.Transform(tempMatrix, localBound); tempMatrix.c0.w = colors[i].x; tempMatrix.c1.w = colors[i].y; tempMatrix.c2.w = colors[i].z; tempMatrix.c3.w = colors[i].w; matrices[i] = tempMatrix; cullData[offset + i] = new CullData() { bound = aabb, position = pos[i], minDistance = 0, maxDistance = lodDis }; } //----------------- for (int i = 0; i < count; i++) { colors[i] = (new Vector4(Random.value, Random.value, Random.value, Random.value)); } // 因为srp batcher buffer的关系 instance buffer 会混乱 // block.SetVectorArray(BaseColor_ID, colors); //https://docs.unity3d.com/ScriptReference/Rendering.BatchRendererGroup.AddBatch.html //下面的Bounds是需要组合过的 batchIndex = batchRendererGroup.AddBatch( lowMesh, 0, material, 0, ShadowCastingMode.On, true, false, new Bounds(Vector3.zero, 1000 * Vector3.one), count, block, null ); matrices = batchRendererGroup.GetBatchMatrices(batchIndex); for (int i = 0; i < count; i++) { var tempMatrix = float4x4.TRS(pos[i], rot[i], scale[i]); Bounds aabb = OtherUtils.Transform(tempMatrix, localBound); tempMatrix.c0.w = colors[i].x; tempMatrix.c1.w = colors[i].y; tempMatrix.c2.w = colors[i].z; tempMatrix.c3.w = colors[i].w; matrices[i] = tempMatrix; cullData[offset + count + i] = new CullData() { bound = aabb, position = pos[i], minDistance = lodDis, maxDistance = 10000, }; } }
public static void Export(GameObject[] gameObjects, string saveFileName, ExportSettings settings) { MeshConverter.ClearCaches(); TextureConverter.ClearCaches(); MaterialConverter.ClearCaches(); ShaderMappingIO.ClearCaches(); GraphBuilderInterface.unity2vsg_BeginExport(); List <PipelineData> storePipelines = new List <PipelineData>(); bool insideLODGroup = false; bool firstNodeAdded = false; System.Action <GameObject> processGameObject = null; processGameObject = (GameObject go) => { // determine the gameObject type Transform gotrans = go.transform; bool nodeAdded = false; // does it have a none identiy local matrix if (gotrans.localPosition != Vector3.zero || gotrans.localRotation != Quaternion.identity || gotrans.localScale != Vector3.one) { if (firstNodeAdded || !settings.zeroRootTransform) { // add as a transform TransformData transformdata = TransformConverter.CreateTransformData(gotrans); GraphBuilderInterface.unity2vsg_AddTransformNode(transformdata); nodeAdded = true; } } // do we need to insert a group if (!nodeAdded)// && gotrans.childCount > 0) { //add as a group GraphBuilderInterface.unity2vsg_AddGroupNode(); nodeAdded = true; } firstNodeAdded = true; bool meshexported = false; // get the meshrender here so we can check if the LOD exports the the mesh MeshFilter meshFilter = go.GetComponent <MeshFilter>(); MeshRenderer meshRenderer = go.GetComponent <MeshRenderer>(); // does this node have an LOD group LODGroup lodgroup = go.GetComponent <LODGroup>(); if (lodgroup != null && !insideLODGroup) { // rather than process the children we figure out which renderers are in which children and add them as LOD children LOD[] lods = lodgroup.GetLODs(); if (lods.Length > 0) { // get bounds from first renderer if (lods[0].renderers.Length > 0) { CullData lodCullData = new CullData(); Bounds bounds = new Bounds(lods[0].renderers[0].bounds.center, lods[0].renderers[0].bounds.size); foreach (Renderer boundsrenderer in lods[0].renderers) { if (boundsrenderer != null) { bounds.Encapsulate(boundsrenderer.bounds); } } Vector3 center = bounds.center - gotrans.position; CoordSytemConverter.Convert(ref center); lodCullData.center = NativeUtils.ToNative(center); lodCullData.radius = bounds.size.magnitude * 0.5f; GraphBuilderInterface.unity2vsg_AddLODNode(lodCullData); insideLODGroup = true; for (int i = 0; i < lods.Length; i++) { // for now just support one renderer and assume it's under a seperate child gameObject if (lods[i].renderers.Length == 0) { continue; } LODChildData lodChild = new LODChildData(); lodChild.minimumScreenHeightRatio = lods[i].screenRelativeTransitionHeight; GraphBuilderInterface.unity2vsg_AddLODChild(lodChild); foreach (Renderer lodrenderer in lods[i].renderers) { if (lodrenderer == meshRenderer) { meshexported = true; ExportMesh(meshFilter.sharedMesh, meshRenderer, gotrans, settings, storePipelines); } else if (lodrenderer != null) { // now process the renderers gameobject, it'll be added to the group we just created by adding an LOD child processGameObject(lodrenderer.gameObject); } } GraphBuilderInterface.unity2vsg_EndNode(); } insideLODGroup = false; GraphBuilderInterface.unity2vsg_EndNode(); // end the lod node } } } else { // transverse any children for (int i = 0; i < gotrans.childCount; i++) { processGameObject(gotrans.GetChild(i).gameObject); } } // does it have a mesh if (!meshexported && meshFilter && meshFilter.sharedMesh && meshRenderer) { Mesh mesh = meshFilter.sharedMesh; ExportMesh(mesh, meshRenderer, gotrans, settings, storePipelines); } // does this node have a terrain Terrain terrain = go.GetComponent <Terrain>(); if (terrain != null) { ExportTerrainMesh(terrain, settings, storePipelines); } // if we added a group or transform step out if (nodeAdded) { GraphBuilderInterface.unity2vsg_EndNode(); } }; foreach (GameObject go in gameObjects) { processGameObject(go); } //GraphBuilderInterface.unity2vsg_EndNode(); // step out of convert coord system node GraphBuilderInterface.unity2vsg_EndExport(saveFileName); NativeLog.PrintReport(); }
private static void ExportMesh(Mesh mesh, MeshRenderer meshRenderer, Transform gotrans, ExportSettings settings, List <PipelineData> storePipelines = null) { bool addedCullGroup = false; if (settings.autoAddCullNodes) { CullData culldata = new CullData(); Vector3 center = meshRenderer.bounds.center - gotrans.position; CoordSytemConverter.Convert(ref center); culldata.center = NativeUtils.ToNative(center); culldata.radius = meshRenderer.bounds.size.magnitude * 0.5f; GraphBuilderInterface.unity2vsg_AddCullGroupNode(culldata); addedCullGroup = true; } // Material[] materials = meshRenderer.sharedMaterials; if (mesh != null && mesh.isReadable && mesh.vertexCount > 0 && mesh.GetIndexCount(0) > 0) { int meshid = mesh.GetInstanceID(); MeshInfo meshInfo = MeshConverter.GetOrCreateMeshInfo(mesh); int subMeshCount = mesh.subMeshCount; // shader instance id, Material Data, sub mesh indicies Dictionary <int, Dictionary <MaterialInfo, List <int> > > meshMaterials = new Dictionary <int, Dictionary <MaterialInfo, List <int> > >(); for (int matindex = 0; matindex < materials.Length && matindex < subMeshCount; matindex++) { Material mat = materials[matindex]; if (mat == null) { continue; } MaterialInfo matdata = MaterialConverter.GetOrCreateMaterialData(mat); int matshaderid = matdata.shaderStages.id; if (!meshMaterials.ContainsKey(matshaderid)) { meshMaterials.Add(matshaderid, new Dictionary <MaterialInfo, List <int> >()); } if (!meshMaterials[matshaderid].ContainsKey(matdata)) { meshMaterials[matshaderid].Add(matdata, new List <int>()); } meshMaterials[matshaderid][matdata].Add(matindex); } if (subMeshCount > 1) { // create mesh data, if the mesh has already been created we only need to pass the ID to the addGeometry function foreach (int shaderkey in meshMaterials.Keys) { List <MaterialInfo> mds = new List <MaterialInfo>(meshMaterials[shaderkey].Keys); if (mds.Count == 0) { continue; } // add stategroup and pipeline for shader GraphBuilderInterface.unity2vsg_AddStateGroupNode(); PipelineData pipelineData = NativeUtils.CreatePipelineData(meshInfo); //WE NEED INFO ABOUT THE SHADER SO WE CAN BUILD A PIPLE LINE pipelineData.descriptorBindings = NativeUtils.WrapArray(mds[0].descriptorBindings.ToArray()); pipelineData.shaderStages = mds[0].shaderStages.ToNative(); pipelineData.useAlpha = mds[0].useAlpha; pipelineData.id = NativeUtils.ToNative(NativeUtils.GetIDForPipeline(pipelineData)); storePipelines.Add(pipelineData); if (GraphBuilderInterface.unity2vsg_AddBindGraphicsPipelineCommand(pipelineData, 1) == 1) { GraphBuilderInterface.unity2vsg_AddCommandsNode(); VertexBuffersData vertexBuffersData = MeshConverter.GetOrCreateVertexBuffersData(meshInfo); GraphBuilderInterface.unity2vsg_AddBindVertexBuffersCommand(vertexBuffersData); IndexBufferData indexBufferData = MeshConverter.GetOrCreateIndexBufferData(meshInfo); GraphBuilderInterface.unity2vsg_AddBindIndexBufferCommand(indexBufferData); foreach (MaterialInfo md in mds) { BindDescriptors(md, false); foreach (int submeshIndex in meshMaterials[shaderkey][md]) { DrawIndexedData drawIndexedData = MeshConverter.GetOrCreateDrawIndexedData(meshInfo, submeshIndex); GraphBuilderInterface.unity2vsg_AddDrawIndexedCommand(drawIndexedData); } } GraphBuilderInterface.unity2vsg_EndNode(); // step out of commands node for descriptors and draw indexed commands } GraphBuilderInterface.unity2vsg_EndNode(); // step out of stategroup node for shader } } else { List <int> sids = new List <int>(meshMaterials.Keys); if (sids.Count > 0) { List <MaterialInfo> mds = new List <MaterialInfo>(meshMaterials[sids[0]].Keys); if (mds.Count > 0) { // add stategroup and pipeline for shader GraphBuilderInterface.unity2vsg_AddStateGroupNode(); PipelineData pipelineData = NativeUtils.CreatePipelineData(meshInfo); //WE NEED INFO ABOUT THE SHADER SO WE CAN BUILD A PIPLE LINE pipelineData.descriptorBindings = NativeUtils.WrapArray(mds[0].descriptorBindings.ToArray()); pipelineData.shaderStages = mds[0].shaderStages.ToNative(); pipelineData.useAlpha = mds[0].useAlpha; pipelineData.id = NativeUtils.ToNative(NativeUtils.GetIDForPipeline(pipelineData)); storePipelines.Add(pipelineData); if (GraphBuilderInterface.unity2vsg_AddBindGraphicsPipelineCommand(pipelineData, 1) == 1) { BindDescriptors(mds[0], true); VertexIndexDrawData vertexIndexDrawData = MeshConverter.GetOrCreateVertexIndexDrawData(meshInfo); GraphBuilderInterface.unity2vsg_AddVertexIndexDrawNode(vertexIndexDrawData); GraphBuilderInterface.unity2vsg_EndNode(); // step out of vertex index draw node } GraphBuilderInterface.unity2vsg_EndNode(); // step out of stategroup node } } } } else { string reason = mesh == null ? "mesh is null." : (!mesh.isReadable ? "mesh '" + mesh.name + "' is not readable. Please enabled read/write in the models import settings." : "mesh '" + mesh.name + "' has an unknown error."); NativeLog.WriteLine("ExportMesh: Unable to export mesh for gameobject " + gotrans.gameObject.name + ", " + reason); } if (addedCullGroup) { GraphBuilderInterface.unity2vsg_EndNode(); } }
public void AddBatch(int offset, int count, float3[] pos, quaternion[] rot, float3[] scale) { AABB localBond; localBond.Center = this.mesh.bounds.center; localBond.Extents = this.mesh.bounds.extents; MaterialPropertyBlock block = new MaterialPropertyBlock(); var colors = new List <Vector4>(); for (int i = 0; i < count; i++) { colors.Add(new Vector4(UnityEngine.Random.Range(0f, 1f), UnityEngine.Random.Range(0f, 1f), UnityEngine.Random.Range(0f, 1f), UnityEngine.Random.Range(0f, 1f))); } block.SetVectorArray("_Color1", colors); var batchIndex = this.batchRendererGroup.AddBatch( this.mesh, 0, this.material, 0, ShadowCastingMode.On, true, false, new Bounds(Vector3.zero, 1000 * Vector3.one), count, block, null); var matrices = this.batchRendererGroup.GetBatchMatrices(batchIndex); for (int i = 0; i < count; i++) { matrices[i] = float4x4.TRS(pos[i], rot[i], scale[i]); var aabb = AABB.Transform(matrices[i], localBond); cullData[offset + i] = new CullData() { bound = aabb, position = pos[i], minDistance = 0, maxDistance = lodDis, }; } for (int i = 0; i < count; i++) { colors[i] = new Vector4(UnityEngine.Random.Range(0f, 1f), UnityEngine.Random.Range(0f, 1f), UnityEngine.Random.Range(0f, 1f), UnityEngine.Random.Range(0f, 1f)); } block.SetVectorArray("_Color1", colors); batchIndex = this.batchRendererGroup.AddBatch( this.lowMesh, 0, this.material, 0, ShadowCastingMode.On, true, false, new Bounds(Vector3.zero, 1000 * Vector3.one), count, block, null); matrices = this.batchRendererGroup.GetBatchMatrices(batchIndex); for (int i = 0; i < count; i++) { matrices[i] = float4x4.TRS(pos[i], rot[i], scale[i]); var aabb = AABB.Transform(matrices[i], localBond); cullData[offset + count + i] = new CullData() { bound = aabb, position = pos[i], minDistance = lodDis, maxDistance = 10000, }; } }