Skip to content

Instantly share code, notes, and snippets.

@yuriks
Last active May 27, 2017 07:17
Show Gist options
  • Save yuriks/e5b9fbacbc558587525fb22733a14fa1 to your computer and use it in GitHub Desktop.
Save yuriks/e5b9fbacbc558587525fb22733a14fa1 to your computer and use it in GitHub Desktop.
Quaternion Interpolation Test
#include <3ds.h>
#include <citro3d.h>
#include <string.h>
#include "vshader_shbin.h"
#define CLEAR_COLOR 0x68B0D8FF
#define DISPLAY_TRANSFER_FLAGS \
(GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(0) | GX_TRANSFER_RAW_COPY(0) | \
GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) | \
GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO))
typedef struct { float position[3]; float texcoord[2]; float normal[3]; } vertex;
#define COS_70 0.34202f
#define SIN_70 0.93969f
#define COS_80 0.17364f
#define SIN_80 0.98480f
#define COS_85 0.08716f
#define SIN_85 0.99619f
#define COS_T COS_70
#define SIN_T SIN_70
static const vertex vertex_list[] =
{
// First face (PZ)
// First triangle
{ {-1.0f, -1.0f, +0.0f}, {0.0f, 0.0f}, {-SIN_T, 0.0f, -COS_T} },
{ {+1.0f, -1.0f, +0.0f}, {1.0f, 0.0f}, { SIN_T, 0.0f, -COS_T} },
{ {+1.0f, +1.0f, +0.0f}, {1.0f, 1.0f}, { SIN_T, 0.0f, -COS_T} },
// Second triangle
{ {+1.0f, +1.0f, +0.0f}, {1.0f, 1.0f}, {0.0f, SIN_T, -COS_T} },
{ {-1.0f, +1.0f, +0.0f}, {0.0f, 1.0f}, {0.0f, -SIN_T, -COS_T} },
{ {-1.0f, -1.0f, +0.0f}, {0.0f, 0.0f}, {0.0f, -SIN_T, -COS_T} },
};
#define vertex_list_count (sizeof(vertex_list)/sizeof(vertex_list[0]))
static DVLB_s* vshader_dvlb;
static shaderProgram_s program;
static int uLoc_projection, uLoc_modelView;
static C3D_Mtx projection;
static C3D_LightEnv lightEnv;
static C3D_Light light;
static C3D_LightLut lut_Identity;
static void* vbo_data;
static float quantizeFloat(float x, float steps) {
float i = truncf(x * steps);
return (float)i * (1.0f / steps);
}
static float identityFunc(float x, float param) {
//x = acosf(x);
x = quantizeFloat(fabs(x), param);
return x;
}
static void sceneInit(void)
{
// Load the vertex shader, create a shader program and bind it
vshader_dvlb = DVLB_ParseFile((u32*)vshader_shbin, vshader_shbin_size);
shaderProgramInit(&program);
shaderProgramSetVsh(&program, &vshader_dvlb->DVLE[0]);
C3D_BindProgram(&program);
// Get the location of the uniforms
uLoc_projection = shaderInstanceGetUniformLocation(program.vertexShader, "projection");
uLoc_modelView = shaderInstanceGetUniformLocation(program.vertexShader, "modelView");
// Configure attributes for use with the vertex shader
C3D_AttrInfo* attrInfo = C3D_GetAttrInfo();
AttrInfo_Init(attrInfo);
AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 3); // v0=position
AttrInfo_AddLoader(attrInfo, 1, GPU_FLOAT, 2); // v1=texcoord
AttrInfo_AddLoader(attrInfo, 2, GPU_FLOAT, 3); // v2=normal
// Create the VBO (vertex buffer object)
vbo_data = linearAlloc(sizeof(vertex_list));
memcpy(vbo_data, vertex_list, sizeof(vertex_list));
// Configure buffers
C3D_BufInfo* bufInfo = C3D_GetBufInfo();
BufInfo_Init(bufInfo);
BufInfo_Add(bufInfo, vbo_data, sizeof(vertex), 3, 0x210);
// Configure the first fragment shading substage to blend the fragment primary color
// with the fragment secondary color.
// See https://www.opengl.org/sdk/docs/man2/xhtml/glTexEnv.xml for more insight
C3D_TexEnv* env = C3D_GetTexEnv(0);
C3D_TexEnvSrc(env, C3D_Both, GPU_FRAGMENT_SECONDARY_COLOR, GPU_FRAGMENT_SECONDARY_COLOR, 0);
C3D_TexEnvOp(env, C3D_Both, 0, 0, 0);
C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE);
static const C3D_Material material =
{
{ 0.0f, 0.0f, 0.0f }, //ambient
{ 0.0f, 0.0f, 0.0f }, //diffuse
{ 1.0f, 1.0f, 1.0f }, //specular0
{ 0.0f, 0.0f, 0.0f }, //specular1
{ 0.0f, 0.0f, 0.0f }, //emission
};
C3D_LightEnvInit(&lightEnv);
C3D_LightEnvBind(&lightEnv);
C3D_LightEnvMaterial(&lightEnv, &material);
LightLut_FromFunc(&lut_Identity, identityFunc, 10.0f, true);
C3D_LightEnvLut(&lightEnv, GPU_LUT_D0, GPU_LUTINPUT_LN, false, &lut_Identity);
C3D_FVec lightVec = FVec4_New(0.0, 0.0, -1.0, 0.0);
C3D_LightInit(&light, &lightEnv);
C3D_LightColor(&light, 1.0, 1.0, 1.0);
C3D_LightPosition(&light, &lightVec);
}
static void sceneRender(float iod)
{
// Compute the projection matrix
Mtx_OrthoTilt(&projection, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, false);
// Calculate the modelView matrix
C3D_Mtx modelView;
Mtx_Identity(&modelView);
// Update the uniforms
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &projection);
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_modelView, &modelView);
// Draw the VBO
C3D_DrawArrays(GPU_TRIANGLES, 0, vertex_list_count);
}
static void sceneExit(void)
{
// Free the VBO
linearFree(vbo_data);
// Free the shader program
shaderProgramFree(&program);
DVLB_Free(vshader_dvlb);
}
int main()
{
// Initialize graphics
gfxInitDefault();
gfxSet3D(true); // Enable stereoscopic 3D
C3D_Init(C3D_DEFAULT_CMDBUF_SIZE);
// Initialize the render targets
C3D_RenderTarget* targetLeft = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
C3D_RenderTarget* targetRight = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
C3D_RenderTargetSetClear(targetLeft, C3D_CLEAR_ALL, CLEAR_COLOR, 0);
C3D_RenderTargetSetClear(targetRight, C3D_CLEAR_ALL, CLEAR_COLOR, 0);
C3D_RenderTargetSetOutput(targetLeft, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS);
C3D_RenderTargetSetOutput(targetRight, GFX_TOP, GFX_RIGHT, DISPLAY_TRANSFER_FLAGS);
// Initialize the scene
sceneInit();
// Main loop
while (aptMainLoop())
{
hidScanInput();
// Respond to user input
u32 kDown = hidKeysDown();
if (kDown & KEY_START)
break; // break in order to return to hbmenu
float slider = osGet3DSliderState();
float iod = slider/3;
// Render the scene
C3D_FrameBegin(C3D_FRAME_SYNCDRAW);
{
C3D_FrameDrawOn(targetLeft);
sceneRender(-iod);
if (iod > 0.0f)
{
C3D_FrameDrawOn(targetRight);
sceneRender(iod);
}
}
C3D_FrameEnd(0);
}
// Deinitialize the scene
sceneExit();
// Deinitialize graphics
C3D_Fini();
gfxExit();
return 0;
}
; Example PICA200 vertex shader
; Uniforms
.fvec projection[4], modelView[4]
; Constants
.constf myconst(0.0, 1.0, -1.0, 0.5)
.alias zeros myconst.xxxx ; Vector full of zeros
.alias ones myconst.yyyy ; Vector full of ones
.alias half myconst.wwww
; Outputs
.out outpos position
.out outtc0 texcoord0
.out outclr color
.out outview view
.out outnq normalquat
; Inputs (defined as aliases for convenience)
.alias inpos v0
.alias intex v1
.alias innrm v2
.proc main
; Force the w component of inpos to be 1.0
mov r0.xyz, inpos
mov r0.w, ones
; r1 = modelView * inpos
dp4 r1.x, modelView[0], r0
dp4 r1.y, modelView[1], r0
dp4 r1.z, modelView[2], r0
dp4 r1.w, modelView[3], r0
; outview = -r1
mov outview, -r1
; outpos = projection * r1
dp4 outpos.x, projection[0], r1
dp4 outpos.y, projection[1], r1
dp4 outpos.z, projection[2], r1
dp4 outpos.w, projection[3], r1
; outtex = intex
mov outtc0, intex
; Transform the normal vector with the modelView matrix
; TODO: use a separate normal matrix that is the transpose of the inverse of modelView
dp3 r14.x, modelView[0], innrm
dp3 r14.y, modelView[1], innrm
dp3 r14.z, modelView[2], innrm
dp3 r6.x, r14, r14
rsq r6.x, r6.x
mul r14.xyz, r14.xyz, r6.x
mov r0, myconst.yxxx
add r4, ones, r14.z
mul r4, half, r4
cmp zeros, ge, ge, r4.x
rsq r4, r4.x
mul r5, half, r14
jmpc cmp.x, degenerate
rcp r0.z, r4.x
mul r0.xy, r5, r4
degenerate:
mov outnq, r0
mov outclr, ones
; We're finished
end
.end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment