private void RenderCache_IterateMaterial(int materialIndex) {
	// Set up context variables
	KeyValuePair<Material, ModelInstanceManager.MIDArray> currentKVP = currentInstanceData[materialIndex];
	Material currentMaterial = currentKVP.Key;
	ModelInstanceManager.MIDArray currentMID = currentKVP.Value;

	// Skip this material if it or its shader are disposed
	if (currentMaterial.IsDisposed || currentMaterial.Shader.IsDisposed) return;

	// Skip this material if we're not using it
	bool inUse = false;
	for (int i = 0; i < currentMID.Length; ++i) {
		if (currentMID.Data[i].InUse) {
			inUse = true;
			break;
		}
	}
	if (!inUse) return;

	// Prepare shader according to material params, and switch to it or update it
	if (lastSetFragmentShader != currentMaterial.Shader || lastFrameNum != frameNum) {
		lastSetFragmentShader = currentMaterial.Shader;
		lastFrameNum = frameNum;
		QueueShaderSwitch(lastSetFragmentShader);
	}
	var queuedSRP = currentMaterial.FragmentShaderResourcePackage;
	if (lastSetFragmentShader == geomFSWithShadowSupport) {
		if (modifiedSRP == null) modifiedSRP = new ShaderResourcePackage();
		modifiedSRP.CopyFrom(queuedSRP);
		modifiedSRP.SetValue((ResourceViewBinding) lastSetFragmentShader.GetBindingByIdentifier("ShadowMap"), previousShadowBufferSRV);
		queuedSRP = modifiedSRP;
	}
	QueueShaderResourceUpdate(lastSetFragmentShader, queuedSRP);

	// Filter & sort
	if (materialFilteringWorkspace == null || materialFilteringWorkspace.Length < currentCache.NumModels) {
		materialFilteringWorkspace = new List<Transform>[currentCache.NumModels];
		for (int i = 0; i < materialFilteringWorkspace.Length; ++i) materialFilteringWorkspace[i] = new List<Transform>();
	}
	for (int i = 0; i < materialFilteringWorkspace.Length; ++i) materialFilteringWorkspace[i].Clear();

	SortByProximityToCamera(currentMID);
	uint numInstances = 0U;
	for (uint i = 0U; i < currentMID.Length; ++i) {
		ModelInstanceData curMID = sortedModelData[i];
		if (!curMID.InUse) continue;
		SceneLayer layer = currentSceneLayers[curMID.SceneLayerIndex];
		if (layer == null || !layer.GetRenderingEnabled() || !addedSceneLayers.Contains(layer)) continue;

		if (curMID.ModelIndex == __VEGG_MH.ModelIndex && currentCache.ID == __VEGG_MH.GeoCacheID) {
			int instanceIndex = 0;
			for (int j = 0; j < currentMID.Length; ++j) {
				if (currentMID.Data[j].Transform == curMID.Transform) {
					instanceIndex = j;
					break;
				}
			}
			Quaternion rot = Quaternion.IDENTITY;
			foreach (var kvp in __VEGG_MIH_ARR) {
				if (kvp.Key.InstanceIndex == instanceIndex) {
					rot = kvp.Value;
					break;
				}
			}
			materialFilteringWorkspace[curMID.ModelIndex].Add(curMID.Transform.RotateBy(rot));
		}
		else materialFilteringWorkspace[curMID.ModelIndex].Add(curMID.Transform);
		++numInstances;
	}

	// Concatenate & queue render commands
	if (instanceConcatWorkspace == null || instanceConcatWorkspace.Length < numInstances) {
		instanceConcatWorkspace = new Matrix[numInstances << 1]; // x2 so we don't create loads of garbage if the count keeps increasing by 1
	}

	uint instanceStartOffset = RenderCache_IterateMaterial_ConcatReserve(numInstances);
	uint nextWorkspaceIndex = 0;
	uint outVBStartIndex, outIBStartIndex, outVBCount, outIBCount;

	for (uint mI = 0U; mI < materialFilteringWorkspace.Length; ++mI) {
		List<Transform> filteredTransformList = materialFilteringWorkspace[mI];
		int numFilteredTransforms = filteredTransformList.Count;
		if (numFilteredTransforms == 0) continue;

		currentCache.GetModelBufferValues(mI, out outVBStartIndex, out outIBStartIndex, out outVBCount, out outIBCount);

		QueueRenderCommand(RenderCommand.DrawIndexedInstanced(
			(int) outVBStartIndex,
			outIBStartIndex,
			outIBCount,
			nextWorkspaceIndex + instanceStartOffset,
			(uint) numFilteredTransforms
		));

		for (int iI = 0; iI < numFilteredTransforms; ++iI) {
			if (mI == __EGGHACK_MH.ModelIndex && currentCache.ID == __EGGHACK_MH.GeoCacheID) {
				instanceConcatWorkspace[nextWorkspaceIndex++] = filteredTransformList[iI].RotateBy(__EGGHACK_ROT).AsMatrixTransposed;
			}
			else instanceConcatWorkspace[nextWorkspaceIndex++] = filteredTransformList[iI].AsMatrixTransposed;
		}
	}

	RenderCache_IterateMaterial_Concat(instanceConcatWorkspace, instanceStartOffset, numInstances);
}