void Camera::strafeCamera(float speed) { // Strafing is quite simple if you understand what the cross product is. // If you have 2 vectors (say the up vVector and the view vVector) you can // use the cross product formula to get a vVector that is 90 degrees from the 2 vectors. // For a better explanation on how this works, check out the OpenGL "Normals" tutorial at our site. // In our new Update() function, we set the strafing vector (m_vStrafe). Due // to the fact that we need this vector for many things including the strafing // movement and camera rotation (up and down), we just calculate it once. // // Like our MoveCamera() function, we add the strafing vector to our current position // and view. It's as simple as that. It has already been calculated in Update(). V3f vStrafe = V3f::cross(mView - mEye, mUp); vStrafe.normalize(); // Add the strafe vector to our position *mEye.x += vStrafe.getX() * speed; *mEye.z += vStrafe.getZ() * speed; // Add the strafe vector to our view *mView.x += vStrafe.getX() * speed; *mView.z += vStrafe.getZ() * speed; // applyToGL(); }
void PhongBrdf::randVonMisesFisher3(V3f mu, float kappa, int n, V3f* directions) { V3f normal(0,0,1); V3f u = mu.cross(normal); float cost = dot(mu,normal); float sint = u.length(); u = u.normalize(); M33f rot(cost + u.x * u.x * (1 - cost), u.x * u.y * (1 - cost) - u.z * sint, u.x * u.z * (1 - cost) + u.y * sint, u.y * u.x * (1 - cost) + u.z * sint, cost + u.y * u.y * (1 - cost), u.y * u.z * (1 - cost) - u.x * sint, u.z * u.x * (1 - cost) - u.y * sint, u.z * u.y * (1 - cost) + u.x * sint, cost + u.z * u.z * (1 - cost)); float c = 2/kappa*(sinh(kappa)); // normalizing constant float y, w, v; for (int i=0; i < n; i++) { y = randomGenerator.RandomFloat(); w = 1/kappa * log( exp(-kappa) + kappa * c * y ); v = 2*M_PI*randomGenerator.RandomFloat(); directions[i].x = sqrt(1-w*w)*cos(v); directions[i].y = sqrt(1-w*w)*sin(v); directions[i].z = w; directions[i] = directions[i]*rot; } }
void PhongBrdf::getRandomDirections(const V3f incoming, const V3f normal, int n, V3f* directions) { V3f R = -incoming - 2 * (dot(-incoming, normal)) * normal; R = R.normalize(); randVonMisesFisher3(R, phongExponent, n, directions); }
void Camera::mouseRotate(float angleY, float angleZ) { V3f vAxis = V3f::cross(mView - mEye, mUp); vAxis.normalize(); // Rotate around our perpendicular axis and along the y-axis // rotateView(angleZ, vAxis); // rotateView(angleY, 0.0f, 1.0f, 0.0f); rotateView(angleZ, vAxis); rotateView(angleY, 0.0f, 1.0f,0.0f); // applyToGL(); }
/// \todo Use IECore::RadixSort (might still want to use std::sort for small numbers of points - profile to check this) void PointsPrimitive::depthSort() const { V3f cameraDirection = Camera::viewDirectionInObjectSpace(); cameraDirection.normalize(); const vector<V3f> &points = m_memberData->points->readable(); if( !m_memberData->depthOrder.size() ) { // never sorted before. initialize space. m_memberData->depthOrder.resize( points.size() ); for( unsigned int i=0; i<m_memberData->depthOrder.size(); i++ ) { m_memberData->depthOrder[i] = i; } m_memberData->depths.resize( points.size() ); } else { // sorted before. see if the camera direction has changed enough // to warrant resorting. if( cameraDirection.dot( m_memberData->depthCameraDirection ) > 0.95 ) { return; } } m_memberData->depthCameraDirection = cameraDirection; // calculate all distances for( unsigned int i=0; i<m_memberData->depths.size(); i++ ) { m_memberData->depths[i] = points[i].dot( m_memberData->depthCameraDirection ); } // sort based on those distances SortFn sorter( m_memberData->depths ); sort( m_memberData->depthOrder.begin(), m_memberData->depthOrder.end(), sorter ); }
void CameraController::tumble( const Imath::V2f &p ) { V2f d = p - m_data->motionStart; V3f centreOfInterestInWorld = V3f( 0, 0, -m_data->centreOfInterest ) * m_data->motionMatrix; V3f xAxisInWorld = V3f( 1, 0, 0 ); m_data->motionMatrix.multDirMatrix( xAxisInWorld, xAxisInWorld ); xAxisInWorld.normalize(); M44f t; t.translate( centreOfInterestInWorld ); t.rotate( V3f( 0, -d.x / 100.0f, 0 ) ); M44f xRotate; xRotate.setAxisAngle( xAxisInWorld, -d.y / 100.0f ); t = xRotate * t; t.translate( -centreOfInterestInWorld ); m_data->transform->matrix = m_data->motionMatrix * t; }
Rgba EnvmapImage::filteredLookup (V3f d, float r, int n) const { // // Filtered environment map lookup: Take n by n point samples // from the environment map, clustered around direction d, and // combine the samples with a tent filter. // // // Depending on the type of map, pick an appropriate function // to convert 3D directions to 2D pixel poitions. // V2f (* dirToPos) (const Box2i &, const V3f &); if (_type == ENVMAP_LATLONG) dirToPos = dirToPosLatLong; else dirToPos = dirToPosCube; // // Pick two vectors, dx and dy, of length r, that are orthogonal // to the lookup direction, d, and to each other. // d.normalize(); V3f dx, dy; if (abs (d.x) > 0.707f) dx = (d % V3f (0, 1, 0)).normalized() * r; else dx = (d % V3f (1, 0, 0)).normalized() * r; dy = (d % dx).normalized() * r; // // Take n by n point samples from the map, and add them up. // The directions for the point samples are all within the pyramid // defined by the vectors d-dy-dx, d-dy+dx, d+dy-dx, d+dy+dx. // float wt = 0; float cr = 0; float cg = 0; float cb = 0; float ca = 0; for (int y = 0; y < n; ++y) { float ry = float (2 * y + 2) / float (n + 1) - 1; float wy = 1 - abs (ry); V3f ddy (ry * dy); for (int x = 0; x < n; ++x) { float rx = float (2 * x + 2) / float (n + 1) - 1; float wx = 1 - abs (rx); V3f ddx (rx * dx); Rgba s = sample (dirToPos (_dataWindow, d + ddx + ddy)); float w = wx * wy; wt += w; cr += s.r * w; cg += s.g * w; cb += s.b * w; ca += s.a * w; } } wt = 1 / wt; Rgba c; c.r = cr * wt; c.g = cg * wt; c.b = cb * wt; c.a = ca * wt; return c; }
//-***************************************************************************** void MeshDrwHelper::draw( const DrawContext & iCtx ) const { // Bail if invalid. if ( !m_valid || m_triangles.size() < 1 || !m_meshP ) { return; } const V3f *points = m_meshP->get(); const V3f *normals = NULL; if ( m_meshN && ( m_meshN->size() == m_meshP->size() ) ) { normals = m_meshN->get(); } else if ( m_customN.size() == m_meshP->size() ) { normals = &(m_customN.front()); } #ifndef SIMPLE_ABC_VIEWER_NO_GL_CLIENT_STATE //#if 0 { GL_NOISY( glEnableClientState( GL_VERTEX_ARRAY ) ); if ( normals ) { GL_NOISY( glEnableClientState( GL_NORMAL_ARRAY ) ); GL_NOISY( glNormalPointer( GL_FLOAT, 0, ( const GLvoid * )normals ) ); } GL_NOISY( glVertexPointer( 3, GL_FLOAT, 0, ( const GLvoid * )points ) ); GL_NOISY( glDrawElements( GL_TRIANGLES, ( GLsizei )m_triangles.size() * 3, GL_UNSIGNED_INT, ( const GLvoid * )&(m_triangles[0]) ) ); if ( normals ) { GL_NOISY( glDisableClientState( GL_NORMAL_ARRAY ) ); } GL_NOISY( glDisableClientState( GL_VERTEX_ARRAY ) ); } #else glBegin( GL_TRIANGLES ); for ( size_t i = 0; i < m_triangles.size(); ++i ) { const Tri &tri = m_triangles[i]; const V3f &vertA = points[tri[0]]; const V3f &vertB = points[tri[1]]; const V3f &vertC = points[tri[2]]; if ( normals ) { const V3f &normA = normals[tri[0]]; glNormal3fv( ( const GLfloat * )&normA ); glVertex3fv( ( const GLfloat * )&vertA ); const V3f &normB = normals[tri[1]]; glNormal3fv( ( const GLfloat * )&normB ); glVertex3fv( ( const GLfloat * )&vertB ); const V3f &normC = normals[tri[2]]; glNormal3fv( ( const GLfloat * )&normC ); glVertex3fv( ( const GLfloat * )&vertC ); } else { V3f AB = vertB - vertA; V3f AC = vertC - vertA; V3f N = AB.cross( AC ); if ( N.length() > 1.0e-4f ) { N.normalize(); glNormal3fv( ( const GLfloat * )&N ); } glVertex3fv( ( const GLfloat * )&vertA ); glVertex3fv( ( const GLfloat * )&vertB ); glVertex3fv( ( const GLfloat * )&vertC ); } } glEnd(); #endif }
std::pair<PrimitiveVariable, PrimitiveVariable> IECoreScene::MeshAlgo::calculateTangents( const MeshPrimitive *mesh, const std::string &uvSet, /* = "uv" */ bool orthoTangents, /* = true */ const std::string &position /* = "P" */ ) { if( mesh->minVerticesPerFace() != 3 || mesh->maxVerticesPerFace() != 3 ) { throw InvalidArgumentException( "MeshAlgo::calculateTangents : MeshPrimitive must only contain triangles" ); } const V3fVectorData *positionData = mesh->variableData<V3fVectorData>( position ); if( !positionData ) { std::string e = boost::str( boost::format( "MeshAlgo::calculateTangents : MeshPrimitive has no Vertex \"%s\" primitive variable." ) % position ); throw InvalidArgumentException( e ); } const V3fVectorData::ValueType &points = positionData->readable(); const IntVectorData *vertsPerFaceData = mesh->verticesPerFace(); const IntVectorData::ValueType &vertsPerFace = vertsPerFaceData->readable(); const IntVectorData *vertIdsData = mesh->vertexIds(); const IntVectorData::ValueType &vertIds = vertIdsData->readable(); const auto uvIt = mesh->variables.find( uvSet ); if( uvIt == mesh->variables.end() || uvIt->second.interpolation != PrimitiveVariable::FaceVarying || uvIt->second.data->typeId() != V2fVectorDataTypeId ) { throw InvalidArgumentException( ( boost::format( "MeshAlgo::calculateTangents : MeshPrimitive has no FaceVarying V2fVectorData primitive variable named \"%s\"." ) % ( uvSet ) ).str() ); } const V2fVectorData *uvData = runTimeCast<V2fVectorData>( uvIt->second.data.get() ); const V2fVectorData::ValueType &uvs = uvData->readable(); // I'm a little unsure about using the vertIds as a fallback for the stIndices. const IntVectorData::ValueType &uvIndices = uvIt->second.indices ? uvIt->second.indices->readable() : vertIds; size_t numUVs = uvs.size(); std::vector<V3f> uTangents( numUVs, V3f( 0 ) ); std::vector<V3f> vTangents( numUVs, V3f( 0 ) ); std::vector<V3f> normals( numUVs, V3f( 0 ) ); for( size_t faceIndex = 0; faceIndex < vertsPerFace.size(); faceIndex++ ) { assert( vertsPerFace[faceIndex] == 3 ); // indices into the facevarying data for this face size_t fvi0 = faceIndex * 3; size_t fvi1 = fvi0 + 1; size_t fvi2 = fvi1 + 1; assert( fvi2 < vertIds.size() ); assert( fvi2 < uvIndices.size() ); // positions for each vertex of this face const V3f &p0 = points[vertIds[fvi0]]; const V3f &p1 = points[vertIds[fvi1]]; const V3f &p2 = points[vertIds[fvi2]]; // uv coordinates for each vertex of this face const V2f &uv0 = uvs[uvIndices[fvi0]]; const V2f &uv1 = uvs[uvIndices[fvi1]]; const V2f &uv2 = uvs[uvIndices[fvi2]]; // compute tangents and normal for this face const V3f e0 = p1 - p0; const V3f e1 = p2 - p0; const V2f e0uv = uv1 - uv0; const V2f e1uv = uv2 - uv0; V3f tangent = ( e0 * -e1uv.y + e1 * e0uv.y ).normalized(); V3f bitangent = ( e0 * -e1uv.x + e1 * e0uv.x ).normalized(); V3f normal = ( p2 - p1 ).cross( p0 - p1 ); normal.normalize(); // and accumlate them into the computation so far uTangents[uvIndices[fvi0]] += tangent; uTangents[uvIndices[fvi1]] += tangent; uTangents[uvIndices[fvi2]] += tangent; vTangents[uvIndices[fvi0]] += bitangent; vTangents[uvIndices[fvi1]] += bitangent; vTangents[uvIndices[fvi2]] += bitangent; normals[uvIndices[fvi0]] += normal; normals[uvIndices[fvi1]] += normal; normals[uvIndices[fvi2]] += normal; } // normalize and orthogonalize everything for( size_t i = 0; i < uTangents.size(); i++ ) { normals[i].normalize(); uTangents[i].normalize(); vTangents[i].normalize(); // Make uTangent/vTangent orthogonal to normal uTangents[i] -= normals[i] * uTangents[i].dot( normals[i] ); vTangents[i] -= normals[i] * vTangents[i].dot( normals[i] ); uTangents[i].normalize(); vTangents[i].normalize(); if( orthoTangents ) { vTangents[i] -= uTangents[i] * vTangents[i].dot( uTangents[i] ); vTangents[i].normalize(); } // Ensure we have set of basis vectors (n, uT, vT) with the correct handedness. if( uTangents[i].cross( vTangents[i] ).dot( normals[i] ) < 0.0f ) { uTangents[i] *= -1.0f; } } // convert the tangents back to facevarying data and add that to the mesh V3fVectorDataPtr fvUD = new V3fVectorData(); V3fVectorDataPtr fvVD = new V3fVectorData(); std::vector<V3f> &fvU = fvUD->writable(); std::vector<V3f> &fvV = fvVD->writable(); fvU.resize( uvIndices.size() ); fvV.resize( uvIndices.size() ); for( unsigned i = 0; i < uvIndices.size(); i++ ) { fvU[i] = uTangents[uvIndices[i]]; fvV[i] = vTangents[uvIndices[i]]; } PrimitiveVariable tangentPrimVar( PrimitiveVariable::FaceVarying, fvUD ); PrimitiveVariable bitangentPrimVar( PrimitiveVariable::FaceVarying, fvVD ); return std::make_pair( tangentPrimVar, bitangentPrimVar ); }
//-***************************************************************************** void MeshDrwHelper::draw( const DrawContext & iCtx ) const { // Bail if invalid. if ( !m_valid || m_triangles.size() < 1 || !m_meshP ) { return; } const V3f *points = m_meshP->get(); const V3f *normals = NULL; if ( m_meshN && ( m_meshN->size() == m_meshP->size() ) ) { normals = m_meshN->get(); } else if ( m_customN.size() == m_meshP->size() ) { normals = &(m_customN.front()); } // colors const C4f *colors = NULL; if (m_colors.size() == m_meshP->size() ) { colors = &(m_colors.front()); } static MGLFunctionTable *gGLFT = NULL; if (gGLFT == NULL) gGLFT = MHardwareRenderer::theRenderer()->glFunctionTable(); gGLFT->glBegin( MGL_TRIANGLES ); for ( size_t i = 0; i < m_triangles.size(); ++i ) { const Tri &tri = m_triangles[i]; const V3f &vertA = points[tri[0]]; const V3f &vertB = points[tri[1]]; const V3f &vertC = points[tri[2]]; if ( normals ) { const V3f &normA = normals[tri[0]]; gGLFT->glNormal3fv( ( const GLfloat * )&normA ); gGLFT->glVertex3fv( ( const GLfloat * )&vertA ); const V3f &normB = normals[tri[1]]; gGLFT->glNormal3fv( ( const GLfloat * )&normB ); gGLFT->glVertex3fv( ( const GLfloat * )&vertB ); const V3f &normC = normals[tri[2]]; gGLFT->glNormal3fv( ( const GLfloat * )&normC ); gGLFT->glVertex3fv( ( const GLfloat * )&vertC ); } else { V3f AB = vertB - vertA; V3f AC = vertC - vertA; V3f N = AB.cross( AC ); if ( N.length() > 1.0e-4f ) { N.normalize(); gGLFT->glNormal3fv( ( const GLfloat * )&N ); } gGLFT->glVertex3fv( ( const GLfloat * )&vertA ); gGLFT->glVertex3fv( ( const GLfloat * )&vertB ); gGLFT->glVertex3fv( ( const GLfloat * )&vertC ); } } gGLFT->glEnd(); }