下面是我的 raymarcher,主要改编自https://www.shadertoy.com/view/llt3R4#
预期的行为是球体在屏幕上的投影,但它投影的是空白空间(由黄色像素表示,而不是一个紫色的)。
这是我使用 x87 协处理器编写的第一个程序,所以我不确定是否缺少任何东西。我认识的一些程序员已经检查过了,没有发现问题,所以我不确定该怎么做。
macro bareintro {
org 0x7c00
jmp 0x0:boot
boot:
xor ax, ax
mov ds, ax
mov ss, ax
}
macro zerob b {
times b db 0
}
bareintro
mov ax, 0x13
int 0x10
mov ax, 0xA000
mov es, ax
xor di, di
y_loop:
mov word [ix], 0
mov bx, [iy]
inc bx
cmp bx, 200
je y_end
mov [iy], bx
x_loop:
; first calculate the raymarching direction:
; vec3 rayDirection(float fieldOfView, vec2 size, vec2 fragCoord) {
; vec2 xy = fragCoord - size / 2.0;
; float z = size.y / tan(radians(fieldOfView) / 2.0);
; return normalize(vec3(xy, -z));
; }
fld qword [h]
fld qword [z_diri]
fmulp
fld qword [y_diri]
fild word [iy]
faddp
fld qword [x_diri]
fild word [ix]
faddp
; finally, normalize vector
; do a couple dupes
fld st2
fld st2
fld st2
call len
fdiv st1, st0
fdiv st2, st0
fdivp st3, st0
; store in respective memory locations
fstp qword [dir_x]
fstp qword [dir_y]
fstp qword [dir_z]
call sdts
setc al
add al, 13
stosb
inc word [ix]
cmp word [ix], 319
ja y_loop
jmp x_loop
y_end:
cli
hlt
; int intersect(float rayx, float rayy, float rayz) {
; float depth = MIN_DIST;
; for(int i = 0; i < STEPS; i++) {
; float vx = rayx * depth;
; float vy = rayy * depth;
; float vz = rayz * depth + 5.0;
; float dist = sdf(vx, vy, vz);
; if(dist < EPS) {
; return 1;
; }
; depth += dist;
; if(depth >= MAX_DIST) {
; return 0;
; }
; }
; return 0;
;}
sdts:
fldz
fstp qword [.depth]
mov cx, 255
.loop:
; float dist = sceneSDF(eye + depth * marchingDirection);
; load in direction vector
fld qword [dir_z]
fld qword [dir_y]
fld qword [dir_x]
fld qword [.depth]
fmul st1, st0
fmul st2, st0
fmulp st3, st0
fld qword [eyez]
fld qword [eyey]
fld qword [eyex]
faddp st3, st0
faddp st3, st0
faddp st3, st0
.sdf:
; single sphere for now (len(p) - radius)
call len
; - radius
fld qword [radius]
fsubp st1, st0
.endsdf:
; EPS <=> Dist
fld qword [eps]
fcomip st0, st1
jb .nohit
; cowabunga!
clc
ret
.nohit:
fld qword [.depth]
; MAX <=> Total
faddp
fld qword [.max_depth]
fcomip st0, st1
fstp qword[.depth]
ja .alsofine
stc
ret
.alsofine:
loop .loop
.endloop:
stc
ret
.max_depth:
dq 100.0
.depth:
dq 0.0
; st0 <- sqrt(s0^2 + s1^2 + s2^2)
len:
fmul st0, st0
fxch st1
fmul st0, st0
faddp st1, st0
fxch st1
fmul st0, st0
faddp st1, st0
fsqrt
ret
x_diri:
dq -160.000
y_diri:
dq -100.000
z_diri:
dq 482.8427
dir_x:
dq -160.000
dir_y:
dq -100.000
dir_z:
dq -2.4142135623911343
w:
dq 320.0
h:
dq 200.0
radius:
dq 1.0
eps:
dq 0.001
eyex:
dq 0.0
eyey:
dq 0.0
eyez:
dq 5.0
ix:
dw 0
iy:
dw 0
zerob 510 - ($-$$)
dw 0xaa55
(这是 C 代码的工作版本)
#include <math.h>
#include <SDL2/SDL.h>
const int STEPS = 256;
const float MIN_DIST = 0.0;
const float MAX_DIST = 100.0;
const float EPS = 0.001;
float sdf(float x, float y, float z) {
float len = sqrt(x*x + y*y + z*z);
return len - 1.0;
}
int intersect(float rayx, float rayy, float rayz) {
float depth = MIN_DIST;
for(int i = 0; i < STEPS; i++) {
float vx = rayx * depth;
float vy = rayy * depth;
float vz = rayz * depth + 5.0;
float dist = sdf(vx, vy, vz);
if(dist < EPS) {
return 1;
}
depth += dist;
if(depth >= MAX_DIST) {
return 0;
}
}
return 0;
}
int main() {
SDL_Init(SDL_INIT_EVERYTHING);
uint32_t buff[320*200];
SDL_Window* win;
SDL_Renderer* ren;
SDL_CreateWindowAndRenderer(320, 200, 0, &win, &ren);
SDL_Texture* tex = SDL_CreateTexture(ren, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC,
320, 200);
for(size_t y = 0; y < 200; y++) {
for(size_t x = 0; x < 320; x++) {
float r_z = -200.0 / 0.41421356237;
float r_y = ((float)y) - 100.0;
float r_x = ((float)x) - 160.0;
float len = sqrt(r_x*r_x + r_y*r_y + r_z*r_z);
r_x /= len;
r_y /= len;
r_z /= len;
buff[y*320 + x] = (-1) * intersect(r_x, r_y, r_z);
}
}
SDL_UpdateTexture(tex, NULL, buff, 320*4);
SDL_RenderCopy(ren, tex, NULL, NULL);
SDL_RenderPresent(ren);
SDL_Event e;
while(1) {
SDL_WaitEvent(&e);
if(e.type == SDL_QUIT) {
SDL_Quit();
return 0;
}
}
return 0;
}