// Under 2ms on 512x512 textures, ~7ms with 1024x1024 textures (Deep Profiler mode), much faster in build (under 1ms) //void PaintTexture(RaycastHit hit) //{ // //UnityEngine.Debug.Log("PaintTexture"); // GlobalVariables.instance.paintInProgress = true; // Renderer rend = hit.transform.GetComponent<Renderer>(); // Stopwatch startToEndStopwatch = new Stopwatch(); // startToEndStopwatch.Start(); // int bloodType = Random.Range(1, 4); // if (rend != null) // { // Texture2D originalTex = (Texture2D)rend.material.GetTexture("_BaseMap"); //HDRP/Lit version: GetTexture("_BaseColorMap"); // if (originalTex != null && originalTex.isReadable) // { // Texture2D brush = blood1_64x64; // if (bloodType == 1) // { // brush = blood1_64x64; // } // else if (bloodType == 2) // { // brush = blood2_64x64; // } // else if (bloodType == 3) // { // brush = blood3_64x64; // } // int orgTexWidth = originalTex.width; // int orgTexHeight = originalTex.height; // // Scaling // /* // if (orgWidth > 1024) // { // brush = lowResDecal64; // } // else if (orgWidth > 512) // { // brush = lowResDecal32; // } // else // { // brush = lowResDecal16; // } // */ // int brushWidth = brush.width; // int brushHeight = brush.height; // //Debug.Log("brush width: " + brushWidth); // int uvx = (int)(hit.textureCoord.x * orgTexWidth); // int uvy = (int)(hit.textureCoord.y * orgTexHeight); // //UnityEngine.Debug.LogError("texCords: " + hit.textureCoord); // //UnityEngine.Debug.LogError("x: " + uvx + " y: " + uvy); // //UnityEngine.Debug.Log("tex cord: " + hit.textureCoord); // //Debug.Log("x: " + uvx + " y: " + uvy); // int paintStartX = uvx - (brushWidth / 2); // int paintStartY = uvy - (brushHeight / 2); // bool createNewTex = false; // Texture2D modifiedTex; // // If texture has not been edited/copied yet, create a new one // if (originalTex.updateCount == 0) // { // createNewTex = true; // modifiedTex = new Texture2D(orgTexWidth, orgTexHeight, TextureFormat.RGBA32, false);// Create copy of the original texture // modifiedTex.filterMode = FilterMode.Point; // modifiedTex.SetPixels32(originalTex.GetPixels32()); // } // // If texture has been already edited/copied, edit existing texture rather than creating a new one // else // { // modifiedTex = originalTex; // //UnityEngine.Debug.Log("Edit existing texture"); // //UnityEngine.Debug.LogError("Edit existing texture"); // //UnityEngine.Debug.Log("Existing texture update count : " + modifiedTex.updateCount); // //UnityEngine.Debug.LogError("Existing texture update count : " + modifiedTex.updateCount); // } // for (int i = 0; i < brushWidth; i++) // { // for (int j = 0; j < brushHeight; j++) // { // if (bloodType == 1) // { // Color32 c; // if (nonTransparentBlood1Pixels.TryGetValue(j * brushWidth + i, out c)) // { // modifiedTex.SetPixel(paintStartX + i, paintStartY + j, c); //brush.GetPixel(i, j)); // Alternative: Store pixel colors to Dictionary instead of using GetPixel from Texture2D? (almost the same speed, causes calls to color contructor) // } // } // else if (bloodType == 2) // { // Color32 c; // if (nonTransparentBlood2Pixels.TryGetValue(j * brushWidth + i, out c)) // { // modifiedTex.SetPixel(paintStartX + i, paintStartY + j, c); //brush.GetPixel(i, j)); // Alternative: Store pixel colors to Dictionary instead of using GetPixel from Texture2D? (almost the same speed, causes calls to color contructor) // } // } // else if (bloodType == 3) // { // Color32 c; // if (nonTransparentBlood3Pixels.TryGetValue(j * brushWidth + i, out c)) // { // modifiedTex.SetPixel(paintStartX + i, paintStartY + j, c); //brush.GetPixel(i, j)); // Alternative: Store pixel colors to Dictionary instead of using GetPixel from Texture2D? (almost the same speed, causes calls to color contructor) // } // } // } // } // modifiedTex.Apply(); // if (createNewTex) // { // rend.material.SetTexture("_BaseMap", modifiedTex); // } // else // { // } // if (Mathf.Abs(rend.transform.rotation.eulerAngles.x) > 75) // { // StartCoroutine(decalHandler.WallDrip(modifiedTex, new Vector2(uvx, uvy), bloodType)); // } // } // } // //UnityEngine.Debug.LogError("PaintTime: " + (float)startToEndStopwatch.ElapsedTicks / (float)10000f + "ms"); // paintTimes.Add((float)startToEndStopwatch.ElapsedTicks / (float)10000f); // GlobalVariables.instance.paintInProgress = false; //} // Takes 6(new texture) or 5(editing existing texture) frames to complete to reduce load on single frame //IEnumerator PaintTextureAsync(RaycastHit hit) //{ // GlobalVariables.instance.paintInProgress = true; // Stopwatch startToEndStopwatch = new Stopwatch(); // startToEndStopwatch.Start(); // Renderer rend = hit.transform.GetComponent<Renderer>(); // int bloodType = Random.Range(1, 4); // if (rend != null) // { // Texture2D originalTex = (Texture2D)rend.material.GetTexture("_BaseMap"); //HDRP/Lit version: GetTexture("_BaseColorMap"); // if (originalTex != null && originalTex.isReadable) // { // Texture2D brush = blood1_64x64; // if (bloodType == 1) // { // brush = blood1_64x64; // } // else if (bloodType == 2) // { // brush = blood2_64x64; // } // else if (bloodType == 3) // { // brush = blood3_64x64; // } // int orgTexWidth = originalTex.width; // int orgTexHeight = originalTex.height; // // Scaling // /* // if (orgWidth > 1024) // { // brush = lowResDecal64; // } // else if (orgWidth > 512) // { // brush = lowResDecal32; // } // else // { // brush = lowResDecal16; // } // */ // int brushWidth = brush.width; // int brushHeight = brush.height; // int uvx = (int)(hit.textureCoord.x * orgTexWidth); // int uvy = (int)(hit.textureCoord.y * orgTexHeight); // //UnityEngine.Debug.Log("tex cord: " + hit.textureCoord); // //Debug.Log("x: " + uvx + " y: " + uvy); // int paintStartX = uvx - (brushWidth / 2); // int paintStartY = uvy - (brushHeight / 2); // Texture2D modifiedTex; // bool createNewTex = false; // // If texture has been already edited/copied, edit existing texture rather than creating a new one // if (originalTex.updateCount == 0) // { // createNewTex = true; // modifiedTex = new Texture2D(orgTexWidth, orgTexHeight, TextureFormat.RGBA32, false);// Create copy of the original texture // modifiedTex.filterMode = FilterMode.Point; // //UnityEngine.Debug.Log("Create new texture"); // //UnityEngine.Debug.LogError("Create new texture"); // modifiedTex.SetPixels32(originalTex.GetPixels32()); // //UnityEngine.Debug.Log("original texture update count : " + modifiedTex.updateCount); // //UnityEngine.Debug.LogError("original texture update count : " + modifiedTex.updateCount); // yield return null; // } // // If texture has not been edited/copied yet, create a new one // else // { // modifiedTex = originalTex; // //UnityEngine.Debug.Log("Edit existing texture"); // //UnityEngine.Debug.LogError("Edit existing texture"); // //UnityEngine.Debug.Log("Existing texture update count : " + modifiedTex.updateCount); // //UnityEngine.Debug.LogError("Existing texture update count : " + modifiedTex.updateCount); // } // bool loop1 = false; // bool loop2 = false; // bool loop3 = false; // for (int i = 0; i < brushWidth; i++) // { // // Chop loop to 4 frames // float complete = (float)i / (float)brushWidth; // if (complete > 0.25f && !loop1) // { // loop1 = true; // yield return null; // } // else if (complete > 0.50f && !loop2) // { // loop2 = true; // yield return null; // } // else if (complete > 0.75f && !loop3) // { // loop3 = true; // yield return null; // } // for (int j = 0; j < brushHeight; j++) // { // //int pos = j * decalWidth + i; // //Color32 color = decalColorData[pos]; // if (paintStartX + i >= 0 && paintStartX + i < orgTexWidth && paintStartY + j >= 0 && paintStartY + j < orgTexHeight) // { // if (bloodType == 1) // { // Color32 c; // if (nonTransparentBlood1Pixels.TryGetValue(j * brushWidth + i, out c)) // { // modifiedTex.SetPixel(paintStartX + i, paintStartY + j, c); //brush.GetPixel(i, j)); // Alternative: Store pixel colors to Dictionary instead of using GetPixel from Texture2D? (almost the same speed, causes calls to color contructor) // } // } // else if (bloodType == 2) // { // Color32 c; // if (nonTransparentBlood2Pixels.TryGetValue(j * brushWidth + i, out c)) // { // modifiedTex.SetPixel(paintStartX + i, paintStartY + j, c); //brush.GetPixel(i, j)); // Alternative: Store pixel colors to Dictionary instead of using GetPixel from Texture2D? (almost the same speed, causes calls to color contructor) // } // } // else if (bloodType == 3) // { // Color32 c; // if (nonTransparentBlood3Pixels.TryGetValue(j * brushWidth + i, out c)) // { // modifiedTex.SetPixel(paintStartX + i, paintStartY + j, c); //brush.GetPixel(i, j)); // Alternative: Store pixel colors to Dictionary instead of using GetPixel from Texture2D? (almost the same speed, causes calls to color contructor) // } // } // } // } // } // yield return null; // modifiedTex.Apply(); // if (createNewTex) // { // rend.material.SetTexture("_BaseMap", modifiedTex); // } // else // { // //UnityEngine.Debug.Log("Existing texture update count after: " + modifiedTex.updateCount); // //UnityEngine.Debug.LogError("Existing texture update count after: " + modifiedTex.updateCount); // } // if (Mathf.Abs(rend.transform.rotation.eulerAngles.x) > 75) // { // StartCoroutine(decalHandler.WallDrip(modifiedTex, new Vector2(uvx, uvy), bloodType)); // } // } // } // paintTimes.Add((float)startToEndStopwatch.ElapsedTicks / (float)10000f); // //UnityEngine.Debug.LogError("PaintTime(Async): " + (float)startToEndStopwatch.ElapsedTicks / (float)10000f + "ms"); // //yield return null; // GlobalVariables.instance.paintInProgress = false; //} // Causes problems with paintInProgress // Execution time of this function is limited to maxvalue per frame(some single functions inside this function can still take longer) IEnumerator PaintTextureAsyncTimed(RaycastHit hit) // paintInprogress causes problems { GlobalVariables.instance.paintInProgress = true; GlobalVariables.instance.globalPaintsInProgress++; localPaintsInProgress++; int frames = 0; float maxTimePerFrame = 4f; Stopwatch stopWatch = new Stopwatch(); Stopwatch startToEndStopwatch = new Stopwatch(); //UnityEngine.Debug.Log("frq: " + Stopwatch.Frequency + "ishr: " + Stopwatch.IsHighResolution); startToEndStopwatch.Start(); stopWatch.Start(); Renderer rend = hit.transform.GetComponent <Renderer>(); int bloodType = Random.Range(0, bloodSplatSprites.Length); if (rend != null) { Texture2D originalTex = (Texture2D)rend.material.GetTexture("_BaseMap"); //HDRP/Lit version: GetTexture("_BaseColorMap"); //UnityEngine.Debug.Log("Original texture format: " + originalTex.format); if (originalTex != null && originalTex.isReadable) { float elapsedMs = 0; Texture2D brush = bloodSplatSprites[bloodType]; //blood1_64x64; //if (bloodType == 1) //{ // brush = blood1_64x64; //} //else if (bloodType == 2) //{ // brush = blood2_64x64; //} //else if (bloodType == 3) //{ // brush = blood3_64x64; //} int orgTexWidth = originalTex.width; int orgTexHeight = originalTex.height; // Scaling /* * if (orgWidth > 1024) * { * brush = lowResDecal64; * } * else if (orgWidth > 512) * { * brush = lowResDecal32; * } * else * { * brush = lowResDecal16; * } */ int brushWidth = brush.width; int brushHeight = brush.height; //Debug.Log("brush width: " + brushWidth); int uvx = (int)(hit.textureCoord.x * orgTexWidth); int uvy = (int)(hit.textureCoord.y * orgTexHeight); //UnityEngine.Debug.Log("tex cord: " + hit.textureCoord); //Debug.Log("x: " + uvx + " y: " + uvy); int paintStartX = uvx - (brushWidth / 2); int paintStartY = uvy - (brushHeight / 2); Texture2D modifiedTex; bool createNewTex = false; // If texture has not been edited/copied yet, create a new one if (originalTex.updateCount == 0) { createNewTex = true; modifiedTex = new Texture2D(orgTexWidth, orgTexHeight, TextureFormat.RGBA32, false);// Create copy of the original texture modifiedTex.filterMode = FilterMode.Point; Color32[] newColors = originalTex.GetPixels32(); elapsedMs = (float)stopWatch.ElapsedTicks / (float)10000f; // Tick is 100ns. 10K ticks = 1ms if (elapsedMs > maxTimePerFrame) { frames++; stopWatch.Reset(); startToEndStopwatch.Stop(); yield return(null); startToEndStopwatch.Start(); stopWatch.Start(); } modifiedTex.SetPixels32(newColors); elapsedMs = (float)stopWatch.ElapsedTicks / (float)10000f; // Tick is 100ns. 10K ticks = 1ms if (elapsedMs > maxTimePerFrame) { frames++; stopWatch.Reset(); startToEndStopwatch.Stop(); yield return(null); startToEndStopwatch.Start(); stopWatch.Start(); } } // If texture has been already edited/copied, edit existing texture rather than creating a new one else { modifiedTex = originalTex; //UnityEngine.Debug.Log("Edit existing texture"); //UnityEngine.Debug.LogError("Edit existing texture"); //UnityEngine.Debug.Log("Existing texture update count : " + modifiedTex.updateCount); //UnityEngine.Debug.LogError("Existing texture update count : " + modifiedTex.updateCount); } for (int i = 0; i < brushWidth; i++) { elapsedMs = (float)stopWatch.ElapsedTicks / (float)10000f; // Tick is 100ns. 10K ticks = 1ms if (elapsedMs > maxTimePerFrame) { frames++; stopWatch.Reset(); startToEndStopwatch.Stop(); yield return(null); startToEndStopwatch.Start(); stopWatch.Start(); } for (int j = 0; j < brushHeight; j++) { //int pos = j * decalWidth + i; //Color32 color = decalColorData[pos]; if (paintStartX + i >= 0 && paintStartX + i < orgTexWidth && paintStartY + j >= 0 && paintStartY + j < orgTexHeight) { Color32 c; if (bloodSplatDictionaries[bloodType].TryGetValue(j * brushWidth + i, out c)) { modifiedTex.SetPixel(paintStartX + i, paintStartY + j, c); //brush.GetPixel(i, j)); // Alternative: Store pixel colors to Dictionary instead of using GetPixel from Texture2D? (almost the same speed, causes calls to color contructor) } //if (bloodType == 1) //{ // Color32 c; // if (nonTransparentBlood1Pixels.TryGetValue(j * brushWidth + i, out c)) // { // modifiedTex.SetPixel(paintStartX + i, paintStartY + j, c); //brush.GetPixel(i, j)); // Alternative: Store pixel colors to Dictionary instead of using GetPixel from Texture2D? (almost the same speed, causes calls to color contructor) // } //} //else if (bloodType == 2) //{ // Color32 c; // if (nonTransparentBlood2Pixels.TryGetValue(j * brushWidth + i, out c)) // { // modifiedTex.SetPixel(paintStartX + i, paintStartY + j, c); //brush.GetPixel(i, j)); // Alternative: Store pixel colors to Dictionary instead of using GetPixel from Texture2D? (almost the same speed, causes calls to color contructor) // } //} //else if (bloodType == 3) //{ // Color32 c; // if (nonTransparentBlood3Pixels.TryGetValue(j * brushWidth + i, out c)) // { // modifiedTex.SetPixel(paintStartX + i, paintStartY + j, c); //brush.GetPixel(i, j)); // Alternative: Store pixel colors to Dictionary instead of using GetPixel from Texture2D? (almost the same speed, causes calls to color contructor) // } //} } } } // Apply() is approx 0.7ms for 512x512 texture so this last yield might not be needed //elapsedMs = (float)stopWatch.ElapsedTicks / (float)10000f; // Tick is 100ns. 10K ticks = 1ms //if (elapsedMs > maxTimePerFrame / 1.5) // For larger textures it might be benefitical to have smaller than max value here so that long loop portion doesnt get chained with Apply() //{ // frames++; // stopWatch.Reset(); // yield return null; // stopWatch.Start(); //} modifiedTex.Apply(); if (createNewTex) { rend.material.SetTexture("_BaseMap", modifiedTex); //UnityEngine.Debug.Log("new texture update count after: " + modifiedTex.updateCount); //UnityEngine.Debug.LogError("new texture update count after: " + modifiedTex.updateCount); //UnityEngine.Debug.Log("new: " + modifiedTex.updateCount); //UnityEngine.Debug.Log("orgAfter: " + modifiedTex.updateCount); } else { //UnityEngine.Debug.Log("Existing texture update count after: " + modifiedTex.updateCount); //UnityEngine.Debug.LogError("Existing texture update count after: " + modifiedTex.updateCount); } //UnityEngine.Debug.Log(Mathf.Abs(rend.transform.rotation.eulerAngles.x)); if (Mathf.Abs(rend.transform.rotation.eulerAngles.x) > 75) { //StartCoroutine(WallDrip(modifiedTex, new Vector2(uvx, uvy))); //StartCoroutine(decalHandler.WallDrip(modifiedTex, new Vector2(uvx, uvy))); // Problem //StartWallDripCoroutine(modifiedTex, new Vector2(uvx, uvy)); DecalHandler.wallDripStruct wds = new DecalHandler.wallDripStruct(); wds.tex = modifiedTex; wds.uv = new Vector2(uvx, uvy); wds.bloodType = bloodType; decalHandler.wallDripQueue.Enqueue(wds); } } } timeInInstance += (float)startToEndStopwatch.ElapsedTicks / (float)10000f; paintTimes.Add((float)startToEndStopwatch.ElapsedTicks / (float)10000f); //UnityEngine.Debug.LogError("PaintTime(TimedAsync): " + (float)startToEndStopwatch.ElapsedTicks / (float)10000f + "ms"); if (timeInInstance > maxTimePerInstance) { yield return(null); } GlobalVariables.instance.paintInProgress = false; // Sometimes this object gets destroyed before the coroutne reaches this point GlobalVariables.instance.globalPaintsInProgress--; localPaintsInProgress--; }
IEnumerator PaintTextureAsyncTimed(RaycastHit hit) // paintInprogress causes problems { GlobalVariables.instance.paintInProgress = true; GlobalVariables.instance.globalPaintsInProgress++; localPaintsInProgress++; int frames = 0; float maxTimePerFrame = 4f; Stopwatch stopWatch = new Stopwatch(); Stopwatch startToEndStopwatch = new Stopwatch(); startToEndStopwatch.Start(); stopWatch.Start(); Renderer rend = hit.transform.GetComponent <Renderer>(); int bloodType = Random.Range(0, bloodSplatSprites.Length); if (rend != null) { Texture2D originalTex = (Texture2D)rend.material.GetTexture("_BaseMap"); //HDRP/Lit version: GetTexture("_BaseColorMap"); if (originalTex != null && originalTex.isReadable) { float elapsedMs = 0; Texture2D brush = bloodSplatSprites[bloodType]; int orgTexWidth = originalTex.width; int orgTexHeight = originalTex.height; int brushWidth = brush.width; int brushHeight = brush.height; //Debug.Log("brush width: " + brushWidth); int uvx = (int)(hit.textureCoord.x * orgTexWidth); int uvy = (int)(hit.textureCoord.y * orgTexHeight); //UnityEngine.Debug.Log("tex cord: " + hit.textureCoord); //Debug.Log("x: " + uvx + " y: " + uvy); int paintStartX = uvx - (brushWidth / 2); int paintStartY = uvy - (brushHeight / 2); Texture2D modifiedTex; bool createNewTex = false; // If texture has not been edited/copied yet, create a new one if (originalTex.updateCount == 0) { createNewTex = true; modifiedTex = new Texture2D(orgTexWidth, orgTexHeight, TextureFormat.RGBA32, false);// Create copy of the original texture modifiedTex.filterMode = FilterMode.Point; Color32[] newColors = originalTex.GetPixels32(); elapsedMs = (float)stopWatch.ElapsedTicks / (float)10000f; // Tick is 100ns. 10K ticks = 1ms if (elapsedMs > maxTimePerFrame) { frames++; stopWatch.Reset(); startToEndStopwatch.Stop(); yield return(null); startToEndStopwatch.Start(); stopWatch.Start(); } modifiedTex.SetPixels32(newColors); elapsedMs = (float)stopWatch.ElapsedTicks / (float)10000f; // Tick is 100ns. 10K ticks = 1ms if (elapsedMs > maxTimePerFrame) { frames++; stopWatch.Reset(); startToEndStopwatch.Stop(); yield return(null); startToEndStopwatch.Start(); stopWatch.Start(); } } // If texture has been already edited/copied, edit existing texture rather than creating a new one else { modifiedTex = originalTex; } for (int i = 0; i < brushWidth; i++) { elapsedMs = (float)stopWatch.ElapsedTicks / (float)10000f; // Tick is 100ns. 10K ticks = 1ms if (elapsedMs > maxTimePerFrame) { frames++; stopWatch.Reset(); startToEndStopwatch.Stop(); yield return(null); startToEndStopwatch.Start(); stopWatch.Start(); } for (int j = 0; j < brushHeight; j++) { //int pos = j * decalWidth + i; //Color32 color = decalColorData[pos]; if (paintStartX + i >= 0 && paintStartX + i < orgTexWidth && paintStartY + j >= 0 && paintStartY + j < orgTexHeight) { Color32 c; if (bloodSplatDictionaries[bloodType].TryGetValue(j * brushWidth + i, out c)) { modifiedTex.SetPixel(paintStartX + i, paintStartY + j, c); //brush.GetPixel(i, j)); // Alternative: Store pixel colors to Dictionary instead of using GetPixel from Texture2D? (almost the same speed, causes calls to color contructor) } } } } modifiedTex.Apply(); if (createNewTex) { rend.material.SetTexture("_BaseMap", modifiedTex); } else { } if (Mathf.Abs(rend.transform.rotation.eulerAngles.x) > 75) { DecalHandler.wallDripStruct wds = new DecalHandler.wallDripStruct(); wds.tex = modifiedTex; wds.uv = new Vector2(uvx, uvy); wds.bloodType = bloodType; decalHandler.wallDripQueue.Enqueue(wds); } } } timeInInstance += (float)startToEndStopwatch.ElapsedTicks / (float)10000f; if (timeInInstance > maxTimePerInstance) { yield return(null); } GlobalVariables.instance.paintInProgress = false; // Sometimes this object gets destroyed before the coroutine reaches this point GlobalVariables.instance.globalPaintsInProgress--; localPaintsInProgress--; }