/** * Helper for @ref VuoSceneObject_findLights. */ static void VuoSceneObject_findLightsRecursive(VuoSceneObject so, float modelviewMatrix[16], VuoList_VuoColor ambientColors, float *ambientBrightness, VuoList_VuoSceneObject pointLights, VuoList_VuoSceneObject spotLights) { switch (so.type) { case VuoSceneObjectType_AmbientLight: VuoListAppendValue_VuoColor(ambientColors, so.lightColor); *ambientBrightness += so.lightBrightness; return; case VuoSceneObjectType_PointLight: { float localModelviewMatrix[16]; VuoTransform_getMatrix(so.transform, localModelviewMatrix); float compositeModelviewMatrix[16]; VuoTransform_multiplyMatrices4x4(localModelviewMatrix, modelviewMatrix, compositeModelviewMatrix); so.transform = VuoTransform_makeFromMatrix4x4(compositeModelviewMatrix); VuoListAppendValue_VuoSceneObject(pointLights, so); return; } case VuoSceneObjectType_Spotlight: { float localModelviewMatrix[16]; VuoTransform_getMatrix(so.transform, localModelviewMatrix); float compositeModelviewMatrix[16]; VuoTransform_multiplyMatrices4x4(localModelviewMatrix, modelviewMatrix, compositeModelviewMatrix); so.transform = VuoTransform_makeFromMatrix4x4(compositeModelviewMatrix); VuoListAppendValue_VuoSceneObject(spotLights, so); return; } default: break; } if (so.childObjects) { float localModelviewMatrix[16]; VuoTransform_getMatrix(so.transform, localModelviewMatrix); float compositeModelviewMatrix[16]; VuoTransform_multiplyMatrices4x4(localModelviewMatrix, modelviewMatrix, compositeModelviewMatrix); unsigned long childObjectCount = VuoListGetCount_VuoSceneObject(so.childObjects); for (unsigned long i = 1; i <= childObjectCount; ++i) { VuoSceneObject childObject = VuoListGetValue_VuoSceneObject(so.childObjects, i); VuoSceneObject_findLightsRecursive(childObject, compositeModelviewMatrix, ambientColors, ambientBrightness, pointLights, spotLights); } } }
/** * Outputs the inverse of `matrix` * (which is assumed to consist of a rotation followed by a scale followed by a translation, * like the output of @ref VuoTransform_getMatrix), * such that `outputInvertedMatrix * matrix = identityMatrix`. */ void VuoTransform_invertMatrix4x4(const float *matrix, float *outputInvertedMatrix) { float inverseTranslation[16]; VuoTransform_getMatrix(VuoTransform_makeEuler( VuoPoint3d_make(-matrix[12], -matrix[13], -matrix[14]), VuoPoint3d_make(0,0,0), VuoPoint3d_make(1,1,1)), inverseTranslation); // Transpose the rotation/scale part of the input matrix (which undoes the rotation), and set the last row/column to identity. float inverseRotation[16] = { matrix[0], matrix[4], matrix[8], 0, matrix[1], matrix[5], matrix[9], 0, matrix[2], matrix[6], matrix[10], 0, 0, 0, 0, 1 }; float inverseScale[16]; VuoTransform_getMatrix(VuoTransform_makeEuler( VuoPoint3d_make(0,0,0), VuoPoint3d_make(0,0,0), VuoPoint3d_make( 1/VuoPoint3d_magnitude(VuoPoint3d_make(matrix[0], matrix[1], matrix[2])), 1/VuoPoint3d_magnitude(VuoPoint3d_make(matrix[4], matrix[5], matrix[6])), 1/VuoPoint3d_magnitude(VuoPoint3d_make(matrix[8], matrix[9], matrix[10])))), inverseScale); VuoTransform_multiplyMatrices4x4(inverseTranslation, inverseRotation, outputInvertedMatrix); VuoTransform_multiplyMatrices4x4(outputInvertedMatrix, inverseScale, outputInvertedMatrix); // Apply inverseScale a second time, since inverseRotation includes forward scale. VuoTransform_multiplyMatrices4x4(outputInvertedMatrix, inverseScale, outputInvertedMatrix); }
/** * Performs a depth-first search of the scenegraph. * Returns the first camera whose name contains @c nameToMatch (or, if @c nameToMatch is emptystring, just returns the first camera), * with its transform altered to incorporate the transforms of its ancestor objects. * Output paramater @c foundCamera indicates whether a camera was found. * If no camera was found, returns VuoSceneObject_makeDefaultCamera(). */ VuoSceneObject VuoSceneObject_findCamera(VuoSceneObject so, VuoText nameToMatch, bool *foundCamera) { float localModelviewMatrix[16]; VuoTransform_getMatrix(VuoTransform_makeIdentity(), localModelviewMatrix); return VuoSceneObject_findCameraInternal(so, nameToMatch, foundCamera, localModelviewMatrix); }
/** * @ingroup VuoTransform * Start with an object pointing rightward (increasing X axis). * This function returns a unit vector representing the direction * a rightward-pointing object (+x axis) would be pointing after being transformed by @c transform. */ VuoPoint3d VuoTransform_getDirection(const VuoTransform transform) { // Make a new transform with only the rotational component. VuoTransform r; if (transform.type == VuoTransformTypeEuler) r = VuoTransform_makeEuler(VuoPoint3d_make(0,0,0), transform.rotationSource.euler, VuoPoint3d_make(1,1,1)); else r = VuoTransform_makeQuaternion(VuoPoint3d_make(0,0,0), transform.rotationSource.quaternion, VuoPoint3d_make(1,1,1)); float m[16]; VuoTransform_getMatrix(r, m); return VuoTransform_transformPoint(m, VuoPoint3d_make(1,0,0)); }
/** * Helper for @ref VuoSceneObject_apply. */ VuoSceneObject VuoSceneObject_findCameraInternal(VuoSceneObject so, VuoText nameToMatch, bool *foundCamera, float modelviewMatrix[16]) { float localModelviewMatrix[16]; VuoTransform_getMatrix(so.transform, localModelviewMatrix); float compositeModelviewMatrix[16]; VuoTransform_multiplyMatrices4x4(localModelviewMatrix, modelviewMatrix, compositeModelviewMatrix); if ((so.type == VuoSceneObjectType_PerspectiveCamera || so.type == VuoSceneObjectType_StereoCamera || so.type == VuoSceneObjectType_OrthographicCamera) && strstr(so.name,nameToMatch)) { *foundCamera = true; so.transform = VuoTransform_makeFromMatrix4x4(compositeModelviewMatrix); return so; } if (so.childObjects) { unsigned long childObjectCount = VuoListGetCount_VuoSceneObject(so.childObjects); for (unsigned long i = 1; i <= childObjectCount; ++i) { VuoSceneObject childObject = VuoListGetValue_VuoSceneObject(so.childObjects, i); bool foundChildCamera; VuoSceneObject childCamera = VuoSceneObject_findCameraInternal(childObject, nameToMatch, &foundChildCamera, compositeModelviewMatrix); if (foundChildCamera) { *foundCamera = true; return childCamera; } else { VuoSceneObject_retain(childCamera); VuoSceneObject_release(childCamera); } } } *foundCamera = false; return VuoSceneObject_makeDefaultCamera(); }
/** * Returns a column-major matrix of 16 values that transforms a 1x1 quad so that it renders the specified image at real (pixel-perfect) size. */ void VuoTransform_getBillboardMatrix(VuoInteger imageWidth, VuoInteger imageHeight, VuoReal translationX, VuoReal translationY, VuoInteger viewportWidth, VuoInteger viewportHeight, float *billboardMatrix) { VuoTransform_getMatrix(VuoTransform_makeIdentity(), billboardMatrix); // Apply scale to make the image appear at real size (1:1). billboardMatrix[0] = 2. * imageWidth/viewportWidth; billboardMatrix[5] = billboardMatrix[0] * imageHeight/imageWidth; // Apply 2D translation. // Align the translation to pixel boundaries billboardMatrix[12] = floor((translationX+1.)/2.*viewportWidth) / ((float)viewportWidth) * 2. - 1.; billboardMatrix[13] = floor((translationY+1.)/2.*viewportWidth) / ((float)viewportWidth) * 2. - 1.; // Account for odd-dimensioned image billboardMatrix[12] += (imageWidth % 2 ? (1./viewportWidth) : 0); billboardMatrix[13] -= (imageHeight % 2 ? (1./viewportWidth) : 0); // Account for odd-dimensioned viewport billboardMatrix[13] += (viewportWidth % 2 ? (1./viewportWidth) : 0); billboardMatrix[13] -= (viewportHeight % 2 ? (1./viewportWidth) : 0); }
/** * Finds and returns all the lights in the scene. * * If there are multiple ambient lights, returns the weighted (by alpha) average color and summed brightness. * * If there are no lights in the scene, returns some default lights. */ void VuoSceneObject_findLights(VuoSceneObject so, VuoColor *ambientColor, float *ambientBrightness, VuoList_VuoSceneObject *pointLights, VuoList_VuoSceneObject *spotLights) { VuoList_VuoColor ambientColors = VuoListCreate_VuoColor(); VuoRetain(ambientColors); *ambientBrightness = 0; *pointLights = VuoListCreate_VuoSceneObject(); *spotLights = VuoListCreate_VuoSceneObject(); float localModelviewMatrix[16]; VuoTransform_getMatrix(VuoTransform_makeIdentity(), localModelviewMatrix); VuoSceneObject_findLightsRecursive(so, localModelviewMatrix, ambientColors, ambientBrightness, *pointLights, *spotLights); if (!VuoListGetCount_VuoColor(ambientColors) && !VuoListGetCount_VuoSceneObject(*pointLights) && !VuoListGetCount_VuoSceneObject(*spotLights)) { *ambientColor = VuoColor_makeWithRGBA(1,1,1,1); *ambientBrightness = 0.05; // https://en.wikipedia.org/wiki/Three-point_lighting VuoSceneObject keyLight = VuoSceneObject_makePointLight(VuoColor_makeWithRGBA(1,1,1,1), .70, VuoPoint3d_make(-1,1,1), 5, .5); VuoListAppendValue_VuoSceneObject(*pointLights, keyLight); VuoSceneObject fillLight = VuoSceneObject_makePointLight(VuoColor_makeWithRGBA(1,1,1,1), .2, VuoPoint3d_make(.5,0,1), 5, 0); VuoListAppendValue_VuoSceneObject(*pointLights, fillLight); VuoSceneObject backLight = VuoSceneObject_makePointLight(VuoColor_makeWithRGBA(1,1,1,1), .15, VuoPoint3d_make(1,.75,-.5), 5, 0); VuoListAppendValue_VuoSceneObject(*pointLights, backLight); } else *ambientColor = VuoColor_average(ambientColors); VuoRelease(ambientColors); }