/* returns the rotation quat required to match v1 to v2 */ void vects_to_quat(double v1[3], double v2[3], double q[4]){ double axis[3]; double phi; double denom; /* first normalise each of em */ vnormal(v1); vnormal(v2); /* check that someone isn't playing silly buggers */ if((v1[0] == v2[0]) && (v1[1] == v2[1]) && (v1[2] == v2[2])){ vcopy(axis, v1); phi = 0.0; } else{ /* find the axis with a cross product */ vcross(axis, v2, v1); /* find the angle to rotate around that axis. */ /* v1.v2 = ||v1|| ||v2|| cos(angle) */ denom = vlength(v1) * vlength(v2); if(denom == 0){ phi = 0.0; } else{ phi = acos(vdot(v1, v2) / denom); } } /* create the quat */ axis_to_quat(axis, phi, q); }
//perhaps in engine is better? void find_best_split_plane( const std::vector <face_t >& faces // ,std::vector <face_t >& front // ,std::vector <face_t >& back ) { //all time low score_t low={},s={}; low.score = 999999; //along planes, along edges... for ( size_t i = faces.size() ; i--; ) { face_t f = faces[i]; //xplane_t p = { f.a, f.normal() }; //test_plane(p, faces, s); //enum{ABC,AB,BC,CA}; vec3 N = f.normal(); plane_t planes[4] = { pmake( f.a, N), //this should always end up on front/front_on side pmake( f.a, vnormal(vcross( N, f.b - f.a ) ) ), pmake( f.b, vnormal(vcross( N, f.c - f.b ) ) ), pmake( f.c, vnormal(vcross( N, f.a - f.c ) ) ) }; //test planes for ( int j = 0; j < 4 ; ++j ) { test_plane( planes[j], faces, s); if( s.score < low.score ) low=s,low.face=i; } } //check score //use low.p to split front and backm or stop here if bad score //print printf( "\n\nBest plane for all %d\n", faces.size()); printf( "index %d\n", low.face); printf( "score = %d\n", low.score ); printf( "balance = %d\n", low.balance ); printf( "splits = %d\n", low.split ); printf( "coins = %d\n", low.coin ); printf( "front = %d\n", low.front ); printf( "back = %d\n", low.back ); printf( "plane = %f, %f, %f, %f\n", low.p.x,low.p.y,low.p.z,low.p.w ); }
/* * Given an axis and angle, compute quaternion. * This function computes a quaternion based on an axis (defined by * the given vector) and an angle about which to rotate. The angle is * expressed in radians. The result is put into the third argument. */ void axis_to_quat(float a[3], float phi, float q[4]) { vnormal(a); vcopy(a,q); vscale(q,sin(phi/2.0)); q[3] = cos(phi/2.0); }
//save load vec3 uv_tangent(vec3 v0,vec3 v1,vec3 uv0,vec3 uv1) { // if(vdot(uv0,uv1)==0.f) if(uv0.x==uv1.x && uv0.y==uv1.y) { printf("WARNING!!! Zero area UV.\n"); //set to face tangent return vnormal( vcross( v0, v1 ) ); }else{ float coef = 1./(uv0.x * uv1.y - uv1.x * uv0.y); vec3 t={ coef * ((v0.x * uv1.y) + (v1.x * -uv0.y)), coef * ((v0.y * uv1.y) + (v1.y * -uv0.y)), coef * ((v0.z * uv1.y) + (v1.z * -uv0.y)) }; float len=vlen(t); if(!len){ printf("ERROR: zero area UV @uv_tangent.\n"); exit(-1); } t/=len; return t; } }
/* * Given an axis and angle, compute quaternion. */ void axis_to_quat( double a[3], double phi, double q[4] ) { vnormal( a ); vcopy( a, q ); vscale( q, (double) sin( phi / 2.0) ); q[3] = (double) cos( phi / 2.0 ); }
void Trackball :: spin ( float friction ) { const int RENORMCOUNT = 97 ; static int count=0; //float * q1, * q2, * dest ; float q1[4], * q2, * dest ; float t1[4], t2[4], t3[4]; float tf[4]; //q1 = m_lastquat ; if( friction != 1.0 ) { float temp ; temp = vlength(m_lastquat); if( temp != 0 ) { vcopy(m_lastquat,q1); vnormal(q1) ; temp = asin(temp)*friction ; q1[0] *= sin(temp) ; q1[1] *= sin(temp) ; q1[2] *= sin(temp) ; q1[3] = cos(temp) ; } else { vcopy(m_lastquat,q1); q1[3] = m_lastquat[3] ; } } else { vcopy(m_lastquat,q1); q1[3] = m_lastquat[3] ; } q2 = m_currquat ; dest = m_currquat ; vcopy(q1,t1); vscale(t1,q2[3]); vcopy(q2,t2); vscale(t2,q1[3]); vcross(q2,q1,t3); vadd(t1,t2,tf); vadd(t3,tf,tf); tf[3] = q1[3] * q2[3] - vdot(q1,q2); dest[0] = tf[0]; dest[1] = tf[1]; dest[2] = tf[2]; dest[3] = tf[3]; if (++count > RENORMCOUNT) { count = 0; normalize_quat(dest); } }
/* READ GEO */ void get_geometry(TE*root) { printf("_\t_\tGEOMETRIES\t_\t_\t_\t_\n"); TE*geo = root -> FCE( "library_geometries" )->FCE("geometry"); while ( geo ) { get_object( geo ); geo = geo -> NSE ( "geometry" ); } //get transforms, tranform vertices TE*node = root -> FCE( "library_visual_scenes" )-> FCE("visual_scene") -> FCE("node");; size_t i=0; while ( node && i < dae_geo_objects.size() ) { dae_geo_t &d = dae_geo_objects[i]; std::string name = node->Attribute( "name" ); if( name == d.name ){ std::vector< float >mat=str_fv(node->FCE("matrix")->GetText(),16); //transpose float M[16]; mtranspose( M, &mat[0] ); //multiply each vertex for( size_t k = 0; k < d.pos.size(); k+=3 ){ vec3 vp={d.pos[k],d.pos[k+1],d.pos[k+2]}; vp = mmulv( M, vp, 1.f ); d.pos[k] = vp.x; d.pos[k+1] = vp.y; d.pos[k+2] = vp.z; } for( size_t k = 0; k < d.normal.size(); k+=3 ){ vec3 vp={d.normal[k],d.normal[k+1],d.normal[k+2]}; vp = vnormal(mmulv( M, vp, 0.f)); d.normal[k] = vp.x; d.normal[k+1] = vp.y; d.normal[k+2] = vp.z; } ++i; } node = node -> NSE( "node" ); } printf("count = %d\n", dae_geo_objects.size()); }
void Ctrl3DRotate::drag(int x, int y){ // free rotation control if(sx0 == x && sy0 == y) {angle_r = 0; return;} float x0=sx0-cx, y0=-(sy0-cy), z0=cz; float x1=x-cx, y1=-(y-cy), z1=cz; float n0=sqrt(x0*x0+y0*y0+z0*z0); float n1=sqrt(x1*x1+y1*y1+z1*z1); x0/=n0;y0/=n0;z0/=n0; x1/=n1;y1/=n1;z1/=n1; angle_r=acos(x0*x1+y0*y1+z0*z1)*180/M_PI; vnormal(norm_rx, norm_ry, norm_rz, x0, y0, z0, x1, y1, z1); }
int MouseMoveAndShift::ContinueMOper(int x, int y){ float cx = 2.*float(x-wndw/2)/wndw; float cy = 2.*float(wndh-y-wndh/2)/wndh; float cz = 0; float cx0 = 2.*float(sx0-wndw/2)/wndw; float cy0 = 2.*float(wndh-sy0-wndh/2)/wndh; float cz0 = 0; Ptn p = {cx, cy, cz}; Ptn p0 = {cx0, cy0, cz0}; switch(oper){ double w,w0; case 1: memcpy(mi,m,sizeof(mi)); glInvMat(mi); w = 1.0/(mi[3]*p.x + mi[7]*p.y + mi[11]*p.z + mi[15]); w0 = 1.0/(mi[3]*p0.x + mi[7]*p0.y + mi[11]*p0.z + mi[15]); p = p*w; p0 = p0*w0; p = glMulMat(mi,p,w); p0 = glMulMat(mi,p0,w0); p=p-p0; shift_x = p.x; shift_y = p.y; shift_z = p.z; break; case 2: // free rotation control if(sx0 == x && sy0 == y) {angle_r = 0; break;} int windW = wndw/2; int windH = wndh/2; float x0=sx0-windW, y0=-(sy0-windH), z0=windW/4; float x1=x-windW, y1=-(y-windH), z1=windW/4; float n0=sqrt(x0*x0+y0*y0+z0*z0); float n1=sqrt(x1*x1+y1*y1+z1*z1); x0/=n0;y0/=n0;z0/=n0; x1/=n1;y1/=n1;z1/=n1; angle_r=acos(x0*x1+y0*y1+z0*z1)*180/M_PI; vnormal(norm_rx, norm_ry, norm_rz, x0, y0, z0, x1, y1, z1); break; } return oper; }
/* Given an quaternion compute an axis and angle */ void quat_to_axis(double vec[3], double *phi, double quat[4]){ double scale; scale = quat[0]*quat[0] + quat[1]*quat[1] + quat[2]*quat[2]; if(scale == 0){ /* no rotation, we're stuffed */ vec[0] = 0; vec[1] = 0; vec[2] = 1; *phi = 0; } else{ vcopy(vec, quat); vscale(vec, 1.0/scale); vnormal(vec); *phi = 2.0*acos(quat[3]); } }
/** * \return the id of vertex between two corners. * * If it wasn't previously computed, does #converge() and adds vertex to process. */ static int vertid(PROCESS *process, const CORNER *c1, const CORNER *c2) { float v[3], no[3]; int vid = getedge(process->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k); if (vid != -1) return vid; /* previously computed */ converge(process, c1, c2, v); /* position */ #ifdef USE_ACCUM_NORMAL zero_v3(no); #else vnormal(process, v, no); #endif addtovertices(process, v, no); /* save vertex */ vid = (int)process->curvertex - 1; setedge(process, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k, vid); return vid; }
/* Given an axis and angle, compute quaternion */ void axis_to_quat(double vec[3], double phi, double quat[4]){ vnormal(vec); vcopy(quat, vec); vscale(quat, sin(phi/2.0)); quat[3] = cos(phi/2.0); }
vec3 normal()const{ return vnormal( vcross( b-a, c-a ) );}
//to global verts and faces (not shorts) //ALSO, COMBINES EACH DAE OBJECT void dae_geo_to_polys_and_verts( dae_geo_t dg ) { //mtrl string , count materials.insert( materials.end(), dg.materials.begin(),dg.materials.end()); material_counts.insert( material_counts.end(), dg.material_counts.begin(), dg.material_counts.end()); printf("_\t_\tDAE -> VERTEX / INDICES\t_\t_\t_\t_\t_\n"); int II = 0, pi,ui,ni,ci; poly_t p={}; for ( int f = 0; f < dg.poly_count; ++f) { //vertices / indices for ( int j = 0; j < 3; ++j ) { vertex_t v={}; //get indices, p,normal, pi = dg.poly[II++]; ni = dg.poly[II++]; ui = dg.poly[II++]; ci = dg.poly[II++]; // v.pos.x = dg.pos[ pi*3 + 0 ]; v.pos.y = dg.pos[ pi*3 + 1 ]; v.pos.z = dg.pos[ pi*3 + 2 ]; v.normal.x = dg.normal[ ni*3 + 0 ]; v.normal.y = dg.normal[ ni*3 + 1 ]; v.normal.z = dg.normal[ ni*3 + 2 ]; v.uv.x = dg.uv[ ui*2 + 0 ]; v.uv.y = dg.uv[ ui*2 + 1 ]; //vertex hand painted color //vset(v.init_rgb,.1,.1,.1); v.color.x = dg.rgb[ ci*3 + 0 ]; v.color.y = dg.rgb[ ci*3 + 1 ]; v.color.z = dg.rgb[ ci*3 + 2 ]; int index = vertex_find( v ); if ( index == (int)verts.size() ){ verts.push_back( v ); //debug ( "dupe found\n" ); } p.index[ j ]=index; } const vec3 basis[3]={ { -.40824829046, -.70710678118, .57735026919 },//blue { -.40824829046, .70710678118, .57735026919 },//green { .81649658092, 0., .57735026919 }//red }; //tangent, basis and inset,,, and direction of vertex color light for ( int j=0;j<3;++j ) { vertex_t& a = verts[p.index[j]]; const vertex_t& b = verts[p.index[(j+1)%3]]; const vertex_t& c = verts[p.index[(j+2)%3]]; //inset ( lighting sample point ) //BAD FOR SMOOTH!! a.inset = a.pos + (b.pos-a.pos)*.005f + (c.pos-a.pos)*.005f; //tangent a.tangent = uv_tangent( vnormal(b.pos-a.pos), vnormal(c.pos-a.pos), vnormal(b.uv - a.uv), vnormal(c.uv - a.uv) ); //MUST BE CORRECTED FOR SMOOTH SURFACES // if( vdot ( vnormal( a.normal ), vnormal ( vcross( b.pos-a.pos, c.pos-a.pos ) ) ) < .9 ) // { // printf( "SHOULD BE CORRECTED\n"); vec3 right = vcross( a.tangent, a.normal ); a.tangent = vnormal( vcross( a.normal, right ) ); // } //basis //we have normal vec3 N = a.normal;//vnormal( vcross(b.pos-a.pos, c.pos-a.pos) ); vec3 T = a.tangent; vec3 B = vcross( T, N ); //rotate basis axes by TBN for( int k=0; k<3;++k) a.basis[k] = //exactly like mmulv T*vec3f(basis[k].x,basis[k].x,basis[k].x)+ B*vec3f(basis[k].y,basis[k].y,basis[k].y)+ N*vec3f(basis[k].z,basis[k].z,basis[k].z) ; //vertex color.. FOR NOW JUST ALL // for( int k=0; k<3;++k) // a.basis_color[k]=a.color; } polys.push_back(p); } printf ( "VERTS : %d\n", verts.size() ); printf ( "POLYS : %d\n", polys.size() ); printf ( "\n" ); }
void render_vertex_colors() { printf ( "_\t_\tRENDERING VERTEX COLORS_\t_\t_\t_\t_\n"); for(size_t i = 0; i < verts.size(); ++i )// each vertex { vertex_t&v = verts[i]; for(size_t j = 0; j < lights.size(); ++j )// each light { // int blocked = 0; const light_t&L = lights[j]; if( L.dont_bake ) continue; vec3 start, dir; if( L.type == light_t::SUN ){ start = v.pos;//inset;//+L.dir*.000001; dir = L.dir*2048.f; }else{ start = L.pos; dir = (v.pos - L.pos ); } //early if ( vdot ( L.pos - v.pos, v.normal ) <= 0.f )continue; //test triangles (TODO/NOTE : DONT FACE CULL ) int blocked=0; //ERROR LAYS HERE!!! NOT IN TANGENT for(size_t k = 0; k < polys.size()&& !blocked; ++k )// each polygon { const poly_t&p = polys[k]; //is this vertex used in the poly? // for (int pi = 0; pi < 3 ; ++pi) // alt, use some margin // if( (int)i == (int)p.index[pi] ) // continue; blocked |= ray_triangle( start, dir, verts[p.index[0]].pos, verts[p.index[1]].pos, verts[p.index[2]].pos); } if( !blocked ) { //todo inverse linear / square vec3 d,dN; float f,dp; if( L.type == light_t::SUN ){ dN = L.dir; f = 1.f; }else { d = L.pos - v.pos; dN=vnormal( d ); f = 1.-fmin(1.f, vlen(d) / L.dist ); } for( int k = 0; k<3; ++k ) { dp = fmax(0.f,vdot( v.basis[k], dN ) ); v.basis_color[k]+=L.rgb*f*dp; } //float f = 1.-fmin(1.f, vlen(d) / L.dist ); //float f = 1.f/(1.f + vdot( d, d ) );//inv square //not as prominent but sphere like //float f = 1.f-1.f/(1.f + fmax(0.f,L.dist-vlen( d ) ) );//inv } } //printf ("C = %.2f,%.2f,%.2f\n", v.init_rgb.x, v.init_rgb.y, v.init_rgb.z); } }