//=================================================================================================== // Uniform Variables //=================================================================================================== float dt; float4x4 ViewProj; float4x4 World; float4x4 WorldInverseTranspose; float gpuObjectScale; float gravity = 0.01f; float scaleMinY; float scaleRangeY; float cpScaleMinY; float cpScaleRangeY; float2 playerPosition; float invSpatMapHeight; float invSpatMapWidth; int IndexedPass; float3 normalComponent; float3 normalForce; float3 mass1Velocity; float3 mass1CurrentPosition; float mass; //=================================================================================================== // Object Properties //=================================================================================================== //- LocationMap -- texture LocationMap; sampler LocationMapSampler = sampler_state { texture = ; AddressU = CLAMP; AddressV = CLAMP; AddressW = CLAMP; MIPFILTER = POINT; MINFILTER = POINT; MAGFILTER = POINT; }; //- TerrainHeightMap -- texture TerrainHeightMap; sampler TerrainHeightMapSampler = sampler_state { texture = ; AddressU = CLAMP; AddressV = CLAMP; AddressW = CLAMP; MIPFILTER = POINT; MINFILTER = POINT; MAGFILTER = POINT; }; //- TerrainNormalMap -- texture TerrainNormalMap; sampler TerrainNormalMapSampler = sampler_state { texture = ; AddressU = CLAMP; AddressV = CLAMP; AddressW = CLAMP; MIPFILTER = POINT; MINFILTER = POINT; MAGFILTER = POINT; }; //- Position -- texture CurrentPosition; sampler CurrentPositionSampler = sampler_state { texture = ; AddressU = CLAMP; AddressV = CLAMP; AddressW = CLAMP; MIPFILTER = POINT; MINFILTER = POINT; MAGFILTER = POINT; }; //- Rotation -- texture Rotation; sampler RotationSampler = sampler_state { texture = ; AddressU = CLAMP; AddressV = CLAMP; AddressW = CLAMP; MIPFILTER = POINT; MINFILTER = POINT; MAGFILTER = POINT; }; //- Scale -- texture Scale; sampler ScaleSampler = sampler_state { texture = ; AddressU = CLAMP; AddressV = CLAMP; AddressW = CLAMP; MIPFILTER = POINT; MINFILTER = POINT; MAGFILTER = POINT; }; //- Mass -- texture Mass; sampler MassSampler = sampler_state { texture = ; AddressU = CLAMP; AddressV = CLAMP; AddressW = CLAMP; MIPFILTER = POINT; MINFILTER = POINT; MAGFILTER = POINT; }; //- Velocity -- texture Velocity; sampler VelocitySampler = sampler_state { texture = ; AddressU = CLAMP; AddressV = CLAMP; AddressW = CLAMP; MIPFILTER = POINT; MINFILTER = POINT; MAGFILTER = POINT; }; //- Acceleration -- texture Acceleration; sampler AccelerationSampler = sampler_state { texture = ; AddressU = CLAMP; AddressV = CLAMP; AddressW = CLAMP; MIPFILTER = POINT; MINFILTER = POINT; MAGFILTER = POINT; }; //- LastPosition -- texture LastPosition; sampler LastPositionSampler = sampler_state { texture = ; AddressU = CLAMP; AddressV = CLAMP; AddressW = CLAMP; MIPFILTER = POINT; MINFILTER = POINT; MAGFILTER = POINT; }; //- TotalForce -- texture TotalForce; sampler TotalForceSampler = sampler_state { texture = ; AddressU = CLAMP; AddressV = CLAMP; AddressW = CLAMP; MIPFILTER = POINT; MINFILTER = POINT; MAGFILTER = POINT; }; //- WindMap -- texture WindMap; sampler WindMapSampler = sampler_state { texture = ; AddressU = CLAMP; AddressV = CLAMP; AddressW = CLAMP; MIPFILTER = POINT; MINFILTER = POINT; MAGFILTER = POINT; }; //- Radius -- texture Radius; sampler RadiusSampler = sampler_state { texture = ; AddressU = CLAMP; AddressV = CLAMP; AddressW = CLAMP; MIPFILTER = POINT; MINFILTER = POINT; MAGFILTER = POINT; }; //- Dummy -- texture Dummy; sampler DummySampler = sampler_state { texture = ; AddressU = CLAMP; AddressV = CLAMP; AddressW = CLAMP; MIPFILTER = POINT; MINFILTER = POINT; MAGFILTER = POINT; }; //=================================================================================================== // Uniform, Varying, and FrameBuffer Stream Structures - // Used to Communicate between CPU, VertexProcessor, FragmentProcessor, and FrameBuffer //=================================================================================================== struct VertexInput { float4 position : POSITION0; // Position float4 texCoord : TEXCOORD0; // Texture coordinates }; struct VertexOutput { // These values are used directly by the rasterizer float4 position : POSITION; // Position // These values are interpolated and sent to FragIn float4 color : COLOR0; // Color (example: COLOR0) float4 texCoord : TEXCOORD0; // Texture coordinates (example: TEXCOORD0) }; struct FragmentInput { float4 color : COLOR0; // Color (example: COLOR0) float4 texCoord : TEXCOORD0; // Texture coordinates }; struct FragmentOutput { float4 color : COLOR0; // Color for render target n }; //=================================================================================================== // Utility Functions //=================================================================================================== // Gets Indexed Coordinates from an objects Spatial Position Data float4 GetIndexedPosition(float2 spatialPosition) { return tex2D(LocationMapSampler, spatialPosition); } // Gets Spatial Coordinates from an objects Indexed Position Data float4 GetSpatialPosition(float2 indexedPosition) { return tex2D(CurrentPositionSampler, indexedPosition); } float GetUnscaledHeight(float2 texCoord) { float2 hackTexCoords; hackTexCoords.xy = texCoord.yx; float height = tex2D(TerrainHeightMapSampler, hackTexCoords).g * 3.0f; height += tex2D(TerrainHeightMapSampler, float2(hackTexCoords.x-invSpatMapWidth, hackTexCoords.y+invSpatMapWidth)).g; height += tex2D(TerrainHeightMapSampler, float2(hackTexCoords.x+invSpatMapWidth, hackTexCoords.y+invSpatMapWidth)).g; height += tex2D(TerrainHeightMapSampler, float2(hackTexCoords.x-invSpatMapWidth, hackTexCoords.y-invSpatMapWidth)).g; height += tex2D(TerrainHeightMapSampler, float2(hackTexCoords.x+invSpatMapWidth, hackTexCoords.y-invSpatMapWidth)).g; height = (height) / 7.0f; height = (height * scaleRangeY) + scaleMinY; height = (height) / cpScaleRangeY; return height; } void CalculateVectorComponents(float3 referenceNormal, float3 objectVelocity) { if( length(objectVelocity) >= 0.01f && !isinf(length(objectVelocity)) ) { normalComponent = dot(objectVelocity, referenceNormal) * referenceNormal; } else { normalComponent = (float3) 0.0f; } } void CalculateNormalForces(float mass2, float3 normalVelocity1, float3 normalVelocity2, float COR) { float3 resultantVelocity1, resultantVelocity2; float3 eV1MinusV2, m1V1PlusM2V2; float totalMass = mass + mass2; //float totalMass = 2.0f * mass; eV1MinusV2 = COR * (normalVelocity1 - normalVelocity2); m1V1PlusM2V2 = (mass * normalVelocity1) + (mass2 * normalVelocity2); resultantVelocity1 = (m1V1PlusM2V2 - (mass2 * eV1MinusV2)) / totalMass; normalForce = resultantVelocity1 * mass / dt; } float3 GetVelocity(float2 texCoord) { return tex2D(VelocitySampler, tex2D(LocationMapSampler, texCoord).xy); } float4 GetPosition(float2 texCoord) { return tex2D(CurrentPositionSampler, tex2D(LocationMapSampler, texCoord).xy); } float GetMass(float2 texCoord) { return tex2D(MassSampler, tex2D(LocationMapSampler, texCoord).xy).x; } //=================================================================================================== // Indexed Functions //=================================================================================================== void FS_Dummy(inout FragmentInput IN, inout FragmentOutput OUT) { //--- HACK : READ BELOW ---- // This function exists b/c the our multipass sequence must be null-terminated... // Because of something with xna, or dx, or my code.. the last Render To Texture in a sequence will sometimes come out black. // So we make a extra trivial pass so the graphics card has a chance to finalize the previous texture. OUT.color = tex2D(DummySampler, IN.texCoord); } //=================================================================================================== // Collision Detection //=================================================================================================== // HACK - Assuming that all gpuObjects have the same Mass.mass values float4 ObjObjCollision(float mass2, float3 mass2Velocity, float4 mass2CurrentPosition) { float3 object1NormalVelocity; float3 object2NormalVelocity; float3 normalVectorOfImpact; float3 zeroVector = (float3) 0.0f; if(mass2CurrentPosition.a == 1.0f) { normalVectorOfImpact = mass2CurrentPosition - mass1CurrentPosition; // HACK - This condition needs to be put back in when we start using more than one spatmap //if (distance(normalVectorOfImpact, zeroVector) != 0.0f) //{ normalize(normalVectorOfImpact); //} // Calculate Mass1's normal velocity component CalculateVectorComponents(normalVectorOfImpact, mass1Velocity); object1NormalVelocity = normalComponent; // Calculate Mass2's normal velocity component CalculateVectorComponents(normalVectorOfImpact, mass2Velocity); object2NormalVelocity = normalComponent; normalForce = (float3) 0.0f; if (length(mass1Velocity) > length(mass2Velocity)) { // Ensure that mass1's velocity is not equal to 0 if (length(mass1Velocity) != 0.0f) { // Check that the velocity is not moving away from the impact, ie, the angle between velocity // and impact vector is between 90->0->270. If so the two objects are moving away from each // other, so return. if (dot(mass1Velocity, normalVectorOfImpact) / length(mass1Velocity) > 0.0f) { CalculateNormalForces(mass2, object1NormalVelocity, object2NormalVelocity, 1.0f); } } } else { // Ensure that mass2's velocity is not equal to 0 if (length(mass2Velocity) != 0.0f) { // Check that the velocity is not moving away from the impact, ie, the angle between velocity // and impact vector is between 90->180->270. If so the two objects are moving away from each // other, so return. if (dot(mass2Velocity, normalVectorOfImpact) / length(mass2Velocity) < 0.0f) { CalculateNormalForces(mass2, object1NormalVelocity, object2NormalVelocity, 1.0f); } } } } return (float4)(normalForce, 0.0f); } float4 GetForce(float2 spatialPosition) { // Get Indexed Position of Object from SpatialPosition float4 ip = tex2D(LocationMapSampler, spatialPosition); // If object exists return it's force if(ip.a > 0.0f) { float4 v = tex2D(VelocitySampler, ip.xy); float4 m = tex2D(MassSampler, ip.xy); // Low-pass filter * velocity * mass (only stored in r channel) return v * (float4)m.r; } else{ return (float4)0.0f; } } void FS_TotalForce(inout FragmentInput IN, inout FragmentOutput OUT) { // Indexed CurrentPosition holds the object's Spatial Location float4 spatialPosition = tex2D(CurrentPositionSampler, IN.texCoord); //if(true) if(spatialPosition.a == 1.0f) { /* // Get any surrounding objects, and apply resultant force float4 sumForces = (float4)0.0f; sumForces += GetForce( float2(1 - spatialPosition.x - invSpatMapWidth , spatialPosition.z - invSpatMapHeight) ); sumForces += GetForce( float2(1 - spatialPosition.x - invSpatMapWidth , spatialPosition.z ) ); sumForces += GetForce( float2(1 - spatialPosition.x - invSpatMapWidth , spatialPosition.z + invSpatMapHeight) ); sumForces += GetForce( float2(1 - spatialPosition.x , spatialPosition.z - invSpatMapHeight) ); sumForces += GetForce( float2(1 - spatialPosition.x , spatialPosition.z + invSpatMapHeight) ); sumForces += GetForce( float2(1 - spatialPosition.x + invSpatMapWidth , spatialPosition.z - invSpatMapHeight) ); sumForces += GetForce( float2(1 - spatialPosition.x + invSpatMapWidth , spatialPosition.z ) ); sumForces += GetForce( float2(1 - spatialPosition.x + invSpatMapWidth , spatialPosition.z + invSpatMapHeight) ); OUT.color = sumForces / 8.0f; */ mass1Velocity = tex2D(VelocitySampler, IN.texCoord); mass1CurrentPosition = spatialPosition; mass = tex2D(MassSampler, IN.texCoord).x; // Get any surrounding objects, and apply resultant force float4 sumForces = (float4)0.0f; float2 currentNeighbor; currentNeighbor = float2(1 - spatialPosition.x - invSpatMapWidth , spatialPosition.z - invSpatMapHeight); sumForces += ObjObjCollision(GetMass(currentNeighbor), GetVelocity(currentNeighbor), GetPosition(currentNeighbor)); currentNeighbor = float2(1 - spatialPosition.x - invSpatMapWidth , spatialPosition.z ); sumForces += ObjObjCollision(GetMass(currentNeighbor), GetVelocity(currentNeighbor), GetPosition(currentNeighbor)); currentNeighbor = float2(1 - spatialPosition.x - invSpatMapWidth , spatialPosition.z + invSpatMapHeight); sumForces += ObjObjCollision(GetMass(currentNeighbor), GetVelocity(currentNeighbor), GetPosition(currentNeighbor)); currentNeighbor = float2(1 - spatialPosition.x , spatialPosition.z - invSpatMapHeight); sumForces += ObjObjCollision(GetMass(currentNeighbor), GetVelocity(currentNeighbor), GetPosition(currentNeighbor)); currentNeighbor = float2(1 - spatialPosition.x , spatialPosition.z + invSpatMapHeight); sumForces += ObjObjCollision(GetMass(currentNeighbor), GetVelocity(currentNeighbor), GetPosition(currentNeighbor)); currentNeighbor = float2(1 - spatialPosition.x + invSpatMapWidth , spatialPosition.z - invSpatMapHeight); sumForces += ObjObjCollision(GetMass(currentNeighbor), GetVelocity(currentNeighbor), GetPosition(currentNeighbor)); currentNeighbor = float2(1 - spatialPosition.x + invSpatMapWidth , spatialPosition.z ); sumForces += ObjObjCollision(GetMass(currentNeighbor), GetVelocity(currentNeighbor), GetPosition(currentNeighbor)); currentNeighbor = float2(1 - spatialPosition.x + invSpatMapWidth , spatialPosition.z + invSpatMapHeight); sumForces += ObjObjCollision(GetMass(currentNeighbor), GetVelocity(currentNeighbor), GetPosition(currentNeighbor)); OUT.color = sumForces; // Wind Force (Scale to match lastForce value) float4 windForce = tex2D(WindMapSampler, spatialPosition.xz); // Get wind force from map windForce = (windForce - 0.5f) / 100000.0f; // Get Last TotalForce (removing gravity component) float4 lastForce = tex2D(TotalForceSampler, IN.texCoord); lastForce.g += .00065f; // Resultant wind force = windFriction - windForce; OUT.color += (.25f * lastForce- windForce); // Add Gravity OUT.color.g -= .00065f; // ------------ Start Object Reflex -------------- // Object distance below terrain (positive if below terrain). float objectReflexHeight = GetUnscaledHeight(OUT.color.xz) - OUT.color.g; //-- Reset Object Position To Terrain Height if( objectReflexHeight > 000.0f ) { // Add difference to object's height value //OUT.color.g += .0012f; //OUT.color.r = -OUT.color.r; //OUT.color.b = -OUT.color.b; } // ------------ End Object Reflex -------------- OUT.color.a = 1.0f; } else { clip(-1.0f); } } //=================================================================================================== // Physics //=================================================================================================== //--- Equation: acceleration = totalForce / mass; void FS_Acceleration(inout FragmentInput IN, inout FragmentOutput OUT) { float4 tf = tex2D(TotalForceSampler, IN.texCoord); float4 m = tex2D(MassSampler, IN.texCoord); if(tf.a == 1.0f) { OUT.color.r = tf.r/m.r; OUT.color.g = tf.g/m.r; OUT.color.b = tf.b/m.r; OUT.color.a = 1.0f; } else { clip(-1.0f); } } //--- Equation: velocity += acceleration * dt; void FS_Velocity(inout FragmentInput IN, inout FragmentOutput OUT) { float4 a = tex2D(AccelerationSampler, IN.texCoord); float4 v0 = tex2D(VelocitySampler, IN.texCoord); if(v0.a == 1.0f) { // v = v0 + at OUT.color = v0 + a * dt; OUT.color.a = 1.0f; } else { clip(-1.0f); } } //--- Equation: angular momentum void FS_Rotation(inout FragmentInput IN, inout FragmentOutput OUT) { OUT.color = tex2D(RotationSampler, IN.texCoord); } //--- Equation: currentPosition = lastPosition + velocity * dt + (0.5f * acceleration * dt * dt); void FS_CurrentPosition(inout FragmentInput IN, inout FragmentOutput OUT) { // Get Parameters float4 lp = tex2D(CurrentPositionSampler, IN.texCoord); float4 v = tex2D(VelocitySampler, IN.texCoord); float4 a = tex2D(AccelerationSampler, IN.texCoord); if(lp.a == 1.0f) { // Calc new position using standard physics OUT.color = lp + v*dt + (0.5f * a * dt*dt); OUT.color.a = 1.0f; // Bounding for TerrainMap Positions (ENTIRE BOARD) float xmin = 0.0f; float xmax = 1.0f; float ymax = 1.0f; float zmin = 0.0f; float zmax = 1.0f; // ------------ Start Object Recycler -------------- // Axis Mins to Maxs if(OUT.color.x < xmin){ OUT.color.x = xmax; } if(OUT.color.z < zmin){ OUT.color.z = zmax; } // Axis Maxs to Mins if(OUT.color.x > xmax){ OUT.color.x = xmin; } if(OUT.color.y > ymax){ OUT.color.y = -1.0f; } if(OUT.color.z > zmax){ OUT.color.z = zmin; } // ------------ End Object Recycler -------------- // ------------ Start Object/Terrain Reset -------------- // Object distance below terrain (positive if below terrain). float objectResetHeight = GetUnscaledHeight(OUT.color.xz) - OUT.color.g; // If object below terrain, to terrain height if( objectResetHeight > 0.0f ) { // Add difference to object's height value OUT.color.g += objectResetHeight; } // ------------ End Object/Terrain Reset -------------- } else { clip(-1.0f); } } //--- Trivial vertex shader for Indexed Fragment Shaders void VS_Indexed(inout VertexInput IN, inout VertexOutput OUT) { // Copy OUT to IN OUT.position = mul(IN.position, ViewProj); OUT.texCoord = IN.texCoord; } //================================================================================================== // Spatial Function // Using a Quad of Verts mapped to the CurrentPosition indexed map, // relocate each vert to it's spatial position and render to LocationMap //================================================================================================== void FS_Spatial(inout FragmentInput IN, inout FragmentOutput OUT) { clip(IN.texCoord); OUT.color = IN.color; } void VS_Spatial(inout VertexInput IN, inout VertexOutput OUT) { // Set Vertex Position to the location stored in Position Indexed Map OUT.position = tex2Dlod(CurrentPositionSampler, float4(IN.position.x, IN.position.y, 0, 0)); // IN.position; if(OUT.position.a == 1.0f) { OUT.position.g = OUT.position.b; OUT.position.b = 0.0f; OUT.position = mul(OUT.position, ViewProj); // Pack data into pixel values OUT.color.rg = IN.texCoord.xy; // Pointer to Indexed Object OUT.color.b = 0.0f; // Empty OUT.color.a = 1.0f; // isObject Flag - marks object as active //HACK FOR VISIBILITY //OUT.color.r = 1.0f; // Pass texCoords along OUT.texCoord = IN.position; } else { OUT.position = (float4) -1.0f; OUT.texCoord = -1.0f; } } //=================================================================================================== // Mains and Techniques //=================================================================================================== // Indexed Mains //-------------------------------------------------------------------------------------------------- //--- Indexed Vertex Shaders VertexOutput IndexedVertexMain(VertexInput VS_IN) { VertexOutput VS_OUT = (VertexOutput)0; VS_Indexed(VS_IN, VS_OUT); return VS_OUT; } //--- Indexed Fragment Shaders FragmentOutput TotalForceFragmentMain(FragmentInput FS_IN) { FragmentOutput FS_OUT = (FragmentOutput)0; FS_TotalForce(FS_IN, FS_OUT); return FS_OUT; } FragmentOutput AccelerationFragmentMain(FragmentInput FS_IN) { FragmentOutput FS_OUT = (FragmentOutput)0; FS_Acceleration(FS_IN, FS_OUT); return FS_OUT; } FragmentOutput VelocityFragmentMain(FragmentInput FS_IN) { FragmentOutput FS_OUT = (FragmentOutput)0; FS_Velocity(FS_IN, FS_OUT); return FS_OUT; } FragmentOutput RotationFragmentMain(FragmentInput FS_IN) { FragmentOutput FS_OUT = (FragmentOutput)0; FS_Rotation(FS_IN, FS_OUT); return FS_OUT; } FragmentOutput CurrentPositionFragmentMain(FragmentInput FS_IN) { FragmentOutput FS_OUT = (FragmentOutput)0; FS_CurrentPosition(FS_IN, FS_OUT); return FS_OUT; } FragmentOutput DummyFragmentMain(FragmentInput FS_IN) { FragmentOutput FS_OUT = (FragmentOutput)0; FS_Dummy(FS_IN, FS_OUT); return FS_OUT; } // Indexed Techniques //-------------------------------------------------------------------------------------------------- technique TotalForce { pass Pass0 { VertexShader = compile vs_3_0 IndexedVertexMain(); PixelShader = compile ps_3_0 TotalForceFragmentMain(); AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha; FillMode = Solid; } } technique Acceleration { pass Pass0 { VertexShader = compile vs_3_0 IndexedVertexMain(); PixelShader = compile ps_3_0 AccelerationFragmentMain(); AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha; FillMode = Solid; } } technique Velocity { pass Pass0 { VertexShader = compile vs_3_0 IndexedVertexMain(); PixelShader = compile ps_3_0 VelocityFragmentMain(); AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha; FillMode = Solid; } } technique Rotation { pass Pass0 { VertexShader = compile vs_3_0 IndexedVertexMain(); PixelShader = compile ps_3_0 RotationFragmentMain(); AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha; FillMode = Solid; } } technique CurrentPosition { pass Pass0 { VertexShader = compile vs_3_0 IndexedVertexMain(); PixelShader = compile ps_3_0 CurrentPositionFragmentMain(); AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha; FillMode = Solid; } } technique Dummy { pass Pass0 { VertexShader = compile vs_3_0 IndexedVertexMain(); PixelShader = compile ps_3_0 DummyFragmentMain(); AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha; FillMode = Solid; } } // Spatial Mains //-------------------------------------------------------------------------------------------------- VertexOutput SpatialVertexMain(VertexInput VS_IN) { VertexOutput VS_OUT = (VertexOutput)0; VS_Spatial(VS_IN, VS_OUT); return VS_OUT; } FragmentOutput SpatialFragmentMain(FragmentInput FS_IN) { FragmentOutput FS_OUT = (FragmentOutput)0; FS_Spatial(FS_IN, FS_OUT); return FS_OUT; } // SpatialMapping Techniques //-------------------------------------------------------------------------------------------------- technique SpatialMain { pass Pass0 { VertexShader = compile vs_3_0 SpatialVertexMain(); PixelShader = compile ps_3_0 SpatialFragmentMain(); AlphaBlendEnable = true; SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha; FillMode = Solid; } }