예제 #1
0
파일: Sphere.cpp 프로젝트: 0x0002/Renderer
bool Sphere::Intersect( Ray const &objSpaceRay, float *tHit ) const {
    Ray r = objSpaceRay;
    Scalar a = Dot3( r.m_direction, r.m_direction );
    Scalar b = 2.0f * Dot3( r.m_direction, r.m_origin );
    Scalar c = Dot3( r.m_origin, r.m_origin ) - m_radius * m_radius;

    Scalar t0, t1;
    if( !Quadratic( a, b, c, &t0, &t1 ) ) {
        // ray does not intersect sphere
        return false;
    }

    if( t0 > r.m_maxt || t1 < r.m_mint ) {
        // intersection is outside of ray range
        return false;
    }

    Scalar t = t0;
    if( t0 < r.m_mint ) {
        // t0 is out of range, try t1
        t = t1;
        if( t > r.m_maxt ) {
            // t1 is out of range
            return false;
        }
    }

    *tHit = t;
    return true;
}
예제 #2
0
Point3 Projection3 (Point3 point, Vector3 direction, Vector3 normal)
{
	double scalar = Dot3 (direction, normal);	// Compute scalar value used in matrix
	double vectorScalar;						// Vector scalar
	Point3 projection;							// Point of projection to be returned
	Vector3 basis [3], vectorCast;				// A matrix, and a vector to cast point to

	vectorCast = CastToVector3 (normal.tail);	// Cast point to vector

	vectorScalar = Dot3 (vectorCast, normal) / scalar;
	// Compute vector scalar

	basis->x = (float) (1.0 - (direction.x * normal.x) / scalar);		// Row 1, Column 1 of matrix
	(basis + 1)->x = (float) ((direction.x * normal.y) / scalar);		// Row 1, Column 2 of matrix
	(basis + 2)->x = (float) ((direction.x * normal.z) / scalar);		// Row 1, Column 3 of matrix
	basis->y = (float) ((direction.y * normal.x) / scalar);				// Row 2, Column 1 of matrix
	(basis + 1)->y = (float) (1.0 - (direction.y * normal.y) / scalar);	// Row 2, Column 2 of matrix
	(basis + 2)->y = (float) ((direction.y * normal.z) / scalar);		// Row 2, Column 3 of matrix
	basis->z = (float) ((direction.z * normal.x) / scalar);				// Row 3, Column 1 of matrix
	(basis + 1)->z = (float) ((direction.z * normal.y) / scalar);		// Row 3, Column 2 of matrix
	(basis + 2)->z = (float) (1.0 - (direction.z * normal.z) / scalar);	// Row 3, Column 3 of matrix

	Map3 (basis, &point, NULL);
	// Map pointCopy into a new space

	projection.x = (float) (point.x + vectorScalar * direction.x);	// Compute the x coordinate of projection
	projection.y = (float) (point.y + vectorScalar * direction.y);	// Compute the y coordinate of projection
	projection.z = (float) (point.z + vectorScalar * direction.z);	// Compute the z coordinate of projection

	return projection;
	// Return point of projection
}
예제 #3
0
void Matrix4x4::LookAt(const Vector4 & vFrom, const Vector4 & vTo, const Vector4 & vUp)
{
	Vector4 vZ = Normalise(vFrom - vTo);
	Vector4 vX = Normalise(Cross(vUp, vZ));
	Vector4 vY = Cross(vZ, vX);

    elem[0][0] = vX.x;	elem[0][1] = vY.x;	elem[0][2] = vZ.x;	elem[0][3] = 0;
	elem[1][0] = vX.y;	elem[1][1] = vY.y;	elem[1][2] = vZ.y;	elem[1][3] = 0;
	elem[2][0] = vX.z;	elem[2][1] = vY.z;	elem[2][2] = vZ.z;	elem[2][3] = 0;

	elem[3][0] = Dot3(-vX, vFrom);
	elem[3][1] = Dot3(-vY, vFrom);
	elem[3][2] = Dot3(-vZ, vFrom);
	elem[3][3] = 1;
}
예제 #4
0
double Angle3 (Vector3 vector1, Vector3 vector2, AngleMode mode)
{
	double angle = acos (Dot3 (vector1, vector2) / (Mag3 (vector1) * Mag3 (vector2)));	// Angle in given mode between two vectors

	switch (mode)	// Get the angle mode
	{
	case kDegrees:	// Degrees case
		angle = RADTODEG(angle);
		// Convert angle to radians

		break;	// Break out of switch statement

	case kGradians:	// Gradians case
		angle = RADTOGRAD(angle);
		// Convert angle to radians

		break;	// Break out of switch statement

	case kRadians:	// Radians case
		break;	// Break out of switch statement

	default:
		NOBREAK_MESSAGE("Unsupported mode: Angle3 failed","1");
		angle = 0.0;// Invalid case

		break;	// Break out of switch statement
	}

	return angle;
	// Return the angle between vectors in radians
}
예제 #5
0
/** 
 * Generates a pseudo-random unit vector in the Z > 0 hemisphere,
 * Whose PDF == (SpecularPower + 1) / (2.0f * PI) * cos(Alpha) ^ SpecularPower in solid angles,
 * Where Alpha is the angle between the perfect specular direction and the outgoing direction.
 */
FVector4 GetModifiedPhongSpecularVector(FLMRandomStream& RandomStream, const FVector4& TangentSpecularDirection, float SpecularPower)
{
	checkSlow(TangentSpecularDirection.Z >= 0.0f);
	checkSlow(SpecularPower > 0.0f);

	FVector4 GeneratedTangentVector;
	do
	{
		// Generate hemispherical coordinates in the local frame of the perfect specular direction
		// Don't allow a value of 0, since that results in a PDF of 0 with large specular powers due to floating point imprecision
		const float Alpha = FMath::Min(FMath::Acos(FMath::Pow(FMath::Max(RandomStream.GetFraction(), DELTA), 1.0f / (SpecularPower + 1.0f))), (float)HALF_PI - DELTA);
		const float Phi = 2.0f * (float)PI * RandomStream.GetFraction();
		
		// Convert to Cartesian, still in the coordinate space of the perfect specular direction
		const float SinTheta = FMath::Sin(Alpha);
		const FVector4 GeneratedSpecularTangentVector(FMath::Cos(Phi) * SinTheta, FMath::Sin(Phi) * SinTheta, FMath::Cos(Alpha));

		// Generate the X and Y axes of the coordinate space whose Z is the perfect specular direction
		FVector4 SpecularTangentX = (TangentSpecularDirection ^ FVector4(0,1,0)).GetUnsafeNormal3();
		if (SpecularTangentX.SizeSquared3() < KINDA_SMALL_NUMBER)
		{
			// The specular direction was nearly equal to the Y axis, use the X axis instead
			SpecularTangentX = (TangentSpecularDirection ^ FVector4(1,0,0)).GetUnsafeNormal3();
		}
		else
		{
			SpecularTangentX = SpecularTangentX.GetUnsafeNormal3();
		}
		const FVector4 SpecularTangentY = TangentSpecularDirection ^ SpecularTangentX;

		// Rotate the generated coordinates into the local frame of the tangent space normal (0,0,1)
		const FVector4 SpecularTangentRow0(SpecularTangentX.X, SpecularTangentY.X, TangentSpecularDirection.X);
		const FVector4 SpecularTangentRow1(SpecularTangentX.Y, SpecularTangentY.Y, TangentSpecularDirection.Y);
		const FVector4 SpecularTangentRow2(SpecularTangentX.Z, SpecularTangentY.Z, TangentSpecularDirection.Z);
		GeneratedTangentVector = FVector4(
			Dot3(SpecularTangentRow0, GeneratedSpecularTangentVector),
			Dot3(SpecularTangentRow1, GeneratedSpecularTangentVector),
			Dot3(SpecularTangentRow2, GeneratedSpecularTangentVector)
			);
	}
	// Regenerate an Alpha as long as the direction is outside of the tangent space Z > 0 hemisphere, 
	// Since some part of the cosine lobe around the specular direction can be outside of the hemisphere around the surface normal.
	while (GeneratedTangentVector.Z < DELTA);
	return GeneratedTangentVector;
}
예제 #6
0
/** Generates valid X and Y axes of a coordinate system, given the Z axis. */
void GenerateCoordinateSystem2(const FVector4& ZAxis, FVector4& XAxis, FVector4& YAxis)
{
	// This implementation is based off of the one from 'Physically Based Rendering'
	if (FMath::Abs(ZAxis.X) > FMath::Abs(ZAxis.Y))
 	{
		const float InverseLength = FMath::InvSqrt(ZAxis.X * ZAxis.X + ZAxis.Z * ZAxis.Z);
		XAxis = FVector4(-ZAxis.Z * InverseLength, 0.0f, ZAxis.X * InverseLength);
 	}
 	else
 	{
		const float InverseLength = FMath::InvSqrt(ZAxis.Y * ZAxis.Y + ZAxis.Z * ZAxis.Z);
		XAxis = FVector4(0.0f, ZAxis.Z * InverseLength, -ZAxis.Y * InverseLength);
 	}

	YAxis = ZAxis ^ XAxis;
 	checkSlow(YAxis.IsUnit3());
	checkSlow(FMath::Abs(Dot3(XAxis, ZAxis)) <= THRESH_NORMALS_ARE_ORTHOGONAL);
	checkSlow(FMath::Abs(Dot3(YAxis, ZAxis)) <= THRESH_NORMALS_ARE_ORTHOGONAL);
	checkSlow(FMath::Abs(Dot3(XAxis, YAxis)) <= THRESH_NORMALS_ARE_ORTHOGONAL);
}
예제 #7
0
bool GetBarycentricWeights(
	const FVector4& Position0,
	const FVector4& Position1,
	const FVector4& Position2,
	const FVector4& InterpolatePosition,
	float Tolerance,
	FVector4& BarycentricWeights
	)
{
	BarycentricWeights = FVector4(0,0,0);
	FVector4 TriangleNormal = (Position0 - Position1) ^ (Position2 - Position0);
	float ParallelogramArea = TriangleNormal.Size3();
	FVector4 UnitTriangleNormal = TriangleNormal / ParallelogramArea;
	float PlaneDistance = Dot3(UnitTriangleNormal, (InterpolatePosition - Position0));

	// Only continue if the position to interpolate to is in the plane of the triangle (within some error)
	if (FMath::Abs(PlaneDistance) < Tolerance)
	{
		// Move the position to interpolate to into the plane of the triangle along the normal, 
		// Otherwise there will be error in our barycentric coordinates
		FVector4 AdjustedInterpolatePosition = InterpolatePosition - UnitTriangleNormal * PlaneDistance;

		FVector4 NormalU = (AdjustedInterpolatePosition - Position1) ^ (Position2 - AdjustedInterpolatePosition);
		// Signed area, if negative then InterpolatePosition is not in the triangle
		float ParallelogramAreaU = NormalU.Size3() * (Dot3(NormalU, TriangleNormal) > 0.0f ? 1.0f : -1.0f);
		float BaryCentricU = ParallelogramAreaU / ParallelogramArea;

		FVector4 NormalV = (AdjustedInterpolatePosition - Position2) ^ (Position0 - AdjustedInterpolatePosition);
		float ParallelogramAreaV = NormalV.Size3() * (Dot3(NormalV, TriangleNormal) > 0.0f ? 1.0f : -1.0f);
		float BaryCentricV = ParallelogramAreaV / ParallelogramArea;

		float BaryCentricW = 1.0f - BaryCentricU - BaryCentricV;
		if (BaryCentricU > -Tolerance && BaryCentricV > -Tolerance && BaryCentricW > -Tolerance)
		{
			BarycentricWeights = FVector4(BaryCentricU, BaryCentricV, BaryCentricW);
			return true;
		}
	}
	return false;
}
예제 #8
0
float ComputeBoundsScreenSize( const FVector4& Origin, const float SphereRadius, const FSceneView& View )
{
	// Only need one component from a view transformation; just calculate the one we're interested in.
	const float Divisor =  Dot3(Origin - View.ViewMatrices.ViewOrigin, View.ViewMatrices.ViewMatrix.GetColumn(2));

	// Get projection multiple accounting for view scaling.
	const float ScreenMultiple = FMath::Max(View.ViewRect.Width() / 2.0f * View.ViewMatrices.ProjMatrix.M[0][0],
		View.ViewRect.Height() / 2.0f * View.ViewMatrices.ProjMatrix.M[1][1]);

	const float ScreenRadius = ScreenMultiple * SphereRadius / FMath::Max(Divisor, 1.0f);
	const float ScreenArea = PI * ScreenRadius * ScreenRadius;
	return FMath::Clamp(ScreenArea / View.ViewRect.Area(), 0.0f, 1.0f);
}
예제 #9
0
Point3 PerspectiveProjection (Point3 point, Vector3 normal)
{
	double scalar;		// Scalar value
	Vector3 vectorCast;	// A vector to cast point to
	Point3 projection;	// Point of perspective projection to be returned

	vectorCast = CastToVector3 (normal.tail);	// Cast point to vector

	scalar = Dot3 (vectorCast, normal);
	// Compute first portion of scalar value

	vectorCast = CastToVector3 (point);			// Cast point to vector

	scalar /= Dot3 (vectorCast, normal);
	// Compute second portion of scalar value

	projection.x = (float) (scalar * point.x);	// Compute x coordinate of projection
	projection.y = (float) (scalar * point.y);	// Compute y coordinate of projection
	projection.z = (float) (scalar * point.z);	// Compute z coordinate of projection

	return projection;
	// Return point of perspective projection
}
void MtlBlinnSW3D::ShadeFragment(ShadeContext3D &sc)
{
	BlinnBlock &block = (BlinnBlock &) sc.GetMaterialBlock(this);

	// diffuse color
	const Vector4f &vertexColor = IsSet(block.VertexColor) ? *block.VertexColor : WHITE4F;

	Color4f diffuseMtl;	

	if (DiffuseMtl)
	{
		DiffuseMtl->Shade(sc);
		diffuseMtl = *block.Color;
	}
	else
		diffuseMtl = WHITE4F;

	Color4f Kd = Mul(vertexColor, Mul(Diffuse, diffuseMtl));


	if (!sc.DoLighting || (!ReceivesLighting && !ReceivesShadows))
		*block.Color = Kd;
	else
	{
		Vector4f oldNormal;
		Color4f diffuseMtl;

		// position
		Vector4f p = Normalize3(*block.EyePosition);

		// normal
		if (BumpmapMtl)
		{
			oldNormal = *block.EyeNormal;							// save normal
			BumpmapMtl->Shade(sc);
		}

		Vector4f n = Normalize3(*block.EyeNormal);

		if (BumpmapMtl)
			*block.EyeNormal = oldNormal;							// restore normal

		if (UseTwoSidedLighting && Dot3(n, p) > 0.0f)
			n = -n;

		// specular
		Color4f specularMtl;
		float32 specularIntensityMtl, specularExponentMtl;

		if (SpecularMtl)
		{
			SpecularMtl->Shade(sc);
			specularMtl = *block.Color;
		}
		else
			specularMtl = WHITE4F;

		if (SpecularIntensityMtl)
		{
			SpecularIntensityMtl->Shade(sc);
			specularIntensityMtl = block.Color->A;
		}
		else
			specularIntensityMtl = 1.0f;

		if (SpecularExponentMtl)
		{
			SpecularExponentMtl->Shade(sc);
			specularExponentMtl = block.Color->A;
		}
		else
			specularExponentMtl = 1.0f;

		Color4f Ks = (SpecularIntensity * specularIntensityMtl) * Mul(vertexColor, Mul(Specular, specularMtl));

		float32 specularExponent = SpecularExponent * specularExponentMtl;

		// do blinn lighting
		Color4f ambientAccum = ZERO4F;
		Color4f diffuseAccum = ZERO4F;
		Color4f specularAccum = ZERO4F;

		//uassert(sc.X != 742 || sc.Y != 320);

		const int nLights = sc.NumLights;
		for (int i = 0; i < nLights; i++)
		{
			if (sc.Illuminate(i))
			{
				if (ReceivesLighting)
				{
					if (sc.CastsShadows(i) && ReceivesShadows)
					{
						// get the transmittance (incl shadowdensity) and transmitted light and use them to apply shadows
						sc.Shadow(i);
						sc.LightColor = Lerp(sc.LightColor, sc.TransmittedLight, sc.Transmittance.A);
					}

					const Vector4f &l = (const Vector4f &) sc.LightVector;

					ambientAccum += sc.AmbientLightColor;

					if (sc.DoDiffuse)
					{
						float32 diffuse = maxf(Dot3(n, l), 0.0f);
						diffuseAccum += diffuse * Mul(Kd, sc.LightColor);
					}

					if (sc.DoSpecular)
					{
						Vector4f h = Normalize3(l - p);		// half angle vector
						float32 specular = powf(maxf(Dot3(n, h), 0.0f), specularExponent);
						specularAccum += specular * sc.LightColor;
					}
				}
				else
				{
					if (sc.CastsShadows(i) && ReceivesShadows)
					{
						sc.Shadow(i);
 						diffuseAccum += Lerp(Kd, Mul(sc.Transmittance, Kd), sc.Transmittance.A);
					}
				}
			}
		}

		if (!sc.DoAmbient)
			ambientAccum = ZERO4F;

		// combine diffuse/specular/ambient
		Color4f outColor = Mul(ambientAccum, Kd) + diffuseAccum + Mul(specularAccum, Ks);
		outColor.A = Kd.A;

		FuASSERT(!outColor.IsNaN(), ("MtlBlinnSW3D::NaN output"));

		*block.Color = outColor;
	}
}
예제 #11
0
bool
Vector::OrthogonalTo3(const Vector& other) const
{
    return fabs(Dot3(other)) < VEC_EPS;
}
/** Generates a single z layer of VolumeDistanceField. */
void FStaticLightingSystem::CalculateVolumeDistanceFieldWorkRange(int32 ZIndex)
{
	const double StartTime = FPlatformTime::Seconds();
	FStaticLightingMappingContext MappingContext(NULL, *this);

	TArray<FVector4> SampleDirections;
	TArray<FVector2D> SampleDirectionUniforms;
	const int32 NumThetaSteps = FMath::Trunc(FMath::Sqrt(VolumeDistanceFieldSettings.NumVoxelDistanceSamples / (2.0f * (float)PI)));
	const int32 NumPhiSteps = FMath::Trunc(NumThetaSteps * (float)PI);
	FLMRandomStream RandomStream(0);
	GenerateStratifiedUniformHemisphereSamples(NumThetaSteps, NumPhiSteps, RandomStream, SampleDirections, SampleDirectionUniforms);
	TArray<FVector4> OtherHemisphereSamples;
	TArray<FVector2D> OtherSampleDirectionUniforms;
	GenerateStratifiedUniformHemisphereSamples(NumThetaSteps, NumPhiSteps, RandomStream, OtherHemisphereSamples, OtherSampleDirectionUniforms);

	for (int32 i = 0; i < OtherHemisphereSamples.Num(); i++)
	{
		FVector4 Sample = OtherHemisphereSamples[i];
		Sample.Z *= -1;
		SampleDirections.Add(Sample);
	}

	const FVector4 CellExtents = FVector4(DistanceFieldVoxelSize / 2, DistanceFieldVoxelSize / 2, DistanceFieldVoxelSize / 2);
	for (int32 YIndex = 0; YIndex < VolumeSizeY; YIndex++)
	{
		for (int32 XIndex = 0; XIndex < VolumeSizeX; XIndex++)
		{
			const FVector4 VoxelPosition = FVector4(XIndex, YIndex, ZIndex) * DistanceFieldVoxelSize + DistanceFieldVolumeBounds.Min + CellExtents;
			const int32 Index = ZIndex * VolumeSizeY * VolumeSizeX + YIndex * VolumeSizeX + XIndex;
	
			float MinDistance[2];
			MinDistance[0] = FLT_MAX;
			MinDistance[1] = FLT_MAX;

			int32 Hit[2];
			Hit[0] = 0;
			Hit[1] = 0;

			int32 HitFront[2];
			HitFront[0] = 0;
			HitFront[1] = 0;

			// Generate two distance fields
			// The first is for mostly horizontal triangles, the second is for mostly vertical triangles
			// Keeping them separate allows reconstructing a cleaner surface,
			// Otherwise there would be holes in the surface where an unclosed wall mesh intersects an unclosed ground mesh
			for (int32 i = 0; i < 2; i++)
			{
				for (int32 SampleIndex = 0; SampleIndex < SampleDirections.Num(); SampleIndex++)
				{
					const float ExtentDistance = DistanceFieldVolumeBounds.GetExtent().GetMax() * 2.0f;
					FLightRay Ray(
						VoxelPosition,
						VoxelPosition + SampleDirections[SampleIndex] * VolumeDistanceFieldSettings.VolumeMaxDistance,
						NULL,
						NULL
						);

					// Trace rays in all directions to find the closest solid surface
					FLightRayIntersection Intersection;
					AggregateMesh.IntersectLightRay(Ray, true, false, false, MappingContext.RayCache, Intersection);

					if (Intersection.bIntersects)
					{
						if ((i == 0 && FMath::Abs(Intersection.IntersectionVertex.WorldTangentZ.Z) >= .707f || i == 1 && FMath::Abs(Intersection.IntersectionVertex.WorldTangentZ.Z) < .707f))
						{
							Hit[i]++;
							if (Dot3(Ray.Direction, Intersection.IntersectionVertex.WorldTangentZ) < 0)
							{
								HitFront[i]++;
							}

							const float CurrentDistance = (VoxelPosition - Intersection.IntersectionVertex.WorldPosition).Size3();
							if (CurrentDistance < MinDistance[i])
							{
								MinDistance[i] = CurrentDistance;
							}
						}
					}
				}
				// Consider this voxel 'outside' an object if more than 75% of the rays hit front faces
				MinDistance[i] *= (Hit[i] == 0 || HitFront[i] > Hit[i] * .75f) ? 1 : -1;
			}
			
			// Create a mask storing where an intersection can possibly take place
			// This allows the reconstruction to ignore areas where large positive and negative distances come together,
			// Which is caused by unclosed surfaces.
			const uint8 Mask0 = FMath::Abs(MinDistance[0]) < DistanceFieldVoxelSize * 2 ? 255 : 0; 
			// 0 will be -MaxDistance, .5 will be 0, 1 will be +MaxDistance
			const float NormalizedDistance0 = FMath::Clamp(MinDistance[0] / VolumeDistanceFieldSettings.VolumeMaxDistance + .5f, 0.0f, 1.0f);

			const uint8 Mask1 = FMath::Abs(MinDistance[1]) < DistanceFieldVoxelSize * 2 ? 255 : 0; 
			const float NormalizedDistance1 = FMath::Clamp(MinDistance[1] / VolumeDistanceFieldSettings.VolumeMaxDistance + .5f, 0.0f, 1.0f);

			const FColor FinalValue(
				FMath::Clamp<uint8>(FMath::Trunc(NormalizedDistance0 * 255), 0, 255), 
				FMath::Clamp<uint8>(FMath::Trunc(NormalizedDistance1 * 255), 0, 255), 
				Mask0,
				Mask1
				);

			VolumeDistanceField[Index] = FinalValue;
		}
	}
	MappingContext.Stats.VolumeDistanceFieldThreadTime = FPlatformTime::Seconds() - StartTime;
}