void Update() { if (planeManager == null) { // True during edit mode execution Awake(); } // Send the text in the child 3D text object to the camera bound to the // plane, to be displayed in the screen when the cam becomes active. //////////////////////////////////////////////////////////////////// string cameraName = transform.parent.parent.parent.name; string planeInfoText = transform.parent.GetChild(1).GetComponent <TextMesh>().text; camToBind.GetComponent <ShaderCamGUI>().SetInfoText( cameraName + ": " + planeInfoText); // Setup camera to follow the plane in the scene. // Also match the viewport size to the plane. //////////////////////////////////////////////// // Set to orthographic. We wish to capture the whole plane, nothing else. camToBind.orthographic = true; // Scale target plane to precisely fit the image //////////////////////////////////////////////// // Get texture image width / height ratio float sizeRatio = (float)planeManager.GetSourceWidth() / planeManager.GetSourceHeight(); // Evaluates possibly to true due to script execution order issues, // that apparently can't be helped with [ExecuteInEditMode] scripts if (!System.Single.IsNaN(sizeRatio)) { // Match camera aspect ratio with texture image camToBind.aspect = sizeRatio; // Set camera viewport size to match the plane size. // x member is the horizontal scaling, x / planeScaleRatio equals the width // of the plane in world units (for a default sized plane, 1 / 0.1 == 10). // Division by two matches the sizing to camera orthographic size setting, // that is, half of the viewport width, and finally division by sizeRatio scales // the width to height. camToBind.orthographicSize = transform.localScale.x / planeScaleRatio / 2 / sizeRatio; } // Set camera position in front of the plane. camToBind.transform.position = transform.position + transform.up; // Make the camera face the plane. camToBind.transform.LookAt(transform); }
void OnRenderImage(RenderTexture src, RenderTexture dest) { // Setup data for detection area cornerpoint // display to be sent to the shader; daDisplay.SetCornerpointDisplayData(material5_EdgeDetectionAreas); // Due to initial first network source image delay on playback start, // a dummy texture of arbitrary size has been created to provide // valid data to scripts that depend on a non-zero sized source // texture. Because the size of the network image, once it arrives, // may be different from initial texture size, the size info needs // to be resent to shaders and processing plane rendertextures // recreated in correct dimensions. // Pass source texture dimensions to materials whose shaders need the info foreach (Material m in needSourceSizeMaterials) { m.SetFloat("_tWidth", (float)planeManager.GetSourceWidth()); m.SetFloat("_tHeight", (float)planeManager.GetSourceHeight()); } // Create and assign temporary rendertextures. // Fortunately, there's little overhead. for (int iTex = 0; iTex < rTextures.Length; ++iTex) { rTextures[iTex] = RenderTexture.GetTemporary( planeManager.GetSourceWidth(), planeManager.GetSourceHeight()); transform.parent.parent.GetChild(1).GetChild((iTex + 1) * 2 + 1). GetChild(0).GetComponent <Renderer>().material.mainTexture = rTextures[iTex]; } // Shader pass 1 // Luminance-Brightness-Contrast-Gamma blitting //////////////////////////////////////////////// Graphics.Blit( src, rTextures[0], material2_LuminanceBrightnessContrastGamma); // Shader pass 2 // Gaussian blur blitting //////////////////////////////////////////////// Graphics.Blit( rTextures[0], rTextures[1], material3_GaussianBlur); // Shader pass 3 // Sobel edge detection //////////////////////////////////////////////// Graphics.Blit( rTextures[1], rTextures[2], material4_SobelEdgeDetection); // Shader // Edge detection areas //////////////////////////////////////////////// Graphics.Blit( rTextures[2], rTextures[3], material5_EdgeDetectionAreas); // Temporary rendertexture cleanup foreach (RenderTexture rt in rTextures) { RenderTexture.ReleaseTemporary(rt); } // Must Blit to screen as well, or OnGUI content won't display Graphics.Blit(src, (RenderTexture)null); }
public void SetCornerpointDisplayData(Material shaderMaterial) { cpList = new List <SlotData.Cornerpoint>(); colorList = new List <Color>(); if (displayEdgeDetectionAreas) { // Edge detection cornerpoints have been selected to show up in the inspector if (slotScript.slotData.numberOfRows == 0) { if (!hasWarningBeenIssued) { Debug.LogWarning("No detection area rows defined for " + transform.parent.parent.name + "."); // Limit warnings to one per each playback hasWarningBeenIssued = true; } return; } // Get corner points for each area for (int iRow = 0; iRow < slotScript.slotData.numberOfRows; ++iRow) { SlotData.Row row = slotScript.slotData.rows[iRow]; for (int iSlot = 0; iSlot < row.numberOfSlots; ++iSlot) { if (row.slots[iSlot].IsUndefined()) { // Unset slot coordinates => skip continue; } cpList.AddRange(row.slots[iSlot].areaCornerpoints); } } // Use texture to pass corner point data to the shader ////////////////////////////////////////////////////// // 4 corner points for each defined slot // Each pixel value in texture can hold data for two points, // (== half a slot), i.e., sizeof(RGBA) == 2 * sizeof(XY). // Therefore, each slot will consume two pixels. // Slot N (Tex line N) Tex px N Px cpnts Slot cornerpoints // 0 0 RG (X, Y) // 0 0 BA (X, Y) // 0 1 RG (X, Y) // 0 1 BA (X, Y) // ----------------------------------------------- // 1 2 RG (X, Y) // 1 2 BA (X, Y) // 1 3 RG (X, Y) // 1 3 BA (X, Y) // ----------------------------------------------- // etc. // Total number of slots in all parking rows int numSlotsTotal = cpList.Count / 4; // Number of required texture pixels to represent // coordinate points for every slot detection area // (one RGBA covers 2 out of 4 cornerpoints for a slot) int texturePixelCount = numSlotsTotal * 2; // Create texture that can hold corner pixel location data tex = new Texture2D(texturePixelsPerLine, numSlotsTotal); Color color = new Color(0f, 0f, 0f, 0f); for (int iPixel = 0; iPixel < texturePixelCount; ++iPixel) { // Two cornerpoints fit in the RGBA structure for (int iCp = 0; iCp < 2; ++iCp) { SlotData.Cornerpoint cp = cpList[iPixel * 2 + iCp]; // Swap Y coordinate and interpolate pixel values imageSlotExtractor.SwapY(ref cp.y, transform.parent.parent.GetSiblingIndex()); Vector2 interpCp = new Vector2( (float)cp.x / planeManager.GetSourceWidth(), (float)cp.y / planeManager.GetSourceHeight()); // Store interpolated [0...1] values. if (iCp % 2 == 0) { // First coordinate pair that populates RG of RGBA color.r = interpCp.x; color.g = interpCp.y; } else { // Second coordinate pair that populates BA of RGBA color.b = interpCp.x; color.a = interpCp.y; colorList.Add(color); } } } // Setting filter mode to Point is a MUST! With default setting, // there's a LOT of pixel averaging and/or blending. We want // pure blocky content! tex.filterMode = FilterMode.Point; // Apply color data to the texture tex.SetPixels(colorList.ToArray()); tex.Apply(); // Pass texture data to the shader /////////////////////////////////// // Texture shaderMaterial.SetTexture("_ColorTex", tex); // Texture dimensions shaderMaterial.SetInt("_ColorTexWidth", texturePixelsPerLine); shaderMaterial.SetInt("_ColorTexHeight", numSlotsTotal); // Alternating colors for adjacent sets of four cornerpoints shaderMaterial.SetColor("_CornerColor0", cornerPointColorA); shaderMaterial.SetColor("_CornerColor1", cornerPointColorB); // Source image aspect ratio shaderMaterial.SetFloat("_MainTexAspectRatio", (float)planeManager.GetSourceWidth() / planeManager.GetSourceHeight()); // Radius of colored cornerpoint square in the screen shaderMaterial.SetFloat("_CornerpointRadius", edgeCornerPointDisplayRadius); } // Enable variable needs to be passed outside of conditional block to ensure once enabled // borders are erased during playback if the user unselects the option in the inspector shaderMaterial.SetFloat("_DisplayCornerpoints", displayEdgeDetectionAreas ? 1.0f : 0.0f); }