• Breaking News

    Forward+ - problem with calculating frustum for tile Hello, I have started implementing forward+ rendering to my own graphic engine and I've noticed a problem. Only half of the screen "see" my point lights. In my opinion a problem is: in calculating frustum for specific tile or in calculating depth from the depth buffer. Here is my code for calculating frustum for specific tile: //Four planes of a view frustum (in view space). //The planes are: // * Left, // * Right, // * Top, // * Bottom. //The back and/or front planes can be computed from depth values in the //light culling compute shader. struct Frustum { vec4 planes[4]; //left, right, top, bottom frustum planes. }; //Convert clip space coordinates to view space vec4 clipToView(vec4 tmp_clip, mat4 tmp_invProjMatrix) { //View space position. vec4 tmp_view = tmp_invProjMatrix * tmp_clip; //Perspective projection. tmp_view = tmp_view / tmp_view.w; return tmp_view; } //Convert screen space coordinates to view space. vec4 screenToView(vec4 tmp_screen, vec2 tmp_screenSize, mat4 tmp_invProjMatrix) { //Convert to normalized texture coordinates vec2 tmp_texCoord = tmp_screen.xy / tmp_screenSize; // Convert to clip space vec4 tmp_clip = vec4(vec2(tmp_texCoord.x, 1.0f - tmp_texCoord.y) * 2.0f - 1.0f, tmp_screen.z, tmp_screen.w); return clipToView(tmp_clip, tmp_invProjMatrix); } vec4 computePlane(vec3 tmp_p0, vec3 tmp_p1, vec3 tmp_p2) { vec4 tmp_plane; vec3 tmp_v0 = tmp_p1 - tmp_p0; vec3 tmp_v2 = tmp_p2 - tmp_p0; tmp_plane.xyz = normalize(cross(tmp_v0, tmp_v2)); //Compute the distance to the origin using p0. tmp_plane.w = dot(tmp_plane.xyz, tmp_p0); return tmp_plane; } Frustum calculateFrustumForGroup(int tmp_pixelPerTile, ivec2 tmp_dispatchThreadID, vec2 tmp_screenSize, mat4 tmp_invProjMatrix) { vec3 tmp_eyePos = vec3(0, 0, 0); //Compute the 4 corner points on the far clipping plane to use as the //frustum vertices. vec4 tmp_screenSpace[4]; //Top left point tmp_screenSpace[0] = vec4(tmp_dispatchThreadID.xy * tmp_pixelPerTile, -1.0f, 1.0f); //Top right point tmp_screenSpace[1] = vec4(vec2(tmp_dispatchThreadID.x + 1, tmp_dispatchThreadID.y) * tmp_pixelPerTile, -1.0f, 1.0f); //Bottom left point tmp_screenSpace[2] = vec4(vec2(tmp_dispatchThreadID.x, tmp_dispatchThreadID.y + 1) * tmp_pixelPerTile, -1.0f, 1.0f); //Bottom right point tmp_screenSpace[3] = vec4(vec2(tmp_dispatchThreadID.x + 1, tmp_dispatchThreadID.y + 1) * tmp_pixelPerTile, -1.0f, 1.0f); vec3 tmp_viewSpace[4]; //Now convert the screen space points to view space for(int i = 0; i < 4; i++) { tmp_viewSpace[i] = screenToView(tmp_screenSpace[i], tmp_screenSize, tmp_invProjMatrix).xyz; } //Now build the frustum planes from the view space points Frustum tmp_frustum; //Left plane tmp_frustum.planes[0] = computePlane(tmp_eyePos, tmp_viewSpace[2], tmp_viewSpace[0]); //Right plane tmp_frustum.planes[1] = computePlane(tmp_eyePos, tmp_viewSpace[1], tmp_viewSpace[3]); //Top plane tmp_frustum.planes[2] = computePlane(tmp_eyePos, tmp_viewSpace[0], tmp_viewSpace[1]); //Bottom plane tmp_frustum.planes[3] = computePlane(tmp_eyePos, tmp_viewSpace[3], tmp_viewSpace[2]); return tmp_frustum; } Next here is my code to check if specific light is inside tile frustum: struct Sphere { vec3 c; //Center point. float r; //Radius. }; struct Cone { vec3 T; //Cone tip. float h; //Height of the cone. vec3 d; //Direction of the cone. float r; //bottom radius of the cone. }; //Check to see if a sphere is fully behind (inside the negative halfspace of) a plane. //Source: Real-time collision detection, Christer Ericson (2005) bool SphereInsidePlane(Sphere sphere, vec4 plane) { return dot(plane.xyz, sphere.c) - plane.w < -sphere.r; } //Check to see if a point is fully behind (inside the negative halfspace of) a plane. bool PointInsidePlane(vec3 p, vec4 plane) { return dot(plane.xyz, p) - plane.w < 0; } //Check to see if a cone if fully behind (inside the negative halfspace of) a plane. //Source: Real-time collision detection, Christer Ericson (2005) bool ConeInsidePlane(Cone cone, vec4 plane) { //Compute the farthest point on the end of the cone to the positive space of the plane. vec3 m = cross(cross(plane.xyz, cone.d), cone.d); vec3 Q = cone.T + cone.d * cone.h - m * cone.r; //The cone is in the negative halfspace of the plane if both //the tip of the cone and the farthest point on the end of the cone to the //positive halfspace of the plane are both inside the negative halfspace //of the plane. return PointInsidePlane(cone.T, plane) && PointInsidePlane(Q, plane); } //Check to see of a light is partially contained within the frustum. bool SphereInsideFrustum(Sphere sphere, Frustum frustum, float zNear, float zFar) { bool result = true; //First check depth //Note: Here, the view vector points in the -Z axis so the //far depth value will be approaching -infinity. if(sphere.c.z - sphere.r > zNear || sphere.c.z + sphere.r < zFar) { result = false; } //Then check frustum planes for(int i = 0; i < 4 && result; i++) { if(SphereInsidePlane( sphere, frustum.planes[i])) { result = false; } } return result; } bool ConeInsideFrustum(Cone cone, Frustum frustum, float zNear, float zFar) { bool result = true; vec4 nearPlane = vec4(0.0, 0.0, -1.0, -zNear); vec4 farPlane = vec4(0.0, 0.0, 1.0, zFar); // First check the near and far clipping planes. if(ConeInsidePlane(cone, nearPlane) || ConeInsidePlane(cone, farPlane)) { result = false; } // Then check frustum planes for(int i = 0; i < 4 && result; i++) { if(ConeInsidePlane(cone, frustum.planes[i])) { result = false; } } return result; } And finally code to read depth from the depth buffer and check all lights: vec2 tmp_tex = vec2(dispatchThreadID) / u_screenSize; float tmp_depth = texture(u_depthMap, tmp_tex).r; uint tmp_uDepth = floatBitsToUint(tmp_depth); atomicMin(uMinDepth, tmp_uDepth); atomicMax(uMaxDepth, tmp_uDepth); barrier(); float fMinDepth = uintBitsToFloat(uMinDepth); float fMaxDepth = uintBitsToFloat(uMaxDepth); //Convert depth values to view space. float minDepthVS = screenToView(vec4(0, 0, fMinDepth, 1), u_screenSize, inv_ProjMatrix).z; float maxDepthVS = screenToView(vec4(0, 0, fMaxDepth, 1), u_screenSize, inv_ProjMatrix).z; float nearClipVS = screenToView(vec4(0, 0, 0, 1), u_screenSize, inv_ProjMatrix).z; //Clipping plane for minimum depth value //(used for testing lights within the bounds of opaque geometry). vec4 minPlane = vec4(0, 0, -1, -minDepthVS); //Cull lights //Each thread in a group will cull 1 light until all lights have been culled. for(uint i = groupIndex; i < u_lightCount; i += TILE_SIZE * TILE_SIZE) { Light currentLight = lightBuffer.data[i]; uint lightType = uint(currentLight.type); switch(lightType) { case DIRECTIONAL_LIGHT_TYPE: { //Directional lights always get added to our light list. //(Hopefully there are not too many directional lights!) t_appendLight(i); o_appendLight(i); } break; case POINT_LIGHT_TYPE: { vec3 lightPos = vec3(currentLight.position[0], currentLight.position[1], currentLight.position[2]); Sphere sphere = {lightPos, currentLight.radius}; if(SphereInsideFrustum(sphere, GroupFrustum, nearClipVS, maxDepthVS)) { //Add light to light list for transparent geometry. t_appendLight(i); if(!SphereInsidePlane(sphere, minPlane)) { //Add light to light list for opaque geometry. o_appendLight(i); } } } break; case SPOT_LIGHT_TYPE: { vec3 lightPos = vec3(currentLight.position[0], currentLight.position[1], currentLight.position[2]); vec3 lightDir = vec3(currentLight.direction[0], currentLight.direction[1], currentLight.direction[2]); float coneRadius = tan(radians(currentLight.outerAngle)) * currentLight.radius; Cone cone = {lightPos, currentLight.radius, lightDir, coneRadius}; if(ConeInsideFrustum(cone, GroupFrustum, nearClipVS, maxDepthVS)) { //Add light to light list for transparent geometry. t_appendLight(i); if(!ConeInsidePlane(cone, minPlane)) { // Add light to light list for opaque geometry. o_appendLight(i); } } } break; } } My code is based on: https://ift.tt/2sn7N1s and I have tried to convert directx code to OpenGL. Any help will be appreciate (sorry for my bad english) https://ift.tt/eA8V8J

    Hello, I have started implementing forward+ rendering to my own graphic engine and I've noticed a problem. Only half of the screen "see" my point lights. In my opinion a problem is: in calculating frustum for specific tile or in calculating depth from the depth buffer. Here is my code for calculating frustum for specific tile: //Four planes of a view frustum (in view space). //The planes are: // * Left, // * Right, // * Top, // * Bottom. //The back and/or front planes can be computed from depth values in the //light culling compute shader. struct Frustum { vec4 planes[4]; //left, right, top, bottom frustum planes. }; //Convert clip space coordinates to view space vec4 clipToView(vec4 tmp_clip, mat4 tmp_invProjMatrix) { //View space position. vec4 tmp_view = tmp_invProjMatrix * tmp_clip; //Perspective projection. tmp_view = tmp_view / tmp_view.w; return tmp_view; } //Convert screen space coordinates to view space. vec4 screenToView(vec4 tmp_screen, vec2 tmp_screenSize, mat4 tmp_invProjMatrix) { //Convert to normalized texture coordinates vec2 tmp_texCoord = tmp_screen.xy / tmp_screenSize; // Convert to clip space vec4 tmp_clip = vec4(vec2(tmp_texCoord.x, 1.0f - tmp_texCoord.y) * 2.0f - 1.0f, tmp_screen.z, tmp_screen.w); return clipToView(tmp_clip, tmp_invProjMatrix); } vec4 computePlane(vec3 tmp_p0, vec3 tmp_p1, vec3 tmp_p2) { vec4 tmp_plane; vec3 tmp_v0 = tmp_p1 - tmp_p0; vec3 tmp_v2 = tmp_p2 - tmp_p0; tmp_plane.xyz = normalize(cross(tmp_v0, tmp_v2)); //Compute the distance to the origin using p0. tmp_plane.w = dot(tmp_plane.xyz, tmp_p0); return tmp_plane; } Frustum calculateFrustumForGroup(int tmp_pixelPerTile, ivec2 tmp_dispatchThreadID, vec2 tmp_screenSize, mat4 tmp_invProjMatrix) { vec3 tmp_eyePos = vec3(0, 0, 0); //Compute the 4 corner points on the far clipping plane to use as the //frustum vertices. vec4 tmp_screenSpace[4]; //Top left point tmp_screenSpace[0] = vec4(tmp_dispatchThreadID.xy * tmp_pixelPerTile, -1.0f, 1.0f); //Top right point tmp_screenSpace[1] = vec4(vec2(tmp_dispatchThreadID.x + 1, tmp_dispatchThreadID.y) * tmp_pixelPerTile, -1.0f, 1.0f); //Bottom left point tmp_screenSpace[2] = vec4(vec2(tmp_dispatchThreadID.x, tmp_dispatchThreadID.y + 1) * tmp_pixelPerTile, -1.0f, 1.0f); //Bottom right point tmp_screenSpace[3] = vec4(vec2(tmp_dispatchThreadID.x + 1, tmp_dispatchThreadID.y + 1) * tmp_pixelPerTile, -1.0f, 1.0f); vec3 tmp_viewSpace[4]; //Now convert the screen space points to view space for(int i = 0; i < 4; i++) { tmp_viewSpace[i] = screenToView(tmp_screenSpace[i], tmp_screenSize, tmp_invProjMatrix).xyz; } //Now build the frustum planes from the view space points Frustum tmp_frustum; //Left plane tmp_frustum.planes[0] = computePlane(tmp_eyePos, tmp_viewSpace[2], tmp_viewSpace[0]); //Right plane tmp_frustum.planes[1] = computePlane(tmp_eyePos, tmp_viewSpace[1], tmp_viewSpace[3]); //Top plane tmp_frustum.planes[2] = computePlane(tmp_eyePos, tmp_viewSpace[0], tmp_viewSpace[1]); //Bottom plane tmp_frustum.planes[3] = computePlane(tmp_eyePos, tmp_viewSpace[3], tmp_viewSpace[2]); return tmp_frustum; } Next here is my code to check if specific light is inside tile frustum: struct Sphere { vec3 c; //Center point. float r; //Radius. }; struct Cone { vec3 T; //Cone tip. float h; //Height of the cone. vec3 d; //Direction of the cone. float r; //bottom radius of the cone. }; //Check to see if a sphere is fully behind (inside the negative halfspace of) a plane. //Source: Real-time collision detection, Christer Ericson (2005) bool SphereInsidePlane(Sphere sphere, vec4 plane) { return dot(plane.xyz, sphere.c) - plane.w < -sphere.r; } //Check to see if a point is fully behind (inside the negative halfspace of) a plane. bool PointInsidePlane(vec3 p, vec4 plane) { return dot(plane.xyz, p) - plane.w < 0; } //Check to see if a cone if fully behind (inside the negative halfspace of) a plane. //Source: Real-time collision detection, Christer Ericson (2005) bool ConeInsidePlane(Cone cone, vec4 plane) { //Compute the farthest point on the end of the cone to the positive space of the plane. vec3 m = cross(cross(plane.xyz, cone.d), cone.d); vec3 Q = cone.T + cone.d * cone.h - m * cone.r; //The cone is in the negative halfspace of the plane if both //the tip of the cone and the farthest point on the end of the cone to the //positive halfspace of the plane are both inside the negative halfspace //of the plane. return PointInsidePlane(cone.T, plane) && PointInsidePlane(Q, plane); } //Check to see of a light is partially contained within the frustum. bool SphereInsideFrustum(Sphere sphere, Frustum frustum, float zNear, float zFar) { bool result = true; //First check depth //Note: Here, the view vector points in the -Z axis so the //far depth value will be approaching -infinity. if(sphere.c.z - sphere.r > zNear || sphere.c.z + sphere.r < zFar) { result = false; } //Then check frustum planes for(int i = 0; i < 4 && result; i++) { if(SphereInsidePlane( sphere, frustum.planes[i])) { result = false; } } return result; } bool ConeInsideFrustum(Cone cone, Frustum frustum, float zNear, float zFar) { bool result = true; vec4 nearPlane = vec4(0.0, 0.0, -1.0, -zNear); vec4 farPlane = vec4(0.0, 0.0, 1.0, zFar); // First check the near and far clipping planes. if(ConeInsidePlane(cone, nearPlane) || ConeInsidePlane(cone, farPlane)) { result = false; } // Then check frustum planes for(int i = 0; i < 4 && result; i++) { if(ConeInsidePlane(cone, frustum.planes[i])) { result = false; } } return result; } And finally code to read depth from the depth buffer and check all lights: vec2 tmp_tex = vec2(dispatchThreadID) / u_screenSize; float tmp_depth = texture(u_depthMap, tmp_tex).r; uint tmp_uDepth = floatBitsToUint(tmp_depth); atomicMin(uMinDepth, tmp_uDepth); atomicMax(uMaxDepth, tmp_uDepth); barrier(); float fMinDepth = uintBitsToFloat(uMinDepth); float fMaxDepth = uintBitsToFloat(uMaxDepth); //Convert depth values to view space. float minDepthVS = screenToView(vec4(0, 0, fMinDepth, 1), u_screenSize, inv_ProjMatrix).z; float maxDepthVS = screenToView(vec4(0, 0, fMaxDepth, 1), u_screenSize, inv_ProjMatrix).z; float nearClipVS = screenToView(vec4(0, 0, 0, 1), u_screenSize, inv_ProjMatrix).z; //Clipping plane for minimum depth value //(used for testing lights within the bounds of opaque geometry). vec4 minPlane = vec4(0, 0, -1, -minDepthVS); //Cull lights //Each thread in a group will cull 1 light until all lights have been culled. for(uint i = groupIndex; i < u_lightCount; i += TILE_SIZE * TILE_SIZE) { Light currentLight = lightBuffer.data[i]; uint lightType = uint(currentLight.type); switch(lightType) { case DIRECTIONAL_LIGHT_TYPE: { //Directional lights always get added to our light list. //(Hopefully there are not too many directional lights!) t_appendLight(i); o_appendLight(i); } break; case POINT_LIGHT_TYPE: { vec3 lightPos = vec3(currentLight.position[0], currentLight.position[1], currentLight.position[2]); Sphere sphere = {lightPos, currentLight.radius}; if(SphereInsideFrustum(sphere, GroupFrustum, nearClipVS, maxDepthVS)) { //Add light to light list for transparent geometry. t_appendLight(i); if(!SphereInsidePlane(sphere, minPlane)) { //Add light to light list for opaque geometry. o_appendLight(i); } } } break; case SPOT_LIGHT_TYPE: { vec3 lightPos = vec3(currentLight.position[0], currentLight.position[1], currentLight.position[2]); vec3 lightDir = vec3(currentLight.direction[0], currentLight.direction[1], currentLight.direction[2]); float coneRadius = tan(radians(currentLight.outerAngle)) * currentLight.radius; Cone cone = {lightPos, currentLight.radius, lightDir, coneRadius}; if(ConeInsideFrustum(cone, GroupFrustum, nearClipVS, maxDepthVS)) { //Add light to light list for transparent geometry. t_appendLight(i); if(!ConeInsidePlane(cone, minPlane)) { // Add light to light list for opaque geometry. o_appendLight(i); } } } break; } } My code is based on: https://ift.tt/2sn7N1s and I have tried to convert directx code to OpenGL. Any help will be appreciate (sorry for my bad english)

    from GameDev.net https://ift.tt/2YISgWU

    ليست هناك تعليقات

    Post Top Ad

    ad728

    Post Bottom Ad

    ad728