This commit is contained in:
ethan merchant 2023-07-01 02:17:13 -04:00
commit 7e1811a8d3
45 changed files with 306 additions and 454 deletions

View file

@ -78,7 +78,7 @@ public class BlockCon {
}
}
if (!bFound) {
blocks[PullRequest.RandomRange(0, blocks.Length)].Enable(cursor, Quat.Identity);
blocks[PR.RandomRange(0, blocks.Length)].Enable(cursor, Quat.Identity);
}
} else {
blocks[index].Disable();
@ -139,7 +139,7 @@ public class BlockCon {
blocks[index].solid.Move(toPos, toRot);
Quat newHeldRot = blocks[index].solid.GetPose().orientation;
angularMomentum = Vec3.Lerp(angularMomentum, PullRequest.AngularDisplacement((newHeldRot * oldHeldRot.Inverse).Normalized), Time.Stepf / 0.1f);
angularMomentum = Vec3.Lerp(angularMomentum, PR.AngularDisplacement((newHeldRot * oldHeldRot.Inverse).Normalized), Time.Stepf / 0.1f);
oldHeldRot = newHeldRot;
delta = (cursor + (con.ori * heldRot * spinRot).Normalized * offset) - blocks[index].solid.GetPose().position;

View file

@ -35,7 +35,7 @@ public class CubicCon {
break;
}
}
Cubic cubic = cubics[PullRequest.RandomRange(0, cubics.Length)];
Cubic cubic = cubics[PR.RandomRange(0, cubics.Length)];
cubic.p0 = rPos;
cubic.p1 = rig.rCon.pos;
cubic.p2 = rig.lCon.pos;

View file

@ -356,7 +356,7 @@ public class Peer {
public void Draw(bool body) {
Mono mono = Mono.inst;
if (body) {
PullRequest.BlockOut(Matrix.TRS(headset.position + Input.Head.Forward * -0.15f, headset.orientation, Vec3.One * 0.3f), color);
PR.BlockOut(Matrix.TRS(headset.position + Input.Head.Forward * -0.15f, headset.orientation, Vec3.One * 0.3f), color);
}
// Bezier.Draw(
@ -370,7 +370,7 @@ public class Peer {
for (int i = 0; i < blocks.Length; i++) {
NetBlock block = blocks[i];
if (block.active) {
PullRequest.BlockOut(block.pose.ToMatrix(block.scale), block.color);
PR.BlockOut(block.pose.ToMatrix(block.scale), block.color);
}
}

Binary file not shown.

View file

@ -0,0 +1,53 @@
#include "stereokit.hlsli"
//--name = dofdev/compositor
//--diffuse = white
Texture2D diffuse : register(t0);
SamplerState diffuse_s : register(s0);
struct vsIn {
float4 pos : SV_Position;
float3 norm : NORMAL0;
float2 uv : TEXCOORD0;
};
struct psIn {
float4 pos : SV_Position;
float3 world : WORLD;
float2 uv : TEXCOORD0;
uint view_id : SV_RenderTargetArrayIndex;
};
psIn vs(vsIn input, uint id : SV_InstanceID) {
psIn o;
o.view_id = id % sk_view_count;
id = id / sk_view_count;
o.world = mul(input.pos, sk_inst[id].world).xyz;
o.pos = mul(float4(o.world, 1), sk_viewproj[o.view_id]);
// float3 normal = normalize(mul(input.norm, (float3x3)sk_inst[id].world));
o.uv = input.uv;
return o;
}
float4 ps(psIn input) : SV_TARGET {
float depth = diffuse.Sample(diffuse_s, input.uv).r;
// 16 bit DepthTexture *non-linear* depth
// render depth for debug
if (depth > 0.0) {
depth = 1.0;
}
// float4 og = mul(float4(input.world, 1), sk_viewproj[input.view_id]);
// float depth = (og * rcp(og.w)).z;
return float4(depth, depth, depth, 1);
// float v = -rcp(-val.r);
// v = val.r;
// return float4(v, v, v, 1);
}

View file

@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7</TargetFramework>
<SKAssetFolder>add</SKAssetFolder>
<SKAssetDestination>add</SKAssetDestination>
</PropertyGroup>

View file

@ -50,7 +50,7 @@ public class Mono {
Oriels.Rig rig = Oriels.Mono.inst.rig;
// angle.x -= rig.rCon.device.stick.y * 90f * Time.Stepf;
// angle.x = PullRequest.Clamp(angle.x, -89, 89);
// angle.x = PR.Clamp(angle.x, -89, 89);
angle.y -= rig.rCon.device.stick.x * 90f * Time.Stepf;
Vec3 input = new Vec3(

5
src/Dofs.cs Normal file
View file

@ -0,0 +1,5 @@
namespace Oriels;
public static class Dofs {
// stretch
// flex
}

View file

@ -8,7 +8,19 @@ public class Compositor {
Greenyard.Mono greenyard = new Greenyard.Mono();
// bool other = false;
Tex tex;
Material mat = new Material(Shader.FromFile("compositor.hlsl"));
public void Init() {
tex = new Tex(TexType.Rendertarget);
tex.SetSize(512, 512);
tex.AddZBuffer(TexFormat.Depth16); // DepthStencil
mat[MatParamName.DiffuseTex] = tex;
mat.FaceCull = Cull.Front;
// Renderer.Blit(tex, newMat)
backrooms.Init();
greenyard.Init();
}
@ -65,6 +77,16 @@ public class Compositor {
// );
// Model model = Model.FromFile("oriel.glb");
// ~ Mesh mesh = model.GetMesh("oriel");
Renderer.RenderTo(tex,
Matrix.TR(V.XYZ(0, 1, 0), Quat.FromAngles(0, 180, 0)),
Matrix.Perspective(60, 1, 0.1f, 100),
RenderLayer.All // & ~RenderLayer.Layer1
);
Default.MeshQuad.Draw(mat,
Matrix.TR(V.XYZ(0, 1, 0), Quat.FromAngles(0, 0, 0))
);
}
void Place() {

View file

@ -59,21 +59,21 @@ public class Oriel {
Vec3 cornerDetect = Vec3.Zero;
public Vec3 XAnchor { get {
float x = PullRequest.Clamp(localCursor.x,
float x = PR.Clamp(localCursor.x,
LocalAnchor.x - cornerRadius,
LocalAnchor.x + cornerRadius
);
return new Vec3(x, LocalAnchor.y, LocalAnchor.z);
} }
public Vec3 YAnchor { get {
float y = PullRequest.Clamp(localCursor.y,
float y = PR.Clamp(localCursor.y,
LocalAnchor.y - cornerRadius,
LocalAnchor.y + cornerRadius
);
return new Vec3(LocalAnchor.x, y, LocalAnchor.z);
} }
public Vec3 ZAnchor { get {
float z = PullRequest.Clamp(localCursor.z,
float z = PR.Clamp(localCursor.z,
LocalAnchor.z - cornerRadius,
LocalAnchor.z + cornerRadius
);
@ -251,7 +251,7 @@ public class Oriel {
// cursor
Color col = new Color(0.15f, 0.15f, 0.15f);
float thk = 0.002f;
float prx = PullRequest.Clamp(
float prx = PR.Clamp(
cursorRadius - (localCursor - LocalAnchor).Magnitude / 3, 0, cursorRadius
) / cursorRadius;
if (detectCount == 1 || detectCount == 2) {

12
src/Functions.cs Normal file
View file

@ -0,0 +1,12 @@
namespace Oriels;
public static class Functions {
// in SK >= 1.2.0 as Vec3.Direction()
public static Vec3 Dir(Vec3 to, Vec3 from) {
return (to - from).Normalized;
}
// deadzone
// magnitude
// extension
}

View file

@ -58,7 +58,7 @@ public class Glove {
if (lift) {
pullPoint = con.pos + -direction * stretch;
} else {
direction = PullRequest.Direction(con.pos, pullPoint);
direction = PR.Direction(con.pos, pullPoint);
}
} else {
pullPoint = con.pos;
@ -83,7 +83,7 @@ public class Glove {
case Pull.Backhanded:
pullPoint = otherCon.pos;
direction = PullRequest.Direction(con.pos, otherCon.pos);
direction = PR.Direction(con.pos, otherCon.pos);
virtualGlove.orientation = con.ori;
break;
}

View file

@ -32,7 +32,7 @@ public class Mono {
Oriels.Rig rig = Oriels.Mono.inst.rig;
// angle.x -= rig.rCon.device.stick.y * 90f * Time.Stepf;
// angle.x = PullRequest.Clamp(angle.x, -89, 89);
// angle.x = PR.Clamp(angle.x, -89, 89);
angle.y -= rig.rCon.device.stick.x * 90f * Time.Stepf;
Vec3 input = new Vec3(

View file

@ -1,4 +1,4 @@
public interface dof { // <T> ?
public interface Interaction { // <T> ?
void Init();
void Frame();
// void Drop();

View file

@ -0,0 +1,9 @@
namespace Oriels;
public class Fullstick {
public Vec3 Direction(bool chirality) {
Controller con = Mono.inst.rig.Con(chirality).device;
Quat rot = Quat.FromAngles(con.stick.y * -90, 0, con.stick.x * 90);
Vec3 dir = Vec3.Up * (con.IsStickClicked ? -1 : 1);
return con.aim.orientation * rot * dir;
}
}

View file

@ -1,6 +1,6 @@
namespace Oriels;
class RollsCursor : dof {
class RollsCursor : Interaction {
public bool Active { get; set; }
// input
@ -25,7 +25,7 @@ class RollsCursor : dof {
Vec3 to = Roll(hand, JointId.KnuckleMid, fI, fM, fR, fL);
Vec3 from = Roll(hand, JointId.KnuckleMajor, fI, fM, fR, fL);
Vec3 dir = PullRequest.Direction(to, from);
Vec3 dir = PR.Direction(to, from);
cursor.raw = to + dir * stretch * reach.value;
@ -44,10 +44,10 @@ class RollsCursor : dof {
Vec3 r = hand.Get(FingerId.Ring, jointId).position;
Vec3 l = hand.Get(FingerId.Little, jointId).position;
fI = PullRequest.Clamp(fI, 0.0001f, 1f);
fM = PullRequest.Clamp(fM, 0.0001f, 1f);
fR = PullRequest.Clamp(fR, 0.0001f, 1f);
fL = PullRequest.Clamp(fL, 0.0001f, 1f);
fI = PR.Clamp(fI, 0.0001f, 1f);
fM = PR.Clamp(fM, 0.0001f, 1f);
fR = PR.Clamp(fR, 0.0001f, 1f);
fL = PR.Clamp(fL, 0.0001f, 1f);
Vec3 im = Vec3.Lerp(i , m , fM / (fM + fI));
Vec3 mr = Vec3.Lerp( m , r , fR / (fR + fM));

View file

@ -1,6 +1,6 @@
namespace Oriels;
class StretchCursor : dof {
class StretchCursor : Interaction {
public bool Active { get; set; }
// input

View file

@ -1,6 +1,6 @@
namespace Oriels;
class Trackballer : dof {
class Trackballer : Interaction {
public bool Active { get; set; }
// input
@ -18,7 +18,7 @@ class Trackballer : dof {
Matrix oldPad = Matrix.Identity;
int lastClosestIndex;
PullRequest.Vec3PID compliance = new PullRequest.Vec3PID();
PR.Vec3PID compliance = new PR.Vec3PID();
Model model = Model.FromFile("thumb_pad.glb");
Mesh mesh;
@ -140,7 +140,7 @@ class Trackballer : dof {
compliance.value += offset * compliant.value;
compliance.integral = Vec3.Zero;
} else {
PullRequest.ToAxisAngle(momentum, out Vec3 axis, out float angle);
PR.ToAxisAngle(momentum, out Vec3 axis, out float angle);
if (angle < stop.value) {
momentum = Quat.Slerp(momentum, Quat.Identity, Time.Stepf * 10f);
}
@ -184,12 +184,12 @@ class Trackballer : dof {
);
cursorPos.x = PullRequest.Clamp(
cursorPos.x = PR.Clamp(
cursorPos.x + (momentum * Vec3.Right).z * 0.1f,
width / -2f,
width / 2f
);
cursorPos.y = PullRequest.Clamp(
cursorPos.y = PR.Clamp(
cursorPos.y + (momentum * Vec3.Right).y * -0.1f,
height / -2f,
height / 2f

View file

@ -1,6 +1,6 @@
namespace Oriels;
class WaveCursor : dof {
class WaveCursor : Interaction {
public bool Active { get; set; }
// input
@ -68,7 +68,7 @@ class WaveCursor : dof {
// if (i > 0) {
// Vec3 dir = Vec3.Forward;
// if (points[i].v != points[i - 1].v) {
// dir = PullRequest.Direction(points[i], points[i - 1]);
// dir = PR.Direction(points[i], points[i - 1]);
// }
// // points[i] = points[i - 1] + dir * 0.02f * scale;
// }

View file

@ -4,7 +4,7 @@ public class Mono {
private static readonly Lazy<Oriels.Mono> lazy = new Lazy<Oriels.Mono>(() => new Oriels.Mono());
public static Oriels.Mono inst { get { return lazy.Value; } }
public PullRequest.Noise noise = new PullRequest.Noise(939949595);
public PR.Noise noise = new PR.Noise(939949595);
public Material matDev;
public Material matHoloframe = new Material(Shader.FromFile("above.hlsl"));
@ -18,41 +18,28 @@ public class Mono {
// -------------------------------------------------
public dof[] dofs;
public Interaction[] dofs;
public ColorCube colorCube = new ColorCube();
public Glove rGlove = new Glove(true), lGlove = new Glove(false);
public Glove Glove(bool chirality) { return chirality ? rGlove : lGlove; }
public BlockCon rBlock = new BlockCon(true), lBlock = new BlockCon(false);
public BlockCon BlockCon(bool chirality) { return chirality ? rBlock : lBlock; }
public Block[] blocks = new Block[] {
new Block(), new Block(), new Block(), new Block(), new Block(), new Block()
};
public CubicCon cubicCon = new CubicCon();
public Cubic[] cubics = new Cubic[] {
new Cubic(), new Cubic(), new Cubic(), new Cubic(), new Cubic(), new Cubic()
};
// -------------------------------------------------
public MonoNet net = new MonoNet();
// public MonoNet net = new MonoNet();
public Mono() {
Renderer.SetClip(0.02f, 1000f);
dofs = new dof[] {
new Chiral(new dof[] {
dofs = new Interaction[] {
new Chiral(new Interaction[] {
new WaveCursor() { handed = Handed.Left },
new WaveCursor() { handed = Handed.Right }
}),
new Chiral(new dof[] {
new Chiral(new Interaction[] {
new Trackballer() { handed = Handed.Left },
new Trackballer() { handed = Handed.Right }
}),
new Chiral(new dof[] {
new Chiral(new Interaction[] {
new RollsCursor() { handed = Handed.Left },
new RollsCursor() { handed = Handed.Right }
}),
@ -91,6 +78,11 @@ public class Mono {
Pose shape = new Pose(new Vec3(0, 1f, -3f), Quat.FromAngles(45, 0, 45));
bool shapeHeld = false;
Spatial spatial = new Spatial();
public void Frame() {
// Input.HandClearOverride(Handed.Left);
@ -156,8 +148,23 @@ public class Mono {
new Color(0.5f, 0.55f, 0.75f) * 0.3f
);
spatial.Frame();
// </Heresy>
// pinch drawers
// do this quick and fun
// what's inside?
// friction flip thumb swipe
// overcome with >x force impulse
// local to palm
// dofchan bows on the back of the ankles that double as trackers
// rBlock.Step(); lBlock.Step();
// cubicCon.Step();
@ -166,8 +173,8 @@ public class Mono {
// -------------------------------------------------
net.me.Step();
net.send = true;
// net.me.Step();
// net.send = true;
ShowWindowButton();
}
@ -202,7 +209,7 @@ public class Mono {
}
dof dof = dofs[dofIndex];
Interaction dof = dofs[dofIndex];
Type type = dof.GetType();
// active toggle
Color tint = dof.Active ? new Color(0, 1, 0) : new Color(1, 0, 0);
@ -239,7 +246,7 @@ public class Mono {
UI.WindowEnd();
}
void RenderDof(dof dof) {
void RenderDof(Interaction dof) {
Type type = dof.GetType();
UI.Label("°" + type.Name);
System.Reflection.FieldInfo[] fields = type.GetFields();
@ -261,15 +268,15 @@ public class Mono {
}
// Chiral : handedness implies symmetry
public class Chiral : dof {
public Chiral(dof[] dofs) => this.dofs = dofs;
public class Chiral : Interaction {
public Chiral(Interaction[] dofs) => this.dofs = dofs;
private bool active;
public bool Active {
get { return this.active; }
set {
this.active = value;
for (int i = 0; i < this.dofs.Length; i++) {
dof dof = this.dofs[i];
Interaction dof = this.dofs[i];
if ((int)this.handed == 2 || i == (int)this.handed) {
dof.Active = value;
} else {
@ -278,7 +285,7 @@ public class Chiral : dof {
}
}
}
public dof[] dofs = new dof[2];
public Interaction[] dofs = new Interaction[2];
// public Design handed = new Design { str = "2", min = 0, max = 2};
public Handed handed = Handed.Max;
@ -298,7 +305,7 @@ public class Chiral : dof {
}
for (int i = 0; i < dofs.Length; i++) {
dof dof = dofs[i];
Interaction dof = dofs[i];
if ((int)handed == 2 || i == (int)handed) {
dof.Frame();
dof.Active = true;
@ -320,7 +327,7 @@ public class Design {
public float value {
get {
try {
float value = PullRequest.Clamp(float.Parse(str), min, max);
float value = PR.Clamp(float.Parse(str), min, max);
// if clamped, update string
if (value != float.Parse(str)) {
if (Input.Key(Key.Return).IsJustActive()) {
@ -337,9 +344,9 @@ public class Design {
}
public class Cursor {
PullRequest.OneEuroFilter xF = new PullRequest.OneEuroFilter(0.001f, 0.1f);
PullRequest.OneEuroFilter yF = new PullRequest.OneEuroFilter(0.001f, 0.1f);
PullRequest.OneEuroFilter zF = new PullRequest.OneEuroFilter(0.001f, 0.1f);
PR.OneEuroFilter xF = new PR.OneEuroFilter(0.001f, 0.1f);
PR.OneEuroFilter yF = new PR.OneEuroFilter(0.001f, 0.1f);
PR.OneEuroFilter zF = new PR.OneEuroFilter(0.001f, 0.1f);
Vec3 _raw;
public Vec3 raw {
get => _raw;
@ -392,4 +399,110 @@ public class Cursor {
particularly for hand tracking dofs (so Moses can better test them!)
raw = 0.333f alpha ~
*/
*/
/*
we have a whole inspector thing going on here
but people are working on better alternatives:
malek's foss social xr project
which was part of the reason that i chopped off the networking parts of this project.
as we have vrc for reaching larger audiences + malek's project to develop w/the fossxr community
so running our own networking is needlessly redundant, and not my strong suit.
refocusing this project on just prototyping and hosting our xr tools centrally
to then be ported to wherever they can best be applied ^-^
the inspector is a crutch for the lack of a native spatial interface for prototyping
as it's an incredibly limited and an awkward abstraction of what is happening spatially
expose spatial functions and dofs
allow the user to bind them to tracked inputs+
*don't need it all to be fully featured and extensible out of the gate
just need a better foundation than a paper paradigm inspector
'world origin' needs to be adjustable~
otherwise the visualizations will be difficult to decipher in different contexts
no names! as everything remains in it's original context
text for math symbols is fine~
but don't use that as an excuse to abstract things back into text
you can do vector math spatially
by wrapping the living vectors with operators~
i.e av + bv = cv
(-- + --) -> --
it's hard to represent this with text :<
but just think of different points/lines(vectors) being encapsulated by
underlying larger points/lines(vectors) with symbols or other identifiers
with an output, managing to represent the underlying math within the spatial context
side notes
need to run it in a way where if it crashes, it doesn't take the whole app down (ask malek?)
*/
public class Spatial {
// example, to build out from
// just adding two vectors
// with great interactivity and visual feedback
float scale = 0.1f;
float thickness => 0.01f * scale;
Vec3 origin = new Vec3(0, 1, -1);
float t = 1.0f;
Vec3 aFrom, aTo;
Vec3 a => Vec3.Lerp(aFrom, aTo, MathF.Min(t, 1f));
Vec3 bFrom, bTo;
Vec3 b => Vec3.Lerp(bFrom, bTo, MathF.Min(t, 1f));
Vec3 c => a + b;
public void Frame() {
// origin axis
Lines.Add(origin, World(new Vec3(1, 0, 0)), new Color(1, 0, 0), thickness);
Lines.Add(origin, World(new Vec3(0, 1, 0)), new Color(0, 1, 0), thickness);
Lines.Add(origin, World(new Vec3(0, 0, 1)), new Color(0, 0, 1), thickness);
Mesh.Sphere.Draw(Material.Unlit, Matrix.TS(origin, thickness), new Color(0.5f, 0.5f, 0.5f));
Random rand = Random.Shared;
if (t >= 1.3f) {
aFrom = aTo;
bFrom = bTo;
if (rand.NextSingle() < 0.5f) {
aTo = new Vec3(rand.NextSingle(), rand.NextSingle(), rand.NextSingle()) * 0.5f;
} else {
bTo = new Vec3(rand.NextSingle(), rand.NextSingle(), rand.NextSingle()) * 0.5f;
}
t = 0.0f;
}
t += Time.Stepf / 2f;
Lines.Add(origin, World(a), new Color(1, 1, 0), thickness);
Mesh.Sphere.Draw(Material.Unlit, Matrix.TS(World(a), thickness), new Color(1, 1, 0));
Lines.Add(origin, World(b), new Color(0, 1, 1), thickness);
Mesh.Sphere.Draw(Material.Unlit, Matrix.TS(World(b), thickness), new Color(0, 1, 1));
Lines.Add(World(a), World(c), new Color(0, 1, 1), thickness);
Lines.Add(World(b), World(c), new Color(1, 1, 0), thickness);
// color between yellow and cyan using HSV
Mesh.Sphere.Draw(Material.Unlit, Matrix.TS(World(c), thickness), new Color(0.5f, 1, 1));
}
Vec3 World(Vec3 local) {
return origin + local * scale;
}
//
}

View file

@ -1,5 +1,5 @@
namespace Oriels;
public static class PullRequest {
public static class PR {
public static void BoundsDraw(Bounds b, float thickness, Color color) {
Vec3 c = Vec3.One / 2;
Vec3 ds = b.dimensions;

View file

@ -1,7 +1,6 @@
namespace Oriels;
public class Rig {
public Mic mic = new Mic();
public Vec3 pos = new Vec3(0, 0, 0);
public Quat ori = Quat.Identity;
@ -83,7 +82,7 @@ public class Rig {
lWrist = new Pose(lCon.pos + lCon.ori * new Vec3(0, 0, 0.052f), lCon.ori);
}
public float Flexion(Hand hand, FingerId id) {
public float Flexion(Hand hand, FingerId id, float deadzone = 0.15f) {
float fingerFlex = (Vec3.Dot(
Vec3.Direction(
hand.Get(id, JointId.Tip).position,
@ -94,8 +93,7 @@ public class Rig {
hand.Get(id, JointId.KnuckleMajor).position
)
) + 1f) / 2;
float fingerTrim = 0.15f;
float fingerTrim = 0f + deadzone; // 180°
fingerFlex = Math.Max(fingerFlex - fingerTrim, 0f) / (1 - fingerTrim);
float knuckleFlex = (Vec3.Dot(
@ -108,21 +106,12 @@ public class Rig {
hand.Get(id, JointId.Root).position
)
) + 1f) / 2;
float knuckleTrim = 0.666f;
float knuckleTrim = 0.5f + deadzone; // 90°
knuckleFlex = Math.Max(knuckleFlex - knuckleTrim, 0f) / (1 - knuckleTrim);
float flexion = knuckleFlex + fingerFlex;
return flexion * flexion;
}
public Vec3 Fullstick(bool chirality) {
Controller con = Con(chirality).device;
Quat rot = Quat.FromAngles(con.stick.y * -90, 0, con.stick.x * 90);
Vec3 dir = Vec3.Up * (con.IsStickClicked ? -1 : 1);
return con.aim.orientation * rot * dir;
}
}
public class Con {

View file

@ -1,131 +0,0 @@
namespace Oriels;
public class Mic {
public float[] bufferRaw = new float[0];
public int bufferRawSize = 0;
public int comp = 8;
public float[] buffer = new float[0];
public int bufferSize = 0;
FilterButterworth filter;
public void Step() {
if (Microphone.IsRecording) {
// Ensure our buffer of samples is large enough to contain all the
// data the mic has ready for us this frame
if (Microphone.Sound.UnreadSamples > bufferRaw.Length) {
bufferRaw = new float[Microphone.Sound.UnreadSamples];
buffer = new float[Microphone.Sound.UnreadSamples / comp];
}
// Read data from the microphone stream into our buffer, and track
// how much was actually read. Since the mic data collection runs in
// a separate thread, this will often be a little inconsistent. Some
// frames will have nothing ready, and others may have a lot!
bufferRawSize = Microphone.Sound.ReadSamples(ref bufferRaw);
bufferSize = bufferRawSize / comp;
if (bufferSize > 0) {
// LowPassFilter lowpass = new LowPassFilter(48000 / comp / 2, 2, 48000);
for (int i = 0; i < bufferRawSize; i++) {
// bufferRaw[i] = (float)lowpass.compute(bufferRaw[i]);
filter.Update(bufferRaw[i]);
bufferRaw[i] = filter.Value;
}
// voice.WriteSamples(bufferRaw);
buffer[0] = bufferRaw[0];
for (int i = 1; i < bufferSize; i++) {
buffer[i] = bufferRaw[i * comp - 1];
}
// upsample
float[] upsampled = new float[bufferSize * comp];
for (int i = 0; i < bufferSize - 1; i++) {
upsampled[Math.Max(i * comp - 1, 0)] = buffer[i];
for (int j = 1; j < comp; j++) {
upsampled[i * comp - 1 + j] = SKMath.Lerp(buffer[i], buffer[i + 1], (float)j / (float)comp);
}
}
voice.WriteSamples(upsampled);
}
} else {
Microphone.Start();
voice = Sound.CreateStream(0.5f);
voiceInst = voice.Play(Vec3.Zero, 0.5f);
filter = new FilterButterworth(48000 / comp / 2, 48000, FilterButterworth.PassType.Lowpass, (float)Math.Sqrt(2));
}
}
public Sound voice;
public SoundInst voiceInst; // update position
public class FilterButterworth {
/// <summary>
/// rez amount, from sqrt(2) to ~ 0.1
/// </summary>
private readonly float resonance;
private readonly float frequency;
private readonly int sampleRate;
private readonly PassType passType;
private readonly float c, a1, a2, a3, b1, b2;
/// <summary>
/// Array of input values, latest are in front
/// </summary>
private float[] inputHistory = new float[2];
/// <summary>
/// Array of output values, latest are in front
/// </summary>
private float[] outputHistory = new float[3];
public FilterButterworth(float frequency, int sampleRate, PassType passType, float resonance) {
this.resonance = resonance;
this.frequency = frequency;
this.sampleRate = sampleRate;
this.passType = passType;
switch (passType) {
case PassType.Lowpass:
c = 1.0f / (float)Math.Tan(Math.PI * frequency / sampleRate);
a1 = 1.0f / (1.0f + resonance * c + c * c);
a2 = 2f * a1;
a3 = a1;
b1 = 2.0f * (1.0f - c * c) * a1;
b2 = (1.0f - resonance * c + c * c) * a1;
break;
case PassType.Highpass:
c = (float)Math.Tan(Math.PI * frequency / sampleRate);
a1 = 1.0f / (1.0f + resonance * c + c * c);
a2 = -2f * a1;
a3 = a1;
b1 = 2.0f * (c * c - 1.0f) * a1;
b2 = (1.0f - resonance * c + c * c) * a1;
break;
}
}
public enum PassType {
Highpass,
Lowpass,
}
public void Update(float newInput) {
float newOutput = a1 * newInput + a2 * this.inputHistory[0] + a3 * this.inputHistory[1] - b1 * this.outputHistory[0] - b2 * this.outputHistory[1];
this.inputHistory[1] = this.inputHistory[0];
this.inputHistory[0] = newInput;
this.outputHistory[2] = this.outputHistory[1];
this.outputHistory[1] = this.outputHistory[0];
this.outputHistory[0] = newOutput;
}
public float Value {
get { return this.outputHistory[0]; }
}
}
}

View file

@ -14,7 +14,6 @@ public class Space {
Material matFloor = new Material(Shader.Default);
Model shed = Model.FromFile("shed/shed.glb", Shader.FromFile("room.hlsl"));
Model leek = Model.FromFile("houseleek_plant.glb", Shader.FromFile("room.hlsl"));
Mesh cube = Mesh.Cube;
Solid floor;
@ -24,28 +23,28 @@ public class Space {
// recenter the nodes in the leek model
// so that the leek is centered at the origin
// and the scale is 1
Vec3 center = new Vec3(0, 0, 0);
foreach (ModelNode node in leek.Nodes) {
if (node.Mesh != null) {
// average the vertices to find the center
foreach (Vertex vertex in node.Mesh.GetVerts()) {
center += vertex.pos;
}
center /= node.Mesh.VertCount;
}
node.LocalTransform = Matrix.TS(
Vec3.Zero,
1f
);
// node.ModelTransform = Matrix.TS(
// new Vec3(0, 0, 0),
// 1f
// );
}
leek.RootNode.LocalTransform = Matrix.TS(
-center,
1f
);
// Vec3 center = new Vec3(0, 0, 0);
// foreach (ModelNode node in leek.Nodes) {
// if (node.Mesh != null) {
// // average the vertices to find the center
// foreach (Vertex vertex in node.Mesh.GetVerts()) {
// center += vertex.pos;
// }
// center /= node.Mesh.VertCount;
// }
// node.LocalTransform = Matrix.TS(
// Vec3.Zero,
// 1f
// );
// // node.ModelTransform = Matrix.TS(
// // new Vec3(0, 0, 0),
// // 1f
// // );
// }
// leek.RootNode.LocalTransform = Matrix.TS(
// -center,
// 1f
// );
floor = new Solid(World.BoundsPose.position, Quat.Identity, SolidType.Immovable);
@ -86,7 +85,7 @@ public class Space {
// PullRequest.BlockOut(floor.GetPose().ToMatrix(floorScale), Color.White * 0.333f, matFloor);
// PR.BlockOut(floor.GetPose().ToMatrix(floorScale), Color.White * 0.333f, matFloor);
// foreach (ModelNode node in shed.Visuals) {
// Console.WriteLine(i + " - " + node.Name);

View file

@ -1,221 +0,0 @@
using System.Collections.Generic;
using Oriels;
// [X] stretch cursor move
// [X] nodes *point of reference rather than interest for now
// [X] follow player *cam? matrix? name?
// [ ] orbital view
// [ ] dummy enemies
// [ ] trackballer spin
// [ ] roll dodge move
namespace Space;
public class Mono {
public Oriel oriel = new Oriel(
new Vec3(1.0f, -0.5f, 0.5f),
Quat.Identity,
new Vec3(0.8f, 0.5f, 0.5f)
);
Node[] nodes = new Node[18];
Vec3 playerPos;
List<Vec3> enemies = new List<Vec3>();
float spawnTime;
Oriels.PullRequest.PID pidX = new Oriels.PullRequest.PID();
Oriels.PullRequest.PID pidY = new Oriels.PullRequest.PID();
Oriels.PullRequest.PID pidZ = new Oriels.PullRequest.PID();
Mesh meshCube;
// Model skyboxModel = Model.FromFile("fantasy_skybox.glb");
// Mesh skybox;
// Material skyboxMat = new Material(Shader.FromFile("/oriel.hlsl"));
public Mono() {
}
public void Init() {
Oriels.PullRequest.Noise noise = Oriels.Mono.inst.noise;
// place nodes around a 10x4x10 cube
float scalar = 3f;
for (int i = 0; i < nodes.Length; i++) {
nodes[i] = new Node(
new Vec3(
noise.value * 5f * scalar,
noise.value * 2f * scalar,
noise.value * 5f * scalar
),
noise.uvalue
);
}
meshCube = Mesh.Cube;
// skybox = skyboxModel.GetMesh("sky");
// skyboxMat.SetMat(101, Cull.None, true);
// skyboxMat.SetTexture("diffuse", Tex.FromFile("fantasy_skybox.jpeg"));
}
public void Frame() {
Oriels.Rig rig = Oriels.Mono.inst.rig;
Matrix simMatrix = Matrix.TRS(
-playerPos * 0.5f * oriel.bounds.dimensions.y, //-oriel.bounds.dimensions.y / 2.01f, -playerWorldPos.z),
Quat.Identity,
Vec3.One * 0.5f * oriel.bounds.dimensions.y
);
// stretch cursor pattern:
// stretch = dist(offHand, mainHand)
// max(stretch - deadzone, 0)
// dir = mainHand.fwd
// cursor = mainHand.pos + dir * stretch * 3
// stretch cursor code:
float deadzone = 0.1f;
float stretch = Vec3.Distance(rig.lCon.pos, rig.rCon.pos);
stretch = Math.Max(stretch - deadzone, 0);
Vec3 cursor = rig.rCon.pos + rig.rCon.ori * Vec3.Forward * stretch * 3;
Vec3 localCursor = simMatrix.Inverse.Transform(oriel.matrixInv.Transform(cursor));
localCursor = new Vec3(
MathF.Sin(Time.Totalf * 2f) * 3f,
MathF.Sin(Time.Totalf * 0.5f) * 3f,
MathF.Sin(Time.Totalf * 1f) * 3f
);
// fly player towards cursor:
// playerPos += (localCursor - playerPos).Normalized * 1f * Time.Stepf;
pidX.p = moveP; pidY.p = moveP; pidZ.p = moveP;
pidX.i = moveI; pidY.i = moveI; pidZ.i = moveI;
playerPos = new Vec3(
pidX.Update(localCursor.x),
pidY.Update(localCursor.y),
pidZ.Update(localCursor.z)
);
// RENDER
for (int i = 0; i < nodes.Length; i++) {
meshCube.Draw(oriel.matOriel,
Matrix.TRS(nodes[i].pos, Quat.Identity, Vec3.One * 1f) * simMatrix * oriel.matrix,
Color.HSV(nodes[i].hue, 1f, 1f)
);
}
meshCube.Draw(oriel.matOriel,
Matrix.TRS(cursor, Quat.Identity, Vec3.One * 0.02f),
new Color(1f, 1f, 1f)
);
meshCube.Draw(oriel.matOriel,
Matrix.TRS(localCursor, Quat.Identity, Vec3.One * 0.02f) * simMatrix * oriel.matrix,
new Color(0f, 0f, 0f)
);
meshCube.Draw(oriel.matOriel,
Matrix.TRS(
playerPos,
Quat.LookDir((localCursor - playerPos).Normalized),
new Vec3(0.4f, 0.2f, 0.4f)
) * simMatrix * oriel.matrix,
new Color(1.0f, 0.0f, 0.05f)
);
// skyboxMat.SetVector("_center", oriel.bounds.center);
// skyboxMat.SetVector("_dimensions", oriel.bounds.dimensions);
// skyboxMat.SetVector("_light", oriel.ori * new Vec3(0.6f, -0.9f, 0.3f));
// skyboxMat.SetFloat("_lit", 0);
// skyboxMat["_matrix"] = (Matrix)System.Numerics.Matrix4x4.Transpose(oriel.matrix);
// skybox.Draw(skyboxMat,
// Matrix.TRS(
// playerPos,
// Quat.Identity,
// new Vec3(10f, 10f, 10f)
// ) * simMatrix * oriel.matrix,
// Color.White
// );
// meshCube.Draw(oriel.matOriel,
// rGlove.virtualGlove.ToMatrix(new Vec3(0.025f, 0.1f, 0.1f) / 3 * 1.05f),
// new Color(0.3f, 0.3f, 0.6f)
// );
// return;
// ENEMIES
// destroy enemies that are too close to the playerPos
for (int i = 0; i < enemies.Count; i++) {
if (Vec3.Distance(enemies[i], playerPos) < 0.5f) {
// enemies.RemoveAt(i);
// i--;
enemies[i] = playerPos + Quat.FromAngles(0, Oriels.Mono.inst.noise.value * 360f, 0) * Vec3.Forward * 8;
}
}
if (enemies.Count < 100 && Time.Totalf > spawnTime) {
// enemies.Add(playerPos + Quat.FromAngles(0, Oriels.Mono.inst.noise.value * 360f, 0) * Vec3.Forward * 8);
spawnTime = Time.Totalf + 0.05f;
}
for (int i = 0; i < enemies.Count; i++) {
// move towards player
Vec3 toPlayer = (playerPos - enemies[i]).Normalized;
float variation = Oriels.Mono.inst.noise.D1(i);
toPlayer *= Quat.FromAngles(0, MathF.Sin(Time.Totalf * variation) * 90 * variation, 0);
Vec3 newPos = enemies[i] + toPlayer * Time.Stepf * 0.5f;
// if far enough away from other enemies than set new pos
bool setNewPos = true;
int iteration = 0;
while (iteration < 6) {
for (int j = 0; j < enemies.Count; j++) {
if (i == j) continue;
float radius = 0.5f;
float depth = (newPos - enemies[j]).Length - radius;
if (depth < 0) {
Vec3 toEnemy = (enemies[j] - newPos).Normalized;
newPos = enemies[j] - toEnemy * radius * 1.01f;
}
}
iteration++;
}
if (setNewPos) {
enemies[i] = newPos;
}
meshCube.Draw(oriel.matOriel,
Matrix.TRS(enemies[i],
Quat.LookAt(enemies[i], playerPos, Vec3.Up),
new Vec3(0.4f, 1f, 0.2f)
) * simMatrix * oriel.matrix,
Color.White * 0.62f
);
}
}
// design variables
float moveP = 8f;
float moveI = 0.2f;
}
public class Node {
public Vec3 pos;
public float hue;
public Node(Vec3 pos, float hue) {
this.pos = pos;
this.hue = hue;
}
}

View file

@ -16,6 +16,8 @@ if (!SK.Initialize(settings))
Input.HandSolid(Handed.Max, false);
Input.HandVisible(Handed.Max, true);
// Input.HandMaterial(Handed.Max, Material.Default);
Renderer.SetClip(0.02f, 100f);
Renderer.EnableSky = false;
Renderer.ClearColor = new Color(0f / 256f, 162f / 256f, 206f / 256f);