bool SimpleSkeletalAnimatedObject_cl::GetHeadRotation(const hkvVec3 &vTargetPos, hkvQuat &targetRot, float fMaxViewAngle) { hkvMat4 objectMatrix; hkvMat4 parentObjectMatrix; // get the index of the parent bone int parentBoneIndex = GetMesh()->GetSkeleton()->GetBone(m_iHeadBoneIndex)->m_iParentIndex; // get the 4x4 matrix of the head bone and its parent in object space const VisSkeletalAnimResult_cl* pObjectSpaceResult = GetAnimConfig()->GetFinalResult()->GetCurrentObjectSpaceResult(); pObjectSpaceResult->GetBoneTransformationMatrix(m_iHeadBoneIndex, objectMatrix); pObjectSpaceResult->GetBoneTransformationMatrix(parentBoneIndex, parentObjectMatrix); // get the current position of the target in object space hkvVec3 targetObjectspace = TransformToObjectSpace(vTargetPos); // get the current position of the bone in object space hkvVec3 boneObjectspace = objectMatrix.getTranslation(); // calculate the look at direction in object space (just for the angle constraints) hkvVec3 vLookAtDir = targetObjectspace - boneObjectspace; // check if we are within the angle constraints vLookAtDir.normalizeIfNotZero(); float fCosMax = hkvMath::cosDeg (180.f - fMaxViewAngle); bool bInsideFocusArea = vLookAtDir.y < fCosMax; if (!bInsideFocusArea) { // out of focus, so just look straight ahead targetRot.setIdentity(); return false; } // create a LookAt-3x3 matrix from the bone position and the target position (both are in object space) // This orientation is later used to replace(!) the head bone in local space (VIS_REPLACE_BONE|VIS_LOCAL_SPACE flags) hkvMat3 lookatMatrix(hkvNoInitialization); lookatMatrix.setLookInDirectionMatrix(targetObjectspace - boneObjectspace); // Apply our custom rotation matrix that tells the bone to focus with the eyes and not with the back of the head :-) lookatMatrix = lookatMatrix.multiply(m_RelativeHeadOrientation); // Invert the parents object matrix rotation to cancel out all parent bone orientations hkvMat3 parentObject = parentObjectMatrix.getRotationalPart(); parentObject.invert(); // put everything together hkvMat3 result = parentObject; result = result.multiply (lookatMatrix); // ...and make a quaternion from it targetRot.setFromMat3 (result); return true; }
// Draw the scene to the screen void draw() { // Update time time += 2.0f * timeStep; /////////////////////// PART 1: SIMULATION ///////////////////////////////// // Grab buffers for OpenCL acquireGLBuffer(particles.particleBuffer[particles.currentBuffer]); acquireGLBuffer(particles.particleBuffer[1 - particles.currentBuffer]); // Prepare to run some kernels cl_int numParticles = NUM_PARTICLES; cl_int gridElements = GRID_SIZE * GRID_SIZE * GRID_SIZE; cl_uint workSize[3] = {numParticles, 0, 0}; cl_uint gridWorkSize[3] = {gridElements, 0, 0}; cl_uint workgroupSize[3] = {256, 0, 0}; // Clear grid clSetKernelArg(openCLKernels.gridClearKernel, 0, sizeof(cl_mem), &particles.gridSizeBuffer); clSetKernelArg(openCLKernels.gridClearKernel, 1, sizeof(cl_int), &gridElements); clRunKernel(openCLKernels.gridClearKernel, gridWorkSize, workgroupSize); // Compute grid positions clSetKernelArg(openCLKernels.gridKernel, 0, sizeof(cl_mem), &particles.particleBuffer[particles.currentBuffer]); clSetKernelArg(openCLKernels.gridKernel, 1, sizeof(cl_mem), &particles.offsetBuffer); clSetKernelArg(openCLKernels.gridKernel, 2, sizeof(cl_mem), &particles.gridSizeBuffer); clSetKernelArg(openCLKernels.gridKernel, 3, sizeof(cl_int), &numParticles); clRunKernel(openCLKernels.gridKernel, workSize, workgroupSize); // Compute prefix sum for grid clSetKernelArg(openCLKernels.prefixSumKernel, 2, sizeof(cl_uint), (void*)&gridElements); int pingpong = 0; for(cl_int offset = 1; offset <= gridElements; offset *= 2) { if(offset == 1) { clSetKernelArg(openCLKernels.prefixSumKernel, 0, sizeof(cl_mem), (void*)&particles.gridSizeBuffer); } else { clSetKernelArg(openCLKernels.prefixSumKernel, 0, sizeof(cl_mem), (void*)&(pingpong == 0 ? particles.gridBuffer[0] : particles.gridBuffer[1])); } clSetKernelArg(openCLKernels.prefixSumKernel, 1, sizeof(cl_mem), (void*)&(pingpong == 0 ? particles.gridBuffer[1] : particles.gridBuffer[0])); clSetKernelArg(openCLKernels.prefixSumKernel, 3, sizeof(cl_int), (void*)&offset); clRunKernel(openCLKernels.prefixSumKernel, gridWorkSize, workgroupSize); pingpong = 1 - pingpong; } // Reorganize particles clSetKernelArg(openCLKernels.gridReorderKernel, 0, sizeof(cl_mem), &particles.particleBuffer[particles.currentBuffer]); clSetKernelArg(openCLKernels.gridReorderKernel, 1, sizeof(cl_mem), &particles.particleBuffer[1 - particles.currentBuffer]); clSetKernelArg(openCLKernels.gridReorderKernel, 2, sizeof(cl_mem), &particles.velocityBuffer[particles.currentBuffer]); clSetKernelArg(openCLKernels.gridReorderKernel, 3, sizeof(cl_mem), &particles.velocityBuffer[1 - particles.currentBuffer]); clSetKernelArg(openCLKernels.gridReorderKernel, 4, sizeof(cl_mem), &particles.offsetBuffer); clSetKernelArg(openCLKernels.gridReorderKernel, 5, sizeof(cl_mem), (void*)&particles.gridSizeBuffer); clSetKernelArg(openCLKernels.gridReorderKernel, 6, sizeof(cl_mem), (void*)&(pingpong == 0 ? particles.gridBuffer[0] : particles.gridBuffer[1])); clSetKernelArg(openCLKernels.gridReorderKernel, 7, sizeof(cl_int), &numParticles); clRunKernel(openCLKernels.gridReorderKernel, workSize, workgroupSize); particle* testData = (particle*)malloc(sizeof(cl_float) * numParticles * 4); // Swap particle buffers particles.currentBuffer = 1 - particles.currentBuffer; // Send new cell select buffer int cellSelect[27]; for(int i = 0; i < 27; i++) { cellSelect[i] = i; } shuffle(cellSelect, 27); clEnqueueWriteBuffer(clCommandQueue(), particles.cellSelectBuffer, true, 0, 27 * sizeof(cl_int), cellSelect, 0, 0, 0); clFinish(clCommandQueue()); // Recalculate densities and normalized pressure derivatives clSetKernelArg(openCLKernels.dataKernel, 0, sizeof(cl_mem), &particles.particleBuffer[particles.currentBuffer]); clSetKernelArg(openCLKernels.dataKernel, 1, sizeof(cl_mem), &particles.dataBuffer); clSetKernelArg(openCLKernels.dataKernel, 2, sizeof(cl_mem), (void*)&particles.gridSizeBuffer); clSetKernelArg(openCLKernels.dataKernel, 3, sizeof(cl_mem), (void*)&(pingpong == 0 ? particles.gridBuffer[1] : particles.gridBuffer[0])); clSetKernelArg(openCLKernels.dataKernel, 4, sizeof(cl_mem), (void*)&particles.cellSelectBuffer); clSetKernelArg(openCLKernels.dataKernel, 5, sizeof(cl_int), &numParticles); clRunKernel(openCLKernels.dataKernel, workSize, workgroupSize); // Send new cell select buffer cellSelect[27]; for(int i = 0; i < 27; i++) { cellSelect[i] = i; } shuffle(cellSelect, 27); clEnqueueWriteBuffer(clCommandQueue(), particles.cellSelectBuffer, true, 0, 27 * sizeof(cl_int), cellSelect, 0, 0, 0); clFinish(clCommandQueue()); // Integrate position float dT = timeStep; clSetKernelArg(openCLKernels.simulationKernel, 0, sizeof(cl_mem), &particles.particleBuffer[particles.currentBuffer]); clSetKernelArg(openCLKernels.simulationKernel, 1, sizeof(cl_mem), &particles.particleBuffer[1 - particles.currentBuffer]); clSetKernelArg(openCLKernels.simulationKernel, 2, sizeof(cl_mem), &particles.velocityBuffer[particles.currentBuffer]); clSetKernelArg(openCLKernels.simulationKernel, 3, sizeof(cl_mem), &particles.velocityBuffer[1 - particles.currentBuffer]); clSetKernelArg(openCLKernels.simulationKernel, 4, sizeof(cl_mem), &particles.dataBuffer); clSetKernelArg(openCLKernels.simulationKernel, 5, sizeof(cl_mem), (void*)&particles.gridSizeBuffer); clSetKernelArg(openCLKernels.simulationKernel, 6, sizeof(cl_mem), (void*)&(pingpong == 0 ? particles.gridBuffer[1] : particles.gridBuffer[0])); clSetKernelArg(openCLKernels.simulationKernel, 7, sizeof(cl_mem), (void*)&particles.cellSelectBuffer); clSetKernelArg(openCLKernels.simulationKernel, 8, sizeof(cl_float), &dT); clSetKernelArg(openCLKernels.simulationKernel, 9, sizeof(cl_float), &time); clSetKernelArg(openCLKernels.simulationKernel, 10, sizeof(cl_int), &numParticles); clSetKernelArg(openCLKernels.simulationKernel, 11, sizeof(cl_mem), &particles.terrainBuffer); PaddedVector windDir = PadVector( TransformVector(YAxisRotationMatrix(particles.windAngle), MakeVector(1.0f, 0.0f, 0.0f)) ); clSetKernelArg(openCLKernels.simulationKernel, 12, sizeof(cl_float) * 4, &windDir); clSetKernelArg(openCLKernels.simulationKernel, 13, sizeof(cl_float), &particles.windPower); clRunKernel(openCLKernels.simulationKernel, workSize, workgroupSize); // Release buffers back to OpenGL releaseGLBuffer(particles.particleBuffer[particles.currentBuffer]); releaseGLBuffer(particles.particleBuffer[1 - particles.currentBuffer]); // Swap particle buffers particles.currentBuffer = 1 - particles.currentBuffer; //////////////////////// PART 2: RENDERIING //////////////////////////////// // Clear everything first thing. glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glBindFramebuffer(GL_FRAMEBUFFER, framebuffers.backgroundFBO); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Activate shader. glUseProgram(objectShader.shaderProgram); // Set projection Matrix projection = PerspectiveMatrix( 45.0f, (float)WINDOW_WIDTH/(float)WINDOW_HEIGHT, 0.01f, 100.0f ); MatrixAsUniform(objectShader.projectionMatrix, projection); // Vertices glBindBuffer(GL_ARRAY_BUFFER, terrain.vertexBuffer); glVertexAttribPointer( objectShader.vertexPosition, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4, (void*)0 ); glEnableVertexAttribArray(objectShader.vertexPosition); // Set modelview according to camera Matrix rot = lookatMatrix(camera.pos, VectorAdd(camera.pos, camera.front), camera.up); rot = MatrixMul(RotationMatrix(camera.elevation, MakeVector(1, 0, 0)), rot); Matrix trans = TranslationMatrix(-camera.pos.x, -camera.pos.y, -camera.pos.z); Matrix modelview = MatrixMul(rot, trans); MatrixAsUniform(objectShader.modelviewMatrix, modelview); // Normal view matrix - inverse transpose of modelview. Matrix normalview = MatrixTranspose(FastMatrixInverse(modelview)); MatrixAsUniform(objectShader.normalviewMatrix, normalview); // Set heightmap texture glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, terrain.heightTexture ); glUniform1i(objectShader.terrainTexture, 0); // Set color textures glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, terrain.lowTexture); glUniform1i(objectShader.lowTexture, 1); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, terrain.highTexture); glUniform1i(objectShader.highTexture, 2); // Turn off culling glDisable(GL_CULL_FACE); // Send element buffer to GPU and draw. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, terrain.elementBuffer); glDrawElements( GL_TRIANGLES, 512 * 512 * 6, GL_UNSIGNED_INT, (void*)0 ); // Turn culling back on glEnable(GL_CULL_FACE); // Switch to low-res viewport glViewport(0, 0, WINDOW_WIDTH / RESOLUTION_DIVIDER, WINDOW_HEIGHT / RESOLUTION_DIVIDER); // Low-res projection matrix Matrix projectionLowres = PerspectiveMatrix( 45.0f, (float)(WINDOW_WIDTH / RESOLUTION_DIVIDER) / (float)(WINDOW_HEIGHT / RESOLUTION_DIVIDER), 0.01f, 100.0f ); // Activate particle depth FBO glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glBindFramebuffer(GL_FRAMEBUFFER, framebuffers.particleFBO[0]); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Activate shader glUseProgram(particleShader.shaderProgram); // Set textures glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, framebuffers.backgroundTexture); glUniform1i(particleShader.terrainTexture, 0); // Send uniforms MatrixAsUniform(particleShader.modelviewMatrix, modelview); MatrixAsUniform(particleShader.projectionMatrix, projectionLowres); glUniform2f(particleShader.screenSize, WINDOW_WIDTH / RESOLUTION_DIVIDER, WINDOW_HEIGHT / RESOLUTION_DIVIDER); // Bind new buffer and set up arrtibutes glBindBuffer(GL_ARRAY_BUFFER, particles.vertexBuffer[particles.currentBuffer]); glVertexAttribPointer( particleShader.vertexPosition, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4, (void*)0 ); glEnableVertexAttribArray(particleShader.vertexPosition); // Bind element buffer and draw particles glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, particles.elementBuffer); glDrawElements( GL_POINTS, NUM_PARTICLES, GL_UNSIGNED_INT, (void*)0 ); // Activate particle thickness FBO glBindFramebuffer(GL_FRAMEBUFFER, framebuffers.particleThicknessFBO[0]); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Activate shader glUseProgram(particleThicknessShader.shaderProgram); // Send uniforms MatrixAsUniform(particleThicknessShader.modelviewMatrix, modelview); MatrixAsUniform(particleThicknessShader.projectionMatrix, projectionLowres); glUniform2f(particleThicknessShader.screenSize, WINDOW_WIDTH / RESOLUTION_DIVIDER, WINDOW_HEIGHT / RESOLUTION_DIVIDER); // Set textures glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, framebuffers.backgroundTexture); glUniform1i(particleThicknessShader.terrainTexture, 0); // Bind new buffer and set up arrtibutes glBindBuffer(GL_ARRAY_BUFFER, particles.vertexBuffer[particles.currentBuffer]); glVertexAttribPointer( particleThicknessShader.vertexPosition, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4, (void*)0 ); glEnableVertexAttribArray(particleThicknessShader.vertexPosition); // Enable additive blending and disable depth test glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDisable(GL_DEPTH_TEST); // Bind element buffer and draw particles, this time rendering thickness map glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, particles.elementBuffer); glDrawElements( GL_POINTS, NUM_PARTICLES, GL_UNSIGNED_INT, (void*)0 ); // Turn blending back off and depth test back on glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); // Activate particle velocity FBO glBindFramebuffer(GL_FRAMEBUFFER, framebuffers.velocityFBO); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Activate shader glUseProgram(particleVelocityShader.shaderProgram); // Send uniforms MatrixAsUniform(particleVelocityShader.modelviewMatrix, modelview); MatrixAsUniform(particleVelocityShader.projectionMatrix, projectionLowres); glUniform2f(particleVelocityShader.screenSize, WINDOW_WIDTH / RESOLUTION_DIVIDER, WINDOW_HEIGHT / RESOLUTION_DIVIDER); // Bind new buffer and set up arrtibutes glBindBuffer(GL_ARRAY_BUFFER, particles.vertexBuffer[particles.currentBuffer]); glVertexAttribPointer( particleVelocityShader.vertexPosition, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4, (void*)0 ); glEnableVertexAttribArray(particleVelocityShader.vertexPosition); // Bind element buffer and draw particles, this time rendering velocity map glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, particles.elementBuffer); glDrawElements( GL_POINTS, NUM_PARTICLES, GL_UNSIGNED_INT, (void*)0 ); // Curvature flow smoothing begins glUseProgram(curvatureFlowShader.shaderProgram); // Send uniforms glUniform1i(curvatureFlowShader.particleTexture, 0); glUniform2f(curvatureFlowShader.screenSize, WINDOW_WIDTH / RESOLUTION_DIVIDER, WINDOW_HEIGHT / RESOLUTION_DIVIDER); MatrixAsUniform(curvatureFlowShader.projectionMatrix, projectionLowres); // Prepare state glActiveTexture(GL_TEXTURE0); glBindBuffer(GL_ARRAY_BUFFER, screenQuad.vertexBuffer); glVertexAttribPointer( curvatureFlowShader.vertexPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, (void*)0 ); glEnableVertexAttribArray(curvatureFlowShader.vertexPosition); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, screenQuad.elementBuffer); // Smoothing loop glDisable(GL_DEPTH_TEST); pingpong = 0; for(int i = 0; i < smoothingIterations; i++) { // Bind no FBO glBindFramebuffer(GL_FRAMEBUFFER, 0); // Bind texture glBindTexture(GL_TEXTURE_2D, framebuffers.particleTexture[pingpong]); // Activate proper FBO and clear glBindFramebuffer(GL_FRAMEBUFFER, framebuffers.particleFBO[1 - pingpong]); // Draw a quad glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void*)0 ); // Switch buffers pingpong = 1 - pingpong; } glEnable(GL_DEPTH_TEST); // Activate particle color FBO glBindFramebuffer(GL_FRAMEBUFFER, framebuffers.particleColorFBO); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Liquid shading shader glUseProgram(liquidShadeShader.shaderProgram); // Bind and set textures glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, framebuffers.particleTexture[0]); glUniform1i(liquidShadeShader.particleTexture, 0); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, framebuffers.particleThicknessTexture[0]); glUniform1i(liquidShadeShader.particleThicknessTexture, 1); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, terrain.envTexture); glUniform1i(liquidShadeShader.environmentTexture, 2); glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, framebuffers.particleVelocityTexture); glUniform1i(liquidShadeShader.velocityTexture, 3); // Send uniforms glUniform2f(liquidShadeShader.screenSize, WINDOW_WIDTH, WINDOW_HEIGHT); MatrixAsUniform(liquidShadeShader.modelviewMatrix, modelview); MatrixAsUniform(liquidShadeShader.projectionMatrix, projection); glUniform1i(liquidShadeShader.useThickness, useThickness); // Draw a quad glDisable(GL_DEPTH_TEST); glBindBuffer(GL_ARRAY_BUFFER, screenQuad.vertexBuffer); glVertexAttribPointer( liquidShadeShader.vertexPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, (void*)0 ); glEnableVertexAttribArray(liquidShadeShader.vertexPosition); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, screenQuad.elementBuffer); glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void*)0 ); glEnable(GL_DEPTH_TEST); // Switch back to full-res viewport glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); // Deactivate FBOs glBindFramebuffer(GL_FRAMEBUFFER, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Compose shader glUseProgram(compositionShader.shaderProgram); // Bind and set textures glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, terrain.envTexture); glUniform1i(compositionShader.backgroundTexture, 0); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, framebuffers.particleColorTexture); glUniform1i(compositionShader.particleTexture, 1); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, framebuffers.backgroundTexture); glUniform1i(compositionShader.terrainTexture, 2); // Send uniforms MatrixAsUniform(compositionShader.modelviewMatrix, modelview); // Draw a quad glDisable(GL_DEPTH_TEST); glBindBuffer(GL_ARRAY_BUFFER, screenQuad.vertexBuffer); glVertexAttribPointer( compositionShader.vertexPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, (void*)0 ); glEnableVertexAttribArray(compositionShader.vertexPosition); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, screenQuad.elementBuffer); glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void*)0 ); glEnable(GL_DEPTH_TEST); // Switch drawing area and displayed area. glutSwapBuffers(); }