hi, The following code is supposed to cast a ray from camera to almost each pixel in camera's view, but the result is wrong. Why ? Code (CSharp): using System; using System.Collections.Generic; using UnityEngine; using UnityEditor; [CustomEditor(typeof(Camera))] public class CameraEditor:Editor { private void OnSceneGUI() { if (Event.current.type != EventType.Repaint) return; Camera camera = target as Camera; Transform t = camera.transform; float h = Mathf.Tan(camera.fieldOfView); float w = h * camera.aspect; Vector3 forward = t.forward, right = t.right, up = t.up, dir, cameraPos = t.position; Debug.Log(h + ":" + w); int count = (camera.scaledPixelWidth * camera.pixelHeight); Handles.Label(cameraPos, "Pixel Count : " + count + " w:" + camera.pixelWidth + " h:" + camera.pixelHeight); float x, y; for(int i = 0; i < count; i+=1000) { x = i % camera.pixelWidth - camera.pixelWidth * 0.5f; y = i / camera.pixelHeight - camera.pixelHeight * 0.5f; dir = (forward + x * w * right + y * h * up).normalized; Handles.color = new Color(dir.x, dir.y, dir.z, 1); //Handles.Label(cameraPos + dir, x + ":" + y + ":" + dir); Handles.DrawLine(cameraPos, cameraPos + dir); } } } Result : Thanks
Line 33 your modulo should be with the width, not with height. When one iterates all the pixels on a raster screen from 0 to w*h-1, one derives cartesian coordinates with: Code (csharp): int x = i % w; int y = i / w; You don't use h for that purpose, assuming you're going across scanline wise, then down one line, etc. PS: note that your for loop is also stepping by +1000 right now, but I assume that is for rapid testing purposes...
Yes, i++ draw millions handles lines and kill the fps. I found another solution but yours is shorter. Thanks. I tried to port this to my post process shader but it still buggy. It is supposed to draw pixel ray or white if pointing at a sphere at world center with a radius of 2. But it only draw the ray as a color or full white if the camera is inside the sphere. It's a raymarching with signed distance function. Code (CSharp): Shader "Hidden/Custom/RayMarcher" { HLSLINCLUDE #include "Packages/com.unity.postprocessing/PostProcessing/Shaders/StdLib.hlsl" #include "DistanceFunctions.cginc" uniform float3 forward, right, up; uniform float _maxDistance; uniform float fov; uniform float aspect; struct VertexInput { float4 vertex : POSITION; }; struct v2f { float4 vertex : SV_POSITION; float4 ray : TEXCOORD0; }; inline float4 ComputeNonStereoScreenPos(float4 pos) { float4 o = pos * 0.5f; o.xy = float2(o.x, o.y * _ProjectionParams.x) + o.w; o.zw = pos.zw; return o; } inline float4 ComputeScreenPos(float4 pos) { float4 o = ComputeNonStereoScreenPos(pos); #if defined(UNITY_SINGLE_PASS_STEREO) o.xy = TransformStereoScreenSpaceTex(o.xy, pos.w); #endif return o; } v2f vert(VertexInput v) { v2f o; o.vertex = float4(v.vertex.xyz, 1.0); float4 screenpos = ComputeScreenPos(v.vertex); o.ray = screenpos; return o; } float distanceField(float3 p) { return sdSphere(p - float3(0, 0, 0), 2.0); } float4 raymarching(float3 ro, float3 rd, float depth) { float4 result = float4(0, 0, 0, 1); const int maxi = 64; float t = 0; float d; float3 p; for (int i = 0; i < maxi; i++) { if (t > _maxDistance) { result = float4(rd, 1); break; } p = ro + rd * t; d = distanceField(p); if (d < 0.01) { result = float4(1, 1, 1, 1); break; } t += d; } return result; } static float h = tan(fov); static float w = h * aspect; float4 frag(v2f i) : SV_Target { float3 rayOrigin = _WorldSpaceCameraPos; float x = i.ray.x * 2.0f - 1.0f; float y = i.ray.y * 2.0f - 1.0f; float3 dir = normalize(forward + x * w * right + y * h * up); float4 result = raymarching(rayOrigin, dir, 1000); return result; } ENDHLSL SubShader { // No culling or depth Cull Off ZWrite Off ZTest Always Pass { HLSLPROGRAM #pragma vertex vert #pragma fragment frag #pragma target 3.0 ENDHLSL } } } The raymarcher c# class : Code (CSharp): using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering.PostProcessing; [Serializable][ExecuteAlways] [PostProcess(typeof(RayMarcherRenderer), PostProcessEvent.AfterStack, "Custom/RayMarcher", true)] public class RayMarcher : PostProcessEffectSettings { public float _maxDistance; public FloatParameter MaxDistance = new FloatParameter { value = 100.0f }; } [ExecuteAlways] public sealed class RayMarcherRenderer : PostProcessEffectRenderer<RayMarcher> { public override void Render(PostProcessRenderContext context) { PropertySheet sheet = context.propertySheets.Get("Hidden/Custom/RayMarcher"); Camera camera = context.camera; sheet.properties.SetVector("forward", camera.transform.forward); sheet.properties.SetVector("right", camera.transform.right); sheet.properties.SetVector("up", camera.transform.up); sheet.properties.SetFloat("fov", camera.fieldOfView * Mathf.Deg2Rad * 0.5f); sheet.properties.SetFloat("aspect", camera.aspect); sheet.properties.SetFloat("_MaxDistance", settings.MaxDistance); context.command.BlitFullscreenTriangle(context.source, context.destination, sheet, 0); } } And the result looks ok for the rays, but the sphere is nowhere :