Skip to content

Instantly share code, notes, and snippets.

@HurricanKai
Created April 17, 2020 12:35
Show Gist options
  • Save HurricanKai/8b220ce6cbe7c1eb805dd1b246faee98 to your computer and use it in GitHub Desktop.
Save HurricanKai/8b220ce6cbe7c1eb805dd1b246faee98 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;
using UnityEngine;
using static Unity.Mathematics.math;
using float3 = Unity.Mathematics.float3;
using float4x4 = Unity.Mathematics.float4x4;
[UpdateAfter(typeof(SetupOctreeWorldSystem))]
[UpdateInGroup(typeof(PresentationSystemGroup))]
public class HERORaytracingSystem : JobComponentSystem
{
private SetupOctreeWorldSystem _setupOctreeWorldSystem;
public JobHandle LastHandle;
[BurstCompile]
struct HERORaytracingJob : IJobParallelFor
{
public NativeArray<int> Texture;
public int height;
public int width;
public float imageAspectRatio;
public float scale;
public float3 orig;
public float4x4 cameraToWorld;
public float3 octreeOrigin;
[ReadOnly] public NativeList<OctreeNode> nodes;
public void Execute(int index)
{
Color32 c;
var i = index % width;
var j = index / width;
/*var r = (float)i / width;
var g = (float)j / height;
var b = 0.2f;
Texture[index] = new Color32((byte)(r * 255), (byte)(g * 255), (byte)(b * 255), 255).AsInt32();
*/
var x = (2 * (i + 0.5f) / width - 1) * imageAspectRatio * scale;
var y = (1 - 2 * (j + 0.5f) / height) * (imageAspectRatio) * scale;
var dir = normalize(mul(cameraToWorld, float4(x, -y, -1, 0)).xyz);
/*var r = HERO.Raytrace(orig, dir, octreeOrigin, nodes);
if (r != null)
c = r.Value.AsColor32();
else
c = Color.magenta;*/
c = Raytrace(orig, dir);
Texture[index] = c.AsInt32();
// Texture[index] = ((Color32)new Color(abs(dir.x), abs(dir.y), abs(dir.z), 255)).AsInt32();
}
private Color32 Raytrace(float3 orig1, float3 dir)
{
const int LoD = 10000;
const float min = 1f / LoD;
const float max = LoD;
Color32 c = Color.grey;
float depth = 0;
const int maxIterations = LoD / 400;
int i = 0;
for (; i < maxIterations; i++) {
float dist = sceneSDF(orig1 + depth * dir);
if (dist < min) {
// We're inside the scene surface!
c = Color.white;
break;
}
// Move along the view ray
depth += dist;
if (depth >= max) {
// Gone too far; give up
break;
}
}
c.r = (byte) (((float)i / (float) maxIterations) * 255);
return c;
}
private static float sceneSDF(float3 p)
{
// var c = float3(250);
// p = abs(((p + 0.5f * c) % c) - 0.5f * c);
return length(p) - 1f;
}
}
[InternalBufferCapacity(0)]
public struct CameraTexture : ISystemStateBufferElementData
{
public int Color;
}
protected override void OnCreate()
{
base.OnCreate();
_setupOctreeWorldSystem = World.GetOrCreateSystem<SetupOctreeWorldSystem>();
}
protected override JobHandle OnUpdate(JobHandle inputDependencies)
{
inputDependencies.Complete();
JobHandle handle = default;
// Ensure buffer
Entities
.WithStructuralChanges()
.ForEach((Entity e, in CameraComponent cc) =>
{
var size = cc.ScreenHeight * cc.ScreenWidth;
if (!EntityManager.HasComponent<CameraTexture>(e))
{
EntityManager.AddBuffer<CameraTexture>(e);
}
var buffer = EntityManager.GetBuffer<CameraTexture>(e);
var sizeDiff = buffer.Length - size;
if (sizeDiff < 0)
{
var toAdd = sizeDiff * -1;
var b = new NativeArray<CameraTexture>(toAdd, Allocator.Temp);
buffer.AddRange(b);
b.Dispose();
}
else if (sizeDiff > 0)
{
var toRemove = sizeDiff;
buffer.RemoveRange(buffer.Length - toRemove, toRemove);
}
}).Run();
Entities
.WithStructuralChanges()
.WithAll<CameraTexture>()
.WithNone<CameraComponent>().ForEach(
(Entity e) =>
{
EntityManager.RemoveComponent<DynamicBuffer<CameraTexture>>(e);
}).Run();
Entities.WithoutBurst().ForEach((ref DynamicBuffer<CameraTexture> buff, in CameraComponent cc) =>
{
var height = cc.ScreenHeight;
var width = cc.ScreenWidth;
var job = new HERORaytracingJob
{
Texture = buff.Reinterpret<int>().AsNativeArray(),
height = height,
width = width,
imageAspectRatio = (float)height / (float)width,
scale = tan(degrees(cc.FoV * 0.5f)),
orig = cc.Origin,
cameraToWorld = cc.CameraToWorld,
nodes = _setupOctreeWorldSystem.Octree.Nodes,
octreeOrigin = _setupOctreeWorldSystem.Octree.Origin,
};
var h = job.Schedule(height * width, 64, inputDependencies);
handle = JobHandle.CombineDependencies(h, handle);
}).Run();
_setupOctreeWorldSystem.AddDependency(handle);
LastHandle = handle;
return handle;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment