// `計算點光源, 它和頂點位置, 頂點面向, 光源位置有關.` void CalculatePointLight(Vertex_VCN *pVertices, int num_vertices) { for ( int i=0; i<num_vertices; i++ ) { // `求出轉換後在世界座標系的頂點位置` Vector4 vPosition = pVertices[i].m_Position * g_world_matrix; // `求出轉換後在世界座標系的頂點面向, RotateVector函式只做旋轉, 忽略位移.` Vector4 vNormal = g_world_matrix.RotateVector(pVertices[i].m_Normal); // `計算出頂點位置到光源的方向跟長度` Vector4 vVertex_to_Light = g_vLightPosition - vPosition; float light_distance = vVertex_to_Light.NormalizeAndGetLength(); // `vDistance用來計算光線隨距離衰減公式中1/(a*1 + b*d + c*d^2)分母的(1, d, d^2)` Vector4 vDistance(1.0f, light_distance, light_distance * light_distance); // `g_vLightAttenuation里記錄了計算衰減公式1/(a + b*d + c*d^2)里的(a,b,c)` // `Vector3Dot(vDistance, g_vLightAttenuation) = (a,b,c) dot (1,d,d^2) = (a + b*d + c*d^2)` Vector4 vAttenuation = Vector3Dot(vDistance, g_vLightAttenuation); // `頂點面向跟光線方向的交角, 決定反射光的強度.` Vector4 vIntensity = Vector3Dot(vNormal, vVertex_to_Light); // `把intensity局限在永遠大於0的范圍` vIntensity.Clamp_to_0(); // `累加上隨距離衰減的光線強度` pVertices[i].m_Color += vIntensity * g_vLightColor / vAttenuation; pVertices[i].m_Color.Clamp_to_1(); } }
// `計算點光源, 它和頂點位置, 頂點面向, 光源位置, 光源方向, 光柱交角有關.` void CalculateSpotLight(Vertex_VCN *pVertices, int num_vertices) { float fSpotLightCutoffCos = FastMath::Cos( FastMath::DegreeToRadian(g_fSpotLightCutoff) ); for ( int i=0; i<num_vertices; i++ ) { // `求出轉換後在世界座標系的頂點位置` Vector4 vPosition = pVertices[i].m_Position * g_world_matrix; // `求出轉換後在世界座標系的頂點面向, RotateVector函式只做旋轉, 忽略位移.` Vector4 vNormal = g_world_matrix.RotateVector(pVertices[i].m_Normal); // `計算出頂點位置到光源的方向跟長度` Vector4 vVertex_to_Light = g_vLightPosition - vPosition; float light_distance = vVertex_to_Light.NormalizeAndGetLength(); // `頂點面向跟光線方向的交角, 可以決定反射光的強度.` Vector4 vCosine = Vector3Dot(g_vLightDirection, vVertex_to_Light); // `把vCosine局限在永遠大於0的范圍` vCosine.Clamp_to_0(); float fCosine = vCosine.GetX(); if ( fCosine >= fSpotLightCutoffCos ) { // `頂點跟光線的交角小於fSpotightCutoffCos時, 才落在光柱范圍內.` Vector4 vDistance(1.0f, light_distance, light_distance * light_distance); // `g_vLightAttenuation里記錄了計算衰減公式1/(a + b*d + c*d^2)里的(a,b,c)` // `Vector3Dot(vDistance, g_vLightAttenuation) = (a,b,c) dot (1,d,d^2) = (a + b*d + c*d^2)` Vector4 vAttenuation = Vector3Dot(vDistance, g_vLightAttenuation); // `比較靠近光柱外圍部分的頂點, 光線會衰減.` float fFalloff = pow(fCosine, g_fSpotLightExponent); Vector4 vIntensity = Vector3Dot(vNormal, vVertex_to_Light); pVertices[i].m_Color += fFalloff * vIntensity * g_vLightColor / vAttenuation; pVertices[i].m_Color.Clamp_to_1(); } } }
bool Collision::GetReflectFloor( const float& height, Vector3& pos, Vector3& vec, float rate ) { Vector3 p = pos; Vector3 v = vec; Vector3 n = Vector3( 0.0f, 1.0f, 0.0f ); Vector3 out; float dist = 50.0f; float length = height - pos.y; if ( length > 5.0f ) return false; // 移動量の長さ float vec_len = vec.Length(); if ( vec_len > length ) { // 法線正規化 n.Normalize(); // 入射ベクトルを法線に射影 float dot = Vector3Dot( -vec, n ); // 入射ベクトルと反射ベクトルの // 合成ベクトルから // 入射ベクトルを引く。 vec = n*2.0f*dot - ( -vec ); // 反射率の計算 vec *= rate; return true; } return false; }
// オブジェクトの反射(固定) bool Collision::GetRefrectFix( iexMesh* org, Vector3& pos, Vector3& vec, float rate ) { Vector3 p = pos; Vector3 v = vec; Vector3 out; float dist = 50.0f; org->Update(); if ( org->RayPick( &out, &p, &v, &dist ) == -1 ) return false; // 移動量の長さ float vec_len = vec.Length(); // 壁までのベクトル Vector3 pos_out_vec = out - pos; // 壁までの距離 float pos_out_len = pos_out_vec.Length(); if ( vec_len > pos_out_len ) { // 法線正規化 v.Normalize(); // 入射ベクトルを法線に射影 float dot = Vector3Dot( -vec, v ); // 入射ベクトルと反射ベクトルの // 合成ベクトルから // 入射ベクトルを引く。 vec = v*2.0f*dot - ( -vec ); // 反射率の計算 vec *= rate; return true; } return false; }
// 線分と線分の距離の平方を返す(カプセル用) float Collision::DistanceSegmentSegmentSq( const Vector3& l1p1, const Vector3& l1p2, const Vector3& l2p1, const Vector3& l2p2 ) { // ねじれの位置の判定 Vector3 v1 = l1p2 - l1p1; Vector3 v2 = l2p2 - l2p1; Vector3 n; Vector3Cross( n, v1, v2 ); float nn = n.LengthSq(); if ( nn ) { // 平行ではない Vector3 v12 = l2p1 - l1p1; float nv12 = Vector3Dot( n, v12 ); Vector3 vd = n * ( nv12 / nn ); Vector3 q1 = l2p1 - vd; Vector3 q2 = l2p2 - vd; Vector3 p1q1 = q1 - l1p1; Vector3 p1q2 = q2 - l1p1; Vector3 r1, r2; Vector3Cross( r1, v1, p1q1 ); Vector3Cross( r2, v1, p1q2 ); if ( Vector3Dot( r1, r2 ) < 0 ) { Vector3 v3 = q2 - q1; Vector3 q1p1 = l1p1 - q1; Vector3 q1p2 = l1p2 - q1; Vector3Cross( r1, v3, q1p1 ); Vector3Cross( r2, v3, q1p2 ); if (Vector3Dot( r1, r2 ) < 0 ) { // ねじれの位置 return nv12 * nv12 / nn; } } } // ねじれじゃない位置 return min( min( DistancePointSegmentSq( l1p1, l2p1, l2p2 ), DistancePointSegmentSq( l1p2, l2p1, l2p2 ) ), min(DistancePointSegmentSq( l2p1, l1p1, l1p2 ), DistancePointSegmentSq( l2p2, l1p1, l1p2 ) ) ); }
// 点と線分の距離の平方を返す(カプセル用) float Collision::DistancePointSegmentSq( const Vector3& p1, const Vector3& l1p1, const Vector3& l1p2 ) { Vector3 v1 = p1 - l1p1; Vector3 v2 = l1p2 - l1p1; float v1v2 = Vector3Dot( v1, v2 ); if ( v1v2 <= 0.0f ) return v1.LengthSq(); float v2v2 = v2.LengthSq(); if ( v2v2 <= v1v2 ) { Vector3 v3 = p1 - l1p2; return v3.LengthSq(); } return v1.LengthSq() - v1v2 * v1v2 / v2v2; }
// 動くオブジェクトの反射 bool Collision::GetReflect( iexMesh* org, Vector3& pos, Vector3& vec, float rate ) { // オブジェクトの逆行列を算出 org->Update(); Matrix mat = org->TransMatrix; Matrix invMat; // 逆行列 D3DXMatrixInverse( &invMat, null, &mat ); // 逆行列でレイをローカル化 Vector3 invVec; invVec.x = invMat._11 * vec.x + invMat._21 * vec.y + invMat._31 * vec.z; invVec.y = invMat._12 * vec.x + invMat._22 * vec.y + invMat._32 * vec.z; invVec.z = invMat._13 * vec.x + invMat._23 * vec.y + invMat._33 * vec.z; Vector3 invPos; invPos.x = invMat._11 * pos.x + invMat._21 * pos.y + invMat._31 * pos.z + invMat._41; invPos.y = invMat._12 * pos.x + invMat._22 * pos.y + invMat._32 * pos.z + invMat._42; invPos.z = invMat._13 * pos.x + invMat._23 * pos.y + invMat._33 * pos.z + invMat._43; Vector3 v = invVec; Vector3 p = invPos; Vector3 out; float d = 100.0f; if ( org->RayPick( &out, &p, &v, &d ) >= 0 ) { Vector3 vv = out - p; float dd = vv.Length(); float dm = invVec.Length(); if ( dd < dm ){ v.Normalize(); // 法線算出 float dot = Vector3Dot( -invVec, v ); // 法線方向に射影 invVec = v*dot*2.0f - ( -invVec ); Vector3 p; p.x = mat._11 * out.x + mat._21 * out.y + mat._31 * out.z + mat._41; p.y = mat._12 * out.x + mat._22 * out.y + mat._32 * out.z + mat._42; p.z = mat._13 * out.x + mat._23 * out.y + mat._33 * out.z + mat._43; pos = p; Vector3 v; v.x = mat._11 * invVec.x + mat._21 * invVec.y + mat._31 * invVec.z; v.y = mat._12 * invVec.x + mat._22 * invVec.y + mat._32 * invVec.z; v.z = mat._13 * invVec.x + mat._23 * invVec.y + mat._33 * invVec.z; vec = v*rate; return true; } } return false; }
// `計算方向光, 它只跟頂點面向和光源方向有關.` void CalculateDirectionalLight(Vertex_VCN *pVertices, int num_vertices) { for ( int i=0; i<num_vertices; i++ ) { // `求出轉換後在世界座標系的頂點面向, RotateVector函式只做旋轉, 忽略位移.` Vector4 normal = g_world_matrix.RotateVector(pVertices[i].m_Normal); // `頂點面向跟光線方向的交角, 決定反射光的強度.` Vector4 intensity = Vector3Dot(normal, g_vLightDirection); // `把intensity局限在永遠大於0的范圍` intensity.Clamp_to_0(); // `累加上計算出來方向光的強度` pVertices[i].m_Color += intensity * g_vLightColor; pVertices[i].m_Color.Clamp_to_1(); } }
// 壁との当たり判定 bool Collision::CheckWall( iexMesh* org, const Vector3& pos, Vector3& p_move ) { //org->Update(); const float DIST = 2.0f; // 壁との距離 Vector3 p_pos = Vector3(pos.x, pos.y + 1.0f, pos.z); Vector3 vec = Vector3(p_move.x, 0.0f, p_move.z); vec.Normalize(); Vector3 takePos; float dist = 100.0f; // オブジェクトの逆行列を算出 if ( org->RayPick( &takePos, &p_pos, &vec, &dist ) != -1 ){ float disToWall = Vector3( Vector3( takePos.x, 0.0f, takePos.z ) - Vector3( p_pos.x, 0.0f, p_pos.z ) ).Length(); if ( disToWall <= DIST ) { // 移動量 float move = Vector3( p_move.x, 0.0f, p_move.z ).Length(); // プレイヤーからレイの交差点へのベクトル Vector3 vPtoWall( takePos - p_pos ); vPtoWall.y = 0.0f; vPtoWall.Normalize(); vec.y = 0.0f; vec.Normalize(); // 法線の上方向(?)を求める Vector3 vCrossUp; Vector3Cross( vCrossUp, vec, vPtoWall ); vCrossUp.Normalize(); // 法線の上方向(?)と法線の外積から滑る方向を計算 Vector3 vCrossSide; Vector3Cross( vCrossSide, vCrossUp, vec ); vCrossSide.Normalize(); // 法線とプレーヤーからレイの交差点へのベクトルの内積 float dotNP = Vector3Dot( vec, vPtoWall ); // 移動量の調整 p_move.x = vCrossSide.x * move * ( dotNP + 1.0f ); p_move.z = vCrossSide.z * move * ( dotNP + 1.0f ); return true; } } return false; }
bool Flyer::Can_do(BasePlayer *player) { if( broken ) return false; // 位置と向き判定 Vector3 ppos; // playerの位置 ppos = player->Get_pos(); Vector3 poster_player( ppos - position ); // ポスターからプレイヤー // 距離 if( poster_player.LengthSq() > DIST * DIST ) return false; // 向き if( Vector3Dot( player->Get_forward(), poster_player ) >= 0.0f ) return false; return true; }
void Deferred::AddPLSdata(const Vector3 pos, const Vector3 color, const float range, const float power) { PLSData data; // 今のままだとカリングが意味をなさない Matrix mWV = matView;// ビュー行列 // 視錐台カリング処理 Vector3 flont(mWV._13, mWV._23, mWV._33); flont.Normalize(); Vector3 dir = pos - (m_vViewPos - flont * range); //レンジの値分下げて、カリングを緩める。 dir.Normalize(); float dot = Vector3Dot(dir, flont); if (dot < 0.2f) { return; // 見えていないポイントライトを消去 } // ワールド座標のデータも詰める data.wpos = pos; // カメラ空間変換 Matrix mat = matView; data.pos.x = pos.x * mat._11 + pos.y * mat._21 + pos.z * mat._31 + mat._41; data.pos.y = pos.x * mat._12 + pos.y * mat._22 + pos.z * mat._32 + mat._42; data.pos.z = pos.x * mat._13 + pos.y * mat._23 + pos.z * mat._33 + mat._43; data.range = range; data.color = color; data.power = power; if ((int)PLSdata.size() >= PLS_MAX)assert(0); // 配列に加える PLSdata.push_back(data); }
float Vector3Length(const float *a) { float lengthSquared = Vector3Dot(a,a); float length = sqrt(lengthSquared); return length; }
LUX_API void lxMatrix44RotateAngle(lxMatrix44PTR mat, lxVector3PTR from, lxVector3PTR to){ /* Vector3 vs; Vector3 vt; Vector3 v; float ca; Vector3NormalizedA(from); Vector3NormalizedA(to); Vector3Cross(vs,from, to); // axis multiplied by sin Vector3Copy(v,vs); Vector3NormalizedA(v); // axis of rotation ca = Vector3Dot(from, to) ; // cos angle Vector3Copy(vt,v); Vector3Scale(v,v,(1.0f -ca)); Matrix44Identity(m); mat[0] = vt[0] * v[0] + ca; mat[5] = vt[1] * v[1] + ca; mat[10] = vt[2] * v[2] + ca; vt[0] *= v[1]; vt[2] *= v[0]; vt[1] *= v[2]; mat[1] = vt[0] - vs[2]; mat[2] = vt[2] + vs[1]; mat[4] = vt[0] + vs[2]; mat[6] = vt[1] - vs[0]; mat[8] = vt[2] - vs[1]; mat[9] = vt[1] + vs[0]; */ // http://lists.apple.com/archives/mac-opengl/2001/Jan/msg00059.html // Author: Tomas Moller, 1999 #define M(row,col) mat[row*4+col] float v[3]; float e,h; lxVector3Normalized(from); lxVector3Normalized(to); lxVector3Cross(v,from,to); e=lxVector3Dot(from,to); if(e>1.0-LUX_FLOAT_EPSILON) // "from" almost or equal to "to"-vector? { // return identity M(0, 0)=1.0; M(0, 1)=0.0; M(0, 2)=0.0; M(1, 0)=0.0; M(1, 1)=1.0; M(1, 2)=0.0; M(2, 0)=0.0; M(2, 1)=0.0; M(2, 2)=1.0; } else if(e<-1.0+LUX_FLOAT_EPSILON) // "from" almost or equal to negated "to"? { float up[3],left[3]; float fxx,fyy,fzz,fxy,fxz,fyz; float uxx,uyy,uzz,uxy,uxz,uyz; float lxx,lyy,lzz,lxy,lxz,lyz; // left=CROSS(from, (1,0,0)) left[0]=0.0; left[1]=from[2]; left[2]=-from[1]; if(lxVector3Dot(left,left)<LUX_FLOAT_EPSILON) // was left=CROSS(from,(1,0,0)) a good choice? { // here we now that left = CROSS(from, (1,0,0)) will be a good choice left[0]=-from[2]; left[1]=0.0; left[2]=from[0]; } // normalize "left" lxVector3Normalized(left); lxVector3Cross(up,left,from); // now we have a coordinate system, i.e., a basis; // M=(from, up, left), and we want to rotate to: // N=(-from, up, -left). This is done with the mat: // N*M^T where M^T is the transpose of M fxx=-from[0]*from[0]; fyy=-from[1]*from[1]; fzz=-from[2]*from[2]; fxy=-from[0]*from[1]; fxz=-from[0]*from[2]; fyz=-from[1]*from[2]; uxx=up[0]*up[0]; uyy=up[1]*up[1]; uzz=up[2]*up[2]; uxy=up[0]*up[1]; uxz=up[0]*up[2]; uyz=up[1]*up[2]; lxx=-left[0]*left[0]; lyy=-left[1]*left[1]; lzz=-left[2]*left[2]; lxy=-left[0]*left[1]; lxz=-left[0]*left[2]; lyz=-left[1]*left[2]; // symmetric mat M(0, 0)=fxx+uxx+lxx; M(0, 1)=fxy+uxy+lxy; M(0, 2)=fxz+uxz+lxz; M(1, 0)=M(0, 1); M(1, 1)=fyy+uyy+lyy; M(1, 2)=fyz+uyz+lyz; M(2, 0)=M(0, 2); M(2, 1)=M(1, 2); M(2, 2)=fzz+uzz+lzz; } else // the most common case, unless "from"="to", or "from"=-"to" { #if 0 // unoptimized version - a good compiler will optimize this. h=(1.0-e)/Vector3Dot(v,v); M(0, 0)=e+h*v[0]*v[0]; M(0, 1)=h*v[0]*v[1]-v[2]; M(0, 2)=h*v[0]*v[2]+v[1]; M(1, 0)=h*v[0]*v[1]+v[2]; M(1, 1)=e+h*v[1]*v[1]; M(1, 2)h*v[1]*v[2]-v[0]; M(2, 0)=h*v[0]*v[2]-v[1]; M(2, 1)=h*v[1]*v[2]+v[0]; M(2, 2)=e+h*v[2]*v[2]; #else // ...otherwise use this hand optimized version (9 mults less) float hvx,hvz,hvxy,hvxz,hvyz; //h=(1.0-e)/Vector3Dot(v,v); h = 1.0f/(1+e); hvx=h*v[0]; hvz=h*v[2]; hvxy=hvx*v[1]; hvxz=hvx*v[2]; hvyz=hvz*v[1]; M(0, 0)=e+hvx*v[0]; M(0, 1)=hvxy-v[2]; M(0, 2)=hvxz+v[1]; M(1, 0)=hvxy+v[2]; M(1, 1)=e+h*v[1]*v[1]; M(1, 2)=hvyz-v[0]; M(2, 0)=hvxz-v[1]; M(2, 1)=hvyz+v[0]; M(2, 2)=e+hvz*v[2]; #endif } #undef M }
// 追加した関数 void iexMesh::NearestPoint( NearestPointOut *out, const Vector3 &inPos ) { // 情報取得 u32 fvf = lpMesh->GetFVF(); // 頂点サイズ計算 int vertexSize = D3DXGetFVFVertexSize( fvf ) / sizeof( float ); // バッファロック float *pVertices; u16 *pIndices; u32 numIndices = lpMesh->GetNumFaces(); lpMesh->LockVertexBuffer( D3DLOCK_READONLY, ( void** ) &pVertices ); lpMesh->LockIndexBuffer( D3DLOCK_READONLY, ( void** ) &pIndices ); struct { Vector3 vertex[3]; Vector3 normal; Vector3 line[3]; // 頂点情報から残りの情報を計算 inline void ComputeFromVertex() { line[1] = vertex[2] - vertex[1]; line[2] = vertex[3] - vertex[2]; line[3] = vertex[1] - vertex[3]; Vector3Cross( normal, line[1], line[2] ); normal.Normalize(); } }triangle; // 三角ポリゴン out->length = FLT_MAX; for( u32 j = 0; j < numIndices; j++ ) { // 面頂点取得 { int index = pIndices[j * 3 + 0] * vertexSize; triangle.vertex[1].x = pVertices[index]; triangle.vertex[1].y = pVertices[index + 1]; triangle.vertex[1].z = pVertices[index + 2]; index = pIndices[j * 3 + 1] * vertexSize; triangle.vertex[2].x = pVertices[index]; triangle.vertex[2].y = pVertices[index + 1]; triangle.vertex[2].z = pVertices[index + 2]; index = pIndices[j * 3 + 2] * vertexSize; triangle.vertex[3].x = pVertices[index]; triangle.vertex[3].y = pVertices[index + 1]; triangle.vertex[3].z = pVertices[index + 2]; } // 法線と辺計算 triangle.ComputeFromVertex(); // 法線方向に距離計算 FLOAT lengthNormal( 0 ); lengthNormal = Vector3Dot( ( inPos - triangle.vertex[1] ), triangle.normal ); // ポリゴンが裏向き if( lengthNormal <= 0 ) continue; // 遠い if( lengthNormal > out->length ) continue; Vector3 nearestPos( 0, 0, 0 ); // とりあえず無限平面上で nearestPos = inPos - ( triangle.normal * lengthNormal ); Vector3 decisionVector( 0, 0, 0 ); // 内点判定 for( unsigned int i = 0; i < 3; i++ ) { Vector3Cross( decisionVector, ( triangle.vertex[i] - nearestPos ), triangle.line[i] ); // 外にあった場合 if( Vector3Dot( decisionVector, triangle.normal ) < 0 ) { // nearestPosを辺上の最接近点へ移動 float t = triangle.line[i].LengthSq(); if( t != 0 ) // 辺上へ t = Vector3Dot( ( nearestPos - triangle.vertex[i] ), triangle.line[i] ) / t; // 頂点へ if( t < 0 ) t = 0; else if( t > 1 )t = 1; // 移動 nearestPos = triangle.vertex[i] + triangle.line[i] * t; } } // 距離判定 float length = ( nearestPos - inPos ).Length(); if( length > out->length ) continue; out->length = length; out->Normal = triangle.normal; out->Pos = nearestPos; } // バッファアンロック lpMesh->UnlockVertexBuffer(); lpMesh->UnlockIndexBuffer(); }
//------------------------------------------------------ // 上下最適化 //------------------------------------------------------ int iexMesh::RayPickUD( Vector3* out, Vector3* pos, Vector3* vec, float *Dist ) { float t, neart; float vy; int ret = -1; int VertexSize; Vector3 p = *pos; vy = vec->y; neart = *Dist; // 情報取得 int fvf = lpMesh->GetFVF(); // 頂点サイズ計算 VertexSize = D3DXGetFVFVertexSize(fvf) / sizeof(float); // バッファロック float *pVertices; u16 *pIndices; int NumIndices = lpMesh->GetNumFaces(); lpMesh->LockVertexBuffer( D3DLOCK_READONLY , (void**)&pVertices ); lpMesh->LockIndexBuffer( D3DLOCK_READONLY , (void**)&pIndices ); Vector l1, l2, l3; Vector p1, p2, p3; Vector v[3]; Vector n; for( int j=0 ; j<NumIndices ; j++ ) { // 面頂点取得 int a = pIndices[j*3+0] * VertexSize; int b = pIndices[j*3+1] * VertexSize; int c = pIndices[j*3+2] * VertexSize; v[0].x = pVertices[a]; v[1].x = pVertices[b]; v[2].x = pVertices[c]; if( v[0].x > p.x && v[1].x > p.x && v[2].x > p.x ) continue; v[0].z = pVertices[a+2]; v[1].z = pVertices[b+2]; v[2].z = pVertices[c+2]; if( v[0].z > p.z && v[1].z > p.z && v[2].z > p.z ) continue; v[0].y = pVertices[a+1]; v[1].y = pVertices[b+1]; v[2].y = pVertices[c+1]; // 内点判定(全外積がマイナス) l1.x = v[1].x - v[0].x; l1.z = v[1].z - v[0].z; p1.x = v[0].x - p.x; p1.z = v[0].z - p.z; if( (p1.x*l1.z - p1.z*l1.x)*vy < 0 ) continue; l2.x = v[2].x - v[1].x; l2.z = v[2].z - v[1].z; p2.x = v[1].x - p.x; p2.z = v[1].z - p.z; if( (p2.x*l2.z - p2.z*l2.x)*vy < 0 ) continue; l3.x = v[0].x - v[2].x; l3.z = v[0].z - v[2].z; p3.x = v[2].x - p.x; p3.z = v[2].z - p.z; if( (p3.x*l3.z - p3.z*l3.x)*vy < 0 ) continue; // 外積による法線算出 l1.y = v[1].y - v[0].y; l2.y = v[2].y - v[1].y; Vector3Cross( n, l1, l2 ); // 表裏判定 if( vy*n.y >= 0 ) continue; // 交点算出 p1.y = v[0].y - p.y; t = Vector3Dot( n, p1 ) / (n.y*vy); if( t < .0f || t > neart ) continue; *vec = n; ret = j; neart = t; } lpMesh->UnlockVertexBuffer(); lpMesh->UnlockIndexBuffer(); out->y = neart*vy + p.y; out->x = pos->x; out->z = pos->z; *Dist = neart; return ret; }
//************************************************************************************************** // // レイピック // //************************************************************************************************** //------------------------------------------------------ // レイピック //------------------------------------------------------ int iexMesh::RayPick( Vector3* out, Vector3* pos, Vector3* vec, float *Dist ) { int ret = -1; if( vec->x == .0f && vec->z == .0f ) return RayPickUD( out, pos, vec, Dist ); Vector3 p = *pos; Vector3 vv = *vec; float neart = *Dist; float dist = *Dist; dist = dist*dist; *out = p; // 情報取得 u32 fvf = lpMesh->GetFVF(); // 頂点サイズ計算 int VertexSize = D3DXGetFVFVertexSize(fvf) / sizeof(float); // バッファロック float *pVertices; u16 *pIndices; u32 NumIndices = lpMesh->GetNumFaces(); lpMesh->LockVertexBuffer( D3DLOCK_READONLY, (void**)&pVertices ); lpMesh->LockIndexBuffer( D3DLOCK_READONLY, (void**)&pIndices ); Vector3 v1, v2, v3; Vector3 n; Vector3 l1, l2, l3; Vector3 temp; Vector3 cp; Vector3 p1, p2, p3; for( u32 j=0 ; j<NumIndices ; j++ ) { // 面頂点取得 int a = pIndices[j*3+0] * VertexSize; v1.x = pVertices[a]; v1.y = pVertices[a+1]; v1.z = pVertices[a+2]; int b = pIndices[j*3+1] * VertexSize; v2.x = pVertices[b]; v2.y = pVertices[b+1]; v2.z = pVertices[b+2]; int c = pIndices[j*3+2] * VertexSize; v3.x = pVertices[c]; v3.y = pVertices[c+1]; v3.z = pVertices[c+2]; // 距離判定 //Vector3 ss = (v1 + v2 + v3) / 3.0f - p; //if( ss.LengthSq() > dist ) continue; l1.x = v2.x - v1.x; l1.y = v2.y - v1.y; l1.z = v2.z - v1.z; l2.x = v3.x - v2.x; l2.y = v3.y - v2.y; l2.z = v3.z - v2.z; // 外積による法線算出 Vector3Cross( n, l1, l2 ); // 内積の結果がプラスならば裏向き float dot = Vector3Dot( vv, n ); if( dot >= 0 ) continue; // 交点算出 p1.x = v1.x - p.x; p1.y = v1.y - p.y; p1.z = v1.z - p.z; float t = Vector3Dot( n, p1 ) / dot; if( t < .0f || t > neart ) continue; cp.x = vv.x*t + p.x; cp.y = vv.y*t + p.y; cp.z = vv.z*t + p.z; // 内点判定 p1.x = v1.x - cp.x; p1.y = v1.y - cp.y; p1.z = v1.z - cp.z; Vector3Cross( temp, p1, l1 ); if( Vector3Dot(temp, n) < .0f ) continue; p2.x = v2.x - cp.x; p2.y = v2.y - cp.y; p2.z = v2.z - cp.z; Vector3Cross( temp, p2, l2 ); if( Vector3Dot(temp, n) < .0f ) continue; l3.x = v1.x - v3.x; l3.y = v1.y - v3.y; l3.z = v1.z - v3.z; p3.x = v3.x - cp.x; p3.y = v3.y - cp.y; p3.z = v3.z - cp.z; Vector3Cross( temp, p3, l3 ); if( Vector3Dot(temp, n) < .0f ) continue; *out = cp; *vec = n; ret = j; neart = t; } lpMesh->UnlockVertexBuffer(); lpMesh->UnlockIndexBuffer(); *Dist = neart; return ret; }
float Vector3LengthSq(const LPVECTOR3 pVec) { return Vector3Dot(pVec, pVec); }