add basic stereoscopic 3d support
This commit is contained in:
parent
5b8816c2fe
commit
43ab9f9393
138
source/main.cpp
138
source/main.cpp
@ -20,24 +20,50 @@ struct vertex
|
|||||||
float uv[2];
|
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
|
class camera
|
||||||
{
|
{
|
||||||
public:
|
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 theta = C3D_AngleFromDegrees(vfov);
|
||||||
const float h = tanf(theta / 2.0f);
|
const float h = tanf(theta / 2.0f);
|
||||||
const float viewportHeight = 2.0f * h;
|
const float viewportHeight = 2.0f * h;
|
||||||
const float viewportWidth = aspectRatio * viewportHeight;
|
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 w = FVec3_Normalize(FVec3_Subtract(lookfrom, lookat));
|
||||||
const C3D_FVec u = FVec3_Normalize(FVec3_Cross(vup, w));
|
const C3D_FVec u = FVec3_Normalize(FVec3_Cross(vup, w));
|
||||||
const C3D_FVec v = FVec3_Cross(w, u);
|
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);
|
horizontal = FVec3_Scale(u, viewportWidth);
|
||||||
vertical = FVec3_Scale(v, viewportHeight);
|
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
|
void setupFixed() const
|
||||||
@ -48,39 +74,27 @@ public:
|
|||||||
*C3D_FixedAttribGetWritePtr(3) = vertical;
|
*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:
|
private:
|
||||||
C3D_FVec origin;
|
C3D_FVec origin;
|
||||||
C3D_FVec lowerLeftCorner;
|
C3D_FVec lowerLeftCorner;
|
||||||
C3D_FVec horizontal;
|
C3D_FVec horizontal;
|
||||||
C3D_FVec vertical;
|
C3D_FVec vertical;
|
||||||
|
float shift;
|
||||||
};
|
};
|
||||||
|
|
||||||
static DVLB_s* vshaderDVLB;
|
static void setupCam(C3D_FVec lookFrom, C3D_FVec lookAt, C3D_FVec up, float iod)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
constexpr float VFOV = 90;
|
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.setupFixed();
|
||||||
|
cam.setupUniform();
|
||||||
}
|
}
|
||||||
|
|
||||||
static float rand01()
|
static float rand01()
|
||||||
@ -102,6 +116,8 @@ static C3D_FVec randvec()
|
|||||||
while (FVec3_Magnitude(out) > 1.0f);
|
while (FVec3_Magnitude(out) > 1.0f);
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
|
|
||||||
|
return FVec4_New(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setupVertices()
|
static void setupVertices()
|
||||||
@ -121,7 +137,7 @@ static void setupVertices()
|
|||||||
|
|
||||||
v.coords[0] = 2.0f * s - 1.0f;
|
v.coords[0] = 2.0f * s - 1.0f;
|
||||||
v.coords[1] = 2.0f * t - 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[0] = s * (240.0f / 256.0f);
|
||||||
v.uv[1] = t * (400.0f / 512.0f);
|
v.uv[1] = t * (400.0f / 512.0f);
|
||||||
@ -168,6 +184,7 @@ static void sceneInit()
|
|||||||
sphereColorsUniformLocation = shaderInstanceGetUniformLocation(program.vertexShader, "sphereColors");
|
sphereColorsUniformLocation = shaderInstanceGetUniformLocation(program.vertexShader, "sphereColors");
|
||||||
sphereLightsUniformLocation = shaderInstanceGetUniformLocation(program.vertexShader, "sphereLights");
|
sphereLightsUniformLocation = shaderInstanceGetUniformLocation(program.vertexShader, "sphereLights");
|
||||||
randUniformLocation = shaderInstanceGetUniformLocation(program.vertexShader, "rand");
|
randUniformLocation = shaderInstanceGetUniformLocation(program.vertexShader, "rand");
|
||||||
|
shiftUniformLocation = shaderInstanceGetUniformLocation(program.vertexShader, "shift");
|
||||||
|
|
||||||
C3D_AttrInfo* attrInfo = C3D_GetAttrInfo();
|
C3D_AttrInfo* attrInfo = C3D_GetAttrInfo();
|
||||||
AttrInfo_Init(attrInfo);
|
AttrInfo_Init(attrInfo);
|
||||||
@ -254,24 +271,28 @@ static u32 getFrameNumColor(unsigned int frameNum)
|
|||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
gfxInitDefault();
|
gfxInitDefault();
|
||||||
|
gfxSet3D(true);
|
||||||
C3D_Init(C3D_DEFAULT_CMDBUF_SIZE);
|
C3D_Init(C3D_DEFAULT_CMDBUF_SIZE);
|
||||||
|
|
||||||
C3D_RenderTarget* target = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
|
C3D_RenderTarget* targetLeft = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
|
||||||
C3D_RenderTargetSetOutput(target, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS);
|
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_TexInit(&prevFrameLeft, 256, 512, GPU_RGBA8);
|
||||||
C3D_TexBind(0, &prevFrame);
|
|
||||||
|
C3D_TexInit(&prevFrameRight, 256, 512, GPU_RGBA8);
|
||||||
|
|
||||||
sceneInit();
|
sceneInit();
|
||||||
|
|
||||||
C3D_FVec lookFrom = FVec3_New(0, 0.6125f, 0);
|
C3D_FVec lookFrom = FVec3_New(0, 0.6125f, 0);
|
||||||
C3D_FVec lookAt = FVec3_New(0, 0, -1.0f);
|
C3D_FVec lookAt = FVec3_New(0, 0, -1.0f);
|
||||||
C3D_FVec vup = FVec3_New(0, 1.0f, 0);
|
C3D_FVec vup = FVec3_New(0, 1.0f, 0);
|
||||||
bool dirty = false;
|
bool dirty = true;
|
||||||
|
|
||||||
setupFixed(lookFrom, lookAt, vup);
|
|
||||||
|
|
||||||
unsigned int frameNum = 0;
|
unsigned int frameNum = 0;
|
||||||
|
float previousIOD = osGet3DSliderState() / 4.0f;
|
||||||
|
|
||||||
// Main loop
|
// Main loop
|
||||||
while (aptMainLoop())
|
while (aptMainLoop())
|
||||||
@ -326,12 +347,19 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
lookFrom = FVec3_Add(lookFrom, diff);
|
lookFrom = FVec3_Add(lookFrom, diff);
|
||||||
|
|
||||||
|
const float iod = osGet3DSliderState() / 4.0f;
|
||||||
|
|
||||||
|
if (fabsf(iod - previousIOD) > 0.01f)
|
||||||
|
{
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (dirty)
|
if (dirty)
|
||||||
{
|
{
|
||||||
setupFixed(lookFrom, lookAt, vup);
|
|
||||||
|
|
||||||
frameNum = 0;
|
frameNum = 0;
|
||||||
|
|
||||||
|
previousIOD = iod;
|
||||||
|
|
||||||
dirty = false;
|
dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,26 +368,48 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
C3D_TexEnvColor(C3D_GetTexEnv(0), getFrameNumColor(frameNum));
|
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);
|
setupCam(lookFrom, lookAt, vup, -iod);
|
||||||
C3D_FrameDrawOn(target);
|
C3D_TexBind(0, &prevFrameLeft);
|
||||||
|
C3D_RenderTargetClear(targetLeft, C3D_CLEAR_ALL, 0, 0);
|
||||||
|
C3D_FrameDrawOn(targetLeft);
|
||||||
sceneRender();
|
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_FrameEnd(0);
|
||||||
|
|
||||||
C3D_SyncTextureCopy(
|
C3D_SyncTextureCopy(
|
||||||
(u32*)target->frameBuf.colorBuf, GX_BUFFER_DIM((240 * 8 * 4) >> 4, 0),
|
(u32*)targetLeft->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*)prevFrameLeft.data + (512 - 400) * 256, GX_BUFFER_DIM((240 * 8 * 4) >> 4, ((256 - 240) * 8 * 4) >> 4),
|
||||||
240 * 400 * 4, FRAMEBUFFER_TRANSFER_FLAGS
|
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();
|
sceneExit();
|
||||||
|
|
||||||
C3D_TexDelete(&prevFrame);
|
C3D_TexDelete(&prevFrameLeft);
|
||||||
C3D_RenderTargetDelete(target);
|
C3D_RenderTargetDelete(targetLeft);
|
||||||
|
|
||||||
C3D_Fini();
|
C3D_Fini();
|
||||||
gfxExit();
|
gfxExit();
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
.constf myconst(0.0, 1.0, 0.01, 1000.0)
|
.constf myconst(0.0, 1.0, 0.001, 1000.0)
|
||||||
.constf myconst2(0.5, 999.0, 0.0, 0.0)
|
.constf myconst2(0.5, 999.0, 1.1, 0.0)
|
||||||
.alias zeros myconst.xxxx
|
.alias zeros myconst.xxxx
|
||||||
.alias halfs myconst2.xxxx
|
.alias halfs myconst2.xxxx
|
||||||
.alias ones myconst.yyyy
|
.alias ones myconst.yyyy
|
||||||
.alias near myconst.zzzz
|
.alias tooclose myconst.zzzz
|
||||||
.alias far myconst.wwww
|
.alias far myconst.wwww
|
||||||
.alias noHit myconst2.yyyy
|
.alias noHit myconst2.yyyy
|
||||||
|
.alias defaultDist myconst.wxxx
|
||||||
|
.alias nearplane myconst2.zzzz
|
||||||
|
|
||||||
.consti bounceLoopParams(9, 0, 1, 0)
|
.consti bounceLoopParams(9, 0, 1, 0)
|
||||||
.consti calcSphereLoopParams(3, 0, 1, 0)
|
.consti calcSphereLoopParams(3, 0, 1, 0)
|
||||||
@ -26,6 +28,9 @@
|
|||||||
; random numbers
|
; random numbers
|
||||||
.fvec rand[10]
|
.fvec rand[10]
|
||||||
|
|
||||||
|
; stereoscopic 3d shift
|
||||||
|
.fvec shift
|
||||||
|
|
||||||
.in inOrigin v0
|
.in inOrigin v0
|
||||||
.in inLowerLeftCorner v1
|
.in inLowerLeftCorner v1
|
||||||
.in inHorizontal v2
|
.in inHorizontal v2
|
||||||
@ -39,12 +44,6 @@
|
|||||||
.out outColor color
|
.out outColor color
|
||||||
|
|
||||||
.proc main
|
.proc main
|
||||||
; outPos = inPos
|
|
||||||
mov outPos, inPos
|
|
||||||
|
|
||||||
; outUV = inUV
|
|
||||||
mov outUV, inUV
|
|
||||||
|
|
||||||
; r1 = inOrigin
|
; r1 = inOrigin
|
||||||
mov r1, inOrigin
|
mov r1, inOrigin
|
||||||
|
|
||||||
@ -60,6 +59,9 @@
|
|||||||
; set initial color to (0, 0, 0)
|
; set initial color to (0, 0, 0)
|
||||||
mov r13.xyz, zeros
|
mov r13.xyz, zeros
|
||||||
|
|
||||||
|
; set initial hit location to (far, far, far)
|
||||||
|
mov r15.y, far
|
||||||
|
|
||||||
; calculate light bounces
|
; calculate light bounces
|
||||||
for bounceLoopParams
|
for bounceLoopParams
|
||||||
; setup random numbers for this iteration
|
; setup random numbers for this iteration
|
||||||
@ -87,7 +89,8 @@
|
|||||||
; which only happens when
|
; which only happens when
|
||||||
; a ray does not hit any spheres
|
; a ray does not hit any spheres
|
||||||
cmp noHit.xyz, lt, lt, r10.xyz
|
cmp noHit.xyz, lt, lt, r10.xyz
|
||||||
breakc cmp.x
|
;breakc cmp.x
|
||||||
|
jmpc cmp.x, labl
|
||||||
|
|
||||||
; multiply color by albedo
|
; multiply color by albedo
|
||||||
mul r4.xyz, r4.xyz, r10.xyz
|
mul r4.xyz, r4.xyz, r10.xyz
|
||||||
@ -100,13 +103,46 @@
|
|||||||
|
|
||||||
; set r2 to new ray direction
|
; set r2 to new ray direction
|
||||||
call diffuse
|
call diffuse
|
||||||
|
|
||||||
|
; update distance if not set
|
||||||
|
cmp noHit, le, le, r15.y
|
||||||
|
ifc cmp.x
|
||||||
|
mov r15.y, r4.w
|
||||||
|
.end
|
||||||
.end
|
.end
|
||||||
|
|
||||||
|
labl:
|
||||||
|
|
||||||
; copy final color to output
|
; copy final color to output
|
||||||
mov outColor.xyz, r13.xyz
|
mov outColor.xyz, r13.xyz
|
||||||
|
|
||||||
; set alpha to 1
|
; set alpha to 1
|
||||||
mov outColor.w, ones
|
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
|
||||||
.end
|
.end
|
||||||
@ -181,7 +217,7 @@
|
|||||||
mul r9.z, r9.z, r9.x
|
mul r9.z, r9.z, r9.x
|
||||||
|
|
||||||
; if root < min distance, check other root
|
; if root < min distance, check other root
|
||||||
cmp near, gt, gt, r9.z
|
cmp tooclose, gt, gt, r9.z
|
||||||
jmpc cmp.x, calcSphereCheckOtherRoot
|
jmpc cmp.x, calcSphereCheckOtherRoot
|
||||||
|
|
||||||
; if root > max distance, check other root
|
; if root > max distance, check other root
|
||||||
@ -198,7 +234,7 @@
|
|||||||
mul r9.z, r9.z, r9.x
|
mul r9.z, r9.z, r9.x
|
||||||
|
|
||||||
; if root < min distance, check other root
|
; if root < min distance, check other root
|
||||||
cmp near, gt, gt, r9.z
|
cmp tooclose, gt, gt, r9.z
|
||||||
jmpc cmp.x, calcSphereExit
|
jmpc cmp.x, calcSphereExit
|
||||||
|
|
||||||
; if root > max distance, check other root
|
; if root > max distance, check other root
|
||||||
@ -211,8 +247,7 @@
|
|||||||
mov r4.w, r9.z
|
mov r4.w, r9.z
|
||||||
|
|
||||||
; calculate new origin
|
; calculate new origin
|
||||||
mul r5.xyz, r2.xyz, r9.zzz
|
mad r5.xyz, r2.xyz, r9.zzz, r1.xyz
|
||||||
add r5.xyz, r5.xyz, r1.xyz
|
|
||||||
|
|
||||||
; calculate normal
|
; calculate normal
|
||||||
add r7.xyz, r5.xyz, -r3.xyz
|
add r7.xyz, r5.xyz, -r3.xyz
|
||||||
|
Loading…
Reference in New Issue
Block a user