From 43ab9f93932c74f97912e1462b7844a11cf05825 Mon Sep 17 00:00:00 2001 From: Shylie Date: Sat, 15 Apr 2023 11:48:20 -0400 Subject: [PATCH] add basic stereoscopic 3d support --- source/main.cpp | 138 ++++++++++++++++++++++++++++-------------- source/vshader.v.pica | 63 ++++++++++++++----- 2 files changed, 143 insertions(+), 58 deletions(-) diff --git a/source/main.cpp b/source/main.cpp index c63f46f..5420fe0 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -20,24 +20,50 @@ struct vertex float uv[2]; }; +static DVLB_s* vshaderDVLB; +static shaderProgram_s program; +static s8 spheresUniformLocation; +static s8 sphereColorsUniformLocation; +static s8 sphereLightsUniformLocation; +static s8 randUniformLocation; +static s8 shiftUniformLocation; + +static constexpr unsigned int VERTEX_COUNT_W = 120; +static constexpr unsigned int VERTEX_COUNT_H = 10 * VERTEX_COUNT_W / 6; +static constexpr unsigned int VERTEX_COUNT = VERTEX_COUNT_W * VERTEX_COUNT_H; + +static vertex vertexList[VERTEX_COUNT]; +static u16 vertexIndices[VERTEX_COUNT * 2 + VERTEX_COUNT_H * 2]; + +static void* vboData; +static void* iboData; + +static C3D_Tex prevFrameLeft; +static C3D_Tex prevFrameRight; + class camera { public: - camera(const C3D_FVec lookfrom, const C3D_FVec lookat, const C3D_FVec vup, const float vfov, const float aspectRatio) + camera(const C3D_FVec lookfrom, const C3D_FVec lookat, const C3D_FVec vup, const float vfov, const float aspectRatio, const float iod) { const float theta = C3D_AngleFromDegrees(vfov); const float h = tanf(theta / 2.0f); const float viewportHeight = 2.0f * h; const float viewportWidth = aspectRatio * viewportHeight; + const float screen = FVec3_Distance(lookfrom, lookat) / 2.0f; + shift = iod / (-400.0f * screen * viewportWidth); const C3D_FVec w = FVec3_Normalize(FVec3_Subtract(lookfrom, lookat)); const C3D_FVec u = FVec3_Normalize(FVec3_Cross(vup, w)); const C3D_FVec v = FVec3_Cross(w, u); - origin = lookfrom; + origin = FVec3_Add(lookfrom, FVec3_New(-iod / 3.0f, 0, 0)); horizontal = FVec3_Scale(u, viewportWidth); vertical = FVec3_Scale(v, viewportHeight); - lowerLeftCorner = FVec3_Subtract(FVec3_Add(FVec3_Scale(horizontal, -0.5f), FVec3_Scale(vertical, -0.5f)), w); + lowerLeftCorner = FVec3_Add( + FVec3_Subtract(FVec3_Add(FVec3_Scale(horizontal, -0.5f), FVec3_Scale(vertical, -0.5f)), w), + FVec3_New(-iod / 3.0f, 0, 0) + ); } void setupFixed() const @@ -48,39 +74,27 @@ public: *C3D_FixedAttribGetWritePtr(3) = vertical; } + void setupUniform() const + { + C3D_FVUnifSet(GPU_VERTEX_SHADER, shiftUniformLocation, shift / 200.0f, 240.0f / 256.0f, 400.0f / 512.0f, 0); + } + private: C3D_FVec origin; C3D_FVec lowerLeftCorner; C3D_FVec horizontal; C3D_FVec vertical; + float shift; }; -static DVLB_s* vshaderDVLB; -static shaderProgram_s program; -static s8 spheresUniformLocation; -static s8 sphereColorsUniformLocation; -static s8 sphereLightsUniformLocation; -static s8 randUniformLocation; - -static constexpr unsigned int VERTEX_COUNT_W = 150; -static constexpr unsigned int VERTEX_COUNT_H = 10 * VERTEX_COUNT_W / 6; -static constexpr unsigned int VERTEX_COUNT = VERTEX_COUNT_W * VERTEX_COUNT_H; - -static vertex vertexList[VERTEX_COUNT]; -static u16 vertexIndices[VERTEX_COUNT * 2 + VERTEX_COUNT_H * 2]; - -static void* vboData; -static void* iboData; - -static C3D_Tex prevFrame; - -static void setupFixed(C3D_FVec lookFrom, C3D_FVec lookAt, C3D_FVec up) +static void setupCam(C3D_FVec lookFrom, C3D_FVec lookAt, C3D_FVec up, float iod) { constexpr float VFOV = 90; - constexpr float ASPECT_RATIO = 400.0f / 240.0f; + constexpr float ASPECT_RATIO = C3D_AspectRatioTop; - camera cam(lookFrom, lookAt, up, VFOV, ASPECT_RATIO); + camera cam(lookFrom, lookAt, up, VFOV, ASPECT_RATIO, iod); cam.setupFixed(); + cam.setupUniform(); } static float rand01() @@ -102,6 +116,8 @@ static C3D_FVec randvec() while (FVec3_Magnitude(out) > 1.0f); return out; + + return FVec4_New(0, 0, 0, 0); } static void setupVertices() @@ -121,7 +137,7 @@ static void setupVertices() v.coords[0] = 2.0f * s - 1.0f; v.coords[1] = 2.0f * t - 1.0f; - v.coords[2] = -0.5f; + v.coords[2] = -0.05f; v.uv[0] = s * (240.0f / 256.0f); v.uv[1] = t * (400.0f / 512.0f); @@ -168,6 +184,7 @@ static void sceneInit() sphereColorsUniformLocation = shaderInstanceGetUniformLocation(program.vertexShader, "sphereColors"); sphereLightsUniformLocation = shaderInstanceGetUniformLocation(program.vertexShader, "sphereLights"); randUniformLocation = shaderInstanceGetUniformLocation(program.vertexShader, "rand"); + shiftUniformLocation = shaderInstanceGetUniformLocation(program.vertexShader, "shift"); C3D_AttrInfo* attrInfo = C3D_GetAttrInfo(); AttrInfo_Init(attrInfo); @@ -254,24 +271,28 @@ static u32 getFrameNumColor(unsigned int frameNum) int main(int argc, char* argv[]) { gfxInitDefault(); + gfxSet3D(true); C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); - C3D_RenderTarget* target = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); - C3D_RenderTargetSetOutput(target, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS); + C3D_RenderTarget* targetLeft = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); + C3D_RenderTargetSetOutput(targetLeft, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS); + + C3D_RenderTarget* targetRight = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); + C3D_RenderTargetSetOutput(targetRight, GFX_TOP, GFX_RIGHT, DISPLAY_TRANSFER_FLAGS); - C3D_TexInit(&prevFrame, 256, 512, GPU_RGBA8); - C3D_TexBind(0, &prevFrame); + C3D_TexInit(&prevFrameLeft, 256, 512, GPU_RGBA8); + + C3D_TexInit(&prevFrameRight, 256, 512, GPU_RGBA8); sceneInit(); C3D_FVec lookFrom = FVec3_New(0, 0.6125f, 0); C3D_FVec lookAt = FVec3_New(0, 0, -1.0f); C3D_FVec vup = FVec3_New(0, 1.0f, 0); - bool dirty = false; - - setupFixed(lookFrom, lookAt, vup); + bool dirty = true; unsigned int frameNum = 0; + float previousIOD = osGet3DSliderState() / 4.0f; // Main loop while (aptMainLoop()) @@ -326,12 +347,19 @@ int main(int argc, char* argv[]) lookFrom = FVec3_Add(lookFrom, diff); + const float iod = osGet3DSliderState() / 4.0f; + + if (fabsf(iod - previousIOD) > 0.01f) + { + dirty = true; + } + if (dirty) { - setupFixed(lookFrom, lookAt, vup); - frameNum = 0; + previousIOD = iod; + dirty = false; } @@ -340,26 +368,48 @@ int main(int argc, char* argv[]) C3D_TexEnvColor(C3D_GetTexEnv(0), getFrameNumColor(frameNum)); - if (C3D_FrameBegin(C3D_FRAME_SYNCDRAW)) + if (frameNum < 256 && C3D_FrameBegin(C3D_FRAME_SYNCDRAW)) { - C3D_RenderTargetClear(target, C3D_CLEAR_ALL, 0, 0); - C3D_FrameDrawOn(target); + setupCam(lookFrom, lookAt, vup, -iod); + C3D_TexBind(0, &prevFrameLeft); + C3D_RenderTargetClear(targetLeft, C3D_CLEAR_ALL, 0, 0); + C3D_FrameDrawOn(targetLeft); sceneRender(); + + if (iod > 0) + { + setupCam(lookFrom, lookAt, vup, iod); + C3D_TexBind(0, &prevFrameRight); + C3D_RenderTargetClear(targetRight, C3D_CLEAR_ALL, 0, 0); + C3D_FrameDrawOn(targetRight); + sceneRender(); + } + C3D_FrameEnd(0); + C3D_SyncTextureCopy( - (u32*)target->frameBuf.colorBuf, GX_BUFFER_DIM((240 * 8 * 4) >> 4, 0), - (u32*)prevFrame.data + (512 - 400) * 256, GX_BUFFER_DIM((240 * 8 * 4) >> 4, ((256 - 240) * 8 * 4) >> 4), + (u32*)targetLeft->frameBuf.colorBuf, GX_BUFFER_DIM((240 * 8 * 4) >> 4, 0), + (u32*)prevFrameLeft.data + (512 - 400) * 256, GX_BUFFER_DIM((240 * 8 * 4) >> 4, ((256 - 240) * 8 * 4) >> 4), 240 * 400 * 4, FRAMEBUFFER_TRANSFER_FLAGS ); - } - frameNum++; + if (iod > 0) + { + C3D_SyncTextureCopy( + (u32*)targetRight->frameBuf.colorBuf, GX_BUFFER_DIM((240 * 8 * 4) >> 4, 0), + (u32*)prevFrameRight.data + (512 - 400) * 256, GX_BUFFER_DIM((240 * 8 * 4) >> 4, ((256 - 240) * 8 * 4) >> 4), + 240 * 400 * 4, FRAMEBUFFER_TRANSFER_FLAGS + ); + } + + frameNum++; + } } sceneExit(); - C3D_TexDelete(&prevFrame); - C3D_RenderTargetDelete(target); + C3D_TexDelete(&prevFrameLeft); + C3D_RenderTargetDelete(targetLeft); C3D_Fini(); gfxExit(); diff --git a/source/vshader.v.pica b/source/vshader.v.pica index 744e571..be58c37 100644 --- a/source/vshader.v.pica +++ b/source/vshader.v.pica @@ -1,11 +1,13 @@ -.constf myconst(0.0, 1.0, 0.01, 1000.0) -.constf myconst2(0.5, 999.0, 0.0, 0.0) +.constf myconst(0.0, 1.0, 0.001, 1000.0) +.constf myconst2(0.5, 999.0, 1.1, 0.0) .alias zeros myconst.xxxx .alias halfs myconst2.xxxx .alias ones myconst.yyyy -.alias near myconst.zzzz +.alias tooclose myconst.zzzz .alias far myconst.wwww .alias noHit myconst2.yyyy +.alias defaultDist myconst.wxxx +.alias nearplane myconst2.zzzz .consti bounceLoopParams(9, 0, 1, 0) .consti calcSphereLoopParams(3, 0, 1, 0) @@ -26,6 +28,9 @@ ; random numbers .fvec rand[10] +; stereoscopic 3d shift +.fvec shift + .in inOrigin v0 .in inLowerLeftCorner v1 .in inHorizontal v2 @@ -39,12 +44,6 @@ .out outColor color .proc main - ; outPos = inPos - mov outPos, inPos - - ; outUV = inUV - mov outUV, inUV - ; r1 = inOrigin mov r1, inOrigin @@ -60,6 +59,9 @@ ; set initial color to (0, 0, 0) mov r13.xyz, zeros + ; set initial hit location to (far, far, far) + mov r15.y, far + ; calculate light bounces for bounceLoopParams ; setup random numbers for this iteration @@ -87,7 +89,8 @@ ; which only happens when ; a ray does not hit any spheres cmp noHit.xyz, lt, lt, r10.xyz - breakc cmp.x + ;breakc cmp.x + jmpc cmp.x, labl ; multiply color by albedo mul r4.xyz, r4.xyz, r10.xyz @@ -100,13 +103,46 @@ ; set r2 to new ray direction call diffuse + + ; update distance if not set + cmp noHit, le, le, r15.y + ifc cmp.x + mov r15.y, r4.w + .end .end + labl: + ; copy final color to output mov outColor.xyz, r13.xyz ; set alpha to 1 mov outColor.w, ones + + ; set distance + cmp noHit, le, le, r15.y + ifc cmp.x + ; to (0, 0, 0, 0) since there was no hit + mov r15, zeros + .end + + ; clamp r15.y to [nearplane, far] + max r15.y, nearplane, r15.y + min r15.y, far, r15.y + + ; invert ordering for z-depth + rcp r15.z, -r15.y + + ; multiply distance by shift + mul r15.y, shift.x, r15.y + + ; outPos = inPos + shift + add outPos, inPos, r15 + + ; assign uv coordinates + mul r15, shift.z, r15 + mul r15, halfs, r15 + add outUV, inUV, r15 end .end @@ -181,7 +217,7 @@ mul r9.z, r9.z, r9.x ; if root < min distance, check other root - cmp near, gt, gt, r9.z + cmp tooclose, gt, gt, r9.z jmpc cmp.x, calcSphereCheckOtherRoot ; if root > max distance, check other root @@ -198,7 +234,7 @@ mul r9.z, r9.z, r9.x ; if root < min distance, check other root - cmp near, gt, gt, r9.z + cmp tooclose, gt, gt, r9.z jmpc cmp.x, calcSphereExit ; if root > max distance, check other root @@ -211,8 +247,7 @@ mov r4.w, r9.z ; calculate new origin - mul r5.xyz, r2.xyz, r9.zzz - add r5.xyz, r5.xyz, r1.xyz + mad r5.xyz, r2.xyz, r9.zzz, r1.xyz ; calculate normal add r7.xyz, r5.xyz, -r3.xyz