/** * This function assumes that the old colours are passed as 8bit and new colours are passed in float32 with range (0-1) * In our case: the buffer has HDR with float32 but we use 8bit png values to compare because it helps avoid * floating point errors * * PARAM: Octane Pixel Buffer, * number of channels of image in pixel buffer, * old colours are to be changed for * new colours (e.g. all 1.0, 1.0, 1.0 for 0.0, 0.0, 0.0) * * RETR: Unity Texture2D (can be encoded as png to be saved as bytes) */ public static Texture2D CorrectColoursOnPixelBuffer(Octane.Renderer.PixelBuffer pb, int channels, Color[] oldColours, Color[] newColours, bool verbose = false) { if (pb == null) { throw new System.ArgumentNullException("Pixel Buffer is null. Render pass might not have been found", "pb"); } IntPtr pixels = pb.Pixels; Texture2D tex = new Texture2D((int)pb.ResX, (int)pb.ResY); int counter = 0; int minColourIndex = System.Math.Min(oldColours.Length, newColours.Length); if (verbose) { Debug.Log(String.Format("Pixel Buffer Info -> Sizes: {0}, {1}. Format: {2}", pb.ResX, pb.ResY, pb.OctaneImageFormat)); } unsafe { for (int i = 0; i < pb.ResY; i++) { float *pI = (float *)pixels.ToPointer() + i * pb.ResX * channels; //pointer to start of row for (int j = 0; j < pb.ResX; j++) { for (int k = 0; k < minColourIndex; k++) { // We don't care about the old alpha if ((int)(255 * pI[j * channels + 0]) == (int)(255 * oldColours[k].r) && (int)(255 * pI[j * channels + 1]) == (int)(255 * oldColours[k].g) && (int)(255 * pI[j * channels + 2]) == (int)(255 * oldColours[k].b)) { counter++; tex.SetPixel(j, i, newColours[k]); } else { tex.SetPixel(j, i, new Color(pI[j * channels + 0], pI[j * channels + 1], pI[j * channels + 2], pI[j * channels + 3])); } } } } } if (verbose) { Debug.Log(String.Format("{0} pixels changed", counter)); } return(tex); }
static void Correct_colours() { Octane.Renderer.PixelBuffer pb = Octane.Renderer.GetPixels(Octane.RenderPassId.RENDER_PASS_RENDER_LAYER_ID); if (pb == null) { throw new System.ArgumentNullException("No Render Layer ID render pass found", "pb"); } string sd_path = Application.dataPath; string savepath = "E:\\Dan\\Projects"; // This method reads the given pixel buffer to copy it into a Texture2D with the correct format // (in our case PNG8 for the old colours and float32 for the new ones) and returns the texture Color[] oldC = { new Color((float)186 / 255.0f, 0.0f, 0.0f, 1.0f) }; Color[] newC = { new Color((float)142 / 255.0f, 0.0f, 0.0f, 1.0f) }; Texture2D tex = CorrectColoursOnPixelBuffer(pb, 4, oldC, newC); File.WriteAllBytes(savepath + "\\corrected.png", tex.EncodeToPNG()); }
// Update is called once per frame void Update() { float t_since_start = (float)(Math.Round((double)Time.time - start_time, 3)); // Custom state machine to handle which image is being rendered for the composition, // whether the models are loaded, which mode is on, which is the current iteration if (restarted) { if (i_img < imgCount) { target = sd_path + paramList[i_img].imgName + ".json"; Debug.Log(m_standby); if (m_standby < 3) { if (m_standby < 1) { Debug.Log("Setting first scene"); setScene(); m_standby++; } else if (m_standby == 1) { m_standby++; StartCoroutine(OpenTheGates(m_waittime)); } } else { if (FinishedRendering()) { if (AllClear()) { string fullPath = outputPath + "/" + paramList[i_img].imgName + "_" + m_currStage + ".exr"; Debug.Log(String.Format("{0}/{1} - Name: {2} - Saving: {3}\nFull Path: {4}", i_img + 1, imgCount, paramList[i_img].imgName, m_currStage, fullPath)); if (m_currStage == "alpha") { string semanticPath = outputPath + "/" + paramList[i_img].imgName + "_semantic.png"; Debug.Log(String.Format("{0}/{1} - Name: {2} - Saving: {3}\nFull Path: {4}", i_img + 1, imgCount, paramList[i_img].imgName, "semantic", semanticPath)); Octane.Renderer.PixelBuffer pb = Octane.Renderer.GetPixels(Octane.RenderPassId.RENDER_PASS_RENDER_LAYER_ID); if (pb == null) { throw new System.ArgumentNullException("No Render Layer ID render pass found", "pb"); } Color[] oldC = SemanticTools.GetOldColoursByObj(paramList[i_img].obj); Color[] newC = SemanticTools.GetNewColoursByObj(paramList[i_img].obj); Texture2D tex = CorrectColoursOnPixelBuffer(pb, 4, oldC, newC); File.WriteAllBytes(semanticPath, tex.EncodeToPNG()); } Octane.Renderer.SaveImage(Octane.RenderPassId.RENDER_PASS_BEAUTY, fullPath, Octane.ImageSaveType.IMAGE_SAVE_TYPE_EXR16, true); switch (m_currStage) { case "irpv": m_currStage = "ir"; setIR(); break; case "ir": m_currStage = "irpv"; setIRPV(); i_img++; if (i_img < imgCount) { m_obj = FindInCOArrayByName(paramList[i_img].objName); setScene(); // Crashed here due to this being right after i++ } break; case "alpha": setAlpha(); i_img++; if (i_img < imgCount) { m_obj = FindInCOArrayByName(paramList[i_img].objName); setScene(); } break; default: throw new System.ArgumentException("Stage not recognised", "m_currStage"); } if (i_img < imgCount) { restarted = false; m_waittime = 5; reset = false; } } else { ResetStage(); } } } } else { float rounded_timedelta = (float)(Math.Round((double)Time.time - start_time, 3)); Debug.Log(String.Format("Finished rendering!\nTime elapsed: {0}s", rounded_timedelta)); if (composeOnFinish) { RunSynthetizenBatch(); } Application.Quit(); // Doesn't quit in Editor mode, but I left it just in case UnityEditor.EditorApplication.isPlaying = false; } } else { restarted = Octane.Renderer.SampleCount < m_MaxSamplesPerPixel; // 128; if (!restarted && !reset) { setScene(); Octane.Renderer.Restart(); m_standby = 1; reset = true; } Debug.Log(String.Format("Restarted: {0}", restarted)); Debug.Log(String.Format("Reset: {0}", reset)); } }