private void StoreCoeff(int earCh, int speakerCh, WWFirCoefficient coeff) { int n = earCh + speakerCh * 2; switch (n) { case 0: mLeftSpeakerToLeftEar.Add(coeff); break; case 1: mLeftSpeakerToRightEar.Add(coeff); break; case 2: mRightSpeakerToLeftEar.Add(coeff); break; case 3: mRightSpeakerToRightEar.Add(coeff); break; default: System.Diagnostics.Debug.Assert(false); break; } }
/// <summary> /// スピーカーから耳に届く音がたどる経路を調べる。 /// </summary> /// <param name="room"></param> /// <param name="earCh">耳 0:左耳, 1:右耳</param> public void Trace(WWRoom room, ReflectionType reflectionType, int earCh) { var route = new WWRoute(earCh); // 耳の位置 var rayPos = room.ListenerEarPos(earCh); var earDir = room.ListenerEarDir(earCh); Vector3D rayDir = RayGen(earDir); //耳からrayが発射して、部屋の壁に当たる // 音が耳に向かう方向。 Vector3D soundDir = -rayDir; var accumReflectionGain = new double[] {1.0, 1.0}; for (int i = 0; i < MaxReflectionCount; ++i) { Point3D hitPos; Vector3D hitSurfaceNormal; double rayLength; if (!room.RayIntersection(rayPos, rayDir, out hitPos, out hitSurfaceNormal, out rayLength)) { // 終わり。 break; } // 1.0 - 反射率の確率で、計算を打ち切る。 // たとえば反射率0.8の壁にRayが10本入射すると、8本のRayが強度を100%保ったまま反射する。 if (WallReflectionRatio < NextDouble()) { break; } // スピーカーから耳への道のりを計算する。 var lineSegment = new WWLineSegment(rayPos, rayDir, rayLength, 1.0f /* 仮 Intensity */ ); { int speakerCh = earCh; var distance = CalcRouteDistance(room, speakerCh, route, lineSegment, hitPos); double gain = CalcReflectionGain(reflectionType, room, speakerCh, hitPos, rayDir, hitSurfaceNormal); accumReflectionGain[0] *= gain; var coeffS = new WWFirCoefficient(distance / SoundSpeed, soundDir, accumReflectionGain[0] / distance, false); lineSegment.Intensity = coeffS.Gain; if (1.0 / distance < SMALL_GAIN_THRESHOLD) { break; } if (SMALL_GAIN_THRESHOLD <= coeffS.Gain) { StoreCoeff(earCh, earCh, coeffS); } } { int speakerCh = (earCh == 0) ? 1 : 0; var distance = CalcRouteDistance(room, speakerCh, route, lineSegment, hitPos); double gain = CalcReflectionGain(reflectionType, room, speakerCh, hitPos, rayDir, hitSurfaceNormal); accumReflectionGain[1] *= gain; var coeffD = new WWFirCoefficient(distance / SoundSpeed, soundDir, accumReflectionGain[1] / distance, false); if (SMALL_GAIN_THRESHOLD <= coeffD.Gain) { StoreCoeff(earCh, speakerCh, coeffD); } } route.Add(lineSegment); rayPos = hitPos; // 反射後の出射方向rayDir switch (reflectionType) { case ReflectionType.Diffuse: rayDir = RayGen(hitSurfaceNormal); break; case ReflectionType.Specular: rayDir = SpecularReflection(rayDir, hitSurfaceNormal); break; default: System.Diagnostics.Debug.Assert(false); break; } } // routeの中に、1つもlineSegmentが入っていないことがある。 mRouteList.Add(route); Interlocked.Increment(ref mRouteCount[earCh]); }
/// <summary> /// スピーカーから耳に届く音がたどる経路を調べる。 /// </summary> /// <param name="room"></param> /// <param name="earCh">耳 0:左耳, 1:右耳</param> public void Trace(WWRoom room, ReflectionType reflectionType, int earCh) { var route = new WWRoute(earCh); // 耳の位置 var rayPos = room.ListenerEarPos(earCh); var earDir = room.ListenerEarDir(earCh); Vector3D rayDir = RayGen(earDir); //耳からrayが発射して、部屋の壁に当たる // 音が耳に向かう方向。 Vector3D soundDir = -rayDir; var accumReflectionGain = new double[] { 1.0, 1.0 }; for (int i = 0; i < MaxReflectionCount; ++i) { Point3D hitPos; Vector3D hitSurfaceNormal; double rayLength; if (!room.RayIntersection(rayPos, rayDir, out hitPos, out hitSurfaceNormal, out rayLength)) { // 終わり。 break; } // 1.0 - 反射率の確率で、計算を打ち切る。 // たとえば反射率0.8の壁にRayが10本入射すると、8本のRayが強度を100%保ったまま反射する。 if (WallReflectionRatio < NextDouble()) { break; } // スピーカーから耳への道のりを計算する。 var lineSegment = new WWLineSegment(rayPos, rayDir, rayLength, 1.0f /* 仮 Intensity */); { int speakerCh = earCh; var distance = CalcRouteDistance(room, speakerCh, route, lineSegment, hitPos); double gain = CalcReflectionGain(reflectionType, room, speakerCh, hitPos, rayDir, hitSurfaceNormal); accumReflectionGain[0] *= gain; var coeffS = new WWFirCoefficient(distance / SoundSpeed, soundDir, accumReflectionGain[0] / distance, false); lineSegment.Intensity = coeffS.Gain; if (1.0 / distance < SMALL_GAIN_THRESHOLD) { break; } if (SMALL_GAIN_THRESHOLD <= coeffS.Gain) { StoreCoeff(earCh, earCh, coeffS); } } { int speakerCh = (earCh == 0) ? 1 : 0; var distance = CalcRouteDistance(room, speakerCh, route, lineSegment, hitPos); double gain = CalcReflectionGain(reflectionType, room, speakerCh, hitPos, rayDir, hitSurfaceNormal); accumReflectionGain[1] *= gain; var coeffD = new WWFirCoefficient(distance / SoundSpeed, soundDir, accumReflectionGain[1] / distance, false); if (SMALL_GAIN_THRESHOLD <= coeffD.Gain) { StoreCoeff(earCh, speakerCh, coeffD); } } route.Add(lineSegment); rayPos = hitPos; // 反射後の出射方向rayDir switch (reflectionType) { case ReflectionType.Diffuse: rayDir = RayGen(hitSurfaceNormal); break; case ReflectionType.Specular: rayDir = SpecularReflection(rayDir, hitSurfaceNormal); break; default: System.Diagnostics.Debug.Assert(false); break; } } // routeの中に、1つもlineSegmentが入っていないことがある。 mRouteList.Add(route); Interlocked.Increment(ref mRouteCount[earCh]); }