/* * Copyright (C) 2006 Robert Geist * All rights reserved. */ #define GL_GLEXT_PROTOTYPES 1 #include #include #include #include #include #include #include #include #include #include #include "xrgba.h" #define G (0.6) #define SIGMA_A (0.008) #define SIGMA_S (0.792) #define SIGMA_T (SIGMA_A + SIGMA_S) #define SUN_AMBIENT 0.65 #define SUN_DIFFUSE 4.0 #define DIRECTIONS 19 #define FINAL_TIME (2*(EDGE)) #define EPSILON 0.00001 struct ivector { int x; /* col */ int y; /* row */ int z; /* dep */ }; struct ivector ci[DIRECTIONS] = { /* index 0 is rest density == absorbed/transmitted */ 0, 0, 0, /* axis directions are indices 1 - 6 */ 1, 0, 0, 0, 1, 0, 0, 0, 1, -1, 0, 0, 0,-1, 0, 0, 0, -1, /* non-corner cube lattice points for 7 - 18 */ 1, 1, 0, 1,-1, 0, -1, 1, 0, -1,-1, 0, 1, 0, 1, 1, 0,-1, -1, 0, 1, -1, 0,-1, 0, 1, 1, 0, 1,-1, 0,-1, 1, 0,-1,-1 }; struct rvector { float x; float y; float z; }; float dot(struct rvector *uptr, struct rvector *vptr) { return(uptr->x*vptr->x + uptr->y*vptr->y + uptr->z*vptr->z); } void normalize(struct rvector *pv) { float length; length = sqrt(dot(pv,pv)); if(length<=0.0){ fprintf(stderr,"eek\n"); exit(1); } pv->x /= length; pv->y /= length; pv->z /= length; } int vec_eq(struct rvector *uptr, struct rvector *vptr) { float sum; sum = fabs(uptr->x - vptr->x)+fabs(uptr->y - vptr->y)+fabs(uptr->z - vptr->z); if(sumx*s; p.y = uptr->y*s; p.z = uptr->z*s; return(p); } struct rvector vec_sub(struct rvector *uptr, struct rvector *vptr) { struct rvector p; p.x = uptr->x - vptr->x; p.y = uptr->y - vptr->y; p.z = uptr->z - vptr->z; return(p); } /* * This is needed for both init_lattice and collision matrix setup. */ struct rvector univ[DIRECTIONS]; fix_univ() { /* * compute unit-length direction vectors; these are * used for the collision matrix too, hence the global */ int i; univ[0].x = univ[0].y = univ[0].z = 0.0; for(i=1;i pingpong[mod(k,EDGE/4)*EDGE+i][j*DIRECTIONS+m][floor(k,EDGE/4)] * so cube coordinates can be recovered from texture coordinates (s,t) * within the fragment program by * * i = mod(t,EDGE) * j = floor(s/DIRECTIONS) * mod(k,(EDGE/4)) = floor(t/EDGE), * +0 (red) = 0*(EDGE/4) + mod(k,EDGE/4) * +1 (green) = 1*(EDGE/4) + mod(k,EDGE/4) * +2 (blue) = 2*(EDGE/4) + mod(k,EDGE/4) * +3 (alpha) = 3*(EDGE/4) + mod(k,EDGE/4) * m = mod(s,DIRECTIONS) * * and that for cloud density is: * cd(i,j,k) -> cloud_d[mod(k,EDGE/4)*EDGE+i][j][floor(k,EDGE/4)] * * where dimensions are pingpong[(EDGE/4)*EDGE][EDGE*DIRECTIONS][4] and * cloud_d[(EDGE/4)*EDGE][EDGE][4]. If EDGE==128, EDGE*EDGE would exceed * the 4096 limit on texture dimensions, so we fold the arrays into RGBA * components to reduce the row dimension from EDGE*EDGE to (EDGE/4)*EDGE. * */ int i,j,k,m; struct rvector sun_dir, dyn_sun_dir, this_much; float sun_ambient, sun_diffuse; FILE *fptr; int dim[3], size; float *densities; float max_component; float sun_component[DIRECTIONS]; int max_comp_index; sun_ambient = SUN_AMBIENT; sun_diffuse = SUN_DIFFUSE; /* sun goes somewhere like (-1000,1000,-1000) and points back at us */ sun_dir.x = 1.0; sun_dir.y = -1.0; sun_dir.z = 1.0; normalize(&sun_dir); /* get cloud densities here ... assume Karl's format */ fptr=fopen(filename,"r"); fread(dim,sizeof(int),3,fptr); if(dim[0]!=EDGE || dim[1]!=EDGE || dim[2]!=EDGE){ fprintf(stderr,"can't handle dimensions\n"); fclose(fptr); exit(1); } size=dim[0]*dim[1]*dim[2]; densities = (float *)calloc(sizeof(float),size); fread(densities,sizeof(float),size,fptr); fclose(fptr); /* load cloud densities and zip out photon densities */ for(i=0;i=(max_component)){ max_component = dot(&univ[m],&dyn_sun_dir); max_comp_index = m; } } if(max_component<=0.0){ fprintf(stderr,"eek\n"); exit(1); } sun_component[max_comp_index] += max_component; this_much = vec_smult(&univ[max_comp_index],max_component); dyn_sun_dir = vec_sub(&dyn_sun_dir,&this_much); } /* now load up the cube boundary values */ for(m=1;m0 is forward, * g<0 is backward, g=0 is isotropic */ float hg(float g, float cos_theta) { float val, dval; dval = 1.0 + g*g - 2.0*g*cos_theta; val = (1.0 - g*g)/pow(dval,1.5); return(val); } void load_collision_matrix() { /* omega[i,j] controls scattering from dir j into dir i */ float hg_row[DIRECTIONS]; float hg_sum; float row_wt[DIRECTIONS]; int i,j; row_wt[0] = 1.0; for(i=1;i<=6;i++) row_wt[i] = 1.0/12.0; for(i=7;i