Skip to content

Commit

Permalink
add ray tracing spheres
Browse files Browse the repository at this point in the history
  • Loading branch information
teamclouday committed Sep 7, 2021
1 parent 1b2f64d commit 890ea5e
Show file tree
Hide file tree
Showing 14 changed files with 562 additions and 28 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ Library/*
Logs/*
Temp/*
obj/*
SampleBuilds/*
UserSettings/*
.vsconfig
*.csproj
Expand Down
29 changes: 25 additions & 4 deletions Assets/Scenes/Basic.unity
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ GameObject:
- component: {fileID: 465702723}
- component: {fileID: 465702722}
- component: {fileID: 465702725}
- component: {fileID: 465702726}
m_Layer: 0
m_Name: Main Camera
m_TagString: MainCamera
Expand All @@ -159,8 +160,8 @@ Camera:
m_GameObject: {fileID: 465702721}
m_Enabled: 1
serializedVersion: 2
m_ClearFlags: 1
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
m_ClearFlags: 2
m_BackGroundColor: {r: 0, g: 0, b: 0, a: 0}
m_projectionMatrixMode: 1
m_GateFitMode: 2
m_FOVAxisMode: 0
Expand Down Expand Up @@ -201,7 +202,7 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 465702721}
m_LocalRotation: {x: -0, y: 0.000000119209275, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 1, z: -10}
m_LocalPosition: {x: 0, y: 50, z: -100}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
Expand All @@ -220,7 +221,27 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
RayTracingShader: {fileID: 7200000, guid: 937c15c591618624e9c977b3e0632c0b, type: 3}
SkyboxTexture: {fileID: 8900000, guid: 572c79f514cecd843aca2b276a0e5c0f, type: 2}
SkyboxTexture: {fileID: 8900000, guid: e8791888d6d354b48a57b55226d8d69d, type: 2}
DirectionalLight: {fileID: 1184883991}
SphereRadiusMinMax: {x: 5, y: 30}
SphereNum: 10000
SpherePlacementRadius: 100
SphereSeed: 2021
--- !u!114 &465702726
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 465702721}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1fbc9cf86d149794d90df92bf0bc3d0c, type: 3}
m_Name:
m_EditorClassIdentifier:
scrollSpeed: 0.5
dragSpeed: 0.1
keySpeed: 0.2
--- !u!1 &1184883990
GameObject:
m_ObjectHideFlags: 0
Expand Down
101 changes: 101 additions & 0 deletions Assets/Scripts/CameraControl.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
using UnityEngine;

public class CameraControl : MonoBehaviour
{
[SerializeField, Range(0.001f, 2.0f)]
float scrollSpeed = 0.5f;

[SerializeField, Range(0.001f, 2.0f)]
float dragSpeed = 0.1f;

[SerializeField, Range(0.001f, 2.0f)]
float keySpeed = 0.2f;

private Vector3 _pos;
private Vector3 _dir;
private Vector3 _right = Vector3.right;
private float _yaw = 90.0f;
private float _pitch = 0.0f;

private bool _mouseDown = false;
private Vector3 _mousePos = Vector3.zero;

private void OnEnable()
{
_pos = transform.position;
_dir = Vector3.forward;
UpdateCamera();
}

private void Update()
{
bool updated = false;
// check for scroll
float scroll = Input.GetAxis("Mouse ScrollWheel");
if(scroll > 0.0f)
{
_pos += _dir * scrollSpeed;
updated = true;
}
else if(scroll < 0.0f)
{
_pos -= _dir * scrollSpeed;
updated = true;
}
if(Input.GetMouseButtonDown(0))
{
_mouseDown = true;
_mousePos = Input.mousePosition;
}
// check for click and drag
if (Input.GetMouseButtonUp(0)) _mouseDown = false;
if(_mouseDown)
{
Vector3 mousePos = Input.mousePosition;
Vector3 delta = mousePos - _mousePos;
_mousePos = mousePos;
_yaw += delta.x * dragSpeed;
_pitch += -delta.y * dragSpeed;
_pitch = Mathf.Clamp(_pitch, -89.9f, 89.9f);
UpdateDir();
updated = true;
}
// check for key controls
if(Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
{
_pos += _right * keySpeed;
updated = true;
}
if(Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
{
_pos -= _right * keySpeed;
updated = true;
}
if(Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
{
_pos += _dir * keySpeed;
updated = true;
}
if(Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
{
_pos -= _dir * keySpeed;
updated = true;
}
if (updated) UpdateCamera();
}

private void UpdateDir()
{
_dir.x = Mathf.Cos(Mathf.Deg2Rad * _yaw) * Mathf.Cos(Mathf.Deg2Rad * _pitch);
_dir.y = Mathf.Sin(Mathf.Deg2Rad * _pitch);
_dir.z = Mathf.Sin(Mathf.Deg2Rad * _yaw) * Mathf.Cos(Mathf.Deg2Rad * _pitch);
_dir = Vector3.Normalize(_dir);
_right = Vector3.Normalize(Vector3.Cross(_dir, Vector3.up));
}

private void UpdateCamera()
{
transform.position = _pos;
transform.LookAt(_pos + _dir);
}
}
11 changes: 11 additions & 0 deletions Assets/Scripts/CameraControl.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

125 changes: 124 additions & 1 deletion Assets/Scripts/RayTracer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using UnityEngine;
using System.Collections.Generic;

public class RayTracer : MonoBehaviour
{
Expand All @@ -8,20 +9,87 @@ public class RayTracer : MonoBehaviour
[SerializeField]
Texture SkyboxTexture;

[SerializeField]
Light DirectionalLight;

[SerializeField]
Vector2 SphereRadiusMinMax = new Vector2(5.0f, 30.0f);

[SerializeField]
uint SphereNum = 10000;

[SerializeField]
float SpherePlacementRadius = 100.0f;

[SerializeField]
int SphereSeed = 1999;

private RenderTexture _target;
private RenderTexture _converged;

private Camera _camera;

// anti-aliasing
private uint _currentSample = 0;
private Material _addMaterial;

// spheres
private ComputeBuffer _sphereBuffer;

private void Awake()
{
_camera = GetComponent<Camera>();
}

private void Start()
{
Application.targetFrameRate = 72; // 144 / 2
}

private void OnEnable()
{
_currentSample = 0;
SetupScene();
}

private void OnDisable()
{
if (_sphereBuffer != null)
_sphereBuffer.Release();
}

private void Update()
{
if(transform.hasChanged)
{
_currentSample = 0;
transform.hasChanged = false;
}
if(DirectionalLight.transform.hasChanged)
{
_currentSample = 0;
DirectionalLight.transform.hasChanged = false;
}
//if(Input.GetKeyDown(KeyCode.R))
//{
// OnDisable();
// OnEnable();
//}
if (Input.GetKeyDown(KeyCode.Escape))
Application.Quit();
}

private void SetShaderParameters()
{
RayTracingShader.SetMatrix("_CameraToWorld", _camera.cameraToWorldMatrix);
RayTracingShader.SetMatrix("_CameraInverseProjection", _camera.projectionMatrix.inverse);
RayTracingShader.SetTexture(0, "_SkyboxTexture", SkyboxTexture);
RayTracingShader.SetVector("_PixelOffset", new Vector2(Random.value, Random.value));
Vector3 lightDir = DirectionalLight.transform.forward;
RayTracingShader.SetVector("_DirectionalLight",
new Vector4(lightDir.x, lightDir.y, lightDir.z, DirectionalLight.intensity));
RayTracingShader.SetBuffer(0, "_Spheres", _sphereBuffer);
RayTracingShader.SetFloat("_Seed", Random.value);
}

private void OnRenderImage(RenderTexture source, RenderTexture destination)
Expand All @@ -37,7 +105,12 @@ private void Render(RenderTexture destination)
int threadGroupX = Mathf.CeilToInt(Screen.width / 8.0f);
int threadGroupY = Mathf.CeilToInt(Screen.height / 8.0f);
RayTracingShader.Dispatch(0, threadGroupX, threadGroupY, 1);
Graphics.Blit(_target, destination);
if (_addMaterial == null)
_addMaterial = new Material(Shader.Find("Hidden/AddShader"));
_addMaterial.SetFloat("_Sample", _currentSample);
Graphics.Blit(_target, _converged, _addMaterial);
Graphics.Blit(_converged, destination);
_currentSample++;
}

private void InitRenderTexture()
Expand All @@ -53,5 +126,55 @@ private void InitRenderTexture()
_target.enableRandomWrite = true;
_target.Create();
}
if(_converged == null ||
_converged.width != Screen.width ||
_converged.height != Screen.height)
{
if (_converged != null)
_converged.Release();
_converged = new RenderTexture(Screen.width, Screen.height, 0,
RenderTextureFormat.ARGBFloat, RenderTextureReadWrite.Linear);
_converged.enableRandomWrite = true;
_converged.Create();
}
}

private void SetupScene()
{
Random.InitState(SphereSeed);
List<Sphere> spheres = new List<Sphere>();
for(int i = 0; i < SphereNum; i++)
{
Sphere sphere = new Sphere();
sphere.Radius = Random.Range(SphereRadiusMinMax.x, SphereRadiusMinMax.y);
Vector2 pos = Random.insideUnitCircle * SpherePlacementRadius;
sphere.Position = new Vector3(pos.x, sphere.Radius, pos.y);
bool intersected = false;
// avoid intersections
foreach (Sphere other in spheres)
{
float dist = sphere.Radius + other.Radius;
if (Vector3.SqrMagnitude(sphere.Position - other.Position) < dist * dist)
{
intersected = true;
break;
}
}
if (intersected) continue;
// set colors
Color color = Random.ColorHSV();
bool metal = Random.value < 0.5f;
sphere.Albedo = metal ? Vector3.zero : new Vector3(color.r, color.g, color.b);
sphere.Specular = metal ? new Vector3(color.r, color.g, color.b) : Vector3.one * 0.04f;
// set emission
bool emit = Random.value < 0.8f;
color = Random.ColorHSV();
sphere.Emission = emit ? new Vector3(color.r, color.g, color.b) : Vector3.zero;
// set smoothness
sphere.Smoothness = Random.value;
spheres.Add(sphere);
}
_sphereBuffer = new ComputeBuffer(spheres.Count, Sphere.Size);
_sphereBuffer.SetData(spheres);
}
}
12 changes: 12 additions & 0 deletions Assets/Scripts/Structures.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using UnityEngine;

public struct Sphere
{
public Vector3 Position;
public float Radius;
public Vector3 Emission;
public float Smoothness;
public Vector3 Albedo;
public Vector3 Specular;
public static readonly int Size = 56; // structure size
}
11 changes: 11 additions & 0 deletions Assets/Scripts/Structures.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 890ea5e

Please sign in to comment.