/*! sets the rotation of this node. The axis parameter will be transformed into 'relativeTo' space. So an passing in an axis of (0, 1, 0) with TS_Object will rotate the node around its own up axis. */ void SLNode::rotation(const SLQuat4f& rot, SLTransformSpace relativeTo) { SLMat4f rotation = rot.toMat4(); if (_parent && relativeTo == TS_world) { // get the inverse parent rotation to remove it from our current rotation // we want the input quaternion to absolutely set our new rotation relative // to the world axes SLMat4f parentRotInv = _parent->updateAndGetWMI(); parentRotInv.translation(0, 0, 0); // set the om rotation to the inverse of the parents rotation to achieve a // 0, 0, 0 relative rotation in world space _om.rotation(0, 0, 0, 0); _om *= parentRotInv; needUpdate(); rotate(rot, relativeTo); } else if (relativeTo == TS_parent) { // relative to parent, reset current rotation and just rotate again _om.rotation(0, 0, 0, 0); needUpdate(); rotate(rot, relativeTo); } else { // in TS_Object everything is relative to our current orientation _om.rotation(0, 0, 0, 0); _om *= rotation; needUpdate(); } }
/*! SLCurveBezier::subdivideRender adds points along the curve to the point vector renderPoints by recursively subdividing the curve with the Casteljau scheme. */ void SLCurveBezier::subdivideRender(SLVVec3f &renderPoints, const SLMat4f &wm, SLfloat epsilon, const SLVec3f& P0, const SLVec3f& P1, const SLVec3f& P2, const SLVec3f& P3) { // add first point transformed by wm if not already in the list if (renderPoints.size()==0) renderPoints.push_back(wm.multVec(P0)); else if (P0 != renderPoints[renderPoints.size()-1]) renderPoints.push_back(wm.multVec(P0)); // check to see if basically straight SLfloat Lmin = P0.distance(P3); SLfloat Lmax = P0.distance(P1) + P1.distance(P2) + P2.distance(P3); SLfloat diff = Lmin - Lmax; if (diff*diff < epsilon) return; // otherwise get control points for subdivision SLVec3f L1 = (P0 + P1) * 0.5f; SLVec3f H = (P1 + P2) * 0.5f; SLVec3f L2 = (L1 + H) * 0.5f; SLVec3f R2 = (P2 + P3) * 0.5f; SLVec3f R1 = (H + R2) * 0.5f; SLVec3f mid = (L2 + R1) * 0.5f; // subdivide subdivideRender(renderPoints, wm, epsilon, P0, L1, L2, mid); subdivideRender(renderPoints, wm, epsilon, mid, R1, R2, P3); }
/*! Scans all meshes in the assimp scene and populates nameToBone and jointGroups */ void SLAssimpImporter::findJoints(const aiScene* scene) { for (SLuint i = 0; i < scene->mNumMeshes; i++) { aiMesh* mesh = scene->mMeshes[i]; if(!mesh->HasBones()) continue; logMessage(LV_normal, " Mesh '%s' contains %d joints.\n", mesh->mName.C_Str(), mesh->mNumBones); for (SLuint j = 0; j < mesh->mNumBones; j++) { SLstring name = mesh->mBones[j]->mName.C_Str(); std::map<SLstring, SLMat4f>::iterator it = _jointOffsets.find(name); if(it != _jointOffsets.end()) continue; // add the offset matrix to our offset matrix map SLMat4f offsetMat; memcpy(&offsetMat, &mesh->mBones[j]->mOffsetMatrix, sizeof(SLMat4f)); offsetMat.transpose(); _jointOffsets[name] = offsetMat; logMessage(LV_detailed, " Bone '%s' found.\n", name.c_str()); } } }
/*! Rotates the node around its local origin relative to the space expressed by 'relativeTo'. */ void SLNode::rotate(const SLQuat4f& rot, SLTransformSpace relativeTo) { SLQuat4f norm = rot.normalized(); SLMat4f rotation = rot.toMat4(); if (relativeTo == TS_object) { _om *= rotation; } else if (_parent && relativeTo == TS_world) { SLMat4f rot; rot.translate(updateAndGetWM().translation()); rot.multiply(rotation); rot.translate(-updateAndGetWM().translation()); _om = _parent->_wm.inverse() * rot * updateAndGetWM(); } else // relativeTo == TS_Parent || relativeTo == TS_World && !_parent { SLMat4f rot; rot.translate(translation()); rot.multiply(rotation); rot.translate(-translation()); _om.setMatrix(rot * _om); } needUpdate(); }
/*! onResize: Event handler called on the resize event of the window. This event should called once before the onPaint event. Do everything that is dependent on the size and ratio of the window. */ void onResize(GLFWwindow* window, int width, int height) { double w = (double)width; double h = (double)height; // define the projection matrix _projectionMatrix.perspective(45, w/h, 0.01f, 10.0f); // define the viewport glViewport(0, 0, width, height); onPaint(); }
/*! Applies the view transform to the modelview matrix depending on the eye: eye=-1 for left, eye=1 for right */ void SLCamera::setView(const SLEye eye) { SLSceneView* sv = SLScene::current->activeSV(); if (eye == centerEye) { stateGL->modelViewMatrix.identity(); stateGL->modelViewMatrix.multiply(_vm); } else // stereo viewing { if (_projection == stereoSideBySideD) { // half interpupilar distance _eyeSeparation = sv->oculus()->eyeSeparation(); SLfloat halfIPD = (SLfloat)eye * _eyeSeparation * -0.5f; // get the oculus orientation SLMat4f rotation(sv->oculus()->orientation().toMat4()); SLMat4f vmEye(SLMat4f(halfIPD, 0.0f, 0.f) * rotation * _vm); stateGL->modelViewMatrix = vmEye; stateGL->viewMatrix = vmEye; } else { // Get central camera vectors eye, lookAt, lookUp out of the view matrix vm SLVec3f EYE, LA, LU, LR; _vm.lookAt(&EYE, &LA, &LU, &LR); // Shorten LR to half of the eye dist (eye=-1 for left, eye=1 for right) LR *= _eyeSeparation * 0.5f * (SLfloat)eye; // Set the OpenGL view matrix for the left eye SLMat4f vmEye; vmEye.lookAt(EYE+LR, EYE + _focalDist*LA+LR, LU); stateGL->modelViewMatrix = vmEye; stateGL->viewMatrix = vmEye; } } }
/*! Rotates the node around an arbitrary point. The 'axis' and 'point' parameter are relative to the space described by 'relativeTo'. */ void SLNode::rotateAround(const SLVec3f& point, SLVec3f& axis, SLfloat angleDeg, SLTransformSpace relativeTo) { SLVec3f localPoint = point; SLVec3f localAxis = axis; if (relativeTo == TS_world && _parent) { localPoint = _parent->updateAndGetWMI() * point; localAxis = _parent->updateAndGetWMI().mat3() * axis; } SLMat4f rot; rot.translate(localPoint); rot.rotate(angleDeg, localAxis); rot.translate(-localPoint); if (relativeTo == TS_object) _om.setMatrix(_om * rot); else _om.setMatrix(rot * _om); needUpdate(); }
//----------------------------------------------------------------------------- //! Gets called whenever the mouse is moved. SLbool SLCamera::onMouseMove(const SLMouseButton button, const SLint x, const SLint y, const SLKey mod) { if (button == ButtonLeft) //================================================ { // new vars needed SLVec3f position = this->translation(); SLVec3f forward = this->forward(); SLVec3f right = this->right(); SLVec3f up = this->up(); // The lookAt point SLVec3f laP = position + _focalDist * forward; // Determine rotation point as the center of the AABB of the hitNode SLVec3f rtP; if (_lookAtRay.length < FLT_MAX && _lookAtRay.hitNode) rtP = _lookAtRay.hitNode->aabb()->centerWS(); else rtP = laP; // Determine rot angles around x- & y-axis SLfloat dY = (y-_oldTouchPos1.y) * _rotFactor; SLfloat dX = (x-_oldTouchPos1.x) * _rotFactor; if (_camAnim==turntableYUp) //....................................... { SLMat4f rot; rot.translate(rtP); rot.rotate(-dX, SLVec3f(0,1,0)); rot.rotate(-dY, right); rot.translate(-rtP); _om.setMatrix(rot * _om); needWMUpdate(); } else if (_camAnim==turntableZUp) //.................................. { SLMat4f rot; rot.translate(rtP); rot.rotate(dX, SLVec3f(0,0,1)); rot.rotate(dY, right); rot.translate(-rtP); _om.setMatrix(rot * _om); needWMUpdate(); } else if (_camAnim==walkingYUp) //.................................... { dY *= 0.5f; dX *= 0.5f; SLMat4f rot; rot.rotate(-dX, SLVec3f(0, 1, 0)); rot.rotate(-dY, right); forward.set(rot.multVec(forward)); lookAt(position + forward); } else if (_camAnim==walkingZUp) //.................................... { dY *= 0.5f; dX *= 0.5f; SLMat4f rot; rot.rotate(-dX, SLVec3f(0, 0, 1)); rot.rotate(-dY, right); forward.set(rot.multVec(forward)); lookAt(position + forward, SLVec3f(0, 0, 1)); } _oldTouchPos1.set((SLfloat)x,(SLfloat)y); } else if (button == ButtonMiddle) //============================================== { if (_camAnim==turntableYUp || _camAnim==turntableZUp) { // Calculate the fraction delta of the mouse movement SLVec2f dMouse(x-_oldTouchPos1.x, _oldTouchPos1.y-y); dMouse.x /= (SLfloat)_scrW; dMouse.y /= (SLfloat)_scrH; // Scale the mouse delta by the lookAt distance SLfloat lookAtDist; if (_lookAtRay.length < FLT_MAX) lookAtDist = _lookAtRay.length; else lookAtDist = _focalDist; // scale factor depending on the space sice at focal dist SLfloat spaceH = tan(SL_DEG2RAD*_fov/2) * lookAtDist * 2.0f; SLfloat spaceW = spaceH * _aspect; dMouse.x *= spaceW; dMouse.y *= spaceH; if (mod==KeyCtrl) { translate(SLVec3f(-dMouse.x, 0, dMouse.y), TS_Object); } else { translate(SLVec3f(-dMouse.x, -dMouse.y, 0), TS_Object); } _oldTouchPos1.set((SLfloat)x,(SLfloat)y); } } //======================================================================== return true; }
/*! Applies the view transform to the modelview matrix depending on the eye: eye=-1 for left, eye=1 for right */ void SLCamera::setView(SLSceneView* sv, const SLEye eye) { SLScene* s = SLScene::current; SLMat4f vm = updateAndGetWMI(); if (eye == centerEye) { _stateGL->modelViewMatrix.identity(); _stateGL->viewMatrix.setMatrix(vm); } else // stereo viewing { if (_projection == stereoSideBySideD) { // half interpupilar disqtance //_eyeSeparation = s->oculus()->interpupillaryDistance(); update old rift code SLfloat halfIPD = (SLfloat)eye * _eyeSeparation * -0.5f; SLMat4f trackingPos; if (_useDeviceRot) { // get the oculus or mobile device orientation SLQuat4f rotation; if (s->oculus()->isConnected()) { rotation = s->oculus()->orientation(eye); trackingPos.translate(-s->oculus()->position(eye)); } else rotation = sv->deviceRotation(); SLfloat rotX, rotY, rotZ; rotation.toMat4().toEulerAnglesZYX(rotZ, rotY, rotX); //SL_LOG("rotx : %3.1f, roty: %3.1f, rotz: %3.1f\n", rotX*SL_RAD2DEG, rotY*SL_RAD2DEG, rotZ*SL_RAD2DEG); SLVec3f viewAdjust = s->oculus()->viewAdjust(eye) * _unitScaling; SLMat4f vmEye(SLMat4f(viewAdjust.x, viewAdjust.y, viewAdjust.z) * rotation.inverted().toMat4() * trackingPos * vm); _stateGL->modelViewMatrix = vmEye; _stateGL->viewMatrix = vmEye; } else { SLMat4f vmEye(SLMat4f(halfIPD, 0.0f, 0.f) * vm); _stateGL->modelViewMatrix = vmEye; _stateGL->viewMatrix = vmEye; } } else { // Get central camera vectors eye, lookAt, lookUp out of the view matrix vm SLVec3f EYE, LA, LU, LR; vm.lookAt(&EYE, &LA, &LU, &LR); // Shorten LR to half of the eye dist (eye=-1 for left, eye=1 for right) LR *= _eyeSeparation * 0.5f * (SLfloat)eye; // Set the OpenGL view matrix for the left eye SLMat4f vmEye; vmEye.lookAt(EYE+LR, EYE + _focalDist*LA+LR, LU); _stateGL->modelViewMatrix = vmEye; _stateGL->viewMatrix = vmEye; } } }
/*! onPaint does all the rendering for one frame from scratch with OpenGL (in core profile). */ bool onPaint() { // Clear the color & depth buffer glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // View transform: move the coordinate system away from the camera _viewMatrix.identity(); _viewMatrix.translate(0, 0, _camZ); // View transform: rotate the coordinate system increasingly by the mouse _viewMatrix.rotate(_rotX + _deltaX, 1,0,0); _viewMatrix.rotate(_rotY + _deltaY, 0,1,0); // Transform light position & direction into view space SLVec3f lightPosVS = _viewMatrix * _lightPos; // The light dir is not a position. We only take the rotation of the mv matrix. SLMat3f viewRot = _viewMatrix.mat3(); SLVec3f lightDirVS = viewRot * _lightDir; // Rotate the model so that we see the square from the front side // or the earth from the equator. _modelMatrix.identity(); _modelMatrix.rotate(90, -1,0,0); // Build the combined model-view and model-view-projection matrix SLMat4f mvp(_projectionMatrix); SLMat4f mv(_viewMatrix * _modelMatrix); mvp.multiply(mv); // Build normal matrix SLMat3f nm(mv.inverseTransposed()); // Pass the matrix uniform variables glUniformMatrix4fv(_mvMatrixLoc, 1, 0, (float*)&mv); glUniformMatrix3fv(_nMatrixLoc, 1, 0, (float*)&nm); glUniformMatrix4fv(_mvpMatrixLoc, 1, 0, (float*)&mvp); // Pass lighting uniforms variables glUniform4fv(_globalAmbiLoc, 1, (float*)&_globalAmbi); glUniform3fv(_lightPosVSLoc, 1, (float*)&lightPosVS); glUniform3fv(_lightDirVSLoc, 1, (float*)&lightDirVS); glUniform4fv(_lightAmbientLoc, 1, (float*)&_lightAmbient); glUniform4fv(_lightDiffuseLoc, 1, (float*)&_lightDiffuse); glUniform4fv(_lightSpecularLoc, 1, (float*)&_lightSpecular); glUniform4fv(_matAmbientLoc, 1, (float*)&_matAmbient); glUniform4fv(_matDiffuseLoc, 1, (float*)&_matDiffuse); glUniform4fv(_matSpecularLoc, 1, (float*)&_matSpecular); glUniform4fv(_matEmissiveLoc, 1, (float*)&_matEmissive); glUniform1f (_matShininessLoc, _matShininess); glUniform1i (_texture0Loc, 0); ////////////////////// // Draw with 2 VBOs // ////////////////////// // Enable all of the vertex attribute arrays glEnableVertexAttribArray(_pLoc); glEnableVertexAttribArray(_nLoc); glEnableVertexAttribArray(_tLoc); // Activate VBOs glBindBuffer(GL_ARRAY_BUFFER, _vboV); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboI); // Activate Texture glBindTexture(GL_TEXTURE_2D, _textureID); // For VBO only offset instead of data pointer GLsizei stride = sizeof(VertexPNT); GLsizei offsetN = sizeof(SLVec3f); GLsizei offsetT = sizeof(SLVec3f) + sizeof(SLVec3f); glVertexAttribPointer(_pLoc, 3, GL_FLOAT, GL_FALSE, stride, 0); glVertexAttribPointer(_nLoc, 3, GL_FLOAT, GL_FALSE, stride, (void*)offsetN); glVertexAttribPointer(_tLoc, 2, GL_FLOAT, GL_FALSE, stride, (void*)offsetT); //////////////////////////////////////////////////////// // Draw cube model triangles by indexes glDrawElements(GL_TRIANGLES, _numI, GL_UNSIGNED_INT, 0); //////////////////////////////////////////////////////// // Deactivate buffers glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // Disable the vertex arrays glDisableVertexAttribArray(_pLoc); glDisableVertexAttribArray(_nLoc); glDisableVertexAttribArray(_tLoc); // Check for errors from time to time GETGLERROR; // Fast copy the back buffer to the front buffer. This is OS dependent. glfwSwapBuffers(window); // Calculate frames per second char title[255]; static float lastTimeSec = 0; float timeNowSec = (float)glfwGetTime(); float fps = calcFPS(timeNowSec-lastTimeSec); sprintf(title, "Sphere, %d x %d, fps: %4.0f", _resolution, _resolution, fps); glfwSetWindowTitle(window, title); lastTimeSec = timeNowSec; // Return true to get an immediate refresh return true; }
/*! SLCurveBezier::draw does the OpenGL rendering of the Bezier curve in world space. */ void SLCurveBezier::draw(const SLMat4f &wm) { SLint numControlPoints = 2*((SLint)_points.size()-1); // Create buffer object if (!_vao.id()) { // Build renderPoints by recursively subdividing the curve SLVVec3f renderPoints; for (SLuint i = 0; i < _points.size()-1; ++i) { subdivideRender(renderPoints, wm, 0.00001f, _points[i].vec3(), _controls[2*i], _controls[2*i+1], _points[i+1].vec3()); } // add last point to the curve vector renderPoints.push_back(wm.multVec(_points[_points.size()-1].vec3())); // add inputs points for (SLuint i = 0; i < _points.size(); ++i) renderPoints.push_back(wm.multVec(_points[i].vec3())); // add control points for (SLint i = 0; i < numControlPoints; ++i) renderPoints.push_back(wm.multVec(_controls[i])); // add tangent points for (SLint i = 0; i < numControlPoints; ++i) { renderPoints.push_back(wm.multVec(_controls[i])); int iPoint = (SLint)((SLfloat)i/2.0f + 0.5f); renderPoints.push_back(wm.multVec(_points[iPoint].vec3())); } // Generate finally the OpenGL rendering buffer _vao.generateVertexPos(&renderPoints); } if (!_vao.id()) return; // Set the view transform SLGLState* stateGL = SLGLState::getInstance(); stateGL->modelViewMatrix.setMatrix(stateGL->viewMatrix); SLint numTangentPoints = numControlPoints * 2; SLint numCurvePoints = _vao.numVertices() - (SLint)_points.size() - numControlPoints - numTangentPoints; // Draw curve as a line strip through interpolated points _vao.drawArrayAsColored(PT_lineStrip, SLCol3f::RED, 1, 0, numCurvePoints); // ES2 has often problems with rendering points #ifndef SL_GLES2 // Draw curve as a line strip through interpolated points _vao.drawArrayAsColored(PT_points, SLCol4f::RED, 3, 0, numCurvePoints); // Draw input points _vao.drawArrayAsColored(PT_points, SLCol4f::BLUE, 6, numCurvePoints, (SLuint)_points.size()); // Draw control points _vao.drawArrayAsColored(PT_points, SLCol4f::YELLOW, 6, numCurvePoints + (SLuint)_points.size(), numControlPoints); // Draw tangent points as lines _vao.drawArrayAsColored(PT_lines, SLCol4f::YELLOW, 1, numCurvePoints + (SLint)_points.size() + numControlPoints, numTangentPoints); #endif }
//----------------------------------------------------------------------------- //! Gets called whenever the mouse is moved. SLbool SLCamera::onMouseMove(const SLMouseButton button, const SLint x, const SLint y, const SLKey mod) { SLScene* s = SLScene::current; SLSceneView* sv = s->activeSV(); if (button == ButtonLeft) //================================================ { // Get camera vectors: eye pos., lookAt, lookUp, lookRight SLVec3f eye, LA, LU, LR; _vm.lookAt(&eye, &LA, &LU, &LR); // The lookAt and lookUp point in VS SLVec3f laP = eye + _focalDist * LA; // Determine rotation point as the center of the AABB of the hitShape SLVec3f rtP; if (_lookAtRay.length < FLT_MAX && _lookAtRay.hitShape) rtP = _lookAtRay.hitShape->aabb()->centerWS(); else rtP = laP; // Determine rot angles around x- & y-axis SLfloat dY = (_oldTouchPos1.y-y) * _rotFactor; SLfloat dX = (_oldTouchPos1.x-x) * _rotFactor; if (_camAnim==turntableYUp) //....................................... { // Apply rotation around the lookAt point SLMat4f rot; rot.translate(rtP); rot.rotate(-dY, LR); rot.rotate(-dX, SLVec3f(0,1,0)); rot.translate(-rtP); _vm *= rot; } else if (_camAnim==turntableZUp) //.................................. { // Apply rotation around the lookAt point SLMat4f rot; rot.translate(rtP); rot.rotate(-dY, LR); rot.rotate(-dX, SLVec3f(0,0,1)); rot.translate(-rtP); _vm *= rot; } else if (_camAnim==walkingYUp) //.................................... { dY *= 0.5f; dX *= 0.5f; // Apply rotation around the lookRight and the Y-axis SLMat4f rot; rot.rotate(-dY, LR); rot.rotate(-dX, SLVec3f(0,1,0)); // rotate eye position LA.set(rot*LA); _vm.lookAt(eye, eye+LA*_focalDist, SLVec3f(0,1,0)); } else if (_camAnim==walkingZUp) //.................................... { dY *= 0.5f; dX *= 0.5f; // Apply rotation around the lookRight and the Z-axis SLMat4f rot; rot.rotate(-dY, LR); rot.rotate(-dX, SLVec3f(0,0,1)); // rotate eye position LA.set(rot*LA); _vm.lookAt(eye, eye+LA*_focalDist, SLVec3f(0,0,1)); } setWMandState(); _oldTouchPos1.set((SLfloat)x,(SLfloat)y); return true; } else if (button == ButtonMiddle) //============================================== { if (_camAnim==turntableYUp || _camAnim==turntableZUp) { // Calculate the fraction delta of the mouse movement SLVec2f dMouse(x-_oldTouchPos1.x, _oldTouchPos1.y-y); dMouse.x /= (SLfloat)sv->scrW(); dMouse.y /= (SLfloat)sv->scrH(); // Scale the mouse delta by the lookAt distance SLfloat lookAtDist; if (_lookAtRay.length < FLT_MAX) lookAtDist = _lookAtRay.length; else lookAtDist = _focalDist; // scale factor depending on the space sice at focal dist SLfloat spaceH = tan(SL_DEG2RAD*_fov/2) * lookAtDist * 2.0f; SLfloat spaceW = spaceH * sv->scrWdivH(); dMouse.x *= spaceW; dMouse.y *= spaceH; if (mod==KeyCtrl) { _vm.translation(_vm.m(12) + dMouse.x, _vm.m(13), _vm.m(14) + dMouse.y); } else { _vm.translation(_vm.m(12) + dMouse.x, _vm.m(13) + dMouse.y, _vm.m(14)); } setWMandState(); _oldTouchPos1.set((SLfloat)x,(SLfloat)y); return true; } } //======================================================================== return false; }