/*! SLCamera::calcMinMax calculates the axis alligned minimum and maximum point of the camera position and the 4 near clipping plane points. */ void SLCamera::calcMinMax(SLVec3f &minV, SLVec3f &maxV) { SLScene* s = SLScene::current; SLSceneView* sv = s->activeSV(); SLVec3f P[5]; SLfloat aspect = (float)sv->scrW() / (float)sv->scrH(); SLfloat tanFov = tan(_fov*SL_DEG2RAD*0.5f); SLfloat tN = tanFov * _clipNear; //top near SLfloat rN = tN * aspect; //right near // frustum pyramid lines P[0].set(0,0,0); // around near clipping plane P[1].set( rN, tN,-_clipNear); P[2].set( rN,-tN,-_clipNear); P[3].set(-rN,-tN,-_clipNear); P[4].set(-rN, tN,-_clipNear); // init min & max points minV.set( FLT_MAX, FLT_MAX, FLT_MAX); maxV.set(-FLT_MAX, -FLT_MAX, -FLT_MAX); // calc min and max point of all vertices for (SLuint i=0; i<5; ++i) { if (P[i].x < minV.x) minV.x = P[i].x; if (P[i].x > maxV.x) maxV.x = P[i].x; if (P[i].y < minV.y) minV.y = P[i].y; if (P[i].y > maxV.y) maxV.y = P[i].y; if (P[i].z < minV.z) minV.z = P[i].z; if (P[i].z > maxV.z) maxV.z = P[i].z; } }
/*! */ SLCol4f SLPhotonMapper::trace(SLRay* ray) { SLScene* s = SLScene::current; SLCol4f color(s->backColor()); return color; }
/*! SLCamera::onDoubleTouch gets called whenever two fingers touch a handheld screen. */ SLbool SLCamera::onTouch2Down(const SLint x1, const SLint y1, const SLint x2, const SLint y2) { SLScene* s = SLScene::current; SLSceneView* sv = s->activeSV(); // Determine the lookAt point by ray cast eyeToPixelRay((SLfloat)sv->scrWdiv2(), (SLfloat)sv->scrHdiv2(), &_lookAtRay); s->root3D()->hit(&_lookAtRay); _oldTouchPos1.set((SLfloat)x1, (SLfloat)y1); _oldTouchPos2.set((SLfloat)x2, (SLfloat)y2); return true; }
/*! SLCamera::onMouseWheel event handler moves camera forwards or backwards */ SLbool SLCamera::onMouseWheel(const SLint delta, const SLKey mod) { SLScene* s = SLScene::current; SLSceneView* sv = s->activeSV(); SLfloat sign = (SLfloat)SL_sign(delta); if (_camAnim==turntableYUp || _camAnim==turntableZUp) //.................... { if (mod==KeyNone) { // Determine the lookAt point by ray cast eyeToPixelRay((SLfloat)sv->scrWdiv2(), (SLfloat)sv->scrHdiv2(), &_lookAtRay); s->root3D()->hit(&_lookAtRay); if (_lookAtRay.length < FLT_MAX) _lookAtRay.hitPoint = _lookAtRay.origin + _lookAtRay.dir*_lookAtRay.length; // Scale the mouse delta by the lookAt distance SLfloat lookAtDist; if (_lookAtRay.length < FLT_MAX && _lookAtRay.hitShape) { lookAtDist = _lookAtRay.length; } else lookAtDist = _focalDist; _vm.translation(_vm.m(12),_vm.m(13),_vm.m(14) + sign*lookAtDist*_dPos); _lookAtRay.length = FLT_MAX; setWMandState(); } if (mod==KeyCtrl) { _eyeSeparation *= (1.0f + sign*0.1f); } if (mod==KeyAlt) { _fov += sign*5.0f; currentFOV = _fov; } if (mod==KeyShift) { _focalDist *= (1.0f + sign*0.05f); } return true; } else if (_camAnim==walkingYUp || _camAnim==walkingZUp) //................... { _speedLimit *= (1.0f + sign*0.1f); } return false; }
//----------------------------------------------------------------------------- //! Gets called whenever a mouse button gets pressed. SLbool SLCamera::onMouseDown(const SLMouseButton button, const SLint x, const SLint y, const SLKey mod) { SLScene* s = SLScene::current; // Determine the lookAt point by ray cast eyeToPixelRay((SLfloat)(_scrW>>1), (SLfloat)(_scrH>>1), &_lookAtRay); //eyeToPixelRay(x, y, &_lookAtRay); if (s->root3D()) s->root3D()->hitRec(&_lookAtRay); // Init both position in case that the second finger came with delay _oldTouchPos1.set((SLfloat)x, (SLfloat)y); _oldTouchPos2.set((SLfloat)x, (SLfloat)y); return false; }
//----------------------------------------------------------------------------- //! Gets called whenever a mouse button gets pressed. SLbool SLCamera::onMouseDown(const SLMouseButton button, const SLint x, const SLint y, const SLKey mod) { SLScene* s = SLScene::current; SLSceneView* sv = s->activeSV(); // Determine the lookAt point by ray cast eyeToPixelRay((SLfloat)sv->scrWdiv2(), (SLfloat)sv->scrHdiv2(), &_lookAtRay); s->root3D()->hit(&_lookAtRay); // Init both position in case that the second finger came with delay _oldTouchPos1.set((SLfloat)x, (SLfloat)y); _oldTouchPos2.set((SLfloat)x, (SLfloat)y); return false; }
/*! SLMaterial::activate applies the material parameter to the global render state and activates the attached shader */ void SLMaterial::activate(SLGLState* state, SLShape* shape) { SLScene* s = SLScene::current; SLSceneView* sv = s->activeSV(); // Deactivate shader program of the current active material if (current && current->shaderProg()) current->shaderProg()->endShader(); // Set this material as the current material current = this; // If no shader program is attached add the default shader program if (!_shaderProg) { if (_textures.size()>0) shaderProg(s->shaderProgs(PerVrtBlinnTex)); else shaderProg(s->shaderProgs(PerVrtBlinn)); } // Check if shader had compile error and the error texture should be shown if (_shaderProg && _shaderProg->name().find("ErrorTex")!=string::npos) { _textures.clear(); _textures.push_back(new SLGLTexture("CompileError.png")); } // Set material in the state state->matAmbient = _ambient; state->matDiffuse = _diffuse; state->matSpecular = _specular; state->matEmissive = _emission; state->matShininess = _shininess; // Determine use of shaders & textures SLbool useTexture = !(sv->drawBits()->get(SL_DB_TEXOFF) || shape->drawBits()->get(SL_DB_TEXOFF)); // Enable or disable texturing if (useTexture && _textures.size()>0) { for (SLuint i=0; i<_textures.size(); ++i) _textures[i]->bindActive(i); } // Activate the shader program now shaderProg()->beginUse(this); }
/*! This method is used for object picking. The calculation is the same as for primary rays in Ray Tracing. */ void SLCamera::eyeToPixelRay(SLfloat x, SLfloat y, SLRay* ray) { SLScene* s = SLScene::current; SLSceneView* sv = s->activeSV(); SLfloat hw, hh, pixel; SLVec3f dir, EYE, LA, LU, LR, C, TL; // calculate half window width & height in world coords hh = tan(SL_DEG2RAD*_fov/2); hw = hh * sv->scrWdivH(); // calculate the size of a pixel in world coords. // height & width must be equal because perspective is undistorted. pixel = hw * 2 / sv->scrW(); // get camera vectors _vm.lookAt(&EYE, &LA, &LU, &LR); // calculate a vector to the center (C) of the top left (TL) pixel C = LA; TL = C - hw*LR + hh*LU + pixel/2*LR - pixel/2*LU; // Calculate direction of ray dir = TL + pixel*x*LR - pixel*y*LU; // Fill in ray parameters dir.normalize(); ray->origin.set(EYE); ray->setDir(dir); ray->length = FLT_MAX; ray->depth = 1; ray->contrib = 1.0f; ray->type = PRIMARY; ray->x = x; ray->y = y; ray->hitTriangle = 0; ray->hitMat = 0; ray->hitNormal.set(SLVec3f::ZERO); ray->hitPoint.set(SLVec3f::ZERO); ray->originMat = &SLMaterial::AIR; ray->originTria = 0; }
/*! SLButton::closeAll closes all menus except the root menu */ void SLButton::closeAll() { SLScene* s = SLScene::current; SLButton* mnu2D = s->menu2D(); if (!mnu2D) return; mnu2D->hideAndReleaseRec(); mnu2D->drawBits()->off(SL_DB_HIDDEN); // update world matrices & AABBs _stateGL->pushModelViewMatrix(); _stateGL->modelViewMatrix.identity(); mnu2D->translation(0, 0, 0); mnu2D->updateAABBRec(); _stateGL->popModelViewMatrix(); newMenuPos.set(0,0); oldMenuPos.set(0,0); buttonDown = 0; buttonParent = 0; }
/*! SLCamera::onMouseWheel event handler moves camera forwards or backwards */ SLbool SLCamera::onMouseWheel(const SLint delta, const SLKey mod) { SLScene* s = SLScene::current; SLfloat sign = (SLfloat)SL_sign(delta); if (_camAnim==turntableYUp || _camAnim==turntableZUp) //.................... { if (mod==KeyNone) { // Determine the lookAt point by ray cast eyeToPixelRay((SLfloat)(_scrW>>1), (SLfloat)(_scrH>>1), &_lookAtRay); if (s->root3D()) s->root3D()->hitRec(&_lookAtRay); if (_lookAtRay.length < FLT_MAX) _lookAtRay.hitPoint = _lookAtRay.origin + _lookAtRay.dir*_lookAtRay.length; // Scale the mouse delta by the lookAt distance SLfloat lookAtDist; if (_lookAtRay.length < FLT_MAX && _lookAtRay.hitNode) lookAtDist = _lookAtRay.length; else lookAtDist = _focalDist; translate(SLVec3f(0, 0, -sign*lookAtDist*_dPos), TS_Object); _lookAtRay.length = FLT_MAX; } if (mod==KeyCtrl) { _eyeSeparation *= (1.0f + sign*0.1f); } if (mod==KeyAlt) { _fov += sign*5.0f; currentFOV = _fov; } if (mod==KeyShift) { _focalDist *= (1.0f + sign*0.05f); } return true; }
/*! SLButton::onMouseUp handles events and returns true if refresh is needed. This method holds the main functionality for the buttons command execution as well as the hiding and showing of the sub menus. */ SLbool SLButton::onMouseUp(const SLMouseButton button, const SLint x, const SLint y, const SLKey mod) { SLScene* s = SLScene::current; SLButton* mnu2D = s->menu2D(); SLButton* btn = 0; // button pointer for various loops if (!mnu2D) return false; // GUI space is bottom left! SLint h = _sv->scrH()-y; if (x > _aabb.minWS().x && x < _aabb.maxWS().x && h > _aabb.minWS().y && h < _aabb.maxWS().y && !_drawBits.get(SL_DB_HIDDEN)) { if (buttonDown==this) { // For a command execute it if (_command != C_menu) { _isDown = false; // Toggle checkable buttons if (_isCheckable && !_radioParent) _isChecked = !_isChecked; // For radio buttons uncheck others if (_radioParent) _radioParent->checkRadioRec(); // Hide all menus again if (_closeOnClick) closeAll(); ///////////////////////// _sv->onCommand(_command); ///////////////////////// if (_closeOnClick) return true; } else if (_children.size()>0) { // if another menu on the same or higher level is open hide it first if (buttonParent && buttonParent!=this && buttonParent->depth()>=_depth) { while (buttonParent && buttonParent->depth() >= depth()) { for (auto child : buttonParent->children()) child->drawBits()->set(SL_DB_HIDDEN, true); buttonParent->isDown(false); buttonParent = (SLButton*)buttonParent->parent(); } } // show my submenu buttons btn = (SLButton*)_children[0]; if (btn && btn->drawBits()->get(SL_DB_HIDDEN)) { for (auto child : _children) child->drawBits()->set(SL_DB_HIDDEN, false); buttonParent = this; } else // submenu is already open so close everything { if (buttonDown==mnu2D) { mnu2D->hideAndReleaseRec(); mnu2D->drawBits()->off(SL_DB_HIDDEN); buttonParent = 0; } else { if (buttonParent) { for (auto child : buttonParent->children()) child->drawBits()->set(SL_DB_HIDDEN, true); buttonParent->isDown(false); buttonParent = (SLButton*)(buttonParent->parent()); } } } } // Move menu left or right if (buttonParent) { newMenuPos.set(-buttonParent->minX()+minMenuPos.x, 0); if (newMenuPos != oldMenuPos) { mnu2D->translate(newMenuPos.x - oldMenuPos.x, 0, 0, TS_object); // update AABB's _stateGL->pushModelViewMatrix(); _stateGL->modelViewMatrix.identity(); oldMenuPos.set(newMenuPos); mnu2D->updateAABBRec(); _stateGL->popModelViewMatrix(); } } buttonDown = 0; return true; } else // mouse up on a different button, so release it { if (buttonDown) { buttonDown->_isDown = false; buttonDown = 0; return true; } } } // check sub menus for (auto child : _children) { if (child->onMouseUp(button, x, y, mod)) return true; } // check if mouse down was on this button and the up was on the scene if (_isDown && buttonDown==this) { closeAll(); return true; } return false; }
/*! 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; } } }
/*! Draws the background as a flat 2D rectangle with a height and a width on two triangles with zero in the bottom left corner: <br> w +-----+ | /| | / | h | / | | / | |/ | 0 +-----+ 0 We render the quad as a triangle strip: <br> 0 2 +-----+ | /| | / | | / | | / | |/ | +-----+ 1 3 */ void SLBackground::render(SLint widthPX, SLint heightPX) { SLGLState* stateGL = SLGLState::getInstance(); SLScene* s = SLScene::current; // Set orthographic projection stateGL->projectionMatrix.ortho(0.0f, (SLfloat)widthPX, 0.0f, (SLfloat)heightPX, 0.0f, 1.0f); stateGL->modelViewMatrix.identity(); // Combine modelview-projection matrix SLMat4f mvp(stateGL->projectionMatrix * stateGL->modelViewMatrix); stateGL->depthTest(false); stateGL->multiSample(false); // Get shader program SLGLProgram* sp = _texture ? s->programs(SP_TextureOnly) : s->programs(SP_colorAttribute); sp->useProgram(); sp->uniformMatrix4fv("u_mvpMatrix", 1, (SLfloat*)&mvp); // Create or update buffer for vertex position and indices if (_resX != widthPX || _resY != heightPX || !_vao.id()) { _resX = widthPX; _resY = heightPX; _vao.clearAttribs(); // Float array with vertex X & Y of corners SLVVec2f P = {{0.0f, (SLfloat)_resY}, {0.0f, 0.0f}, {(SLfloat)_resX, (SLfloat)_resY}, {(SLfloat)_resX, 0.0f}}; _vao.setAttrib(AT_position, sp->getAttribLocation("a_position"), &P); // Indexes for a triangle strip SLVushort I = {0,1,2,3}; _vao.setIndices(&I); if(_texture) { // Float array of texture coordinates SLVVec2f T = {{0.0f, 1.0f}, {0.0f, 0.0f}, {1.0f, 1.0f}, {1.0f, 0.0f}}; _vao.setAttrib(AT_texCoord, sp->getAttribLocation("a_texCoord"), &T); _vao.generate(4); } else { // Float array of colors of corners SLVVec3f C = {{_colors[0].r, _colors[0].g, _colors[0].b}, {_colors[1].r, _colors[1].g, _colors[1].b}, {_colors[2].r, _colors[2].g, _colors[2].b}, {_colors[3].r, _colors[3].g, _colors[3].b}}; _vao.setAttrib(AT_color, sp->getAttribLocation("a_color"), &C); _vao.generate(4); } } // draw a textured or colored quad if(_texture) { _texture->bindActive(0); sp->uniform1i("u_texture0", 0); } /////////////////////////////////////// _vao.drawElementsAs(PT_triangleStrip); /////////////////////////////////////// }
/*! Photons are scattered (or absorbed) according to surface properties. This is done by russian roulette. Photons are stored on diffuse surfaces only. */ void SLPhotonMapper::photonScatter(SLRay* photon, SLVec3f power, SLPhotonType photonType)//, SLint RGB) { SLScene* s = SLScene::current; // scene shortcut s->root3D()->hit(photon); if (photon->length < SL_FLOAT_MAX) { //photons "absorbed" by luminaire if (typeid(*photon->hitShape)==typeid(SLLightSphere) || typeid(*photon->hitShape)==typeid(SLLightRect)) return; //abort if maps are full or depth>100 if((_mapCaustic->isFull() && _mapGlobal->isFull()) || photon->depth>100) //physically plausible ;-) return; photon->normalizeNormal(); SLMaterial* mat = photon->hitMat; //store photon if diffuse surface and not from light if (photon->nodeDiffuse() && photonType!=LIGHT)//photon->type()!=PRIMARY) { if(photonType!=CAUSTIC) _mapGlobal->store(photon->hitPoint,photon->dir,power); else { _mapCaustic->store(photon->hitPoint,photon->dir,power); return; // caustic photons "die" on diffuse surfaces } } //calculate average of materials SLfloat avgDiffuse = (mat->diffuse().x+mat->diffuse().y+mat->diffuse().z)/3.0f; SLfloat avgSpecular = (mat->specular().x+mat->specular().y+mat->specular().z)/3.0f; SLfloat avgTransmission= (mat->transmission().x+mat->transmission().y+mat->transmission().z)/3.0f; SLfloat eta = _russianRandom->Random(); //Decide type of photon (Global or Caustic) if from light if (photonType == LIGHT) { if ((eta*(avgDiffuse+avgSpecular+avgTransmission))<=avgDiffuse) photonType=GLOBAL; else photonType=CAUSTIC; } //Russian Roulette if (eta <= avgDiffuse) { //scattered diffuse (cosine distribution around normal) SLRay scattered; photon->diffuseMC(&scattered); //adjust power power.x*=(mat->diffuse().x/avgDiffuse); power.y*=(mat->diffuse().y/avgDiffuse); power.z*=(mat->diffuse().z/avgDiffuse); ++SLRay::diffusePhotons; photonScatter(&scattered, power, photonType); } else if (eta <= avgDiffuse+avgSpecular) { //scatter toward perfect specular direction SLRay scattered; photon->reflect(&scattered); //scatter around perfect reflected direction only if material not perfect if(photon->hitMat->shininess() < SLMaterial::PERFECT) { //rotation matrix SLMat3f rotMat; SLVec3f rotAxis((SLVec3f(0.0,0.0,1.0) ^ scattered.dir).normalize()); SLfloat rotAngle=acos(scattered.dir.z);//z*scattered.dir() rotMat.rotation(rotAngle*180.0/SL_PI,rotAxis); photon->reflectMC(&scattered,rotMat); } //avoid scattering into surface if (scattered.dir*photon->hitNormal >= 0.0f) { //adjust power power.x*=(mat->specular().x/avgSpecular); power.y*=(mat->specular().y/avgSpecular); power.z*=(mat->specular().z/avgSpecular); ++SLRay::reflectedPhotons; photonScatter(&scattered,power,photonType); } } else if (eta <= avgDiffuse+avgSpecular+avgTransmission) //scattered refracted { //scatter toward perfect transmissive direction SLRay scattered; photon->refract(&scattered); //scatter around perfect transmissive direction only if material not perfect if(photon->hitMat->translucency() < SLMaterial::PERFECT) { //rotation matrix SLMat3f rotMat; SLVec3f rotAxis((SLVec3f(0.0,0.0,1.0) ^ scattered.dir).normalize()); SLfloat rotAngle=acos(scattered.dir.z);//z*scattered.dir() rotMat.rotation(rotAngle*180.0/SL_PI,rotAxis); photon->refractMC(&scattered,rotMat); } SLVec3f N = -photon->hitNormal; if(scattered.type==REFLECTED) N*=-1.0; //In case of total reflection invert the Normal if (scattered.dir*N >= 0.0f) { //adjust power power.x*=(mat->transmission().x/avgTransmission); power.y*=(mat->transmission().y/avgTransmission); power.z*=(mat->transmission().z/avgTransmission); if(scattered.type==TRANSMITTED) ++SLRay::refractedPhotons; else ++SLRay::tirPhotons; photonScatter(&scattered,power,photonType); } } else //absorbed [rest in peace] { } } }
/*! SLCamera::onTouch2Move gets called whenever two fingers move on a handheld screen. */ SLbool SLCamera::onTouch2Move(const SLint x1, const SLint y1, const SLint x2, const SLint y2) { SLScene* s = SLScene::current; SLSceneView* sv = s->activeSV(); SLVec2f now1((SLfloat)x1, (SLfloat)y1); SLVec2f now2((SLfloat)x2, (SLfloat)y2); SLVec2f delta1(now1-_oldTouchPos1); SLVec2f delta2(now2-_oldTouchPos2); // Average out the deltas over the last 4 events for correct 1 pixel moves static SLuint cnt=0; static SLVec2f d1[4]; static SLVec2f d2[4]; d1[cnt%4] = delta1; d2[cnt%4] = delta2; SLVec2f avgDelta1(d1[0].x+d1[1].x+d1[2].x+d1[3].x, d1[0].y+d1[1].y+d1[2].y+d1[3].y); SLVec2f avgDelta2(d2[0].x+d2[1].x+d2[2].x+d2[3].x, d2[0].y+d2[1].y+d2[2].y+d2[3].y); avgDelta1 /= 4.0f; avgDelta2 /= 4.0f; cnt++; SLfloat r1, phi1, r2, phi2; avgDelta1.toPolar(r1, phi1); avgDelta2.toPolar(r2, phi2); // 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(); //SL_LOG("avgDelta1: (%05.2f,%05.2f), dPhi=%05.2f\n", avgDelta1.x, avgDelta1.y, SL_abs(phi1-phi2)); // if fingers move parallel slide camera vertically or horizontally if (SL_abs(phi1-phi2) < 0.2f) { // Calculate center between finger points SLVec2f nowCenter((now1+now2)*0.5f); SLVec2f oldCenter((_oldTouchPos1+_oldTouchPos2)*0.5f); // For first move set oldCenter = nowCenter if (oldCenter == SLVec2f::ZERO) oldCenter = nowCenter; SLVec2f delta(nowCenter - oldCenter); // scale to 0-1 delta.x /= (SLfloat)sv->scrW(); delta.y /= (SLfloat)sv->scrH(); // scale to space size delta.x *= spaceW; delta.y *= spaceH; if (_camAnim==turntableYUp || _camAnim==turntableZUp) { // apply delta to x- and y-position _vm.translation(_vm.m(12) + delta.x, _vm.m(13) - delta.y, _vm.m(14)); setWMandState(); } else if (_camAnim == walkingYUp || _camAnim == walkingZUp) { _maxSpeed.x = delta.x * 100.0f, _maxSpeed.z = delta.y * 100.0f; } } else // Two finger pinch { // Calculate vector between fingers SLVec2f nowDist(now2 - now1); SLVec2f oldDist(_oldTouchPos2-_oldTouchPos1); // For first move set oldDist = nowDist if (oldDist == SLVec2f::ZERO) oldDist = nowDist; SLfloat delta = oldDist.length() - nowDist.length(); if (_camAnim==turntableYUp) { // scale to 0-1 delta /= (SLfloat)sv->scrH(); // scale to space height delta *= spaceH*2; // apply delta to the z-position _vm.translation(_vm.m(12), _vm.m(13), _vm.m(14) - delta); setWMandState(); } else if (_camAnim == walkingYUp) { // change field of view _fov += SL_sign(delta) * 0.5f; currentFOV = _fov; } } _oldTouchPos1.set((SLfloat)x1, (SLfloat)y1); _oldTouchPos2.set((SLfloat)x2, (SLfloat)y2); return true; }
//----------------------------------------------------------------------------- //! 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; }