const SbVec4f & SoTextureCoordinateEnvironment::valueCallback(void *action, const SbVec3f &point, const SbVec3f &normal) // //////////////////////////////////////////////////////////////////////// { SoAction *a = (SoAction *)action; // // See the glTexGen() man page for the math here. // // First, map normal and point into eye space: const SbMatrix &mm = SoModelMatrixElement::get(a->getState()); const SbMatrix &vm = SoViewingMatrixElement::get(a->getState()); // Compute the matrix that transforms normals from object-space to // eye-space; use the inverse transpose to scale correctly SbVec3f normalE; SbMatrix nm = (vm * mm).inverse().transpose(); nm.multDirMatrix(normal, normalE); SbVec3f pointE; mm.multVecMatrix(point, pointE); // Gives world-space point vm.multVecMatrix(pointE, pointE); // ... to eye-space. // Get the normalized vector from the eye (which is conveniently // at 0,0,0 in eye space) to the point. pointE.normalize(); // Now, figure out reflection vector, from formula: // R = P - 2 (N . N) pointE SbVec3f reflection = pointE - 2.0 * normalE.dot(normalE) * pointE; // Finally, compute s/t coordinates... reflection[2] += 1.0; float magnitude = reflection.length(); // This is static so we can return a reference to it static SbVec4f result; result.setValue(reflection[0] / magnitude + 0.5, reflection[1] / magnitude + 0.5, 0.0, 1.0); return result; }
bool ObjMgrCommunicator::getObjAttributeVec4f(const string ObjID, const string LayerID, const string InfoID, SbVec4f& vec4f) { omAttribute attr; if (getObjAttribute(ObjID,LayerID,InfoID, attr)) { vector<string> VecSplit; kBasics::split(attr.getStringValue(),' ',4,&VecSplit); if (VecSplit.size()!=4) { kDebug::Debug("WrongSplitSize: " + kBasics::IntToString(VecSplit.size()),kDebug::DL_HIGH); return false; } vec4f.setValue(kBasics::StringToFloat(VecSplit[0]),kBasics::StringToFloat(VecSplit[1]),kBasics::StringToFloat(VecSplit[2]),kBasics::StringToFloat(VecSplit[3])); return true; } return false; }
void SoCylinder::rayPick(SoRayPickAction *action) // //////////////////////////////////////////////////////////////////////// { // First see if the object is pickable if (! shouldRayPick(action)) return; int curParts =(parts.isIgnored() ? ALL : parts.getValue()); SbLine pickLine; float radius, halfHeight; SbVec3f enterPoint, exitPoint, normal; SbVec4f texCoord; SoPickedPoint *pp; SoCylinderDetail *detail; SbBool materialPerPart; int numHits = 0; // Compute the picking ray in our current object space computeObjectSpaceRay(action); // Get size of this cylinder getSize(radius, halfHeight); // Construct an infinite cylinder to test sides for intersection SbCylinder infiniteCyl; infiniteCyl.setRadius(radius); SoMaterialBindingElement::Binding mbe = SoMaterialBindingElement::get(action->getState()); materialPerPart = (mbe == SoMaterialBindingElement::PER_PART_INDEXED || mbe == SoMaterialBindingElement::PER_PART); // See if the line intersects the cylinder if (HAS_PART(curParts, SIDES) && infiniteCyl.intersect(action->getLine(), enterPoint, exitPoint)) { // See if the enter point is within the real cylinder and is // between the near and far clipping planes. if (enterPoint[1] <= halfHeight && enterPoint[1] >= -halfHeight) { numHits++; if (action->isBetweenPlanes(enterPoint) && (pp = action->addIntersection(enterPoint)) != NULL) { // The normal at the point is the same as the point but // with a 0 y coordinate normal.setValue(enterPoint[0], 0.0, enterPoint[2]); normal.normalize(); pp->setObjectNormal(normal); texCoord.setValue(atan2f(enterPoint[0], enterPoint[2]) * (1.0 / (2.0 * M_PI)) + 0.5, (enterPoint[1] + halfHeight) / (2.0 * halfHeight), 0.0, 1.0); pp->setObjectTextureCoords(texCoord); detail = new SoCylinderDetail(); detail->setPart(SIDES); pp->setDetail(detail, this); } } // Do same for exit point if (exitPoint[1] <= halfHeight && exitPoint[1] >= -halfHeight) { numHits++; if (action->isBetweenPlanes(exitPoint) && (pp = action->addIntersection(exitPoint)) != NULL) { normal.setValue(exitPoint[0], 0.0, exitPoint[2]); normal.normalize(); pp->setObjectNormal(normal); texCoord.setValue(atan2f(exitPoint[0], exitPoint[2]) * (1.0 / (2.0 * M_PI)) + 0.5, (exitPoint[1] + halfHeight) / (2.0 * halfHeight), 0.0, 1.0); pp->setObjectTextureCoords(texCoord); detail = new SoCylinderDetail(); detail->setPart(SIDES); pp->setDetail(detail, this); } } } // If we haven't hit the cylinder twice already, check for an // intersection with the top face if (numHits < 2 && HAS_PART(curParts, TOP)) { SbVec3f norm(0.0, 1.0, 0.0); // Construct a plane containing the top face SbPlane topFacePlane(norm, halfHeight); // See if the ray hits this plane if (topFacePlane.intersect(action->getLine(), enterPoint)) { // See if the intersection is within the correct radius // and is within the clipping planes float distFromYAxisSquared = (enterPoint[0] * enterPoint[0] + enterPoint[2] * enterPoint[2]); if (distFromYAxisSquared <= radius * radius) { numHits++; if (action->isBetweenPlanes(enterPoint) && (pp = action->addIntersection(enterPoint)) != NULL) { pp->setObjectNormal(norm); texCoord.setValue(0.5 + enterPoint[0] / (2.0 * radius), 0.5 - enterPoint[2] / (2.0 * radius), 0.0, 1.0); pp->setObjectTextureCoords(texCoord); if (materialPerPart) pp->setMaterialIndex(1); detail = new SoCylinderDetail(); detail->setPart(TOP); pp->setDetail(detail, this); } } } } // If we haven't hit the cylinder twice already, check for an // intersection with the bottom face if (numHits < 2 && HAS_PART(curParts, BOTTOM)) { SbVec3f norm(0.0, -1.0, 0.0); // Construct a plane containing the bottom face SbPlane bottomFacePlane(norm, halfHeight); // See if the ray hits this plane if (bottomFacePlane.intersect(action->getLine(), enterPoint)) { // See if the intersection is within the correct radius // and is within the clipping planes float distFromYAxisSquared = (enterPoint[0] * enterPoint[0] + enterPoint[2] * enterPoint[2]); if (distFromYAxisSquared <= radius * radius && action->isBetweenPlanes(enterPoint) && (pp = action->addIntersection(enterPoint)) != NULL) { pp->setObjectNormal(norm); texCoord.setValue(0.5 + enterPoint[0] / (2.0 * radius), 0.5 + enterPoint[2] / (2.0 * radius), 0.0, 1.0); pp->setObjectTextureCoords(texCoord); if (materialPerPart) pp->setMaterialIndex(2); detail = new SoCylinderDetail(); detail->setPart(BOTTOM); pp->setDetail(detail, this); } } } }