diff --git a/source/main.cpp b/source/main.cpp index de7a5c5..3b51092 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -18,6 +18,7 @@ struct vertex float st[2]; float coords[3]; float uv[2]; + float rand[3]; }; static DVLB_s* vshaderDVLB; @@ -26,9 +27,10 @@ static s8 spheresUniformLocation; static s8 sphereColorsUniformLocation; static s8 sphereLightsUniformLocation; static s8 randUniformLocation; +static s8 sampleRandUniformLocation; static s8 calcSphereLoopParamsUniformLocation; -static constexpr unsigned int VERTEX_COUNT_W = 150; +static constexpr unsigned int VERTEX_COUNT_W = 50; 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 constexpr unsigned int INDICES_COUNT = (VERTEX_COUNT * 2 + VERTEX_COUNT_H * 2); @@ -135,6 +137,11 @@ static void setupVertices() v.uv[0] = s * (240.0f / 256.0f); v.uv[1] = t * (400.0f / 512.0f); + + const C3D_FVec r = randvec(); + v.rand[0] = r.x; + v.rand[1] = r.y; + v.rand[2] = r.z; } } @@ -143,12 +150,19 @@ static void setupVertices() static void setupRandom() { - constexpr int NUM_RAND = 15; // needs to be the same as rand array length in vshader.v.pica + constexpr int NUM_RAND = 10; // needs to be the same as rand array length in vshader.v.pica C3D_FVec* randPtr = C3D_FVUnifWritePtr(GPU_VERTEX_SHADER, randUniformLocation, NUM_RAND); for (int i = 0; i < NUM_RAND; i++) { randPtr[i] = randvec(); } + + constexpr int NUM_SAMPLE_RAND = 2; + C3D_FVec* sampleRandPtr = C3D_FVUnifWritePtr(GPU_VERTEX_SHADER, sampleRandUniformLocation, NUM_SAMPLE_RAND); + for (int i = 0; i < NUM_SAMPLE_RAND; i++) + { + sampleRandPtr[i] = randvec(); + } } static void sceneInit() @@ -178,6 +192,7 @@ static void sceneInit() sphereColorsUniformLocation = shaderInstanceGetUniformLocation(program.vertexShader, "sphereColors"); sphereLightsUniformLocation = shaderInstanceGetUniformLocation(program.vertexShader, "sphereLights"); randUniformLocation = shaderInstanceGetUniformLocation(program.vertexShader, "rand"); + sampleRandUniformLocation = shaderInstanceGetUniformLocation(program.vertexShader, "sampleRand"); calcSphereLoopParamsUniformLocation = shaderInstanceGetUniformLocation(program.vertexShader, "calcSphereLoopParams"); C3D_AttrInfo* attrInfo = C3D_GetAttrInfo(); @@ -189,13 +204,14 @@ static void sceneInit() AttrInfo_AddLoader(attrInfo, 4, GPU_FLOAT, 2); AttrInfo_AddLoader(attrInfo, 5, GPU_FLOAT, 3); AttrInfo_AddLoader(attrInfo, 6, GPU_FLOAT, 2); + AttrInfo_AddLoader(attrInfo, 7, GPU_FLOAT, 3); iboData = linearAlloc(sizeof(vertexIndices)); memcpy(iboData, vertexIndices, sizeof(vertexIndices)); C3D_BufInfo* bufInfo = C3D_GetBufInfo(); BufInfo_Init(bufInfo); - BufInfo_Add(bufInfo, vboData, sizeof(vertex), 3, 0x654); + BufInfo_Add(bufInfo, vboData, sizeof(vertex), 4, 0x7654); C3D_TexEnv* env = C3D_GetTexEnv(0); C3D_TexEnvInit(env); @@ -203,7 +219,7 @@ static void sceneInit() C3D_TexEnvFunc(env, C3D_RGB, GPU_INTERPOLATE); C3D_TexEnvFunc(env, C3D_Alpha, GPU_REPLACE); - constexpr u16 NUM_SPHERES = 4; + constexpr u16 NUM_SPHERES = 5; C3D_IVUnifSet(GPU_VERTEX_SHADER, calcSphereLoopParamsUniformLocation, NUM_SPHERES - 1, 0, 1, 0); C3D_FVec* spheres = C3D_FVUnifWritePtr(GPU_VERTEX_SHADER, spheresUniformLocation, NUM_SPHERES); @@ -211,18 +227,21 @@ static void sceneInit() spheres[1] = FVec4_New(0.6f, 0.0f, 0.0f, 0.5f); spheres[2] = FVec4_New(-0.6f, 0.0f, 0.0f, 0.5f); spheres[3] = FVec4_New(0.0f, 10.0f, 0.0f, 9.0f); + spheres[4] = FVec4_New(0.0f, 0.4f, 0.0f, 0.2f); C3D_FVec* sphereColors = C3D_FVUnifWritePtr(GPU_VERTEX_SHADER, sphereColorsUniformLocation, NUM_SPHERES); sphereColors[0] = FVec4_New(0.9f, 0.3f, 0.3f, 0); sphereColors[1] = FVec4_New(0.3f, 0.9f, 0.3f, 1); sphereColors[2] = FVec4_New(0.3f, 0.3f, 0.9f, 0); sphereColors[3] = FVec4_New(1.0f, 1.0f, 1.0f, -1); + sphereColors[4] = FVec4_New(0.8f, 0.6f, 0.1f, 2); C3D_FVec* sphereLights = C3D_FVUnifWritePtr(GPU_VERTEX_SHADER, sphereLightsUniformLocation, NUM_SPHERES); sphereLights[0] = FVec4_New(0.0f, 0.0f, 0.0f, 0); sphereLights[1] = FVec4_New(0.0f, 0.0f, 0.0f, 0.2f); sphereLights[2] = FVec4_New(0.0f, 0.0f, 0.0f, 0); - sphereLights[3] = FVec4_New(0.5f, 0.5f, 0.5f, 0); + sphereLights[3] = FVec4_New(2.5f, 2.5f, 2.5f, 0); + sphereLights[4] = FVec4_New(0.0f, 0.0f, 0.0f, 0); } static void sceneRender() @@ -276,9 +295,9 @@ int main(int argc, char* argv[]) sceneInit(); - C3D_FVec lookFrom = FVec3_New(0, 0.0f, 1.0f); - C3D_FVec lookAt = FVec3_New(0, 0, 0.0f); - C3D_FVec vup = FVec3_New(0, 1.0f, 0); + C3D_FVec lookFrom = FVec3_New(0.0f, 0.0f, 1.0f); + C3D_FVec lookAt = FVec3_New(0.0f, 0.0f, 0.0f); + C3D_FVec vup = FVec3_New(0.0f, 1.0f, 0.0f); bool dirty = true; unsigned int frameNum = 0; @@ -346,10 +365,10 @@ int main(int argc, char* argv[]) setupVertices(); setupRandom(); - C3D_TexEnvColor(C3D_GetTexEnv(0), getFrameNumColor(frameNum)); - - if (frameNum < 96 && C3D_FrameBegin(C3D_FRAME_SYNCDRAW)) + if (frameNum < 32 && C3D_FrameBegin(C3D_FRAME_SYNCDRAW)) { + C3D_TexEnvColor(C3D_GetTexEnv(0), getFrameNumColor(frameNum)); + setupCam(lookFrom, lookAt, vup); C3D_TexBind(0, &prevFrame); C3D_RenderTargetClear(target, C3D_CLEAR_ALL, 0, 0); @@ -366,6 +385,8 @@ int main(int argc, char* argv[]) frameNum++; } + + C3D_TexEnvColor(C3D_GetTexEnv(0), 0); } sceneExit(); diff --git a/source/vshader.v.pica b/source/vshader.v.pica index 7189888..dc17355 100644 --- a/source/vshader.v.pica +++ b/source/vshader.v.pica @@ -1,5 +1,6 @@ .constf myconst(0.0, 1.0, 0.001, 1000.0) .constf myconst2(0.5, 999.0, 1.1, 2.0) +.constf myconst3(0.5, 0.0, 0.0, 0.0) .alias zeros myconst.xxxx .alias halfs myconst2.xxxx .alias ones myconst.yyyy @@ -7,10 +8,14 @@ .alias tooclose myconst.zzzz .alias far myconst.wwww .alias noHit myconst2.yyyy +.alias samplesRCP myconst3.xxxx + .alias diffuseID myconst.xxxx .alias metallicID myconst.yyyy +.alias dielectricID myconst2.wwww -.consti bounceLoopParams(14, 0, 1, 0) +.consti sampleLoopParams(4, 0, 1, 0) +.consti bounceLoopParams(9, 0, 1, 0) ; (NUM_SPHERES, 0, 1, 0) .ivec calcSphereLoopParams @@ -31,7 +36,8 @@ .fvec sphereLights[25] ; random numbers -.fvec rand[15] +.fvec rand[10] +.fvec sampleRand[5] .in inOrigin v0 .in inLowerLeftCorner v1 @@ -40,89 +46,109 @@ .in inST v4 .in inPos v5 .in inUV v6 +.in inRand v7 .out outPos position .out outUV texcoord0 .out outColor color .proc main - ; r1 = inOrigin - mov r1, inOrigin + mov r15.xyz, zeros - ; r2 = inDirection - mov r2.xyz, inLowerLeftCorner - mov r3.xy, inST.xy - mad r2.xyz, inHorizontal, r3.x, r2.xyz - mad r2.xyz, inVertical, r3.y, r2.xyz + for sampleLoopParams + ; r1 = inOrigin + mov r1, inOrigin - ; set initial color multiplier to (1, 1, 1) - mov r4.xyz, ones + ; r2 = inDirection + mov r2.xyz, inLowerLeftCorner + mov r3.xy, inST.xy + mad r2.xyz, inHorizontal, r3.x, r2.xyz + mad r2.xyz, inVertical, r3.y, r2.xyz - ; set initial color to (0, 0, 0) - mov r13.xyz, zeros + ; set initial color multiplier to (1, 1, 1) + mov r4.xyz, ones - ; calculate light bounces - for bounceLoopParams - ; setup random numbers for this iteration - mov r11, rand[aL] + ; set initial color to (0, 0, 0) + mov r13.xyz, zeros - ; reset max ray distance - mov r4.w, far + mov r14.xyz, sampleRand[aL].xyz - ; set albedo to a large number for sphere hit check - mov r10.xyz, far + ; calculate light bounces + for bounceLoopParams + ; setup random numbers for this iteration + mov r11, rand[aL] + add r11.xyz, r11.xyz, r14.xyz + add r11.xyz, r11.xyz, inRand.xyz + dp3 r14.w, r11.xyz, r11.xyz + rsq r14.w, r14.w + mul r11.xyz, r11.xyz, r14.w - ; for each sphere - for calcSphereLoopParams - ; r3 = spheres[i] - mov r3, spheres[aL] + ; reset max ray distance + mov r4.w, far + + ; set albedo to a large number for sphere hit check + mov r10.xyz, far + + ; for each sphere + for calcSphereLoopParams + ; r3 = spheres[i] + mov r3, spheres[aL] - ; do calculation - call calcSphere + ; do calculation + call calcSphere + .end + + ; check if noHit < albedo + ; and exit early if true + ; as albedo has not been set + ; after the initial set + ; which only happens when + ; a ray does not hit any spheres + cmp noHit.xyz, lt, lt, r10.xyz + ; not using breakc. it behaves weird. + jmpc cmp.x, labl + + ; multiply color by albedo + mul r4.xyz, r4.xyz, r10.xyz + + ; add emitted light + mad r13.xyz, r4.xyz, r12.xyz, r13.xyz + + ; set r1 to new ray origin + mov r1.xyz, r5.xyz + + ; set r2 to new ray direction + ; try diffuse material + cmp diffuseID.w, eq, eq, r10.w + callc cmp.x, diffuse + jmpc cmp.x, materialFound + + ; try metallic material + cmp metallicID.w, eq, eq, r10.w + callc cmp.x, metallic + jmpc cmp.x, materialFound + + ; try dielectric material + cmp dielectricID.w, eq, eq, r10.w + callc cmp.x, dielectric + jmpc cmp.x, materialFound + + ; material doesn't reflect light + ; used mostly for light-emitting objects + jmpu true, labl + + materialFound: + nop .end - ; check if noHit < albedo - ; and exit early if true - ; as albedo has not been set - ; after the initial set - ; which only happens when - ; a ray does not hit any spheres - cmp noHit.xyz, lt, lt, r10.xyz - ; not using breakc. it behaves weird. - jmpc cmp.x, labl + labl: - ; multiply color by albedo - mul r4.xyz, r4.xyz, r10.xyz - - ; add emitted light - mad r13.xyz, r4.xyz, r12.xyz, r13.xyz - - ; set r1 to new ray origin - mov r1.xyz, r5.xyz - - ; set r2 to new ray direction - ; try diffuse material - cmp diffuseID.w, eq, eq, r10.w - callc cmp.x, diffuse - jmpc cmp.x, materialFound - - ; try metallic material - cmp metallicID.w, eq, eq, r10.w - callc cmp.x, metallic - jmpc cmp.x, materialFound - - ; material doesn't reflect light - ; used mostly for light-emitting objects - jmpu true, labl - - materialFound: - nop + ; add final color to output + add r15.xyz, r13.xyz, r15.xyz .end - labl: - - ; copy final color to output - mov outColor.xyz, r13.xyz + ; divide by sample count + mul outColor.xyz, samplesRCP, r15.xyz ; set alpha to 1 mov outColor.w, ones @@ -133,6 +159,7 @@ end .end +; ----------------------------- ; Calculate Sphere Intersection ; ----------------------------- ; Performs a ray-sphere intersection test. @@ -159,6 +186,7 @@ ; ----------- ; r5.xyz: new origin ; r7.xyz: hit normal +; r7.w: ray is outside sphere (1) or inside sphere (0) ; r8.xyzw: used for calculations ; r9.xyzw: used for calculations @@ -253,8 +281,9 @@ nop .end -; All Materials -; ------------- +; --------- +; Materials +; --------- ; Calculates the new ray direction for a given material. ; ; Inputs @@ -274,16 +303,26 @@ ; Diffuse Material ; ---------------- + .proc diffuse add r2.xyz, r7.xyz, r11.xyz .end ; Metallic Material ; ----------------- + .proc metallic dp3 r6.xyz, r2, r7 mul r6.xyz, twos, r6.xyz mad r2.xyz, -r6.xyz, r7.xyz, r2.xyz ; add a bit of random "fuzziness" to the metal mad r2.xyz, r11.xyz, r12.w, r2.xyz +.end + +; Dielectric Material +; ------------------- + +.proc dielectric + ; currently diffuse material, implement fr later + add r2.xyz, r7.xyz, r11.xyz .end \ No newline at end of file