|
Blender
V2.59
|
00001 /* 00002 * $Id: uvproject.c 38054 2011-07-03 10:48:18Z campbellbarton $ 00003 * 00004 * ***** BEGIN GPL LICENSE BLOCK ***** 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software Foundation, 00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 * 00020 * ***** END GPL LICENSE BLOCK ***** 00021 */ 00022 00028 #include <math.h> 00029 00030 #include "MEM_guardedalloc.h" 00031 00032 #include "DNA_camera_types.h" 00033 #include "DNA_object_types.h" 00034 00035 #include "BLI_math.h" 00036 #include "BLI_uvproject.h" 00037 00038 typedef struct UvCameraInfo { 00039 float camangle; 00040 float camsize; 00041 float xasp, yasp; 00042 float shiftx, shifty; 00043 float rotmat[4][4]; 00044 float caminv[4][4]; 00045 short do_persp, do_pano, do_rotmat; 00046 } UvCameraInfo; 00047 00048 void project_from_camera(float target[2], float source[3], UvCameraInfo *uci) 00049 { 00050 float pv4[4]; 00051 00052 copy_v3_v3(pv4, source); 00053 pv4[3]= 1.0; 00054 00055 /* rotmat is the object matrix in this case */ 00056 if(uci->do_rotmat) 00057 mul_m4_v4(uci->rotmat, pv4); 00058 00059 /* caminv is the inverse camera matrix */ 00060 mul_m4_v4(uci->caminv, pv4); 00061 00062 if(uci->do_pano) { 00063 float angle= atan2f(pv4[0], -pv4[2]) / ((float)M_PI * 2.0f); /* angle around the camera */ 00064 if (uci->do_persp==0) { 00065 target[0]= angle; /* no correct method here, just map to 0-1 */ 00066 target[1]= pv4[1] / uci->camsize; 00067 } 00068 else { 00069 float vec2d[2]; /* 2D position from the camera */ 00070 vec2d[0]= pv4[0]; 00071 vec2d[1]= pv4[2]; 00072 target[0]= angle * ((float)M_PI / uci->camangle); 00073 target[1]= pv4[1] / (len_v2(vec2d) * (uci->camsize * 2.0f)); 00074 } 00075 } 00076 else { 00077 if (pv4[2]==0.0f) pv4[2]= 0.00001f; /* don't allow div by 0 */ 00078 00079 if (uci->do_persp==0) { 00080 target[0]= (pv4[0]/uci->camsize); 00081 target[1]= (pv4[1]/uci->camsize); 00082 } 00083 else { 00084 target[0]= (-pv4[0]*((1.0f/uci->camsize)/pv4[2])) / 2.0f; 00085 target[1]= (-pv4[1]*((1.0f/uci->camsize)/pv4[2])) / 2.0f; 00086 } 00087 } 00088 00089 target[0] *= uci->xasp; 00090 target[1] *= uci->yasp; 00091 00092 /* adds camera shift + 0.5 */ 00093 target[0] += uci->shiftx; 00094 target[1] += uci->shifty; 00095 } 00096 00097 /* could rv3d->persmat */ 00098 void project_from_view(float target[2], float source[3], float persmat[4][4], float rotmat[4][4], float winx, float winy) 00099 { 00100 float pv[3], pv4[4], x= 0.0, y= 0.0; 00101 00102 mul_v3_m4v3(pv, rotmat, source); 00103 00104 copy_v3_v3(pv4, source); 00105 pv4[3]= 1.0; 00106 00107 /* rotmat is the object matrix in this case */ 00108 mul_m4_v4(rotmat, pv4); 00109 00110 /* almost project_short */ 00111 mul_m4_v4(persmat, pv4); 00112 if(fabsf(pv4[3]) > 0.00001f) { /* avoid division by zero */ 00113 target[0] = winx/2.0f + (winx/2.0f) * pv4[0] / pv4[3]; 00114 target[1] = winy/2.0f + (winy/2.0f) * pv4[1] / pv4[3]; 00115 } 00116 else { 00117 /* scaling is lost but give a valid result */ 00118 target[0] = winx/2.0f + (winx/2.0f) * pv4[0]; 00119 target[1] = winy/2.0f + (winy/2.0f) * pv4[1]; 00120 } 00121 00122 /* v3d->persmat seems to do this funky scaling */ 00123 if(winx > winy) { 00124 y= (winx - winy)/2.0f; 00125 winy = winx; 00126 } 00127 else { 00128 x= (winy - winx)/2.0f; 00129 winx = winy; 00130 } 00131 00132 target[0]= (x + target[0]) / winx; 00133 target[1]= (y + target[1]) / winy; 00134 } 00135 00136 /* 'rotmat' can be obedit->obmat when uv project is used. 00137 * 'winx' and 'winy' can be from scene->r.xsch/ysch */ 00138 UvCameraInfo *project_camera_info(Object *ob, float (*rotmat)[4], float winx, float winy) 00139 { 00140 UvCameraInfo uci; 00141 Camera *camera= ob->data; 00142 00143 uci.do_pano = (camera->flag & CAM_PANORAMA); 00144 uci.do_persp = (camera->type==CAM_PERSP); 00145 00146 uci.camangle= lens_to_angle(camera->lens) / 2.0f; 00147 uci.camsize= uci.do_persp ? tanf(uci.camangle) : camera->ortho_scale; 00148 00149 /* account for scaled cameras */ 00150 copy_m4_m4(uci.caminv, ob->obmat); 00151 normalize_m4(uci.caminv); 00152 00153 if (invert_m4(uci.caminv)) { 00154 UvCameraInfo *uci_pt; 00155 00156 /* normal projection */ 00157 if(rotmat) { 00158 copy_m4_m4(uci.rotmat, rotmat); 00159 uci.do_rotmat= 1; 00160 } 00161 else { 00162 uci.do_rotmat= 0; 00163 } 00164 00165 /* also make aspect ratio adjustment factors */ 00166 if (winx > winy) { 00167 uci.xasp= 1.0f; 00168 uci.yasp= winx / winy; 00169 } 00170 else { 00171 uci.xasp= winy / winx; 00172 uci.yasp= 1.0f; 00173 } 00174 00175 /* include 0.5f here to move the UVs into the center */ 00176 uci.shiftx = 0.5f - (camera->shiftx * uci.xasp); 00177 uci.shifty = 0.5f - (camera->shifty * uci.yasp); 00178 00179 uci_pt= MEM_mallocN(sizeof(UvCameraInfo), "UvCameraInfo"); 00180 *uci_pt= uci; 00181 return uci_pt; 00182 } 00183 00184 return NULL; 00185 } 00186 00187 void project_from_view_ortho(float target[2], float source[3], float rotmat[4][4]) 00188 { 00189 float pv[3]; 00190 00191 mul_v3_m4v3(pv, rotmat, source); 00192 00193 /* ortho projection */ 00194 target[0] = -pv[0]; 00195 target[1] = pv[2]; 00196 } 00197 00198 00199 void project_camera_info_scale(UvCameraInfo *uci, float scale_x, float scale_y) 00200 { 00201 uci->xasp *= scale_x; 00202 uci->yasp *= scale_y; 00203 }