└── Hlms ├── Ocean └── GLSL │ ├── Custom │ └── CustomPassBuffer_piece_vs_piece_ps.glsl │ ├── PixelShader_ps.glsl │ ├── Structs_piece_vs_piece_ps.glsl │ ├── Textures_piece_ps.glsl │ └── VertexShader_vs.glsl ├── src ├── Hlms │ ├── OgreHlmsOcean.cpp │ ├── OgreHlmsOcean.h │ ├── OgreHlmsOceanDatablock.cpp │ └── OgreHlmsOceanDatablock.h ├── Ocean.cpp ├── Ocean.h ├── OceanCell.cpp └── OceanCell.h └── textures ├── oceanData.dds └── weight.dds /Hlms/Ocean/GLSL/Custom/CustomPassBuffer_piece_vs_piece_ps.glsl: -------------------------------------------------------------------------------- 1 | @piece( custom_VStoPS ) 2 | vec3 wpos; 3 | @end 4 | 5 | @piece( custom_passBuffer ) 6 | vec4 timer; 7 | @end 8 | -------------------------------------------------------------------------------- /Hlms/Ocean/GLSL/PixelShader_ps.glsl: -------------------------------------------------------------------------------- 1 | @property( false ) 2 | @insertpiece( SetCrossPlatformSettings ) 3 | @insertpiece( SetCompatibilityLayer ) 4 | 5 | layout(std140) uniform; 6 | #define FRAG_COLOR 0 7 | layout(location = FRAG_COLOR, index = 0) out vec4 outColour; 8 | 9 | in block 10 | { 11 | @insertpiece( Terra_VStoPS_block ) 12 | } inPs; 13 | 14 | void main() 15 | { 16 | outColour = vec4( inPs.uv0.xy, 0.0, 1.0 ); 17 | } 18 | 19 | @end 20 | @property( !false ) 21 | @insertpiece( SetCrossPlatformSettings ) 22 | @property( !GL430 ) 23 | @property( hlms_tex_gather )#extension GL_ARB_texture_gather: require@end 24 | @end 25 | @property( hlms_amd_trinary_minmax )#extension GL_AMD_shader_trinary_minmax: require@end 26 | @insertpiece( SetCompatibilityLayer ) 27 | 28 | layout(std140) uniform; 29 | #define FRAG_COLOR 0 30 | layout(location = FRAG_COLOR, index = 0) out vec4 outColour; 31 | 32 | @property( hlms_vpos ) 33 | in vec4 gl_FragCoord; 34 | @end 35 | // START UNIFORM DECLARATION 36 | @insertpiece( PassDecl ) 37 | @insertpiece( TerraMaterialDecl ) 38 | @insertpiece( TerraInstanceDecl ) 39 | @insertpiece( custom_ps_uniformDeclaration ) 40 | // END UNIFORM DECLARATION 41 | in block 42 | { 43 | @insertpiece( Terra_VStoPS_block ) 44 | } inPs; 45 | 46 | uniform sampler3D terrainData; // xy normal, z height, w foam 47 | uniform sampler2D terrainShadows; 48 | 49 | @property( hlms_forwardplus ) 50 | /*layout(binding = 1) */uniform usamplerBuffer f3dGrid; 51 | /*layout(binding = 2) */uniform samplerBuffer f3dLightList; 52 | @end 53 | @property( envprobe_map )uniform samplerCube texEnvProbeMap;@end 54 | 55 | vec4 diffuseCol; 56 | @insertpiece( FresnelType ) F0; 57 | float ROUGHNESS; 58 | 59 | vec3 nNormal; 60 | 61 | @property( hlms_lights_spot_textured )@insertpiece( DeclQuat_zAxis ) 62 | vec3 qmul( vec4 q, vec3 v ) 63 | { 64 | return v + 2.0 * cross( cross( v, q.xyz ) + q.w * v, q.xyz ); 65 | } 66 | @end 67 | 68 | @insertpiece( DeclareBRDF ) 69 | 70 | @insertpiece( DeclShadowMapMacros ) 71 | @insertpiece( DeclShadowSamplers ) 72 | @insertpiece( DeclShadowSamplingFuncs ) 73 | 74 | void main() 75 | { 76 | @insertpiece( custom_ps_preExecution ) 77 | 78 | @insertpiece( custom_ps_posMaterialLoad ) 79 | 80 | 81 | float timer = passBuf.timer.x; //need a timer! 82 | 83 | //sample the data texture using diferent uvs to randomize patterns a little 84 | vec4 textureValue = texture( terrainData, inPs.uv1 ); 85 | vec4 textureValue2 = texture( terrainData, inPs.uv2 ); 86 | vec4 textureValue3 = texture( terrainData, inPs.uv3 ); 87 | vec4 textureValue4 = texture( terrainData, inPs.uv4 ); 88 | //blend them out 89 | textureValue = mix( textureValue, textureValue2, vec4(inPs.blendWeight.x) ); 90 | textureValue = mix( textureValue, textureValue3, vec4(inPs.blendWeight.y) ); 91 | textureValue = mix( textureValue, textureValue4, vec4(inPs.blendWeight.z) ); 92 | 93 | float waveIntensity = inPs.wavesIntensity; 94 | //just a visually tweaked formula for foam factor 95 | float foam = pow( textureValue.w, 3-waveIntensity ) * 0.5 * waveIntensity * waveIntensity; 96 | 97 | //fixed roughness 98 | ROUGHNESS = 0.02 + foam; 99 | 100 | //get the diffuse colour, higher parts uses shallowColour, lower parts uses deepColour, this fakes scattering a little 101 | diffuseCol.xyz = mix( material.deepColour.xyz, material.shallowColour.xyz, vec3( inPs.waveHeight * waveIntensity ) ); 102 | diffuseCol.w = 1.0; 103 | diffuseCol.xyz += foam; 104 | 105 | //non metal 106 | F0 = vec3( 0.03f ); 107 | 108 | //get the normal from the texture 109 | nNormal.xy = textureValue.xy * 2.0 - 1.0; 110 | nNormal.xy *= waveIntensity; 111 | nNormal.z = 1.0; 112 | 113 | @insertpiece( custom_ps_posSampleNormal ); 114 | 115 | //always a plane so geometric normal is unitY, real normals are baked in the texture 116 | vec3 geomNormal = vec3(0,1,0); 117 | geomNormal = geomNormal * mat3(passBuf.view); 118 | 119 | //Get the TBN matrix 120 | vec3 viewSpaceUnitX = vec3( passBuf.view[0].x, passBuf.view[1].x, passBuf.view[2].x ); 121 | vec3 vTangent = normalize( cross( geomNormal, viewSpaceUnitX ) ); 122 | vec3 vBinormal = cross( vTangent, geomNormal ); 123 | mat3 TBN = mat3( vBinormal, vTangent, geomNormal ); 124 | 125 | nNormal = normalize( TBN * nNormal ); 126 | 127 | @property( terra_enabled ) 128 | //TODO Terra shaodws not working yet 129 | float fTerrainShadow = texture( terrainShadows, inPs.uv0.xy ).x; 130 | @end 131 | @property( !(hlms_pssm_splits || (!hlms_pssm_splits && hlms_num_shadow_map_lights && hlms_lights_directional)) ) 132 | float fShadow = 1.0f; 133 | @end 134 | @insertpiece( DoDirectionalShadowMaps ) 135 | @property( terra_enabled ) 136 | fShadow *= fTerrainShadow; 137 | @end 138 | 139 | 140 | //Everything's in Camera space 141 | @property( hlms_lights_spot || ambient_hemisphere || envprobe_map || hlms_forwardplus ) 142 | vec3 viewDir = normalize( -inPs.pos ); 143 | float NdotV = clamp( dot( nNormal, viewDir ), 0.0, 1.0 );@end 144 | 145 | @property( !ambient_fixed ) 146 | vec3 finalColour = vec3(0); 147 | @end @property( ambient_fixed ) 148 | vec3 finalColour = passBuf.ambientUpperHemi.xyz * @insertpiece( kD ).xyz; 149 | @end 150 | 151 | @insertpiece( custom_ps_preLights ) 152 | 153 | @property( !custom_disable_directional_lights ) 154 | @property( hlms_lights_directional ) 155 | finalColour += BRDF( passBuf.lights[0].position.xyz, viewDir, NdotV, passBuf.lights[0].diffuse, passBuf.lights[0].specular )@insertpiece(DarkenWithShadowFirstLight); 156 | @end 157 | @foreach( hlms_lights_directional, n, 1 ) 158 | finalColour += BRDF( passBuf.lights[@n].position.xyz, viewDir, NdotV, passBuf.lights[@n].diffuse, passBuf.lights[@n].specular )@insertpiece( DarkenWithShadow );@end 159 | @foreach( hlms_lights_directional_non_caster, n, hlms_lights_directional ) 160 | finalColour += BRDF( passBuf.lights[@n].position.xyz, viewDir, NdotV, passBuf.lights[@n].diffuse, passBuf.lights[@n].specular );@end 161 | @end 162 | 163 | @property( hlms_lights_point || hlms_lights_spot ) vec3 lightDir; 164 | float fDistance; 165 | vec3 tmpColour; 166 | float spotCosAngle;@end 167 | 168 | //Point lights 169 | @foreach( hlms_lights_point, n, hlms_lights_directional_non_caster ) 170 | lightDir = passBuf.lights[@n].position - inPs.pos; 171 | fDistance= length( lightDir ); 172 | if( fDistance <= passBuf.lights[@n].attenuation.x ) 173 | { 174 | lightDir *= 1.0 / fDistance; 175 | tmpColour = BRDF( lightDir, viewDir, NdotV, passBuf.lights[@n].diffuse, passBuf.lights[@n].specular )@insertpiece( DarkenWithShadowPoint ); 176 | float atten = 1.0 / (0.5 + (passBuf.lights[@n].attenuation.y + passBuf.lights[@n].attenuation.z * fDistance) * fDistance ); 177 | finalColour += tmpColour * atten; 178 | }@end 179 | 180 | //Spot lights 181 | //spotParams[@value(spot_params)].x = 1.0 / cos( InnerAngle ) - cos( OuterAngle ) 182 | //spotParams[@value(spot_params)].y = cos( OuterAngle / 2 ) 183 | //spotParams[@value(spot_params)].z = falloff 184 | @foreach( hlms_lights_spot, n, hlms_lights_point ) 185 | lightDir = passBuf.lights[@n].position - inPs.pos; 186 | fDistance= length( lightDir ); 187 | @property( !hlms_lights_spot_textured ) spotCosAngle = dot( normalize( inPs.pos - passBuf.lights[@n].position ), passBuf.lights[@n].spotDirection );@end 188 | @property( hlms_lights_spot_textured ) spotCosAngle = dot( normalize( inPs.pos - passBuf.lights[@n].position ), zAxis( passBuf.lights[@n].spotQuaternion ) );@end 189 | if( fDistance <= passBuf.lights[@n].attenuation.x && spotCosAngle >= passBuf.lights[@n].spotParams.y ) 190 | { 191 | lightDir *= 1.0 / fDistance; 192 | @property( hlms_lights_spot_textured ) 193 | vec3 posInLightSpace = qmul( spotQuaternion[@value(spot_params)], inPs.pos ); 194 | float spotAtten = texture( texSpotLight, normalize( posInLightSpace ).xy ).x; 195 | @end 196 | @property( !hlms_lights_spot_textured ) 197 | float spotAtten = clamp( (spotCosAngle - passBuf.lights[@n].spotParams.y) * passBuf.lights[@n].spotParams.x, 0.0, 1.0 ); 198 | spotAtten = pow( spotAtten, passBuf.lights[@n].spotParams.z ); 199 | @end 200 | tmpColour = BRDF( lightDir, viewDir, NdotV, passBuf.lights[@n].diffuse, passBuf.lights[@n].specular )@insertpiece( DarkenWithShadow ); 201 | float atten = 1.0 / (0.5 + (passBuf.lights[@n].attenuation.y + passBuf.lights[@n].attenuation.z * fDistance) * fDistance ); 202 | finalColour += tmpColour * (atten * spotAtten); 203 | }@end 204 | 205 | @insertpiece( forward3dLighting ) 206 | 207 | @property( envprobe_map || ambient_hemisphere ) 208 | vec3 reflDir = 2.0 * dot( viewDir, nNormal ) * nNormal - viewDir; 209 | 210 | @property( envprobe_map ) 211 | vec3 envColourS = passBuf.ambientUpperHemi.xyz * textureLod( texEnvProbeMap, reflDir * passBuf.invViewMatCubemap, ROUGHNESS * 12.0 ).xyz @insertpiece( ApplyEnvMapScale );// * 0.0152587890625; 212 | vec3 envColourD = passBuf.ambientUpperHemi.xyz * textureLod( texEnvProbeMap, nNormal * passBuf.invViewMatCubemap, 11.0 ).xyz @insertpiece( ApplyEnvMapScale );// * 0.0152587890625; 213 | @property( !hw_gamma_read ) //Gamma to linear space 214 | envColourS = envColourS * envColourS; 215 | envColourD = envColourD * envColourD; 216 | @end 217 | @end 218 | @property( ambient_hemisphere ) 219 | float ambientWD = dot( passBuf.ambientHemisphereDir.xyz, nNormal ) * 0.5 + 0.5; 220 | float ambientWS = dot( passBuf.ambientHemisphereDir.xyz, reflDir ) * 0.5 + 0.5; 221 | 222 | @property( envprobe_map ) 223 | envColourS += mix( passBuf.ambientLowerHemi.xyz, passBuf.ambientUpperHemi.xyz, ambientWD ); 224 | envColourD += mix( passBuf.ambientLowerHemi.xyz, passBuf.ambientUpperHemi.xyz, ambientWS ); 225 | @end @property( !envprobe_map ) 226 | vec3 envColourS = mix( passBuf.ambientLowerHemi.xyz, passBuf.ambientUpperHemi.xyz, ambientWD ); 227 | vec3 envColourD = mix( passBuf.ambientLowerHemi.xyz, passBuf.ambientUpperHemi.xyz, ambientWS ); 228 | @end 229 | @end 230 | 231 | @insertpiece( BRDF_EnvMap ) 232 | @end 233 | @property( !hw_gamma_write ) 234 | //Linear to Gamma space 235 | outColour.xyz = sqrt( finalColour ); 236 | @end @property( hw_gamma_write ) 237 | outColour.xyz = finalColour; 238 | @end 239 | 240 | @property( hlms_alphablend ) 241 | @property( use_texture_alpha ) 242 | outColour.w = material.F0.w * diffuseCol.w; 243 | @end @property( !use_texture_alpha ) 244 | outColour.w = material.F0.w; 245 | @end 246 | @end @property( !hlms_alphablend ) 247 | outColour.w = 1.0;@end 248 | 249 | @property( debug_pssm_splits ) 250 | outColour.xyz = mix( outColour.xyz, debugPssmSplit.xyz, 0.2f ); 251 | @end 252 | 253 | @insertpiece( custom_ps_posExecution ) 254 | } 255 | @end 256 | -------------------------------------------------------------------------------- /Hlms/Ocean/GLSL/Structs_piece_vs_piece_ps.glsl: -------------------------------------------------------------------------------- 1 | 2 | @piece( TerraMaterialDecl ) 3 | layout_constbuffer(binding = 1) uniform MaterialBuf 4 | { 5 | /* kD is already divided by PI to make it energy conserving. 6 | (formula is finalDiffuse = NdotL * surfaceDiffuse / PI) 7 | */ 8 | vec4 deepColour; //deepColour.w is wave intensity 9 | vec4 shallowColour; //shallowColour.w is wave scale 10 | 11 | } material; 12 | @end 13 | 14 | @piece( TerraInstanceDecl ) 15 | struct CellData 16 | { 17 | //.x = numVertsPerLine 18 | //.y = lodLevel 19 | //.z = vao->getPrimitiveCount() / m_verticesPerLine - 2u 20 | //.w = uvScale (float) 21 | uvec4 numVertsPerLine; 22 | ivec4 xzTexPosBounds; //XZXZ 23 | vec4 pos; //.w contains 1.0 / xzTexPosBounds.z 24 | vec4 scale; //.w contains 1.0 / xzTexPosBounds.w 25 | }; 26 | 27 | layout_constbuffer(binding = 2) uniform InstanceBuffer 28 | { 29 | CellData cellData[256]; 30 | } instance; 31 | @end 32 | 33 | @piece( Terra_VStoPS_block ) 34 | //flat uint drawId; 35 | vec3 pos; 36 | float waveHeight; 37 | float wavesIntensity; 38 | vec2 uv0; 39 | vec3 uv1; 40 | vec3 uv2; 41 | vec3 uv3; 42 | vec3 uv4; 43 | vec3 blendWeight; 44 | 45 | @foreach( hlms_num_shadow_map_lights, n ) 46 | @property( !hlms_shadowmap@n_is_point_light ) 47 | vec4 posL@n;@end @end 48 | @property( hlms_pssm_splits )float depth;@end 49 | @insertpiece( custom_VStoPS ) 50 | @end 51 | -------------------------------------------------------------------------------- /Hlms/Ocean/GLSL/Textures_piece_ps.glsl: -------------------------------------------------------------------------------- 1 | 2 | @undefpiece( kD ) 3 | @piece( kD )diffuseCol@end 4 | 5 | @undefpiece( kS ) 6 | @piece( kS )vec3( 1, 1, 1 )@end 7 | 8 | @foreach( detail_maps_normal, n ) 9 | @undefpiece( SampleDetailMapNm@n ) 10 | @piece( SampleDetailMapNm@n )getTSDetailNormal( textureMaps[@value(detail_map_nm@n_idx)], vec3( inPs.uv0.xy * material.detailOffsetScale[@n].zw + 11 | material.detailOffsetScale[@n].xy , @value(detail_map_nm@n_idx_slice) ) )@end 12 | @end 13 | -------------------------------------------------------------------------------- /Hlms/Ocean/GLSL/VertexShader_vs.glsl: -------------------------------------------------------------------------------- 1 | @insertpiece( SetCrossPlatformSettings ) 2 | @insertpiece( SetCompatibilityLayer ) 3 | 4 | out gl_PerVertex 5 | { 6 | vec4 gl_Position; 7 | }; 8 | 9 | layout(std140) uniform; 10 | 11 | //To render a 2x2 (quads) terrain: 12 | //You'll normally need 6 vertices per line + 2 for degenerates. 13 | //You'll need 8 vertices per line. 14 | //So you'll need a total of 16 vertices. 15 | 16 | //To render a 4x2 (quads) terrain: 17 | //You'll need 10 vertices per line. 18 | //If we include degenerate vertices, you'll need 12 per line 19 | //So you'll need a total of 24 vertices. 20 | //in int gl_VertexID; 21 | 22 | @property( GL_ARB_base_instance ) 23 | in uint drawId; 24 | @end 25 | 26 | @insertpiece( custom_vs_attributes ) 27 | 28 | out block 29 | { 30 | @insertpiece( Terra_VStoPS_block ) 31 | } outVs; 32 | 33 | // START UNIFORM DECLARATION 34 | @insertpiece( PassDecl ) 35 | @insertpiece( TerraInstanceDecl ) 36 | uniform sampler3D terrainData; // xy normal, z height, w foam 37 | uniform sampler2D blendMap; //just a noise texture 38 | @insertpiece( custom_vs_uniformDeclaration ) 39 | @property( !GL_ARB_base_instance )uniform uint baseInstance;@end 40 | // END UNIFORM DECLARATION 41 | 42 | @piece( VertexTransform ) 43 | //Lighting is in view space 44 | outVs.pos = ( vec4(worldPos.xyz, 1.0f) * passBuf.view ).xyz; 45 | @property( !hlms_dual_paraboloid_mapping ) 46 | gl_Position = vec4(worldPos.xyz, 1.0f) * passBuf.viewProj;@end 47 | @property( hlms_dual_paraboloid_mapping ) 48 | //Dual Paraboloid Mapping 49 | gl_Position.w = 1.0f; 50 | gl_Position.xyz = outVs.pos; 51 | float L = length( gl_Position.xyz ); 52 | gl_Position.z += 1.0f; 53 | gl_Position.xy /= gl_Position.z; 54 | gl_Position.z = (L - NearPlane) / (FarPlane - NearPlane);@end 55 | @end 56 | @piece( ShadowReceive ) 57 | @foreach( hlms_num_shadow_map_lights, n ) 58 | @property( !hlms_shadowmap@n_is_point_light ) 59 | outVs.posL@n = vec4(worldPos.xyz, 1.0f) * passBuf.shadowRcv[@n].texViewProj;@end @end 60 | @end 61 | 62 | void main() 63 | { 64 | @property( !GL_ARB_base_instance ) 65 | uint drawId = baseInstance + uint( gl_InstanceID ); 66 | @end 67 | 68 | @insertpiece( custom_vs_preExecution ) 69 | 70 | CellData cellData = instance.cellData[drawId]; 71 | 72 | //Map pointInLine from range [0; 12) to range [0; 9] so that it reads: 73 | // 0 0 1 2 3 4 5 6 7 8 9 9 74 | uint pointInLine = uint(gl_VertexID) % (cellData.numVertsPerLine.x); //cellData.numVertsPerLine.x = 12 75 | pointInLine = uint(clamp( int(pointInLine) - 1, 0, int(cellData.numVertsPerLine.x - 3u) )); 76 | 77 | uvec2 uVertexPos; 78 | 79 | uVertexPos.x = pointInLine >> 1u; 80 | //Even numbers are the next line, odd numbers are current line. 81 | uVertexPos.y = (pointInLine & 0x01u) == 0u ? 1u : 0u; 82 | uVertexPos.y += uint(gl_VertexID) / cellData.numVertsPerLine.x; 83 | //uVertexPos.y += floor( (float)gl_VertexID / (float)cellData.numVertsPerLine ); Could be faster on GCN. 84 | 85 | @property( use_skirts ) 86 | //Apply skirt. 87 | bool isSkirt =( pointInLine.x <= 1u || 88 | pointInLine.x >= (cellData.numVertsPerLine.x - 4u) || 89 | uVertexPos.y == 0u || 90 | uVertexPos.y == (cellData.numVertsPerLine.z + 2u) ); 91 | 92 | //Now shift X position for the left & right skirts 93 | uVertexPos.x = uint( max( int(uVertexPos.x) - 1, 0 ) ); 94 | uVertexPos.x = min( uVertexPos.x, ((cellData.numVertsPerLine.x - 7u) >> 1u) ); 95 | // uVertexPos.x becomes: 96 | // 0 0 0 1 1 2 2 3 3 4 4 4 97 | // 0 0 0 0 0 1 1 2 2 3 3 3 98 | // 0 0 0 0 0 1 1 2 2 2 2 2 99 | 100 | //Now shift Y position for the front & back skirts 101 | uVertexPos.y = uint( max( int(uVertexPos.y) - 1, 0 ) ); 102 | uVertexPos.y = min( uVertexPos.y, cellData.numVertsPerLine.z ); 103 | @end 104 | 105 | uint lodLevel = cellData.numVertsPerLine.y; 106 | uVertexPos = uVertexPos << lodLevel; 107 | 108 | uVertexPos.xy = uvec2( clamp( ivec2(uVertexPos.xy) + cellData.xzTexPosBounds.xy, 109 | ivec2( 0, 0 ), cellData.xzTexPosBounds.zw ) ); 110 | 111 | vec3 worldPos; 112 | //calculate zx right away so we can use it to sample the textures 113 | worldPos.xz = uVertexPos.xy; 114 | worldPos.xz = worldPos.xz * cellData.scale.xz + cellData.pos.xz; 115 | 116 | outVs.wavesIntensity = cellData.scale.y; 117 | float timer = passBuf.timer.x; //need a timer! 118 | float scale = 1.0; 119 | float uvScale = uintBitsToFloat(cellData.numVertsPerLine.w); 120 | 121 | //generate some different uvs with arbitrary values for scale and rotation to decrease pattern/texture repetition 122 | float rotFactor = 0.48; 123 | outVs.uv1.xy = vec2( worldPos.xz ) * mat2(cos(rotFactor), sin(rotFactor), -sin(rotFactor), cos(rotFactor)) * vec2(0.24) * scale; 124 | outVs.uv1.xy *= uvScale; 125 | outVs.uv1.z = timer * 0.08; 126 | 127 | rotFactor = 0.17; 128 | outVs.uv2.xy = vec2( worldPos.xz ) * mat2(cos(rotFactor), sin(rotFactor), -sin(rotFactor), cos(rotFactor)) * vec2(0.08) * scale; 129 | outVs.uv2.xy *= uvScale; 130 | outVs.uv2.z = timer * 0.076; 131 | 132 | rotFactor = 0.09; 133 | outVs.uv3.xy = vec2( worldPos.xz ) * mat2(cos(rotFactor), sin(rotFactor), -sin(rotFactor), cos(rotFactor)) * vec2(0.17) * scale; 134 | outVs.uv3.xy *= uvScale; 135 | outVs.uv3.z = timer * 0.069; 136 | 137 | outVs.uv4.xy = vec2( worldPos.xz ) * vec2(0.3) * scale; 138 | outVs.uv4.xy *= uvScale; 139 | outVs.uv4.z = timer * 0.084; 140 | 141 | //sample a noise texture that is going to be used to blend the 4 samples from the different uvs 142 | outVs.blendWeight = texture( blendMap, vec2(outVs.uv1.xy*0.1) ).xyz; 143 | 144 | float textureValue = texture( terrainData, outVs.uv1 ).z; 145 | float textureValue2 = texture( terrainData, outVs.uv2 ).z; 146 | float textureValue3 = texture( terrainData, outVs.uv3 ).z; 147 | float textureValue4 = texture( terrainData, outVs.uv4 ).z; 148 | 149 | textureValue = mix( textureValue, textureValue2, outVs.blendWeight.x ); 150 | textureValue = mix( textureValue, textureValue3, outVs.blendWeight.y ); 151 | textureValue = mix( textureValue, textureValue4, outVs.blendWeight.z ); 152 | 153 | 154 | worldPos.y = textureValue * 3.0 - 1.7; 155 | worldPos.y *= uvScale; 156 | 157 | @property( use_skirts ) 158 | worldPos.y = isSkirt ? 0.001 : worldPos.y; 159 | @end 160 | 161 | worldPos.y = worldPos.y * cellData.scale.y + cellData.pos.y; 162 | 163 | outVs.wpos = worldPos.xyz; 164 | 165 | outVs.waveHeight = pow( textureValue, 6 )*4; 166 | 167 | @insertpiece( VertexTransform ) 168 | 169 | outVs.uv0.xy = vec2( uVertexPos.xy ) * vec2( cellData.pos.w, cellData.scale.w ); 170 | 171 | @insertpiece( ShadowReceive ) 172 | @foreach( hlms_num_shadow_map_lights, n ) 173 | @property( !hlms_shadowmap@n_is_point_light ) 174 | outVs.posL@n.z = outVs.posL@n.z * passBuf.shadowRcv[@n].shadowDepthRange.y; 175 | outVs.posL@n.z = (outVs.posL@n.z * 0.5) + 0.5; 176 | @end 177 | @end 178 | 179 | @property( hlms_pssm_splits ) outVs.depth = gl_Position.z;@end 180 | 181 | //outVs.drawId = drawId; 182 | 183 | @insertpiece( custom_vs_posExecution ) 184 | } 185 | -------------------------------------------------------------------------------- /Hlms/src/Hlms/OgreHlmsOcean.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file is part of OGRE 4 | (Object-oriented Graphics Rendering Engine) 5 | For the latest info, see http://www.ogre3d.org/ 6 | 7 | Copyright (c) 2000-2014 Torus Knot Software Ltd 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in 17 | all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | THE SOFTWARE. 26 | ----------------------------------------------------------------------------- 27 | */ 28 | 29 | #include "Ocean/Hlms/OgreHlmsOcean.h" 30 | #include "Ocean/Hlms/OgreHlmsOceanDatablock.h" 31 | #include "OgreHlmsManager.h" 32 | #include "OgreHlmsListener.h" 33 | #include "OgreLwString.h" 34 | 35 | #include "OgreViewport.h" 36 | #include "OgreRenderTarget.h" 37 | #include "OgreHighLevelGpuProgramManager.h" 38 | #include "OgreHighLevelGpuProgram.h" 39 | #include "OgreForward3D.h" 40 | #include "OgreCamera.h" 41 | #include 42 | #include 43 | 44 | #include "OgreSceneManager.h" 45 | #include "Compositor/OgreCompositorShadowNode.h" 46 | #include "Vao/OgreVaoManager.h" 47 | #include "Vao/OgreConstBufferPacked.h" 48 | 49 | #include "CommandBuffer/OgreCommandBuffer.h" 50 | #include "CommandBuffer/OgreCbTexture.h" 51 | #include "CommandBuffer/OgreCbShaderBuffer.h" 52 | 53 | #include "Ocean/Ocean.h" 54 | #include "OgreTimer.h" 55 | 56 | #include 57 | 58 | namespace Ogre 59 | { 60 | const IdString OceanProperty::HwGammaRead = IdString( "hw_gamma_read" ); 61 | const IdString OceanProperty::HwGammaWrite = IdString( "hw_gamma_write" ); 62 | const IdString OceanProperty::SignedIntTex = IdString( "signed_int_textures" ); 63 | const IdString OceanProperty::MaterialsPerBuffer= IdString( "materials_per_buffer" ); 64 | const IdString OceanProperty::DebugPssmSplits = IdString( "debug_pssm_splits" ); 65 | 66 | const IdString OceanProperty::UseSkirts = IdString( "use_skirts" ); 67 | 68 | const char *OceanProperty::EnvProbeMap = "envprobe_map"; 69 | 70 | const IdString OceanProperty::FresnelScalar = IdString( "fresnel_scalar" ); 71 | const IdString OceanProperty::MetallicWorkflow = IdString( "metallic_workflow" ); 72 | const IdString OceanProperty::ReceiveShadows = IdString( "receive_shadows" ); 73 | 74 | const IdString OceanProperty::Pcf3x3 = IdString( "pcf_3x3" ); 75 | const IdString OceanProperty::Pcf4x4 = IdString( "pcf_4x4" ); 76 | const IdString OceanProperty::PcfIterations = IdString( "pcf_iterations" ); 77 | 78 | const IdString OceanProperty::EnvMapScale = IdString( "envmap_scale" ); 79 | const IdString OceanProperty::AmbientFixed = IdString( "ambient_fixed" ); 80 | const IdString OceanProperty::AmbientHemisphere = IdString( "ambient_hemisphere" ); 81 | 82 | const IdString OceanProperty::BrdfDefault = IdString( "BRDF_Default" ); 83 | const IdString OceanProperty::BrdfCookTorrance = IdString( "BRDF_CookTorrance" ); 84 | const IdString OceanProperty::BrdfBlinnPhong = IdString( "BRDF_BlinnPhong" ); 85 | const IdString OceanProperty::FresnelSeparateDiffuse = IdString( "fresnel_separate_diffuse" ); 86 | const IdString OceanProperty::GgxHeightCorrelated = IdString( "GGX_height_correlated" ); 87 | 88 | 89 | HlmsOcean::HlmsOcean( Archive *dataFolder, ArchiveVec *libraryFolders ) : 90 | HlmsBufferManager( HLMS_USER2, "Ocean", dataFolder, libraryFolders ), 91 | ConstBufferPool( HlmsOceanDatablock::MaterialSizeInGpuAligned, 92 | ConstBufferPool::ExtraBufferParams() ), 93 | mShadowmapSamplerblock( 0 ), 94 | mShadowmapCmpSamplerblock( 0 ), 95 | mCurrentShadowmapSamplerblock( 0 ), 96 | mOceanSamplerblock( 0 ), 97 | mCurrentPassBuffer( 0 ), 98 | mLastBoundPool( 0 ), 99 | mLastTextureHash( 0 ), 100 | mLastMovableObject( 0 ), 101 | mDebugPssmSplits( false ), 102 | mShadowFilter( PCF_3x3 ), 103 | mAmbientLightMode( AmbientAuto ) 104 | { 105 | //Override defaults 106 | mLightGatheringMode = LightGatherForwardPlus; 107 | mProbe.setNull(); 108 | } 109 | //----------------------------------------------------------------------------------- 110 | HlmsOcean::~HlmsOcean() 111 | { 112 | destroyAllBuffers(); 113 | } 114 | //----------------------------------------------------------------------------------- 115 | void HlmsOcean::_changeRenderSystem( RenderSystem *newRs ) 116 | { 117 | ConstBufferPool::_changeRenderSystem( newRs ); 118 | 119 | //Force the pool to contain only 1 entry. 120 | mSlotsPerPool = 1u; 121 | mBufferSize = HlmsOceanDatablock::MaterialSizeInGpuAligned; 122 | 123 | HlmsBufferManager::_changeRenderSystem( newRs ); 124 | 125 | if( newRs ) 126 | { 127 | HlmsDatablockMap::const_iterator itor = mDatablocks.begin(); 128 | HlmsDatablockMap::const_iterator end = mDatablocks.end(); 129 | 130 | while( itor != end ) 131 | { 132 | assert( dynamic_cast( itor->second.datablock ) ); 133 | HlmsOceanDatablock *datablock = static_cast( itor->second.datablock ); 134 | 135 | requestSlot( datablock->mTextureHash, datablock, false ); 136 | ++itor; 137 | } 138 | 139 | HlmsSamplerblock samplerblock; 140 | samplerblock.mU = TAM_BORDER; 141 | samplerblock.mV = TAM_BORDER; 142 | samplerblock.mW = TAM_CLAMP; 143 | samplerblock.mBorderColour = ColourValue( std::numeric_limits::max(), 144 | std::numeric_limits::max(), 145 | std::numeric_limits::max(), 146 | std::numeric_limits::max() ); 147 | 148 | if( mShaderProfile != "hlsl" ) 149 | { 150 | samplerblock.mMinFilter = FO_POINT; 151 | samplerblock.mMagFilter = FO_POINT; 152 | samplerblock.mMipFilter = FO_NONE; 153 | 154 | if( !mShadowmapSamplerblock ) 155 | mShadowmapSamplerblock = mHlmsManager->getSamplerblock( samplerblock ); 156 | } 157 | 158 | samplerblock.mMinFilter = FO_LINEAR; 159 | samplerblock.mMagFilter = FO_LINEAR; 160 | samplerblock.mMipFilter = FO_NONE; 161 | samplerblock.mCompareFunction = CMPF_LESS_EQUAL; 162 | 163 | if( !mShadowmapCmpSamplerblock ) 164 | mShadowmapCmpSamplerblock = mHlmsManager->getSamplerblock( samplerblock ); 165 | 166 | if( !mOceanSamplerblock ) 167 | mOceanSamplerblock = mHlmsManager->getSamplerblock( HlmsSamplerblock() ); 168 | } 169 | } 170 | //----------------------------------------------------------------------------------- 171 | const HlmsCache* HlmsOcean::createShaderCacheEntry( uint32 renderableHash, 172 | const HlmsCache &passCache, 173 | uint32 finalHash, 174 | const QueuedRenderable &queuedRenderable ) 175 | { 176 | const HlmsCache *retVal = Hlms::createShaderCacheEntry( renderableHash, passCache, finalHash, 177 | queuedRenderable ); 178 | 179 | if( mShaderProfile == "hlsl" ) 180 | { 181 | mListener->shaderCacheEntryCreated( mShaderProfile, retVal, passCache, 182 | mSetProperties, queuedRenderable ); 183 | return retVal; //D3D embeds the texture slots in the shader. 184 | } 185 | 186 | //Set samplers. 187 | if( !retVal->pso.pixelShader.isNull() ) 188 | { 189 | GpuProgramParametersSharedPtr psParams = retVal->pso.pixelShader->getDefaultParameters(); 190 | 191 | int texUnit = 3; //Vertex shader consumes 1 slot with its heightmap, 192 | //PS consumes 2 slot with its normalmap & shadow texture. 193 | 194 | psParams->setNamedConstant( "terrainData", 0 ); 195 | 196 | //Forward3D consumes 2 more slots. 197 | if( mGridBuffer ) 198 | { 199 | psParams->setNamedConstant( "f3dGrid", 3 ); 200 | psParams->setNamedConstant( "f3dLightList", 4 ); 201 | texUnit += 2; 202 | } 203 | 204 | if( !mPreparedPass.shadowMaps.empty() ) 205 | { 206 | char tmpData[32]; 207 | LwString texName = LwString::FromEmptyPointer( tmpData, sizeof(tmpData) ); 208 | texName = "texShadowMap"; 209 | const size_t baseTexSize = texName.size(); 210 | 211 | vector::type shadowMaps; 212 | shadowMaps.reserve( mPreparedPass.shadowMaps.size() ); 213 | for( size_t i=0; isetNamedConstant( texName.c_str(), &texUnit, 1, 1 ); 218 | shadowMaps.push_back( texUnit++ ); 219 | } 220 | } 221 | 222 | if( getProperty( OceanProperty::EnvProbeMap ) ) 223 | { 224 | psParams->setNamedConstant( "texEnvProbeMap", texUnit++ ); 225 | } 226 | 227 | } 228 | 229 | GpuProgramParametersSharedPtr vsParams = retVal->pso.vertexShader->getDefaultParameters(); 230 | vsParams->setNamedConstant( "terrainData", 0 ); 231 | vsParams->setNamedConstant( "blendMap", 1 ); 232 | 233 | mListener->shaderCacheEntryCreated( mShaderProfile, retVal, passCache, 234 | mSetProperties, queuedRenderable ); 235 | 236 | mRenderSystem->_setPipelineStateObject( &retVal->pso ); 237 | 238 | mRenderSystem->bindGpuProgramParameters( GPT_VERTEX_PROGRAM, vsParams, GPV_ALL ); 239 | if( !retVal->pso.pixelShader.isNull() ) 240 | { 241 | GpuProgramParametersSharedPtr psParams = retVal->pso.pixelShader->getDefaultParameters(); 242 | mRenderSystem->bindGpuProgramParameters( GPT_FRAGMENT_PROGRAM, psParams, GPV_ALL ); 243 | } 244 | 245 | return retVal; 246 | } 247 | //----------------------------------------------------------------------------------- 248 | void HlmsOcean::calculateHashForPreCreate( Renderable *renderable, PiecesMap *inOutPieces ) 249 | { 250 | assert( dynamic_cast(renderable) && 251 | "This Hlms can only be used on a Ocean object!" ); 252 | 253 | Ogre::OceanCell *OceanCell = static_cast(renderable); 254 | setProperty( OceanProperty::UseSkirts, OceanCell->getUseSkirts() ); 255 | 256 | assert( dynamic_cast( renderable->getDatablock() ) ); 257 | HlmsOceanDatablock *datablock = static_cast( 258 | renderable->getDatablock() ); 259 | 260 | setProperty( OceanProperty::ReceiveShadows, 1 ); 261 | 262 | setProperty( "terra_enabled", 0 ); 263 | setProperty( OceanProperty::EnvProbeMap, 1 ); 264 | 265 | uint32 brdf = datablock->getBrdf(); 266 | if( (brdf & OceanBrdf::BRDF_MASK) == OceanBrdf::Default ) 267 | { 268 | setProperty( OceanProperty::BrdfDefault, 1 ); 269 | 270 | if( !(brdf & OceanBrdf::FLAG_UNCORRELATED) ) 271 | setProperty( OceanProperty::GgxHeightCorrelated, 1 ); 272 | } 273 | else if( (brdf & OceanBrdf::BRDF_MASK) == OceanBrdf::CookTorrance ) 274 | setProperty( OceanProperty::BrdfCookTorrance, 1 ); 275 | else if( (brdf & OceanBrdf::BRDF_MASK) == OceanBrdf::BlinnPhong ) 276 | setProperty( OceanProperty::BrdfBlinnPhong, 1 ); 277 | 278 | if( brdf & OceanBrdf::FLAG_SPERATE_DIFFUSE_FRESNEL ) 279 | setProperty( OceanProperty::FresnelSeparateDiffuse, 1 ); 280 | } 281 | //----------------------------------------------------------------------------------- 282 | HlmsCache HlmsOcean::preparePassHash( const CompositorShadowNode *shadowNode, bool casterPass, 283 | bool dualParaboloid, SceneManager *sceneManager ) 284 | { 285 | mSetProperties.clear(); 286 | 287 | if( casterPass ) 288 | { 289 | HlmsCache retVal = Hlms::preparePassHashBase( shadowNode, casterPass, 290 | dualParaboloid, sceneManager ); 291 | return retVal; 292 | } 293 | 294 | //The properties need to be set before preparePassHash so that 295 | //they are considered when building the HlmsCache's hash. 296 | if( shadowNode && !casterPass ) 297 | { 298 | //Shadow receiving can be improved in performance by using gather sampling. 299 | //(it's the only feature so far that uses gather) 300 | const RenderSystemCapabilities *capabilities = mRenderSystem->getCapabilities(); 301 | if( capabilities->hasCapability( RSC_TEXTURE_GATHER ) ) 302 | setProperty( HlmsBaseProp::TexGather, 1 ); 303 | 304 | if( mShadowFilter == PCF_3x3 ) 305 | { 306 | setProperty( OceanProperty::Pcf3x3, 1 ); 307 | setProperty( OceanProperty::PcfIterations, 4 ); 308 | } 309 | else if( mShadowFilter == PCF_4x4 ) 310 | { 311 | setProperty( OceanProperty::Pcf4x4, 1 ); 312 | setProperty( OceanProperty::PcfIterations, 9 ); 313 | } 314 | else 315 | { 316 | setProperty( OceanProperty::PcfIterations, 1 ); 317 | } 318 | 319 | if( mDebugPssmSplits ) 320 | { 321 | int32 numPssmSplits = 0; 322 | const vector::type *pssmSplits = shadowNode->getPssmSplits( 0 ); 323 | if( pssmSplits ) 324 | { 325 | numPssmSplits = static_cast( pssmSplits->size() - 1 ); 326 | if( numPssmSplits > 0 ) 327 | setProperty( OceanProperty::DebugPssmSplits, 1 ); 328 | } 329 | } 330 | } 331 | 332 | AmbientLightMode ambientMode = mAmbientLightMode; 333 | ColourValue upperHemisphere = sceneManager->getAmbientLightUpperHemisphere(); 334 | ColourValue lowerHemisphere = sceneManager->getAmbientLightLowerHemisphere(); 335 | 336 | const float envMapScale = upperHemisphere.a; 337 | //Ignore alpha channel 338 | upperHemisphere.a = lowerHemisphere.a = 1.0; 339 | 340 | if( !casterPass ) 341 | { 342 | if( mAmbientLightMode == AmbientAuto ) 343 | { 344 | if( upperHemisphere == lowerHemisphere ) 345 | { 346 | if( upperHemisphere == ColourValue::Black ) 347 | ambientMode = AmbientNone; 348 | else 349 | ambientMode = AmbientFixed; 350 | } 351 | else 352 | { 353 | ambientMode = AmbientHemisphere; 354 | } 355 | } 356 | 357 | if( ambientMode == AmbientFixed ) 358 | setProperty( OceanProperty::AmbientFixed, 1 ); 359 | if( ambientMode == AmbientHemisphere ) 360 | setProperty( OceanProperty::AmbientHemisphere, 1 ); 361 | 362 | if( envMapScale != 1.0f ) 363 | setProperty( OceanProperty::EnvMapScale, 1 ); 364 | } 365 | 366 | setProperty( OceanProperty::FresnelScalar, 1 ); 367 | setProperty( OceanProperty::MetallicWorkflow, 1 ); 368 | 369 | HlmsCache retVal = Hlms::preparePassHashBase( shadowNode, casterPass, 370 | dualParaboloid, sceneManager ); 371 | 372 | if( getProperty( HlmsBaseProp::LightsDirNonCaster ) > 0 ) 373 | { 374 | //First directional light always cast shadows thanks to our Ocean shadows. 375 | int32 shadowCasterDirectional = getProperty( HlmsBaseProp::LightsDirectional ); 376 | shadowCasterDirectional = std::max( shadowCasterDirectional, 1 ); 377 | setProperty( HlmsBaseProp::LightsDirectional, shadowCasterDirectional ); 378 | } 379 | 380 | RenderTarget *renderTarget = sceneManager->getCurrentViewport()->getTarget(); 381 | 382 | const RenderSystemCapabilities *capabilities = mRenderSystem->getCapabilities(); 383 | setProperty( OceanProperty::HwGammaRead, capabilities->hasCapability( RSC_HW_GAMMA ) ); 384 | setProperty( OceanProperty::HwGammaWrite, capabilities->hasCapability( RSC_HW_GAMMA ) && 385 | renderTarget->isHardwareGammaEnabled() ); 386 | setProperty( OceanProperty::SignedIntTex, capabilities->hasCapability( 387 | RSC_TEXTURE_SIGNED_INT ) ); 388 | retVal.setProperties = mSetProperties; 389 | 390 | Camera *camera = sceneManager->getCameraInProgress(); 391 | Matrix4 viewMatrix = camera->getViewMatrix(true); 392 | 393 | Matrix4 projectionMatrix = camera->getProjectionMatrixWithRSDepth(); 394 | 395 | if( renderTarget->requiresTextureFlipping() ) 396 | { 397 | projectionMatrix[1][0] = -projectionMatrix[1][0]; 398 | projectionMatrix[1][1] = -projectionMatrix[1][1]; 399 | projectionMatrix[1][2] = -projectionMatrix[1][2]; 400 | projectionMatrix[1][3] = -projectionMatrix[1][3]; 401 | } 402 | 403 | int32 numLights = getProperty( HlmsBaseProp::LightsSpot ); 404 | int32 numDirectionalLights = getProperty( HlmsBaseProp::LightsDirNonCaster ); 405 | int32 numShadowMapLights = getProperty( HlmsBaseProp::NumShadowMapLights ); 406 | int32 numPssmSplits = getProperty( HlmsBaseProp::PssmSplits ); 407 | 408 | //mat4 viewProj + mat4 view; 409 | size_t mapSize = (16 + 16) * 4; 410 | 411 | mGridBuffer = 0; 412 | mGlobalLightListBuffer = 0; 413 | 414 | ForwardPlusBase *forwardPlus = sceneManager->_getActivePassForwardPlus(); 415 | if( forwardPlus ) 416 | { 417 | mapSize += forwardPlus->getConstBufferSize(); 418 | mGridBuffer = forwardPlus->getGridBuffer( camera ); 419 | mGlobalLightListBuffer = forwardPlus->getGlobalLightListBuffer( camera ); 420 | } 421 | 422 | //mat4 shadowRcv[numShadowMapLights].texViewProj + 423 | // vec2 shadowRcv[numShadowMapLights].shadowDepthRange + 424 | // vec2 padding + 425 | // vec4 shadowRcv[numShadowMapLights].invShadowMapSize + 426 | //mat3 invViewMatCubemap (upgraded to three vec4) 427 | mapSize += ( (16 + 2 + 2 + 4) * numShadowMapLights + 4 * 3 ) * 4; 428 | 429 | //vec3 ambientUpperHemi + float envMapScale 430 | if( ambientMode == AmbientFixed || ambientMode == AmbientHemisphere || envMapScale != 1.0f ) 431 | mapSize += 4 * 4; 432 | 433 | //vec3 ambientLowerHemi + padding + vec3 ambientHemisphereDir + padding 434 | if( ambientMode == AmbientHemisphere ) 435 | mapSize += 8 * 4; 436 | 437 | //float pssmSplitPoints N times. 438 | mapSize += numPssmSplits * 4; 439 | mapSize = alignToNextMultiple( mapSize, 16 ); 440 | 441 | if( shadowNode ) 442 | { 443 | //Six variables * 4 (padded vec3) * 4 (bytes) * numLights 444 | mapSize += ( 6 * 4 * 4 ) * numLights; 445 | } 446 | else 447 | { 448 | //Three variables * 4 (padded vec3) * 4 (bytes) * numDirectionalLights 449 | mapSize += ( 3 * 4 * 4 ) * numDirectionalLights; 450 | } 451 | 452 | mapSize += mListener->getPassBufferSize( shadowNode, casterPass, dualParaboloid, 453 | sceneManager ); 454 | 455 | //Arbitrary 8kb, should be enough. 456 | const size_t maxBufferSize = 8 * 1024; 457 | 458 | assert( mapSize <= maxBufferSize ); 459 | 460 | if( mCurrentPassBuffer >= mPassBuffers.size() ) 461 | { 462 | mPassBuffers.push_back( mVaoManager->createConstBuffer( maxBufferSize, BT_DYNAMIC_PERSISTENT, 463 | 0, false ) ); 464 | } 465 | 466 | ConstBufferPacked *passBuffer = mPassBuffers[mCurrentPassBuffer++]; 467 | float *passBufferPtr = reinterpret_cast( passBuffer->map( 0, mapSize ) ); 468 | 469 | #ifndef NDEBUG 470 | const float *startupPtr = passBufferPtr; 471 | #endif 472 | 473 | //--------------------------------------------------------------------------- 474 | // ---- VERTEX SHADER ---- 475 | //--------------------------------------------------------------------------- 476 | 477 | //mat4 viewProj; 478 | Matrix4 viewProjMatrix = projectionMatrix * viewMatrix; 479 | for( size_t i=0; i<16; ++i ) 480 | *passBufferPtr++ = (float)viewProjMatrix[0][i]; 481 | 482 | mPreparedPass.viewMatrix = viewMatrix; 483 | 484 | mPreparedPass.shadowMaps.clear(); 485 | 486 | //mat4 view; 487 | for( size_t i=0; i<16; ++i ) 488 | *passBufferPtr++ = (float)viewMatrix[0][i]; 489 | 490 | size_t shadowMapTexIdx = 0; 491 | const TextureVec &contiguousShadowMapTex = shadowNode->getContiguousShadowMapTex(); 492 | 493 | for( int32 i=0; iisShadowMapIdxActive( shadowMapTexIdx ) ) 498 | ++shadowMapTexIdx; 499 | 500 | //mat4 shadowRcv[numShadowMapLights].texViewProj 501 | Matrix4 viewProjTex = shadowNode->getViewProjectionMatrix( shadowMapTexIdx ); 502 | for( size_t j=0; j<16; ++j ) 503 | *passBufferPtr++ = (float)viewProjTex[0][j]; 504 | 505 | //vec2 shadowRcv[numShadowMapLights].shadowDepthRange 506 | Real fNear, fFar; 507 | shadowNode->getMinMaxDepthRange( shadowMapTexIdx, fNear, fFar ); 508 | const Real depthRange = fFar - fNear; 509 | *passBufferPtr++ = fNear; 510 | *passBufferPtr++ = 1.0f / depthRange; 511 | ++passBufferPtr; //Padding 512 | ++passBufferPtr; //Padding 513 | 514 | 515 | //vec2 shadowRcv[numShadowMapLights].invShadowMapSize 516 | size_t shadowMapTexContigIdx = 517 | shadowNode->getIndexToContiguousShadowMapTex( (size_t)shadowMapTexIdx ); 518 | uint32 texWidth = contiguousShadowMapTex[shadowMapTexContigIdx]->getWidth(); 519 | uint32 texHeight = contiguousShadowMapTex[shadowMapTexContigIdx]->getHeight(); 520 | *passBufferPtr++ = 1.0f / texWidth; 521 | *passBufferPtr++ = 1.0f / texHeight; 522 | *passBufferPtr++ = static_cast( texWidth ); 523 | *passBufferPtr++ = static_cast( texHeight ); 524 | 525 | ++shadowMapTexIdx; 526 | } 527 | 528 | //--------------------------------------------------------------------------- 529 | // ---- PIXEL SHADER ---- 530 | //--------------------------------------------------------------------------- 531 | 532 | Matrix3 viewMatrix3, invViewMatrixCubemap; 533 | viewMatrix.extract3x3Matrix( viewMatrix3 ); 534 | invViewMatrixCubemap = viewMatrix3.Inverse(); 535 | //Cubemaps are left-handed. 536 | invViewMatrixCubemap = viewMatrix3; 537 | invViewMatrixCubemap[0][2] = -invViewMatrixCubemap[0][2]; 538 | invViewMatrixCubemap[1][2] = -invViewMatrixCubemap[1][2]; 539 | invViewMatrixCubemap[2][2] = -invViewMatrixCubemap[2][2]; 540 | invViewMatrixCubemap = invViewMatrixCubemap.Inverse(); 541 | 542 | //mat3 invViewMatCubemap 543 | for( size_t i=0; i<9; ++i ) 544 | { 545 | #ifdef OGRE_GLES2_WORKAROUND_2 546 | Matrix3 xRot( 1.0f, 0.0f, 0.0f, 547 | 0.0f, 0.0f, -1.0f, 548 | 0.0f, 1.0f, 0.0f ); 549 | xRot = xRot * invViewMatrixCubemap; 550 | *passBufferPtr++ = (float)xRot[0][i]; 551 | #else 552 | *passBufferPtr++ = (float)invViewMatrixCubemap[0][i]; 553 | #endif 554 | 555 | //Alignment: each row/column is one vec4, despite being 3x3 556 | if( !( (i+1) % 3 ) ) 557 | ++passBufferPtr; 558 | } 559 | 560 | //vec3 ambientUpperHemi + padding 561 | if( ambientMode == AmbientFixed || ambientMode == AmbientHemisphere || envMapScale != 1.0f ) 562 | { 563 | *passBufferPtr++ = static_cast( upperHemisphere.r ); 564 | *passBufferPtr++ = static_cast( upperHemisphere.g ); 565 | *passBufferPtr++ = static_cast( upperHemisphere.b ); 566 | *passBufferPtr++ = envMapScale; 567 | } 568 | 569 | //vec3 ambientLowerHemi + padding + vec3 ambientHemisphereDir + padding 570 | if( ambientMode == AmbientHemisphere ) 571 | { 572 | *passBufferPtr++ = static_cast( lowerHemisphere.r ); 573 | *passBufferPtr++ = static_cast( lowerHemisphere.g ); 574 | *passBufferPtr++ = static_cast( lowerHemisphere.b ); 575 | *passBufferPtr++ = 1.0f; 576 | 577 | Vector3 hemisphereDir = viewMatrix3 * sceneManager->getAmbientLightHemisphereDir(); 578 | hemisphereDir.normalise(); 579 | *passBufferPtr++ = static_cast( hemisphereDir.x ); 580 | *passBufferPtr++ = static_cast( hemisphereDir.y ); 581 | *passBufferPtr++ = static_cast( hemisphereDir.z ); 582 | *passBufferPtr++ = 1.0f; 583 | } 584 | 585 | //float pssmSplitPoints 586 | for( int32 i=0; igetPssmSplits(0))[i+1]; 588 | 589 | passBufferPtr += alignToNextMultiple( numPssmSplits, 4 ) - numPssmSplits; 590 | 591 | if( numShadowMapLights > 0 ) 592 | { 593 | //All directional lights (caster and non-caster) are sent. 594 | //Then non-directional shadow-casting shadow lights are sent. 595 | size_t shadowLightIdx = 0; 596 | size_t nonShadowLightIdx = 0; 597 | const LightListInfo &globalLightList = sceneManager->getGlobalLightList(); 598 | const LightClosestArray &lights = shadowNode->getShadowCastingLights(); 599 | 600 | const CompositorShadowNode::LightsBitSet &affectedLights = 601 | shadowNode->getAffectedLightsBitSet(); 602 | 603 | int32 shadowCastingDirLights = getProperty( HlmsBaseProp::LightsDirectional ); 604 | 605 | for( int32 i=0; i= shadowCastingDirLights && i < numDirectionalLights ) 610 | { 611 | while( affectedLights[nonShadowLightIdx] ) 612 | ++nonShadowLightIdx; 613 | 614 | light = globalLightList.lights[nonShadowLightIdx++]; 615 | 616 | assert( light->getType() == Light::LT_DIRECTIONAL ); 617 | } 618 | else 619 | { 620 | //Skip inactive lights (e.g. no directional lights are available 621 | //and there's a shadow map that only accepts dir lights) 622 | while( !lights[shadowLightIdx].light ) 623 | ++shadowLightIdx; 624 | light = lights[shadowLightIdx++].light; 625 | } 626 | 627 | Vector4 lightPos4 = light->getAs4DVector(); 628 | Vector3 lightPos; 629 | 630 | if( light->getType() == Light::LT_DIRECTIONAL ) 631 | lightPos = viewMatrix3 * Vector3( lightPos4.x, lightPos4.y, lightPos4.z ); 632 | else 633 | lightPos = viewMatrix * Vector3( lightPos4.x, lightPos4.y, lightPos4.z ); 634 | 635 | //vec3 lights[numLights].position 636 | *passBufferPtr++ = lightPos.x; 637 | *passBufferPtr++ = lightPos.y; 638 | *passBufferPtr++ = lightPos.z; 639 | ++passBufferPtr; 640 | 641 | //vec3 lights[numLights].diffuse 642 | ColourValue colour = light->getDiffuseColour() * 643 | light->getPowerScale(); 644 | *passBufferPtr++ = colour.r; 645 | *passBufferPtr++ = colour.g; 646 | *passBufferPtr++ = colour.b; 647 | ++passBufferPtr; 648 | 649 | //vec3 lights[numLights].specular 650 | colour = light->getSpecularColour() * light->getPowerScale(); 651 | *passBufferPtr++ = colour.r; 652 | *passBufferPtr++ = colour.g; 653 | *passBufferPtr++ = colour.b; 654 | ++passBufferPtr; 655 | 656 | //vec3 lights[numLights].attenuation; 657 | Real attenRange = light->getAttenuationRange(); 658 | Real attenLinear = light->getAttenuationLinear(); 659 | Real attenQuadratic = light->getAttenuationQuadric(); 660 | *passBufferPtr++ = attenRange; 661 | *passBufferPtr++ = attenLinear; 662 | *passBufferPtr++ = attenQuadratic; 663 | ++passBufferPtr; 664 | 665 | //vec3 lights[numLights].spotDirection; 666 | Vector3 spotDir = viewMatrix3 * light->getDerivedDirection(); 667 | *passBufferPtr++ = spotDir.x; 668 | *passBufferPtr++ = spotDir.y; 669 | *passBufferPtr++ = spotDir.z; 670 | ++passBufferPtr; 671 | 672 | //vec3 lights[numLights].spotParams; 673 | Radian innerAngle = light->getSpotlightInnerAngle(); 674 | Radian outerAngle = light->getSpotlightOuterAngle(); 675 | *passBufferPtr++ = 1.0f / ( cosf( innerAngle.valueRadians() * 0.5f ) - 676 | cosf( outerAngle.valueRadians() * 0.5f ) ); 677 | *passBufferPtr++ = cosf( outerAngle.valueRadians() * 0.5f ); 678 | *passBufferPtr++ = light->getSpotlightFalloff(); 679 | ++passBufferPtr; 680 | } 681 | } 682 | else 683 | { 684 | //No shadow maps, only send directional lights 685 | const LightListInfo &globalLightList = sceneManager->getGlobalLightList(); 686 | 687 | for( int32 i=0; igetType() == Light::LT_DIRECTIONAL ); 690 | 691 | Vector4 lightPos4 = globalLightList.lights[i]->getAs4DVector(); 692 | Vector3 lightPos = viewMatrix3 * Vector3( lightPos4.x, lightPos4.y, lightPos4.z ); 693 | 694 | //vec3 lights[numLights].position 695 | *passBufferPtr++ = lightPos.x; 696 | *passBufferPtr++ = lightPos.y; 697 | *passBufferPtr++ = lightPos.z; 698 | ++passBufferPtr; 699 | 700 | //vec3 lights[numLights].diffuse 701 | ColourValue colour = globalLightList.lights[i]->getDiffuseColour() * 702 | globalLightList.lights[i]->getPowerScale(); 703 | *passBufferPtr++ = colour.r; 704 | *passBufferPtr++ = colour.g; 705 | *passBufferPtr++ = colour.b; 706 | ++passBufferPtr; 707 | 708 | //vec3 lights[numLights].specular 709 | colour = globalLightList.lights[i]->getSpecularColour() * globalLightList.lights[i]->getPowerScale(); 710 | *passBufferPtr++ = colour.r; 711 | *passBufferPtr++ = colour.g; 712 | *passBufferPtr++ = colour.b; 713 | ++passBufferPtr; 714 | } 715 | } 716 | 717 | if( shadowNode ) 718 | { 719 | mPreparedPass.shadowMaps.reserve( contiguousShadowMapTex.size() ); 720 | 721 | TextureVec::const_iterator itShadowMap = contiguousShadowMapTex.begin(); 722 | TextureVec::const_iterator enShadowMap = contiguousShadowMapTex.end(); 723 | 724 | while( itShadowMap != enShadowMap ) 725 | { 726 | mPreparedPass.shadowMaps.push_back( itShadowMap->get() ); 727 | ++itShadowMap; 728 | } 729 | } 730 | 731 | if( forwardPlus ) 732 | { 733 | forwardPlus->fillConstBufferData( renderTarget, passBufferPtr ); 734 | passBufferPtr += forwardPlus->getConstBufferSize() >> 2; 735 | } 736 | 737 | //Timer 738 | *passBufferPtr++ = Ogre::Root::getSingletonPtr()->getTimer()->getMilliseconds()*0.0005; 739 | *passBufferPtr++ = 0; 740 | *passBufferPtr++ = 0; 741 | *passBufferPtr++ = 0; 742 | 743 | 744 | passBufferPtr = mListener->preparePassBuffer( shadowNode, casterPass, dualParaboloid, 745 | sceneManager, passBufferPtr ); 746 | 747 | assert( (size_t)(passBufferPtr - startupPtr) * 4u == mapSize ); 748 | 749 | passBuffer->unmap( UO_KEEP_PERSISTENT ); 750 | 751 | mLastTextureHash = 0; 752 | mLastMovableObject = 0; 753 | 754 | mLastBoundPool = 0; 755 | 756 | if( mShadowmapSamplerblock && !getProperty( HlmsBaseProp::ShadowUsesDepthTexture ) ) 757 | mCurrentShadowmapSamplerblock = mShadowmapSamplerblock; 758 | else 759 | mCurrentShadowmapSamplerblock = mShadowmapCmpSamplerblock; 760 | 761 | uploadDirtyDatablocks(); 762 | 763 | return retVal; 764 | } 765 | //----------------------------------------------------------------------------------- 766 | uint32 HlmsOcean::fillBuffersFor( const HlmsCache *cache, const QueuedRenderable &queuedRenderable, 767 | bool casterPass, uint32 lastCacheHash, 768 | uint32 lastTextureHash ) 769 | { 770 | OGRE_EXCEPT( Exception::ERR_NOT_IMPLEMENTED, 771 | "Trying to use slow-path on a desktop implementation. " 772 | "Change the RenderQueue settings.", 773 | "HlmsOcean::fillBuffersFor" ); 774 | } 775 | //----------------------------------------------------------------------------------- 776 | uint32 HlmsOcean::fillBuffersForV1( const HlmsCache *cache, 777 | const QueuedRenderable &queuedRenderable, 778 | bool casterPass, uint32 lastCacheHash, 779 | CommandBuffer *commandBuffer ) 780 | { 781 | return fillBuffersFor( cache, queuedRenderable, casterPass, 782 | lastCacheHash, commandBuffer, true ); 783 | } 784 | //----------------------------------------------------------------------------------- 785 | uint32 HlmsOcean::fillBuffersForV2( const HlmsCache *cache, 786 | const QueuedRenderable &queuedRenderable, 787 | bool casterPass, uint32 lastCacheHash, 788 | CommandBuffer *commandBuffer ) 789 | { 790 | return fillBuffersFor( cache, queuedRenderable, casterPass, 791 | lastCacheHash, commandBuffer, false ); 792 | } 793 | //----------------------------------------------------------------------------------- 794 | uint32 HlmsOcean::fillBuffersFor( const HlmsCache *cache, const QueuedRenderable &queuedRenderable, 795 | bool casterPass, uint32 lastCacheHash, 796 | CommandBuffer *commandBuffer, bool isV1 ) 797 | { 798 | assert( dynamic_cast( queuedRenderable.renderable->getDatablock() ) ); 799 | const HlmsOceanDatablock *datablock = static_cast( 800 | queuedRenderable.renderable->getDatablock() ); 801 | 802 | if( OGRE_EXTRACT_HLMS_TYPE_FROM_CACHE_HASH( lastCacheHash ) != mType ) 803 | { 804 | //layout(binding = 0) uniform PassBuffer {} pass 805 | ConstBufferPacked *passBuffer = mPassBuffers[mCurrentPassBuffer-1]; 806 | *commandBuffer->addCommand() = CbShaderBuffer( VertexShader, 807 | 0, passBuffer, 0, 808 | passBuffer-> 809 | getTotalSizeBytes() ); 810 | *commandBuffer->addCommand() = CbShaderBuffer( PixelShader, 811 | 0, passBuffer, 0, 812 | passBuffer-> 813 | getTotalSizeBytes() ); 814 | 815 | size_t texUnit = 3; 816 | 817 | if( mGridBuffer ) 818 | { 819 | texUnit = 5; 820 | *commandBuffer->addCommand() = 821 | CbShaderBuffer( PixelShader, 3, mGridBuffer, 0, 0 ); 822 | *commandBuffer->addCommand() = 823 | CbShaderBuffer( PixelShader, 4, mGlobalLightListBuffer, 0, 0 ); 824 | } 825 | 826 | //We changed HlmsType, rebind the shared textures. 827 | FastArray::const_iterator itor = mPreparedPass.shadowMaps.begin(); 828 | FastArray::const_iterator end = mPreparedPass.shadowMaps.end(); 829 | while( itor != end ) 830 | { 831 | *commandBuffer->addCommand() = CbTexture( texUnit, true, *itor, 832 | mCurrentShadowmapSamplerblock ); 833 | ++texUnit; 834 | ++itor; 835 | } 836 | 837 | mLastTextureHash = 0; 838 | mLastMovableObject = 0; 839 | mLastBoundPool = 0; 840 | 841 | //layout(binding = 2) uniform InstanceBuffer {} instance 842 | if( mCurrentConstBuffer < mConstBuffers.size() && 843 | (size_t)((mCurrentMappedConstBuffer - mStartMappedConstBuffer) + 16) <= 844 | mCurrentConstBufferSize ) 845 | { 846 | *commandBuffer->addCommand() = 847 | CbShaderBuffer( VertexShader, 2, mConstBuffers[mCurrentConstBuffer], 0, 0 ); 848 | *commandBuffer->addCommand() = 849 | CbShaderBuffer( PixelShader, 2, mConstBuffers[mCurrentConstBuffer], 0, 0 ); 850 | } 851 | 852 | mListener->hlmsTypeChanged( casterPass, commandBuffer, datablock ); 853 | } 854 | 855 | //Don't bind the material buffer on caster passes (important to keep 856 | //MDI & auto-instancing running on shadow map passes) 857 | if( mLastBoundPool != datablock->getAssignedPool() && 858 | (!casterPass || datablock->getAlphaTest() != CMPF_ALWAYS_PASS) ) 859 | { 860 | //layout(binding = 1) uniform MaterialBuf {} materialArray 861 | const ConstBufferPool::BufferPool *newPool = datablock->getAssignedPool(); 862 | *commandBuffer->addCommand() = CbShaderBuffer( PixelShader, 863 | 1, newPool->materialBuffer, 0, 864 | newPool->materialBuffer-> 865 | getTotalSizeBytes() ); 866 | mLastBoundPool = newPool; 867 | } 868 | 869 | if( mLastMovableObject != queuedRenderable.movableObject ) 870 | { 871 | { 872 | Ogre::TexturePtr tex = Ogre::TextureManager::getSingletonPtr()->getByName("oceanData.dds"); 873 | if (tex.isNull()){ 874 | tex = Ogre::TextureManager::getSingleton().load("oceanData.dds", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_3D); 875 | } 876 | Ogre::HlmsSamplerblock samplerblock; 877 | samplerblock.mU = Ogre::TextureAddressingMode::TAM_WRAP; 878 | samplerblock.mV = Ogre::TextureAddressingMode::TAM_WRAP; 879 | samplerblock.mW = Ogre::TextureAddressingMode::TAM_WRAP; 880 | const Ogre::HlmsSamplerblock* finalSamplerblock = Ogre::Root::getSingleton().getHlmsManager()->getSamplerblock(samplerblock); 881 | *commandBuffer->addCommand() = Ogre::CbTexture( 0, true, tex.getPointer(), finalSamplerblock); 882 | } 883 | { 884 | Ogre::TexturePtr tex = Ogre::TextureManager::getSingletonPtr()->getByName("weight.dds"); 885 | if (tex.isNull()){ 886 | tex = Ogre::TextureManager::getSingleton().load("weight.dds", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D); 887 | } 888 | Ogre::HlmsSamplerblock samplerblock; 889 | samplerblock.mU = Ogre::TextureAddressingMode::TAM_WRAP; 890 | samplerblock.mV = Ogre::TextureAddressingMode::TAM_WRAP; 891 | const Ogre::HlmsSamplerblock* finalSamplerblock = Ogre::Root::getSingleton().getHlmsManager()->getSamplerblock(samplerblock); 892 | *commandBuffer->addCommand() = Ogre::CbTexture( 1, true, tex.getPointer(), finalSamplerblock); 893 | } 894 | if( !mProbe.isNull() ){ 895 | 896 | size_t texUnit = mPreparedPass.shadowMaps.size() + (!mGridBuffer ? 3 : 5); 897 | 898 | *commandBuffer->addCommand() = 899 | CbTexture( texUnit, true, mProbe.get(), mOceanSamplerblock ); 900 | } 901 | 902 | 903 | mLastMovableObject = queuedRenderable.movableObject; 904 | } 905 | 906 | uint32 * RESTRICT_ALIAS currentMappedConstBuffer = mCurrentMappedConstBuffer; 907 | 908 | //--------------------------------------------------------------------------- 909 | // ---- VERTEX SHADER ---- 910 | //--------------------------------------------------------------------------- 911 | //We need to correct currentMappedConstBuffer to point to the right texture buffer's 912 | //offset, which may not be in sync if the previous draw had skeletal animation. 913 | bool exceedsConstBuffer = (size_t)((currentMappedConstBuffer - mStartMappedConstBuffer) + 12) 914 | > mCurrentConstBufferSize; 915 | 916 | if( exceedsConstBuffer ) 917 | currentMappedConstBuffer = mapNextConstBuffer( commandBuffer ); 918 | 919 | const Ogre::OceanCell *OceanCell = static_cast( queuedRenderable.renderable ); 920 | 921 | OceanCell->uploadToGpu( currentMappedConstBuffer ); 922 | currentMappedConstBuffer += 16u; 923 | 924 | //--------------------------------------------------------------------------- 925 | // ---- PIXEL SHADER ---- 926 | //--------------------------------------------------------------------------- 927 | 928 | mCurrentMappedConstBuffer = currentMappedConstBuffer; 929 | 930 | return ((mCurrentMappedConstBuffer - mStartMappedConstBuffer) >> 4) - 1; 931 | } 932 | //----------------------------------------------------------------------------------- 933 | void HlmsOcean::destroyAllBuffers(void) 934 | { 935 | HlmsBufferManager::destroyAllBuffers(); 936 | 937 | mCurrentPassBuffer = 0; 938 | 939 | { 940 | ConstBufferPackedVec::const_iterator itor = mPassBuffers.begin(); 941 | ConstBufferPackedVec::const_iterator end = mPassBuffers.end(); 942 | 943 | while( itor != end ) 944 | { 945 | if( (*itor)->getMappingState() != MS_UNMAPPED ) 946 | (*itor)->unmap( UO_UNMAP_ALL ); 947 | mVaoManager->destroyConstBuffer( *itor ); 948 | ++itor; 949 | } 950 | 951 | mPassBuffers.clear(); 952 | } 953 | } 954 | //----------------------------------------------------------------------------------- 955 | void HlmsOcean::frameEnded(void) 956 | { 957 | HlmsBufferManager::frameEnded(); 958 | mCurrentPassBuffer = 0; 959 | } 960 | //----------------------------------------------------------------------------------- 961 | void HlmsOcean::setDebugPssmSplits( bool bDebug ) 962 | { 963 | mDebugPssmSplits = bDebug; 964 | } 965 | //----------------------------------------------------------------------------------- 966 | void HlmsOcean::setShadowSettings( ShadowFilter filter ) 967 | { 968 | mShadowFilter = filter; 969 | } 970 | //----------------------------------------------------------------------------------- 971 | void HlmsOcean::setAmbientLightMode( AmbientLightMode mode ) 972 | { 973 | mAmbientLightMode = mode; 974 | } 975 | //----------------------------------------------------------------------------------- 976 | void HlmsOcean::setEnvProbe( Ogre::TexturePtr probe ){ 977 | mProbe = probe; 978 | } 979 | //----------------------------------------------------------------------------------- 980 | HlmsDatablock* HlmsOcean::createDatablockImpl( IdString datablockName, 981 | const HlmsMacroblock *macroblock, 982 | const HlmsBlendblock *blendblock, 983 | const HlmsParamVec ¶mVec ) 984 | { 985 | return OGRE_NEW HlmsOceanDatablock( datablockName, this, macroblock, blendblock, paramVec ); 986 | } 987 | } 988 | -------------------------------------------------------------------------------- /Hlms/src/Hlms/OgreHlmsOcean.h: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file is part of OGRE 4 | (Object-oriented Graphics Rendering Engine) 5 | For the latest info, see http://www.ogre3d.org/ 6 | 7 | Copyright (c) 2000-2014 Torus Knot Software Ltd 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in 17 | all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | THE SOFTWARE. 26 | ----------------------------------------------------------------------------- 27 | */ 28 | #ifndef _OgreHlmsOcean_H_ 29 | #define _OgreHlmsOcean_H_ 30 | 31 | #include "OgreHlmsBufferManager.h" 32 | #include "OgreConstBufferPool.h" 33 | #include "OgreMatrix4.h" 34 | #include "OgreHeaderPrefix.h" 35 | 36 | namespace Ogre 37 | { 38 | class CompositorShadowNode; 39 | struct QueuedRenderable; 40 | 41 | /** \addtogroup Component 42 | * @{ 43 | */ 44 | /** \addtogroup Material 45 | * @{ 46 | */ 47 | 48 | class HlmsOceanDatablock; 49 | 50 | /** Physically based shading implementation specfically designed for 51 | OpenGL 3+, D3D11 and other RenderSystems which support uniform buffers. 52 | */ 53 | class HlmsOcean : public HlmsBufferManager, public ConstBufferPool 54 | { 55 | public: 56 | enum ShadowFilter 57 | { 58 | /// Standard quality. Very fast. 59 | PCF_2x2, 60 | 61 | /// Good quality. Still quite fast on most modern hardware. 62 | PCF_3x3, 63 | 64 | /// High quality. Very slow in old hardware (i.e. DX10 level hw and below) 65 | /// Use RSC_TEXTURE_GATHER to check whether it will be slow or not. 66 | PCF_4x4, 67 | 68 | NumShadowFilter 69 | }; 70 | 71 | enum AmbientLightMode 72 | { 73 | /// Use fixed-colour ambient lighting when upper hemisphere = lower hemisphere, 74 | /// use hemisphere lighting when they don't match. 75 | /// Disables ambient lighting if the colours are black. 76 | AmbientAuto, 77 | 78 | /// Force fixed-colour ambient light. Only uses the upper hemisphere paramter. 79 | AmbientFixed, 80 | 81 | /// Force hemisphere ambient light. Useful if you plan on adjusting the colours 82 | /// dynamically very often and this might cause swapping shaders. 83 | AmbientHemisphere, 84 | 85 | /// Disable ambient lighting. 86 | AmbientNone 87 | }; 88 | 89 | protected: 90 | typedef vector::type ConstBufferPackedVec; 91 | typedef vector::type HlmsDatablockVec; 92 | 93 | struct PassData 94 | { 95 | FastArray shadowMaps; 96 | FastArray vertexShaderSharedBuffer; 97 | FastArray pixelShaderSharedBuffer; 98 | 99 | Matrix4 viewMatrix; 100 | }; 101 | 102 | PassData mPreparedPass; 103 | ConstBufferPackedVec mPassBuffers; 104 | HlmsSamplerblock const *mShadowmapSamplerblock; /// GL3+ only when not using depth textures 105 | HlmsSamplerblock const *mShadowmapCmpSamplerblock; /// For depth textures & D3D11 106 | HlmsSamplerblock const *mCurrentShadowmapSamplerblock; 107 | HlmsSamplerblock const *mOceanSamplerblock; 108 | 109 | uint32 mCurrentPassBuffer; /// Resets every to zero every new frame. 110 | 111 | TexBufferPacked *mGridBuffer; 112 | TexBufferPacked *mGlobalLightListBuffer; 113 | 114 | ConstBufferPool::BufferPool const *mLastBoundPool; 115 | 116 | uint32 mLastTextureHash; 117 | MovableObject const *mLastMovableObject; 118 | 119 | bool mDebugPssmSplits; 120 | 121 | ShadowFilter mShadowFilter; 122 | AmbientLightMode mAmbientLightMode; 123 | 124 | Ogre::TexturePtr mProbe; 125 | 126 | virtual const HlmsCache* createShaderCacheEntry( uint32 renderableHash, 127 | const HlmsCache &passCache, 128 | uint32 finalHash, 129 | const QueuedRenderable &queuedRenderable ); 130 | 131 | virtual HlmsDatablock* createDatablockImpl( IdString datablockName, 132 | const HlmsMacroblock *macroblock, 133 | const HlmsBlendblock *blendblock, 134 | const HlmsParamVec ¶mVec ); 135 | 136 | virtual void calculateHashForPreCreate( Renderable *renderable, PiecesMap *inOutPieces ); 137 | 138 | virtual void destroyAllBuffers(void); 139 | 140 | FORCEINLINE uint32 fillBuffersFor( const HlmsCache *cache, 141 | const QueuedRenderable &queuedRenderable, 142 | bool casterPass, uint32 lastCacheHash, 143 | CommandBuffer *commandBuffer, bool isV1 ); 144 | 145 | public: 146 | HlmsOcean( Archive *dataFolder, ArchiveVec *libraryFolders ); 147 | virtual ~HlmsOcean(); 148 | 149 | virtual void _changeRenderSystem( RenderSystem *newRs ); 150 | 151 | /// Not supported 152 | virtual void setOptimizationStrategy( OptimizationStrategy optimizationStrategy ) {} 153 | 154 | virtual HlmsCache preparePassHash( const Ogre::CompositorShadowNode *shadowNode, 155 | bool casterPass, bool dualParaboloid, 156 | SceneManager *sceneManager ); 157 | 158 | virtual uint32 fillBuffersFor( const HlmsCache *cache, const QueuedRenderable &queuedRenderable, 159 | bool casterPass, uint32 lastCacheHash, 160 | uint32 lastTextureHash ); 161 | 162 | virtual uint32 fillBuffersForV1( const HlmsCache *cache, 163 | const QueuedRenderable &queuedRenderable, 164 | bool casterPass, uint32 lastCacheHash, 165 | CommandBuffer *commandBuffer ); 166 | virtual uint32 fillBuffersForV2( const HlmsCache *cache, 167 | const QueuedRenderable &queuedRenderable, 168 | bool casterPass, uint32 lastCacheHash, 169 | CommandBuffer *commandBuffer ); 170 | 171 | virtual void frameEnded(void); 172 | 173 | void setDebugPssmSplits( bool bDebug ); 174 | bool getDebugPssmSplits(void) const { return mDebugPssmSplits; } 175 | 176 | void setShadowSettings( ShadowFilter filter ); 177 | ShadowFilter getShadowFilter(void) const { return mShadowFilter; } 178 | 179 | void setAmbientLightMode( AmbientLightMode mode ); 180 | AmbientLightMode getAmbientLightMode(void) const { return mAmbientLightMode; } 181 | 182 | void setEnvProbe( Ogre::TexturePtr probe ); 183 | }; 184 | 185 | struct OceanProperty 186 | { 187 | static const IdString HwGammaRead; 188 | static const IdString HwGammaWrite; 189 | static const IdString SignedIntTex; 190 | static const IdString MaterialsPerBuffer; 191 | static const IdString DebugPssmSplits; 192 | 193 | static const IdString UseSkirts; 194 | 195 | static const char *EnvProbeMap; 196 | 197 | static const IdString FresnelScalar; 198 | static const IdString MetallicWorkflow; 199 | static const IdString ReceiveShadows; 200 | 201 | static const IdString DetailOffsets0; 202 | static const IdString DetailOffsets1; 203 | static const IdString DetailOffsets2; 204 | static const IdString DetailOffsets3; 205 | 206 | static const IdString DetailMapsDiffuse; 207 | static const IdString DetailMapsNormal; 208 | static const IdString FirstValidDetailMapNm; 209 | 210 | static const IdString Pcf3x3; 211 | static const IdString Pcf4x4; 212 | static const IdString PcfIterations; 213 | 214 | static const IdString EnvMapScale; 215 | static const IdString AmbientFixed; 216 | static const IdString AmbientHemisphere; 217 | 218 | static const IdString BrdfDefault; 219 | static const IdString BrdfCookTorrance; 220 | static const IdString BrdfBlinnPhong; 221 | static const IdString FresnelSeparateDiffuse; 222 | static const IdString GgxHeightCorrelated; 223 | 224 | static const IdString *DetailOffsetsPtrs[4]; 225 | }; 226 | 227 | /** @} */ 228 | /** @} */ 229 | 230 | } 231 | 232 | #include "OgreHeaderSuffix.h" 233 | 234 | #endif 235 | -------------------------------------------------------------------------------- /Hlms/src/Hlms/OgreHlmsOceanDatablock.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file is part of OGRE 4 | (Object-oriented Graphics Rendering Engine) 5 | For the latest info, see http://www.ogre3d.org/ 6 | 7 | Copyright (c) 2000-2014 Torus Knot Software Ltd 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in 17 | all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | THE SOFTWARE. 26 | ----------------------------------------------------------------------------- 27 | */ 28 | 29 | #include "Ocean/Hlms/OgreHlmsOceanDatablock.h" 30 | #include "Ocean/Hlms/OgreHlmsOcean.h" 31 | #include "OgreHlmsManager.h" 32 | #include "OgreHlmsTextureManager.h" 33 | #include "OgreTexture.h" 34 | #include "OgreTextureManager.h" 35 | #include "OgreLogManager.h" 36 | 37 | namespace Ogre 38 | { 39 | const size_t HlmsOceanDatablock::MaterialSizeInGpu = 4 * 2 * 4; 40 | const size_t HlmsOceanDatablock::MaterialSizeInGpuAligned = alignToNextMultiple( 41 | HlmsOceanDatablock::MaterialSizeInGpu, 42 | 4 * 4 ); 43 | 44 | //----------------------------------------------------------------------------------- 45 | HlmsOceanDatablock::HlmsOceanDatablock( IdString name, HlmsOcean *creator, 46 | const HlmsMacroblock *macroblock, 47 | const HlmsBlendblock *blendblock, 48 | const HlmsParamVec ¶ms ) : 49 | HlmsDatablock( name, creator, macroblock, blendblock, params ), 50 | mDeepColuorR( 0.0f ), mDeepColourG( 0.03f * 0.318309886f ), mDeepColourB( 0.05f * 0.318309886f ), //Max Diffuse = 1 / PI 51 | mShallowColourR( 0.0f ), mShallowColourG( 0.08f * 0.318309886f ), mShallowColourB( 0.1f * 0.318309886f ), //Max Diffuse = 1 / PI 52 | _padding0( 0 ), 53 | mWavesScale( 1.0 ), 54 | mBrdf( OceanBrdf::Default ) 55 | { 56 | calculateHash(); 57 | 58 | creator->requestSlot( /*mTextureHash*/0, this, false ); 59 | } 60 | //----------------------------------------------------------------------------------- 61 | HlmsOceanDatablock::~HlmsOceanDatablock() 62 | { 63 | if( mAssignedPool ) 64 | static_cast(mCreator)->releaseSlot( this ); 65 | } 66 | //----------------------------------------------------------------------------------- 67 | void HlmsOceanDatablock::calculateHash() 68 | { 69 | IdString hash; 70 | 71 | if( mTextureHash != hash.mHash ) 72 | { 73 | mTextureHash = hash.mHash; 74 | static_cast(mCreator)->requestSlot( /*mTextureHash*/0, this, false ); 75 | } 76 | } 77 | //----------------------------------------------------------------------------------- 78 | void HlmsOceanDatablock::scheduleConstBufferUpdate(void) 79 | { 80 | static_cast(mCreator)->scheduleForUpdate( this ); 81 | } 82 | //----------------------------------------------------------------------------------- 83 | void HlmsOceanDatablock::uploadToConstBuffer( char *dstPtr ) 84 | { 85 | memcpy( dstPtr, &mDeepColuorR, MaterialSizeInGpu ); 86 | } 87 | //----------------------------------------------------------------------------------- 88 | void HlmsOceanDatablock::setDeepColour( const Vector3 &deepColour ) 89 | { 90 | const float invPI = 0.318309886f; 91 | mDeepColuorR = deepColour.x * invPI; 92 | mDeepColourG = deepColour.y * invPI; 93 | mDeepColourB = deepColour.z * invPI; 94 | scheduleConstBufferUpdate(); 95 | } 96 | //----------------------------------------------------------------------------------- 97 | Vector3 HlmsOceanDatablock::getDeepColour(void) const 98 | { 99 | return Vector3( mDeepColuorR, mDeepColourG, mDeepColourB ) * Ogre::Math::PI; 100 | } 101 | //----------------------------------------------------------------------------------- 102 | void HlmsOceanDatablock::setShallowColour( const Vector3 &shallowColour ) 103 | { 104 | const float invPI = 0.318309886f; 105 | mShallowColourR = shallowColour.x * invPI; 106 | mShallowColourG = shallowColour.y * invPI; 107 | mShallowColourB = shallowColour.z * invPI; 108 | scheduleConstBufferUpdate(); 109 | } 110 | //----------------------------------------------------------------------------------- 111 | Vector3 HlmsOceanDatablock::getShallowColour(void) const 112 | { 113 | return Vector3( mShallowColourR, mShallowColourG, mShallowColourB ) * Ogre::Math::PI; 114 | } 115 | //----------------------------------------------------------------------------------- 116 | void HlmsOceanDatablock::setWavesScale( float scale ) 117 | { 118 | mWavesScale = scale; 119 | scheduleConstBufferUpdate(); 120 | } 121 | //----------------------------------------------------------------------------------- 122 | float HlmsOceanDatablock::getWavesScale() const 123 | { 124 | return mWavesScale; 125 | } 126 | //----------------------------------------------------------------------------------- 127 | void HlmsOceanDatablock::setAlphaTestThreshold( float threshold ) 128 | { 129 | OGRE_EXCEPT( Exception::ERR_NOT_IMPLEMENTED, 130 | "Alpha testing not supported on Ocean Hlms", 131 | "HlmsOceanDatablock::setAlphaTestThreshold" ); 132 | 133 | HlmsDatablock::setAlphaTestThreshold( threshold ); 134 | scheduleConstBufferUpdate(); 135 | } 136 | //----------------------------------------------------------------------------------- 137 | void HlmsOceanDatablock::setBrdf( OceanBrdf::OceanBrdf brdf ) 138 | { 139 | if( mBrdf != brdf ) 140 | { 141 | mBrdf = brdf; 142 | flushRenderables(); 143 | } 144 | } 145 | //----------------------------------------------------------------------------------- 146 | uint32 HlmsOceanDatablock::getBrdf(void) const 147 | { 148 | return mBrdf; 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /Hlms/src/Hlms/OgreHlmsOceanDatablock.h: -------------------------------------------------------------------------------- 1 | /* 2 | ----------------------------------------------------------------------------- 3 | This source file is part of OGRE 4 | (Object-oriented Graphics Rendering Engine) 5 | For the latest info, see http://www.ogre3d.org/ 6 | 7 | Copyright (c) 2000-2014 Torus Knot Software Ltd 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in 17 | all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | THE SOFTWARE. 26 | ----------------------------------------------------------------------------- 27 | */ 28 | #ifndef _OgreHlmsOceanDatablock_H_ 29 | #define _OgreHlmsOceanDatablock_H_ 30 | 31 | #include "OgreHlmsDatablock.h" 32 | #include "OgreHlmsTextureManager.h" 33 | #include "OgreConstBufferPool.h" 34 | #include "OgreVector4.h" 35 | #include "OgreHeaderPrefix.h" 36 | 37 | namespace Ogre 38 | { 39 | /** \addtogroup Core 40 | * @{ 41 | */ 42 | /** \addtogroup Resources 43 | * @{ 44 | */ 45 | 46 | namespace OceanBrdf 47 | { 48 | enum OceanBrdf 49 | { 50 | FLAG_UNCORRELATED = 0x80000000, 51 | FLAG_SPERATE_DIFFUSE_FRESNEL = 0x40000000, 52 | BRDF_MASK = 0x00000FFF, 53 | 54 | /// Most physically accurate BRDF we have. Good for representing 55 | /// the majority of materials. 56 | /// Uses: 57 | /// * Roughness/Distribution/NDF term: GGX 58 | /// * Geometric/Visibility term: Smith GGX Height-Correlated 59 | /// * Normalized Disney Diffuse BRDF,see 60 | /// "Moving Frostbite to Physically Based Rendering" from 61 | /// Sebastien Lagarde & Charles de Rousiers 62 | Default = 0x00000000, 63 | 64 | /// Implements Cook-Torrance BRDF. 65 | /// Uses: 66 | /// * Roughness/Distribution/NDF term: Beckmann 67 | /// * Geometric/Visibility term: Cook-Torrance 68 | /// * Lambertian Diffuse. 69 | /// 70 | /// Ideal for silk (use high roughness values), synthetic fabric 71 | CookTorrance = 0x00000001, 72 | 73 | /// Implements Normalized Blinn Phong using a normalization 74 | /// factor of (n + 8) / (8 * pi) 75 | /// The main reason to use this BRDF is performance. It's cheap. 76 | BlinnPhong = 0x00000002, 77 | 78 | /// Same as Default, but the geometry term is not height-correlated 79 | /// which most notably causes edges to be dimmer and is less correct. 80 | /// Unity (Marmoset too?) use an uncorrelated term, so you may want to 81 | /// use this BRDF to get the closest look for a nice exchangeable 82 | /// pipeline workflow. 83 | DefaultUncorrelated = Default|FLAG_UNCORRELATED, 84 | 85 | /// Same as Default but the fresnel of the diffuse is calculated 86 | /// differently. Normally the diffuse component would be multiplied against 87 | /// the inverse of the specular's fresnel to maintain energy conservation. 88 | /// This has the nice side effect that to achieve a perfect mirror effect, 89 | /// you just need to raise the fresnel term to 1; which is very intuitive 90 | /// to artists (specially if using coloured fresnel) 91 | /// 92 | /// When using this BRDF, the diffuse fresnel will be calculated differently, 93 | /// causing the diffuse component to still affect the colour even when 94 | /// the fresnel = 1 (although subtly). To achieve a perfect mirror you will 95 | /// have to set the fresnel to 1 *and* the diffuse colour to black; 96 | /// which can be unintuitive for artists. 97 | /// 98 | /// This BRDF is very useful for representing surfaces with complex refractions 99 | /// and reflections like glass, transparent plastics, fur, and surface with 100 | /// refractions and multiple rescattering that cannot be represented well 101 | /// with the default BRDF. 102 | DefaultSeparateDiffuseFresnel = Default|FLAG_SPERATE_DIFFUSE_FRESNEL, 103 | 104 | /// @see DefaultSeparateDiffuseFresnel. This is the same 105 | /// but the Cook Torrance model is used instead. 106 | /// 107 | /// Ideal for shiny objects like glass toy marbles, some types of rubber. 108 | /// silk, synthetic fabric. 109 | CookTorranceSeparateDiffuseFresnel = CookTorrance|FLAG_SPERATE_DIFFUSE_FRESNEL, 110 | 111 | BlinnPhongSeparateDiffuseFresnel = BlinnPhong|FLAG_SPERATE_DIFFUSE_FRESNEL, 112 | }; 113 | } 114 | 115 | /** Contains information needed by Ocean (Physically Based Shading) for OpenGL 3+ & D3D11+ 116 | */ 117 | class HlmsOceanDatablock : public HlmsDatablock, public ConstBufferPoolUser 118 | { 119 | friend class HlmsOcean; 120 | 121 | protected: 122 | float mDeepColuorR, mDeepColourG, mDeepColourB; 123 | float _padding0; 124 | float mShallowColourR, mShallowColourG, mShallowColourB; 125 | float mWavesScale; 126 | 127 | /// @see OceanBrdf::OceanBrdf 128 | uint32 mBrdf; 129 | 130 | void scheduleConstBufferUpdate(void); 131 | virtual void uploadToConstBuffer( char *dstPtr ); 132 | 133 | public: 134 | HlmsOceanDatablock( IdString name, HlmsOcean *creator, 135 | const HlmsMacroblock *macroblock, 136 | const HlmsBlendblock *blendblock, 137 | const HlmsParamVec ¶ms ); 138 | virtual ~HlmsOceanDatablock(); 139 | 140 | void setDeepColour( const Vector3 &deepColour ); 141 | Vector3 getDeepColour(void) const; 142 | 143 | void setShallowColour( const Vector3 &shallowColour ); 144 | Vector3 getShallowColour(void) const; 145 | 146 | void setWavesScale( float scale ); 147 | float getWavesScale() const; 148 | 149 | /// Overloaded to tell it's unsupported 150 | virtual void setAlphaTestThreshold( float threshold ); 151 | 152 | /// Changes the BRDF in use. Calling this function may trigger an 153 | /// HlmsDatablock::flushRenderables 154 | void setBrdf( OceanBrdf::OceanBrdf brdf ); 155 | uint32 getBrdf(void) const; 156 | 157 | virtual void calculateHash(); 158 | 159 | static const size_t MaterialSizeInGpu; 160 | static const size_t MaterialSizeInGpuAligned; 161 | }; 162 | 163 | /** @} */ 164 | /** @} */ 165 | 166 | } 167 | 168 | #include "OgreHeaderSuffix.h" 169 | 170 | #endif 171 | -------------------------------------------------------------------------------- /Hlms/src/Ocean.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Ocean/Ocean.h" 3 | 4 | #include "OgreImage.h" 5 | #include "OgreTextureManager.h" 6 | #include "OgreHardwarePixelBuffer.h" 7 | 8 | #include "OgreCamera.h" 9 | #include "OgreSceneManager.h" 10 | #include "Compositor/OgreCompositorManager2.h" 11 | #include "Compositor/OgreCompositorWorkspace.h" 12 | #include "Compositor/OgreCompositorChannel.h" 13 | #include "OgreMaterialManager.h" 14 | #include "OgreTechnique.h" 15 | #include "OgreRenderTexture.h" 16 | 17 | namespace Ogre 18 | { 19 | Ocean::Ocean( IdType id, ObjectMemoryManager *objectMemoryManager, 20 | SceneManager *sceneManager, uint8 renderQueueId, 21 | CompositorManager2 *compositorManager, Camera *camera ) : 22 | MovableObject( id, objectMemoryManager, sceneManager, renderQueueId ), 23 | m_width( 0u ), 24 | m_depth( 0u ), 25 | m_depthWidthRatio( 1.0f ), 26 | m_invWidth( 1.0f ), 27 | m_invDepth( 1.0f ), 28 | m_uvScale( 1.0f ), 29 | m_xzDimensions( Vector2::UNIT_SCALE ), 30 | m_xzInvDimensions( Vector2::UNIT_SCALE ), 31 | m_xzRelativeSize( Vector2::UNIT_SCALE ), 32 | m_height( 1.0f ), 33 | m_WavesIntensity( 0.5f ), 34 | m_OceanOrigin( Vector3::ZERO ), 35 | m_basePixelDimension( 256u ), 36 | m_currentCell( 0u ), 37 | m_prevLightDir( Vector3::ZERO ), 38 | m_compositorManager( compositorManager ), 39 | m_camera( camera ) 40 | { 41 | } 42 | //----------------------------------------------------------------------------------- 43 | Ocean::~Ocean() 44 | { 45 | m_OceanCells.clear(); 46 | } 47 | //----------------------------------------------------------------------------------- 48 | inline OceanGridPoint Ocean::worldToGrid( const Vector3 &vPos ) const 49 | { 50 | OceanGridPoint retVal; 51 | const float fWidth = static_cast( m_width ); 52 | const float fDepth = static_cast( m_depth ); 53 | 54 | retVal.x = (uint32)floorf( ((vPos.x - m_OceanOrigin.x) * m_xzInvDimensions.x) * fWidth ); 55 | retVal.z = (uint32)floorf( ((vPos.z - m_OceanOrigin.z) * m_xzInvDimensions.y) * fDepth ); 56 | 57 | return retVal; 58 | } 59 | //----------------------------------------------------------------------------------- 60 | inline Vector2 Ocean::gridToWorld( const OceanGridPoint &gPos ) const 61 | { 62 | Vector2 retVal; 63 | const float fWidth = static_cast( m_width ); 64 | const float fDepth = static_cast( m_depth ); 65 | 66 | retVal.x = (gPos.x / fWidth) * m_xzDimensions.x + m_OceanOrigin.x; 67 | retVal.y = (gPos.z / fDepth) * m_xzDimensions.y + m_OceanOrigin.z; 68 | 69 | return retVal; 70 | } 71 | //----------------------------------------------------------------------------------- 72 | bool Ocean::isVisible( const OceanGridPoint &gPos, const OceanGridPoint &gSize ) const 73 | { 74 | if( gPos.x >= static_cast( m_width ) || 75 | gPos.z >= static_cast( m_depth ) || 76 | gPos.x + gSize.x <= 0 || 77 | gPos.z + gSize.z <= 0 ) 78 | { 79 | //Outside Ocean bounds. 80 | return false; 81 | } 82 | 83 | // return true; 84 | 85 | const Vector2 cellPos = gridToWorld( gPos ); 86 | const Vector2 cellSize( (gSize.x + 1u) * m_xzRelativeSize.x, 87 | (gSize.z + 1u) * m_xzRelativeSize.y ); 88 | 89 | const Vector3 vHalfSize = Vector3( cellSize.x, m_height, cellSize.y ) * 0.5f; 90 | const Vector3 vCenter = Vector3( cellPos.x, m_OceanOrigin.y, cellPos.y ) + vHalfSize; 91 | 92 | for( int i=0; i<6; ++i ) 93 | { 94 | //Skip far plane if view frustum is infinite 95 | if( i == FRUSTUM_PLANE_FAR && m_camera->getFarClipDistance() == 0 ) 96 | continue; 97 | 98 | Plane::Side side = m_camera->getFrustumPlane(i).getSide( vCenter, vHalfSize ); 99 | 100 | //We only need one negative match to know the obj is outside the frustum 101 | if( side == Plane::NEGATIVE_SIDE ) 102 | return false; 103 | } 104 | 105 | return true; 106 | } 107 | //----------------------------------------------------------------------------------- 108 | void Ocean::addRenderable( const OceanGridPoint &gridPos, const OceanGridPoint &cellSize, uint32 lodLevel ) 109 | { 110 | OceanCell *cell = &m_OceanCells[m_currentCell++]; 111 | cell->setOrigin( gridPos, cellSize.x, cellSize.z, lodLevel ); 112 | m_collectedCells[0].push_back( cell ); 113 | } 114 | //----------------------------------------------------------------------------------- 115 | void Ocean::optimizeCellsAndAdd(void) 116 | { 117 | //Keep iterating until m_collectedCells[0] stops shrinking 118 | size_t numCollectedCells = std::numeric_limits::max(); 119 | while( numCollectedCells != m_collectedCells[0].size() ) 120 | { 121 | numCollectedCells = m_collectedCells[0].size(); 122 | 123 | if( m_collectedCells[0].size() > 1 ) 124 | { 125 | m_collectedCells[1].clear(); 126 | 127 | std::vector::const_iterator itor = m_collectedCells[0].begin(); 128 | std::vector::const_iterator end = m_collectedCells[0].end(); 129 | 130 | while( end - itor >= 2u ) 131 | { 132 | OceanCell *currCell = *itor; 133 | OceanCell *nextCell = *(itor+1); 134 | 135 | m_collectedCells[1].push_back( currCell ); 136 | if( currCell->merge( nextCell ) ) 137 | itor += 2; 138 | else 139 | ++itor; 140 | } 141 | 142 | while( itor != end ) 143 | m_collectedCells[1].push_back( *itor++ ); 144 | 145 | m_collectedCells[1].swap( m_collectedCells[0] ); 146 | } 147 | } 148 | 149 | std::vector::const_iterator itor = m_collectedCells[0].begin(); 150 | std::vector::const_iterator end = m_collectedCells[0].end(); 151 | while( itor != end ) 152 | mRenderables.push_back( *itor++ ); 153 | 154 | m_collectedCells[0].clear(); 155 | } 156 | //----------------------------------------------------------------------------------- 157 | void Ocean::update() 158 | { 159 | m_height = m_WavesIntensity*0.9 + 0.1; //from 10% to 100%, less than 10 looks too flat 160 | 161 | mRenderables.clear(); 162 | m_currentCell = 0; 163 | 164 | Vector3 camPos = m_camera->getDerivedPosition(); 165 | 166 | const uint32 basePixelDimension = m_basePixelDimension; 167 | const uint32 vertPixelDimension = static_cast(m_basePixelDimension * m_depthWidthRatio); 168 | 169 | OceanGridPoint cellSize; 170 | cellSize.x = basePixelDimension; 171 | cellSize.z = vertPixelDimension; 172 | 173 | //Quantize the camera position to basePixelDimension steps 174 | OceanGridPoint camCenter = worldToGrid( camPos ); 175 | camCenter.x = (camCenter.x / basePixelDimension) * basePixelDimension; 176 | camCenter.z = (camCenter.z / vertPixelDimension) * vertPixelDimension; 177 | 178 | uint32 currentLod = 0; 179 | 180 | // camCenter.x = 64; 181 | // camCenter.z = 64; 182 | 183 | //LOD 0: Add full 4x4 grid 184 | for( int32 z=-2; z<2; ++z ) 185 | { 186 | for( int32 x=-2; x<2; ++x ) 187 | { 188 | OceanGridPoint pos = camCenter; 189 | pos.x += x * cellSize.x; 190 | pos.z += z * cellSize.z; 191 | 192 | if( isVisible( pos, cellSize ) ) 193 | addRenderable( pos, cellSize, currentLod ); 194 | } 195 | } 196 | 197 | optimizeCellsAndAdd(); 198 | 199 | m_currentCell = 16u; //The first 16 cells don't use skirts. 200 | 201 | const uint32 maxRes = std::max( m_width, m_depth ); 202 | //TODO: When we're too far (outside the Ocean), just display a 4x4 grid or something like that. 203 | 204 | size_t numObjectsAdded = std::numeric_limits::max(); 205 | //LOD n: Add 4x4 grid, ignore 2x2 center (which 206 | //is the same as saying the borders of the grid) 207 | while( numObjectsAdded != m_currentCell || 208 | (mRenderables.empty() && (1u << currentLod) <= maxRes) ) 209 | { 210 | numObjectsAdded = m_currentCell; 211 | 212 | cellSize.x <<= 1u; 213 | cellSize.z <<= 1u; 214 | ++currentLod; 215 | 216 | //Row 0 217 | { 218 | const int32 z = 1; 219 | for( int32 x=-2; x<2; ++x ) 220 | { 221 | OceanGridPoint pos = camCenter; 222 | pos.x += x * cellSize.x; 223 | pos.z += z * cellSize.z; 224 | 225 | if( isVisible( pos, cellSize ) ) 226 | addRenderable( pos, cellSize, currentLod ); 227 | } 228 | } 229 | //Row 3 230 | { 231 | const int32 z = -2; 232 | for( int32 x=-2; x<2; ++x ) 233 | { 234 | OceanGridPoint pos = camCenter; 235 | pos.x += x * cellSize.x; 236 | pos.z += z * cellSize.z; 237 | 238 | if( isVisible( pos, cellSize ) ) 239 | addRenderable( pos, cellSize, currentLod ); 240 | } 241 | } 242 | //Cells [0, 1] & [0, 2]; 243 | { 244 | const int32 x = -2; 245 | for( int32 z=-1; z<1; ++z ) 246 | { 247 | OceanGridPoint pos = camCenter; 248 | pos.x += x * cellSize.x; 249 | pos.z += z * cellSize.z; 250 | 251 | if( isVisible( pos, cellSize ) ) 252 | addRenderable( pos, cellSize, currentLod ); 253 | } 254 | } 255 | //Cells [3, 1] & [3, 2]; 256 | { 257 | const int32 x = 1; 258 | for( int32 z=-1; z<1; ++z ) 259 | { 260 | OceanGridPoint pos = camCenter; 261 | pos.x += x * cellSize.x; 262 | pos.z += z * cellSize.z; 263 | 264 | if( isVisible( pos, cellSize ) ) 265 | addRenderable( pos, cellSize, currentLod ); 266 | } 267 | } 268 | 269 | optimizeCellsAndAdd(); 270 | } 271 | } 272 | //----------------------------------------------------------------------------------- 273 | void Ocean::create( const Vector3 center, const Vector2 &dimensions ) 274 | { 275 | m_OceanOrigin = center - Ogre::Vector3( dimensions.x, 0, dimensions.y ) * 0.5f; 276 | m_xzDimensions = dimensions; 277 | m_xzInvDimensions = 1.0f / m_xzDimensions; 278 | m_basePixelDimension = 64u; 279 | 280 | m_width = 4096; 281 | m_depth = 4096; 282 | m_depthWidthRatio = m_depth / (float)(m_width); 283 | m_invWidth = 1.0f / m_width; 284 | m_invDepth = 1.0f / m_depth; 285 | 286 | m_xzRelativeSize = m_xzDimensions / Vector2( static_cast(m_width), 287 | static_cast(m_depth) ); 288 | 289 | { 290 | //Find out how many OceanCells we need. I think this might be 291 | //solved analitically with a power series. But my math is rusty. 292 | const uint32 basePixelDimension = m_basePixelDimension; 293 | const uint32 vertPixelDimension = static_cast( m_basePixelDimension * 294 | m_depthWidthRatio ); 295 | const uint32 maxPixelDimension = std::max( basePixelDimension, vertPixelDimension ); 296 | const uint32 maxRes = std::max( m_width, m_depth ); 297 | 298 | uint32 numCells = 16u; //4x4 299 | uint32 accumDim = 0u; 300 | uint32 iteration = 1u; 301 | while( accumDim < maxRes ) 302 | { 303 | numCells += 12u; //4x4 - 2x2 304 | accumDim += maxPixelDimension * (1u << iteration); 305 | ++iteration; 306 | } 307 | 308 | numCells += 12u; 309 | accumDim += maxPixelDimension * (1u << iteration); 310 | ++iteration; 311 | 312 | m_OceanCells.clear(); 313 | m_OceanCells.resize( numCells, OceanCell( this ) ); 314 | } 315 | 316 | VaoManager *vaoManager = mManager->getDestinationRenderSystem()->getVaoManager(); 317 | std::vector::iterator itor = m_OceanCells.begin(); 318 | std::vector::iterator end = m_OceanCells.end(); 319 | 320 | const std::vector::iterator begin = itor; 321 | 322 | while( itor != end ) 323 | { 324 | itor->initialize( vaoManager, (itor - begin) >= 16u ); 325 | ++itor; 326 | } 327 | } 328 | //----------------------------------------------------------------------------------- 329 | void Ocean::setWavesIntensity( float intensity ){ 330 | m_WavesIntensity = intensity; 331 | } 332 | //----------------------------------------------------------------------------------- 333 | void Ocean::setWavesScale( float scale ){ 334 | m_uvScale = 1.0f/scale; 335 | } 336 | //----------------------------------------------------------------------------------- 337 | void Ocean::setDatablock( HlmsDatablock *datablock ) 338 | { 339 | std::vector::iterator itor = m_OceanCells.begin(); 340 | std::vector::iterator end = m_OceanCells.end(); 341 | 342 | while( itor != end ) 343 | { 344 | itor->setDatablock( datablock ); 345 | ++itor; 346 | } 347 | } 348 | //----------------------------------------------------------------------------------- 349 | const String& Ocean::getMovableType(void) const 350 | { 351 | static const String movType = "Ocean"; 352 | return movType; 353 | } 354 | } 355 | -------------------------------------------------------------------------------- /Hlms/src/Ocean.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _OgreOcean_H_ 3 | #define _OgreOcean_H_ 4 | 5 | #include "OgrePrerequisites.h" 6 | #include "OgreMovableObject.h" 7 | #include "OgreShaderParams.h" 8 | 9 | #include "Ocean/OceanCell.h" 10 | 11 | namespace Ogre 12 | { 13 | struct OceanGridPoint 14 | { 15 | int32 x; 16 | int32 z; 17 | }; 18 | 19 | struct OceanGridDirection 20 | { 21 | int x; 22 | int z; 23 | }; 24 | 25 | 26 | class Ocean : public MovableObject 27 | { 28 | friend class OceanCell; 29 | 30 | std::vector m_heightMap; 31 | uint32 m_width; 32 | uint32 m_depth; //PNG's Height 33 | float m_depthWidthRatio; 34 | float m_invWidth; 35 | float m_invDepth; 36 | float m_uvScale; 37 | 38 | Vector2 m_xzDimensions; 39 | Vector2 m_xzInvDimensions; 40 | Vector2 m_xzRelativeSize; // m_xzDimensions / [m_width, m_height] 41 | float m_height; 42 | float m_WavesIntensity; 43 | Vector3 m_OceanOrigin; 44 | uint32 m_basePixelDimension; 45 | 46 | std::vector m_OceanCells; 47 | std::vector m_collectedCells[2]; 48 | size_t m_currentCell; 49 | 50 | Ogre::TexturePtr m_heightMapTex; 51 | Ogre::TexturePtr m_normalMapTex; 52 | 53 | Vector3 m_prevLightDir; 54 | 55 | //Ogre stuff 56 | CompositorManager2 *m_compositorManager; 57 | Camera *m_camera; 58 | 59 | inline OceanGridPoint worldToGrid( const Vector3 &vPos ) const; 60 | inline Vector2 gridToWorld( const OceanGridPoint &gPos ) const; 61 | 62 | bool isVisible( const OceanGridPoint &gPos, const OceanGridPoint &gSize ) const; 63 | 64 | void addRenderable( const OceanGridPoint &gridPos, const OceanGridPoint &cellSize, uint32 lodLevel ); 65 | 66 | void optimizeCellsAndAdd(void); 67 | 68 | public: 69 | Ocean( IdType id, ObjectMemoryManager *objectMemoryManager, SceneManager *sceneManager, 70 | uint8 renderQueueId, CompositorManager2 *compositorManager, Camera *camera ); 71 | ~Ocean(); 72 | 73 | /** Must be called every frame so we can check the camera's position 74 | (passed in the constructor) and update our visible batches (and LODs). 75 | */ 76 | void update(); 77 | 78 | void create(const Vector3 center, const Vector2 &dimensions); 79 | 80 | void setWavesIntensity( float intensity ); 81 | 82 | void setWavesScale( float scale ); 83 | 84 | /// load must already have been called. 85 | void setDatablock( HlmsDatablock *datablock ); 86 | 87 | //MovableObject overloads 88 | const String& getMovableType(void) const; 89 | 90 | Camera* getCamera() const { return m_camera; } 91 | void setCamera( Camera *camera ) { m_camera = camera; } 92 | 93 | const Vector2& getXZDimensions(void) const { return m_xzDimensions; } 94 | const Vector2& getXZInvDimensions(void) const { return m_xzInvDimensions; } 95 | const Vector3& getOceanOrigin(void) const { return m_OceanOrigin; } 96 | }; 97 | } 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /Hlms/src/OceanCell.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Ocean/OceanCell.h" 3 | #include "Ocean/Ocean.h" 4 | 5 | #include "Vao/OgreVaoManager.h" 6 | #include "Vao/OgreVertexArrayObject.h" 7 | 8 | namespace Ogre 9 | { 10 | OceanCell::OceanCell( Ocean *parentOcean ) : 11 | m_gridX( 0 ), 12 | m_gridZ( 0 ), 13 | m_lodLevel( 0 ), 14 | m_verticesPerLine( 1 ), 15 | m_sizeX( 0 ), 16 | m_sizeZ( 0 ), 17 | m_vaoManager( 0 ), 18 | m_parentOcean( parentOcean ), 19 | m_useSkirts( false ) 20 | { 21 | } 22 | //----------------------------------------------------------------------------------- 23 | OceanCell::~OceanCell() 24 | { 25 | VertexArrayObjectArray::const_iterator itor = mVaoPerLod[VpNormal].begin(); 26 | VertexArrayObjectArray::const_iterator end = mVaoPerLod[VpNormal].end(); 27 | 28 | while( itor != end ) 29 | m_vaoManager->destroyVertexArrayObject( *itor++ ); 30 | 31 | mVaoPerLod[VpNormal].clear(); 32 | mVaoPerLod[VpShadow].clear(); 33 | } 34 | //----------------------------------------------------------------------------------- 35 | void OceanCell::initialize( VaoManager *vaoManager, bool useSkirts ) 36 | { 37 | assert( mVaoPerLod[VpNormal].empty() && "Already initialized!" ); 38 | m_vaoManager = vaoManager; 39 | m_useSkirts = useSkirts; 40 | 41 | //Setup bufferless vao 42 | VertexBufferPackedVec vertexBuffers; 43 | VertexArrayObject *vao = vaoManager->createVertexArrayObject( 44 | vertexBuffers, 0, OT_TRIANGLE_STRIP ); 45 | mVaoPerLod[VpNormal].push_back( vao ); 46 | mVaoPerLod[VpShadow].push_back( vao ); 47 | } 48 | //----------------------------------------------------------------------------------- 49 | void OceanCell::setOrigin( const OceanGridPoint &gridPos, uint32 horizontalPixelDim, 50 | uint32 verticalPixelDim, uint32 lodLevel ) 51 | { 52 | m_gridX = gridPos.x; 53 | m_gridZ = gridPos.z; 54 | m_lodLevel = lodLevel; 55 | 56 | horizontalPixelDim = std::min( horizontalPixelDim, m_parentOcean->m_width - m_gridX ); 57 | verticalPixelDim = std::min( verticalPixelDim, m_parentOcean->m_depth - m_gridZ ); 58 | 59 | m_sizeX = horizontalPixelDim; 60 | m_sizeZ = verticalPixelDim; 61 | 62 | //Divide by 2^lodLevel and round up 63 | horizontalPixelDim = (horizontalPixelDim + (1u << lodLevel) - 1u) >> lodLevel; 64 | verticalPixelDim = (verticalPixelDim + (1u << lodLevel) - 1u) >> lodLevel; 65 | 66 | //Add an extra vertex to fill the gaps to the next OceanCell. 67 | horizontalPixelDim += 1u; 68 | verticalPixelDim += 1u; 69 | 70 | horizontalPixelDim = std::max( horizontalPixelDim, 2u ); 71 | verticalPixelDim = std::max( verticalPixelDim, 2u ); 72 | 73 | if( m_useSkirts ) 74 | { 75 | //Add two extra vertices & two extra rows for the skirts. 76 | horizontalPixelDim += 2u; 77 | verticalPixelDim += 2u; 78 | } 79 | 80 | m_verticesPerLine = horizontalPixelDim * 2u + 2u; 81 | 82 | assert( m_verticesPerLine * (verticalPixelDim - 1u) > 0u ); 83 | 84 | VertexArrayObject *vao = mVaoPerLod[VpNormal][0]; 85 | vao->setPrimitiveRange( 0, m_verticesPerLine * (verticalPixelDim - 1u) ); 86 | } 87 | //----------------------------------------------------------------------- 88 | bool OceanCell::merge( OceanCell *next ) 89 | { 90 | bool merged = false; 91 | 92 | if( m_lodLevel == next->m_lodLevel ) 93 | { 94 | OceanGridPoint pos; 95 | pos.x = m_gridX; 96 | pos.z = m_gridZ; 97 | uint32 horizontalPixelDim = m_sizeX; 98 | uint32 verticalPixelDim = m_sizeZ; 99 | 100 | if( (this->m_gridX + this->m_sizeX == next->m_gridX || 101 | next->m_gridX + next->m_sizeX == this->m_gridX) && 102 | m_gridZ == next->m_gridZ && m_sizeZ == next->m_sizeZ ) 103 | { 104 | //Merge horizontally 105 | pos.x = std::min( m_gridX, next->m_gridX ); 106 | horizontalPixelDim += next->m_sizeX; 107 | 108 | this->setOrigin( pos, horizontalPixelDim, verticalPixelDim, m_lodLevel ); 109 | merged = true; 110 | } 111 | else if( (this->m_gridZ + this->m_sizeZ == next->m_gridZ || 112 | next->m_gridZ + next->m_sizeZ == this->m_gridZ) && 113 | m_gridX == next->m_gridX && m_sizeX == next->m_sizeX ) 114 | { 115 | //Merge vertically 116 | pos.z = std::min( m_gridZ, next->m_gridZ ); 117 | verticalPixelDim += next->m_sizeZ; 118 | 119 | this->setOrigin( pos, horizontalPixelDim, verticalPixelDim, m_lodLevel ); 120 | merged = true; 121 | } 122 | } 123 | 124 | return merged; 125 | } 126 | //----------------------------------------------------------------------- 127 | void OceanCell::uploadToGpu( uint32 * RESTRICT_ALIAS gpuPtr ) const 128 | { 129 | //uint32 rows = (m_sizeZ + (1u << m_lodLevel) - 1u) >> m_lodLevel; 130 | VertexArrayObject *vao = mVaoPerLod[VpNormal][0]; 131 | 132 | //uvec4 numVertsPerLine 133 | gpuPtr[0] = m_verticesPerLine; 134 | gpuPtr[1] = m_lodLevel; 135 | gpuPtr[2] = vao->getPrimitiveCount() / m_verticesPerLine - 2u; 136 | gpuPtr[3] = *reinterpret_cast( &m_parentOcean->m_uvScale ); 137 | 138 | //ivec4 xzTexPosBounds 139 | ((int32*RESTRICT_ALIAS)gpuPtr)[4] = m_gridX; 140 | ((int32*RESTRICT_ALIAS)gpuPtr)[5] = m_gridZ; 141 | ((int32*RESTRICT_ALIAS)gpuPtr)[6] = m_parentOcean->m_width - 1u; 142 | ((int32*RESTRICT_ALIAS)gpuPtr)[7] = m_parentOcean->m_depth - 1u; 143 | 144 | ((float*RESTRICT_ALIAS)gpuPtr)[8] = m_parentOcean->m_OceanOrigin.x; 145 | ((float*RESTRICT_ALIAS)gpuPtr)[9] = m_parentOcean->m_OceanOrigin.y; 146 | ((float*RESTRICT_ALIAS)gpuPtr)[10] = m_parentOcean->m_OceanOrigin.z; 147 | ((float*RESTRICT_ALIAS)gpuPtr)[11] = m_parentOcean->m_invWidth; 148 | 149 | ((float*RESTRICT_ALIAS)gpuPtr)[12] = m_parentOcean->m_xzRelativeSize.x; 150 | ((float*RESTRICT_ALIAS)gpuPtr)[13] = m_parentOcean->m_height; 151 | ((float*RESTRICT_ALIAS)gpuPtr)[14] = m_parentOcean->m_xzRelativeSize.y; 152 | ((float*RESTRICT_ALIAS)gpuPtr)[15] = m_parentOcean->m_invDepth; 153 | } 154 | //----------------------------------------------------------------------- 155 | const LightList& OceanCell::getLights(void) const 156 | { 157 | return m_parentOcean->queryLights(); 158 | } 159 | //----------------------------------------------------------------------------- 160 | void OceanCell::getRenderOperation( v1::RenderOperation& op, bool casterPass ) 161 | { 162 | OGRE_EXCEPT( Exception::ERR_NOT_IMPLEMENTED, 163 | "Items do not implement getRenderOperation. You've put an Item in " 164 | "the wrong RenderQueue ID (which is set to be compatible with " 165 | "v1::Entity). Do not mix Items and Entities", 166 | "OceanCell::getRenderOperation" ); 167 | } 168 | //----------------------------------------------------------------------------- 169 | void OceanCell::getWorldTransforms(Matrix4* xform) const 170 | { 171 | OGRE_EXCEPT( Exception::ERR_NOT_IMPLEMENTED, 172 | "Items do not implement getWorldTransforms. You've put an Item in " 173 | "the wrong RenderQueue ID (which is set to be compatible with " 174 | "v1::Entity). Do not mix Items and Entities", 175 | "OceanCell::getWorldTransforms" ); 176 | } 177 | //----------------------------------------------------------------------------- 178 | bool OceanCell::getCastsShadows(void) const 179 | { 180 | OGRE_EXCEPT( Exception::ERR_NOT_IMPLEMENTED, 181 | "Items do not implement getCastsShadows. You've put an Item in " 182 | "the wrong RenderQueue ID (which is set to be compatible with " 183 | "v1::Entity). Do not mix Items and Entities", 184 | "OceanCell::getCastsShadows" ); 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /Hlms/src/OceanCell.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _OgreOceanCell_H_ 3 | #define _OgreOceanCell_H_ 4 | 5 | #include "OgrePrerequisites.h" 6 | #include "OgreRenderable.h" 7 | 8 | namespace Ogre 9 | { 10 | class Ocean; 11 | struct OceanGridPoint; 12 | 13 | class OceanCell : public Renderable 14 | { 15 | int32 m_gridX; 16 | int32 m_gridZ; 17 | uint32 m_lodLevel; 18 | uint32 m_verticesPerLine; 19 | 20 | uint32 m_sizeX; 21 | uint32 m_sizeZ; 22 | 23 | VaoManager *m_vaoManager; 24 | 25 | Ocean *m_parentOcean; 26 | 27 | bool m_useSkirts; 28 | 29 | public: 30 | OceanCell( Ocean *parentOcean ); 31 | virtual ~OceanCell(); 32 | 33 | bool getUseSkirts(void) const { return m_useSkirts; } 34 | 35 | void initialize( VaoManager *vaoManager, bool useSkirts ); 36 | 37 | void setOrigin( const OceanGridPoint &gridPos, uint32 horizontalPixelDim, 38 | uint32 verticalPixelDim, uint32 lodLevel ); 39 | 40 | /** Merges another OceanCell into 'this' for reducing batch counts. 41 | e.g. 42 | Two 32x32 cells will merge into one 64x32 or 32x64 43 | Two 64x32 cells will merge into one 64x64 44 | A 32x64 cell cannot merge with a 32x32 one. 45 | A 64x32 cell cannot merge with a 32x32 one. 46 | @remarks 47 | Merge will only happen if the cells are of the same LOD level and are contiguous. 48 | @param next 49 | The other OceanCell to merge with. 50 | @return 51 | False if couldn't merge, true on success. 52 | */ 53 | bool merge( OceanCell *next ); 54 | 55 | void uploadToGpu( uint32 * RESTRICT_ALIAS gpuPtr ) const; 56 | 57 | //Renderable overloads 58 | virtual const LightList& getLights(void) const; 59 | virtual void getRenderOperation( v1::RenderOperation& op, bool casterPass ); 60 | virtual void getWorldTransforms( Matrix4* xform ) const; 61 | virtual bool getCastsShadows(void) const; 62 | }; 63 | } 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /Hlms/textures/oceanData.dds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoyTeam/OgreOcean/b3646b7ca86f6d31d60ea4719c38618297a7f2b3/Hlms/textures/oceanData.dds -------------------------------------------------------------------------------- /Hlms/textures/weight.dds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoyTeam/OgreOcean/b3646b7ca86f6d31d60ea4719c38618297a7f2b3/Hlms/textures/weight.dds --------------------------------------------------------------------------------