void PannerNode::calculateAzimuthElevation(double* outAzimuth, double* outElevation) { double azimuth = 0.0; // Calculate the source-listener vector FloatPoint3D listenerPosition = listener()->position(); FloatPoint3D sourceListener = m_position - listenerPosition; // normalize() does nothing if the length of |sourceListener| is zero. sourceListener.normalize(); // Align axes FloatPoint3D listenerFront = listener()->orientation(); FloatPoint3D listenerUp = listener()->upVector(); FloatPoint3D listenerRight = listenerFront.cross(listenerUp); listenerRight.normalize(); FloatPoint3D listenerFrontNorm = listenerFront; listenerFrontNorm.normalize(); FloatPoint3D up = listenerRight.cross(listenerFrontNorm); float upProjection = sourceListener.dot(up); FloatPoint3D projectedSource = sourceListener - upProjection * up; projectedSource.normalize(); azimuth = 180.0 * acos(projectedSource.dot(listenerRight)) / piDouble; fixNANs(azimuth); // avoid illegal values // Source in front or behind the listener double frontBack = projectedSource.dot(listenerFrontNorm); if (frontBack < 0.0) azimuth = 360.0 - azimuth; // Make azimuth relative to "front" and not "right" listener vector if ((azimuth >= 0.0) && (azimuth <= 270.0)) azimuth = 90.0 - azimuth; else azimuth = 450.0 - azimuth; // Elevation double elevation = 90.0 - 180.0 * acos(sourceListener.dot(up)) / piDouble; fixNANs(elevation); // avoid illegal values if (elevation > 90.0) elevation = 180.0 - elevation; else if (elevation < -90.0) elevation = -180.0 - elevation; if (outAzimuth) *outAzimuth = azimuth; if (outElevation) *outElevation = elevation; }
ALWAYS_INLINE void FELighting::setPixel(LightingData& data, LightSource::PaintingData& paintingData, int lightX, int lightY, float factorX, int normalX, float factorY, int normalY) { m_lightSource->updatePaintingData(paintingData, lightX, lightY, static_cast<float>(data.pixels->get(data.offset + 3)) * data.surfaceScale); data.normalVector.setX(factorX * static_cast<float>(normalX) * data.surfaceScale); data.normalVector.setY(factorY * static_cast<float>(normalY) * data.surfaceScale); data.normalVector.setZ(1.0f); data.normalVector.normalize(); if (m_lightingType == FELighting::DiffuseLighting) data.lightStrength = m_diffuseConstant * (data.normalVector * paintingData.lightVector); else { FloatPoint3D halfwayVector = paintingData.lightVector; halfwayVector.setZ(halfwayVector.z() + 1.0f); halfwayVector.normalize(); if (m_specularExponent == 1.0f) data.lightStrength = m_specularConstant * (data.normalVector * halfwayVector); else data.lightStrength = m_specularConstant * powf(data.normalVector * halfwayVector, m_specularExponent); } if (data.lightStrength > 1.0f) data.lightStrength = 1.0f; if (data.lightStrength < 0.0f) data.lightStrength = 0.0f; data.pixels->set(data.offset, static_cast<unsigned char>(data.lightStrength * paintingData.colorVector.x())); data.pixels->set(data.offset + 1, static_cast<unsigned char>(data.lightStrength * paintingData.colorVector.y())); data.pixels->set(data.offset + 2, static_cast<unsigned char>(data.lightStrength * paintingData.colorVector.z())); }
double ConeEffect::gain(FloatPoint3D sourcePosition, FloatPoint3D sourceOrientation, FloatPoint3D listenerPosition) { if (sourceOrientation.isZero() || ((m_innerAngle == 360.0) && (m_outerAngle == 360.0))) return 1.0; // no cone specified - unity gain // Normalized source-listener vector FloatPoint3D sourceToListener = listenerPosition - sourcePosition; sourceToListener.normalize(); FloatPoint3D normalizedSourceOrientation = sourceOrientation; normalizedSourceOrientation.normalize(); // Angle between the source orientation vector and the source-listener vector double dotProduct = sourceToListener.dot(normalizedSourceOrientation); double angle = 180.0 * acos(dotProduct) / piDouble; double absAngle = fabs(angle); // Divide by 2.0 here since API is entire angle (not half-angle) double absInnerAngle = fabs(m_innerAngle) / 2.0; double absOuterAngle = fabs(m_outerAngle) / 2.0; double gain = 1.0; if (absAngle <= absInnerAngle) // No attenuation gain = 1.0; else if (absAngle >= absOuterAngle) // Max attenuation gain = m_outerGain; else { // Between inner and outer cones // inner -> outer, x goes from 0 -> 1 double x = (absAngle - absInnerAngle) / (absOuterAngle - absInnerAngle); gain = (1.0 - x) + m_outerGain * x; } return gain; }
void PannerNode::getAzimuthElevation(double* outAzimuth, double* outElevation) { // FIXME: we should cache azimuth and elevation (if possible), so we only re-calculate if a change has been made. double azimuth = 0.0; // Calculate the source-listener vector FloatPoint3D listenerPosition = listener()->position(); FloatPoint3D sourceListener = m_position - listenerPosition; if (sourceListener.isZero()) { // degenerate case if source and listener are at the same point *outAzimuth = 0.0; *outElevation = 0.0; return; } sourceListener.normalize(); // Align axes FloatPoint3D listenerFront = listener()->orientation(); FloatPoint3D listenerUp = listener()->upVector(); FloatPoint3D listenerRight = listenerFront.cross(listenerUp); listenerRight.normalize(); FloatPoint3D listenerFrontNorm = listenerFront; listenerFrontNorm.normalize(); FloatPoint3D up = listenerRight.cross(listenerFrontNorm); float upProjection = sourceListener.dot(up); FloatPoint3D projectedSource = sourceListener - upProjection * up; projectedSource.normalize(); azimuth = 180.0 * acos(projectedSource.dot(listenerRight)) / piDouble; fixNANs(azimuth); // avoid illegal values // Source in front or behind the listener double frontBack = projectedSource.dot(listenerFrontNorm); if (frontBack < 0.0) azimuth = 360.0 - azimuth; // Make azimuth relative to "front" and not "right" listener vector if ((azimuth >= 0.0) && (azimuth <= 270.0)) azimuth = 90.0 - azimuth; else azimuth = 450.0 - azimuth; // Elevation double elevation = 90.0 - 180.0 * acos(sourceListener.dot(up)) / piDouble; fixNANs(elevation); // avoid illegal values if (elevation > 90.0) elevation = 180.0 - elevation; else if (elevation < -90.0) elevation = -180.0 - elevation; if (outAzimuth) *outAzimuth = azimuth; if (outElevation) *outElevation = elevation; }