diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 237b3ec3fc6..b2228a6cfa0 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -117,7 +117,6 @@ void RasterizerCanvasGLES3::canvas_begin(){ glClearColor( storage->frame.clear_request_color.r, storage->frame.clear_request_color.g, storage->frame.clear_request_color.b, storage->frame.clear_request_color.a ); glClear(GL_COLOR_BUFFER_BIT); storage->frame.clear_request=false; - print_line("canvas clear?"); } diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 121620594d0..4ce2bd2f37e 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1,5 +1,10 @@ #include "rasterizer_scene_gles3.h" #include "globals.h" + + + + + static _FORCE_INLINE_ void store_matrix32(const Matrix32& p_mtx, float* p_array) { p_array[ 0]=p_mtx.elements[0][0]; @@ -52,6 +57,121 @@ static _FORCE_INLINE_ void store_camera(const CameraMatrix& p_mtx, float* p_arra + +/* ENVIRONMENT API */ + +RID RasterizerSceneGLES3::environment_create(){ + + + Environment *env = memnew( Environment ); + + return environment_owner.make_rid(env); +} + +void RasterizerSceneGLES3::environment_set_background(RID p_env,VS::EnvironmentBG p_bg){ + + Environment *env=environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + env->bg_mode=p_bg; +} + +void RasterizerSceneGLES3::environment_set_skybox(RID p_env, RID p_skybox, int p_radiance_size, int p_irradiance_size){ + + Environment *env=environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + + if (env->skybox_color.is_valid()) { + env->skybox_color=RID(); + } + if (env->skybox_radiance.is_valid()) { + storage->free(env->skybox_radiance); + env->skybox_radiance=RID(); + } + if (env->skybox_irradiance.is_valid()) { + storage->free(env->skybox_irradiance); + env->skybox_irradiance=RID(); + } + + if (p_skybox.is_valid()) { + + env->skybox_color=p_skybox; + // env->skybox_radiance=storage->texture_create_pbr_cubemap(p_skybox,VS::PBR_CUBEMAP_RADIANCE,p_radiance_size); + //env->skybox_irradiance=storage->texture_create_pbr_cubemap(p_skybox,VS::PBR_CUBEMAP_IRRADIANCE,p_irradiance_size); + } + +} + +void RasterizerSceneGLES3::environment_set_skybox_scale(RID p_env,float p_scale) { + + Environment *env=environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + + env->skybox_scale=p_scale; + +} + +void RasterizerSceneGLES3::environment_set_bg_color(RID p_env,const Color& p_color){ + + Environment *env=environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + + env->bg_color=p_color; + +} +void RasterizerSceneGLES3::environment_set_bg_energy(RID p_env,float p_energy) { + + Environment *env=environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + + env->energy=p_energy; + +} + +void RasterizerSceneGLES3::environment_set_canvas_max_layer(RID p_env,int p_max_layer){ + + Environment *env=environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + + env->canvas_max_layer=p_max_layer; + +} +void RasterizerSceneGLES3::environment_set_ambient_light(RID p_env, const Color& p_color, float p_energy, float p_skybox_energy){ + + Environment *env=environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + + env->ambient_color=p_color; + env->ambient_anergy=p_energy; + env->skybox_ambient=p_skybox_energy; + +} + +void RasterizerSceneGLES3::environment_set_glow(RID p_env,bool p_enable,int p_radius,float p_intensity,float p_strength,float p_bloom_treshold,VS::EnvironmentGlowBlendMode p_blend_mode){ + +} +void RasterizerSceneGLES3::environment_set_fog(RID p_env,bool p_enable,float p_begin,float p_end,RID p_gradient_texture){ + +} + +void RasterizerSceneGLES3::environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,VS::EnvironmentToneMapper p_tone_mapper){ + +} +void RasterizerSceneGLES3::environment_set_brightness(RID p_env,bool p_enable,float p_brightness){ + +} +void RasterizerSceneGLES3::environment_set_contrast(RID p_env,bool p_enable,float p_contrast){ + +} +void RasterizerSceneGLES3::environment_set_saturation(RID p_env,bool p_enable,float p_saturation){ + +} +void RasterizerSceneGLES3::environment_set_color_correction(RID p_env,bool p_enable,RID p_ramp){ + +} + + + + RID RasterizerSceneGLES3::light_instance_create(RID p_light) { @@ -493,6 +613,70 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g #endif } +void RasterizerSceneGLES3::_draw_skybox(RID p_skybox,CameraMatrix& p_projection,const Transform& p_transform,bool p_vflip,float p_scale) { + + RasterizerStorageGLES3::Texture *tex = storage->texture_owner.getornull(p_skybox); + + ERR_FAIL_COND(!tex); + glActiveTexture(GL_TEXTURE0); + glBindTexture(tex->target,tex->tex_id); + + glDepthMask(GL_TRUE); + glEnable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_BLEND); + glColorMask(1,1,1,1); + + float flip_sign = p_vflip?-1:1; + + Vector3 vertices[8]={ + Vector3(-1,-1*flip_sign,0.1), + Vector3( 0, 1, 0), + Vector3( 1,-1*flip_sign,0.1), + Vector3( 1, 1, 0), + Vector3( 1, 1*flip_sign,0.1), + Vector3( 1, 0, 0), + Vector3(-1, 1*flip_sign,0.1), + Vector3( 0, 0, 0), + + }; + + + + //skybox uv vectors + float vw,vh,zn; + p_projection.get_viewport_size(vw,vh); + zn=p_projection.get_z_near(); + + float scale=p_scale; + + for(int i=0;i<4;i++) { + + Vector3 uv=vertices[i*2+1]; + uv.x=(uv.x*2.0-1.0)*vw*scale; + uv.y=-(uv.y*2.0-1.0)*vh*scale; + uv.z=-zn; + vertices[i*2+1] = p_transform.basis.xform(uv).normalized(); + vertices[i*2+1].z = -vertices[i*2+1].z; + } + + glBindBuffer(GL_ARRAY_BUFFER,state.skybox_verts); + glBufferSubData(GL_ARRAY_BUFFER,0,sizeof(Vector3)*8,vertices); + glBindBuffer(GL_ARRAY_BUFFER,0); //unbind + + glBindVertexArray(state.skybox_array); + + storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_CUBEMAP,true); + storage->shaders.copy.bind(); + + glDrawArrays(GL_TRIANGLE_FAN,0,4); + + glBindVertexArray(0); + + storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_CUBEMAP,false); + +} + void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_directional_lights,int p_directional_light_count,RID p_environment){ @@ -561,7 +745,9 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->front.fbo); - if (true) { + Environment *env = environment_owner.getornull(p_environment); + + if (!env || env->bg_mode==VS::ENV_BG_CLEAR_COLOR) { if (storage->frame.clear_request) { @@ -570,6 +756,16 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM storage->frame.clear_request=false; } + } else if (env->bg_mode==VS::ENV_BG_COLOR) { + + + glClearColor( env->bg_color.r, env->bg_color.g, env->bg_color.b, env->bg_color.a ); + glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + storage->frame.clear_request=false; + } else { + glClear(GL_DEPTH_BUFFER_BIT); + storage->frame.clear_request=false; + } state.current_depth_test=true; @@ -616,6 +812,12 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM _render_list(render_list.elements,render_list.element_count,p_cam_transform,p_cam_projection,false,false); + + if (env && env->bg_mode==VS::ENV_BG_SKYBOX) { + + _draw_skybox(env->skybox_color,p_cam_projection,p_cam_transform,storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP],env->skybox_scale); + } + //_render_list_forward(&alpha_render_list,camera_transform,camera_transform_inverse,camera_projection,false,fragment_lighting,true); //glColorMask(1,1,1,1); @@ -793,6 +995,27 @@ void RasterizerSceneGLES3::initialize() { if (render_list.max_elements<1024) render_list.max_elements=1024; + + + { + //quad buffers + + glGenBuffers(1,&state.skybox_verts); + glBindBuffer(GL_ARRAY_BUFFER,state.skybox_verts); + glBufferData(GL_ARRAY_BUFFER,sizeof(Vector3)*8,NULL,GL_DYNAMIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER,0); //unbind + + + glGenVertexArrays(1,&state.skybox_array); + glBindVertexArray(state.skybox_array); + glBindBuffer(GL_ARRAY_BUFFER,state.skybox_verts); + glVertexAttribPointer(VS::ARRAY_VERTEX,3,GL_FLOAT,GL_FALSE,sizeof(Vector3)*2,0); + glEnableVertexAttribArray(VS::ARRAY_VERTEX); + glVertexAttribPointer(VS::ARRAY_TEX_UV,3,GL_FLOAT,GL_FALSE,sizeof(Vector3)*2,((uint8_t*)NULL)+sizeof(Vector3)); + glEnableVertexAttribArray(VS::ARRAY_TEX_UV); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER,0); //unbind + } render_list.init(); } diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 6fba777fc89..53088deb0d7 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -16,8 +16,6 @@ public: RasterizerStorageGLES3 *storage; - - struct State { bool current_depth_test; @@ -40,10 +38,70 @@ public: GLuint scene_ubo; - + GLuint skybox_verts; + GLuint skybox_array; } state; + + + + /* ENVIRONMENT API */ + + struct Environment : public RID_Data { + + VS::EnvironmentBG bg_mode; + + RID skybox_color; + RID skybox_radiance; + RID skybox_irradiance; + float skybox_scale; + + Color bg_color; + float energy; + float skybox_ambient; + + Color ambient_color; + float ambient_anergy; + float ambient_skybox_energy; + + int canvas_max_layer; + + + Environment() { + bg_mode=VS::ENV_BG_CLEAR_COLOR; + skybox_scale=1.0; + energy=1.0; + skybox_ambient=0; + ambient_anergy=1.0; + ambient_skybox_energy=0.0; + canvas_max_layer=0; + } + }; + + RID_Owner environment_owner; + + virtual RID environment_create(); + + virtual void environment_set_background(RID p_env,VS::EnvironmentBG p_bg); + virtual void environment_set_skybox(RID p_env,RID p_skybox,int p_radiance_size,int p_irradiance_size); + virtual void environment_set_skybox_scale(RID p_env,float p_scale); + virtual void environment_set_bg_color(RID p_env,const Color& p_color); + virtual void environment_set_bg_energy(RID p_env,float p_energy); + virtual void environment_set_canvas_max_layer(RID p_env,int p_max_layer); + virtual void environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy=1.0,float p_skybox_energy=0.0); + + virtual void environment_set_glow(RID p_env,bool p_enable,int p_radius,float p_intensity,float p_strength,float p_bloom_treshold,VS::EnvironmentGlowBlendMode p_blend_mode); + virtual void environment_set_fog(RID p_env,bool p_enable,float p_begin,float p_end,RID p_gradient_texture); + + virtual void environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,VS::EnvironmentToneMapper p_tone_mapper); + virtual void environment_set_brightness(RID p_env,bool p_enable,float p_brightness); + virtual void environment_set_contrast(RID p_env,bool p_enable,float p_contrast); + virtual void environment_set_saturation(RID p_env,bool p_enable,float p_saturation); + virtual void environment_set_color_correction(RID p_env,bool p_enable,RID p_ramp); + + /* RENDER LIST */ + struct RenderList { enum { @@ -166,6 +224,8 @@ public: _FORCE_INLINE_ void _add_geometry( RasterizerStorageGLES3::Geometry* p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner,int p_material); + void _draw_skybox(RID p_skybox, CameraMatrix& p_projection, const Transform& p_transform, bool p_vflip, float p_scale); + virtual void render_scene(const Transform& p_cam_transform,CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_directional_lights,int p_directional_light_count,RID p_environment); virtual bool free(RID p_rid); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index f633ef21cc8..94ad2afabee 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -995,6 +995,104 @@ void RasterizerStorageGLES3::texture_set_shrink_all_x2_on_set_data(bool p_enable config.shrink_textures_x2=p_enable; } +RID RasterizerStorageGLES3::texture_create_pbr_cubemap(RID p_source,VS::PBRCubeMapMode p_mode,int p_resolution) const { + + Texture * texture = texture_owner.get(p_source); + ERR_FAIL_COND_V(!texture,RID()); + ERR_FAIL_COND_V(!(texture->flags&VS::TEXTURE_FLAG_CUBEMAP),RID()); + + bool use_float=true; + + if (p_resolution<0) { + p_resolution=texture->width; + } + + + glBindVertexArray(0); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); +#ifdef GLEW_ENABLED + glDisable(GL_POINT_SPRITE); + glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); +#endif + glDisable(GL_BLEND); + + + glActiveTexture(GL_TEXTURE1); + glBindTexture(texture->target, texture->tex_id); + + glActiveTexture(GL_TEXTURE0); + GLuint new_cubemap; + glGenTextures(1, &new_cubemap); + + + GLuint tmp_fb; + + glGenFramebuffers(1, &tmp_fb); + glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb); + + + int w = texture->width; + int h = texture->height; + + int lod=0; + + shaders.cubemap_filter.bind(); + + int mipmaps=6; + + int mm_level=mipmaps; + + while(mm_level) { + + for(int i=0;i<6;i++) { + glTexImage2D(_cube_side_enum[i], lod, use_float?GL_RGBA16F:GL_RGB10_A2, w, h, 0, GL_RGBA, use_float?GL_HALF_FLOAT:GL_UNSIGNED_INT_2_10_10_10_REV, NULL); + glTexParameteri(_cube_side_enum[i], GL_TEXTURE_BASE_LEVEL, lod); + glTexParameteri(_cube_side_enum[i], GL_TEXTURE_MAX_LEVEL, lod); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], new_cubemap, 0); + + glViewport(0,0,w,h); + glBindVertexArray(resources.quadie_array); + + shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::FACE_ID,i); + shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::ROUGHNESS,lod/float(mipmaps)); + + + glDrawArrays(GL_TRIANGLE_FAN,0,4); + glBindVertexArray(0); +#ifdef DEBUG_ENABLED + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + ERR_CONTINUE(status!=GL_FRAMEBUFFER_COMPLETE); +#endif + } + + + + if (w>1) + w>>=1; + if (h>1) + h>>=1; + + lod++; + mm_level--; + + } + + + for(int i=0;i<6;i++) { + //restore ranges + glTexParameteri(_cube_side_enum[i], GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(_cube_side_enum[i], GL_TEXTURE_MAX_LEVEL, lod); + + } + + glBindFramebuffer(GL_FRAMEBUFFER, config.system_fbo); + glDeleteFramebuffers(1, &tmp_fb); + + + return RID(); +} /* SHADER API */ @@ -3649,6 +3747,45 @@ void RasterizerStorageGLES3::initialize() { #else config.use_rgba_2d_shadows=true; #endif + + + //generic quadie for copying + + { + //quad buffers + + glGenBuffers(1,&resources.quadie); + glBindBuffer(GL_ARRAY_BUFFER,resources.quadie); + { + const float qv[16]={ + -1,-1, + 0, 0, + -1, 1, + 0, 1, + 1, 1, + 1, 1, + 1,-1, + 1, 0, + }; + + glBufferData(GL_ARRAY_BUFFER,sizeof(float)*16,qv,GL_STATIC_DRAW); + } + + glBindBuffer(GL_ARRAY_BUFFER,0); //unbind + + + glGenVertexArrays(1,&resources.quadie_array); + glBindVertexArray(resources.quadie_array); + glBindBuffer(GL_ARRAY_BUFFER,resources.quadie); + glVertexAttribPointer(0,2,GL_FLOAT,GL_FALSE,sizeof(float)*4,0); + glEnableVertexAttribArray(0); + glVertexAttribPointer(1,2,GL_FLOAT,GL_FALSE,sizeof(float)*4,((uint8_t*)NULL)+8); + glEnableVertexAttribArray(1); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER,0); //unbind + } + + shaders.cubemap_filter.init(); } void RasterizerStorageGLES3::finalize() { diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index 950d65b9d06..c3022b3ac07 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -6,6 +6,7 @@ #include "shader_gles3.h" #include "shaders/copy.glsl.h" #include "shaders/canvas.glsl.h" +#include "shaders/cubemap_filter.glsl.h" #include "self_list.h" #include "shader_compiler_gles3.h" @@ -60,6 +61,8 @@ public: ShaderCompilerGLES3 compiler; + CubemapFilterShaderGLES3 cubemap_filter; + ShaderCompilerGLES3::IdentifierActions actions_canvas; ShaderCompilerGLES3::IdentifierActions actions_scene; } shaders; @@ -70,6 +73,9 @@ public: GLuint black_tex; GLuint normal_tex; + GLuint quadie; + GLuint quadie_array; + } resources; struct Info { @@ -178,6 +184,8 @@ public: virtual void texture_debug_usage(List *r_info); + virtual RID texture_create_pbr_cubemap(RID p_source,VS::PBRCubeMapMode p_mode,int p_resolution=-1) const; + /* SHADER API */ diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub index 0fa0e3b73a7..afffe103168 100644 --- a/drivers/gles3/shaders/SCsub +++ b/drivers/gles3/shaders/SCsub @@ -5,4 +5,5 @@ if env['BUILDERS'].has_key('GLES3_GLSL'): env.GLES3_GLSL('canvas.glsl'); env.GLES3_GLSL('canvas_shadow.glsl'); env.GLES3_GLSL('scene.glsl'); + env.GLES3_GLSL('cubemap_filter.glsl'); diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl index aba280186ac..eb58d664315 100644 --- a/drivers/gles3/shaders/copy.glsl +++ b/drivers/gles3/shaders/copy.glsl @@ -33,20 +33,31 @@ void main() { #ifdef USE_CUBEMAP in vec3 cube_interp; -uniform samplerCube source_cube; +uniform samplerCube source_cube; //texunit:0 #else in vec2 uv_interp; -uniform sampler2D source; +uniform sampler2D source; //texunit:0 #endif + +uniform float stuff; + in vec2 uv2_interp; -layout(location = 0) vec4 frag_color; //color:0 +layout(location = 0) out vec4 frag_color; void main() { //vec4 color = color_interp; +#ifdef USE_CUBEMAP + vec4 color = texture( source_cube, normalize(cube_interp) ); + +#else + vec4 color = texture( source, uv_interp ); +#endif + + frag_color = color; } diff --git a/drivers/gles3/shaders/cubemap_filter.glsl b/drivers/gles3/shaders/cubemap_filter.glsl new file mode 100644 index 00000000000..f450f341133 --- /dev/null +++ b/drivers/gles3/shaders/cubemap_filter.glsl @@ -0,0 +1,143 @@ +[vertex] + + +layout(location=0) in highp vec2 vertex; + +layout(location=1) in highp vec2 uv; + +out highp vec2 uv_interp; + +void main() { + + uv_interp=uv; + gl_Position=vec4(vertex,0,1); +} + +[fragment] + + +uniform samplerCube source_cube; //texunit:1 +uniform int face_id; +uniform float roughness; +in highp vec2 uv_interp; + + +layout(location = 0) vec4 frag_color; + + +vec3 texelCoordToVec(vec2 uv, int faceID) +{ + mat3 faceUvVectors[6]; + + // -x + faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z + faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y + faceUvVectors[1][2] = vec3(-1.0, 0.0, 0.0); // -x face + + // +x + faceUvVectors[0][0] = vec3(0.0, 0.0, -1.0); // u -> -z + faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y + faceUvVectors[0][2] = vec3(1.0, 0.0, 0.0); // +x face + + // -y + faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x + faceUvVectors[3][1] = vec3(0.0, 0.0, -1.0); // v -> -z + faceUvVectors[3][2] = vec3(0.0, -1.0, 0.0); // -y face + + // +y + faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x + faceUvVectors[2][1] = vec3(0.0, 0.0, 1.0); // v -> +z + faceUvVectors[2][2] = vec3(0.0, 1.0, 0.0); // +y face + + // -z + faceUvVectors[5][0] = vec3(-1.0, 0.0, 0.0); // u -> -x + faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y + faceUvVectors[5][2] = vec3(0.0, 0.0, -1.0); // -z face + + // +z + faceUvVectors[4][0] = vec3(1.0, 0.0, 0.0); // u -> +x + faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y + faceUvVectors[4][2] = vec3(0.0, 0.0, 1.0); // +z face + + // out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2]. + vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2]; + return normalize(result); +} + +vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) +{ + float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph] + + // Compute distribution direction + float Phi = 2.0 * M_PI * Xi.x; + float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y)); + float SinTheta = sqrt(1.0 - CosTheta * CosTheta); + + // Convert to spherical direction + vec3 H; + H.x = SinTheta * cos(Phi); + H.y = SinTheta * sin(Phi); + H.z = CosTheta; + + vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + vec3 TangentX = normalize(cross(UpVector, N)); + vec3 TangentY = cross(N, TangentX); + + // Tangent to world space + return TangentX * H.x + TangentY * H.y + N * H.z; +} + +// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html +float GGX(float NdotV, float a) +{ + float k = a / 2.0; + return NdotV / (NdotV * (1.0 - k) + k); +} + +// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html +float G_Smith(float a, float nDotV, float nDotL) +{ + return GGX(nDotL, a * a) * GGX(nDotV, a * a); +} + +float radicalInverse_VdC(uint bits) { + bits = (bits << 16u) | (bits >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + return float(bits) * 2.3283064365386963e-10; // / 0x100000000 +} + +vec2 Hammersley(uint i, uint N) { + return vec2(float(i)/float(N), radicalInverse_VdC(i)); +} + +#define SAMPLE_COUNT 1024 + +void main() { + + vec2 uv = (uv_interp * 2.0) - 1.0; + vec3 N = texelCoordToVec(uv, face_id); + + //vec4 color = color_interp; + vec4 sum = vec4(0.0, 0.0, 0.0, 0.0); + + for(int sampleNum = 0; sampleNum < SAMPLE_COUNT; sampleNum++) { + vec2 xi = Hammersley(sampleNum, SAMPLE_COUNT); + vec2 xi = texture2DLod(Texture0, vec2(float(sampleNum) / float(SAMPLE_COUNT), 0.5), 0.0).xy; + + vec3 H = ImportanceSampleGGX( xi, roughness, N ); + vec3 V = N; + vec3 L = normalize(2.0 * dot( V, H ) * H - V); + + float ndotl = max(0.0, dot(N, L)); + vec3 s = textureCubeLod(u_skyCube, H, 0.0).rgb * ndotl; + + sum += vec4(s, 1.0); + } + sum /= sum.w; + + frag_color = vec4(sum.rgb, 1.0); +} + diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 6fecdef59d1..85d16da9151 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -28,20 +28,193 @@ /*************************************************************************/ #include "environment.h" #include "texture.h" - +#include "globals.h" +#include "servers/visual_server.h" RID Environment::get_rid() const { return environment; } + +void Environment::set_background(BGMode p_bg) { + + bg_mode=p_bg; + VS::get_singleton()->environment_set_background(environment,VS::EnvironmentBG(p_bg)); + _change_notify(); +} + +void Environment::set_skybox(const Ref& p_skybox){ + + bg_skybox=p_skybox; + + RID sb_rid; + if (bg_skybox.is_valid()) + sb_rid=bg_skybox->get_rid(); + print_line("skybox valid: "+itos(sb_rid.is_valid())); + + VS::get_singleton()->environment_set_skybox(environment,sb_rid,Globals::get_singleton()->get("rendering/skybox/radiance_cube_resolution"),Globals::get_singleton()->get("rendering/skybox/iradiance_cube_resolution")); +} + +void Environment::set_skybox_scale(float p_scale) { + + bg_skybox_scale=p_scale; + VS::get_singleton()->environment_set_skybox_scale(environment,p_scale); +} + +void Environment::set_bg_color(const Color& p_color){ + + bg_color=p_color; + VS::get_singleton()->environment_set_bg_color(environment,p_color); +} +void Environment::set_bg_energy(float p_energy){ + + bg_energy=p_energy; + VS::get_singleton()->environment_set_bg_energy(environment,p_energy); +} +void Environment::set_canvas_max_layer(int p_max_layer){ + + bg_canvas_max_layer=p_max_layer; + VS::get_singleton()->environment_set_canvas_max_layer(environment,p_max_layer); +} +void Environment::set_ambient_light_color(const Color& p_color){ + + ambient_color=p_color; + VS::get_singleton()->environment_set_ambient_light(environment,ambient_color,ambient_energy,ambient_skybox_energy); +} +void Environment::set_ambient_light_energy(float p_energy){ + + ambient_energy=p_energy; + VS::get_singleton()->environment_set_ambient_light(environment,ambient_color,ambient_energy,ambient_skybox_energy); +} +void Environment::set_ambient_light_skybox_energy(float p_energy){ + + ambient_skybox_energy=p_energy; + VS::get_singleton()->environment_set_ambient_light(environment,ambient_color,ambient_energy,ambient_skybox_energy); +} + +Environment::BGMode Environment::get_background() const{ + + return bg_mode; +} +Ref Environment::get_skybox() const{ + + return bg_skybox; +} + +float Environment::get_skybox_scale() const { + + return bg_skybox_scale; +} + +Color Environment::get_bg_color() const{ + + return bg_color; +} +float Environment::get_bg_energy() const{ + + return bg_energy; +} +int Environment::get_canvas_max_layer() const{ + + return bg_canvas_max_layer; +} +Color Environment::get_ambient_light_color() const{ + + return ambient_color; +} +float Environment::get_ambient_light_energy() const{ + + return ambient_energy; +} +float Environment::get_ambient_light_skybox_energy() const{ + + return ambient_skybox_energy; +} + + + +void Environment::_validate_property(PropertyInfo& property) const { + + if (property.name=="background/skybox" || property.name=="ambient_light/skybox_energy") { + if (bg_mode!=BG_SKYBOX) { + property.usage=PROPERTY_USAGE_NOEDITOR; + } + } + + if (property.name=="background/color") { + if (bg_mode!=BG_COLOR) { + property.usage=PROPERTY_USAGE_NOEDITOR; + } + } + + if (property.name=="background/canvas_max_layer") { + if (bg_mode!=BG_CANVAS) { + property.usage=PROPERTY_USAGE_NOEDITOR; + } + } + +} + void Environment::_bind_methods() { + ObjectTypeDB::bind_method(_MD("set_background","mode"),&Environment::set_background); + ObjectTypeDB::bind_method(_MD("set_skybox","skybox:CubeMap"),&Environment::set_skybox); + ObjectTypeDB::bind_method(_MD("set_skybox_scale","scale"),&Environment::set_skybox_scale); + ObjectTypeDB::bind_method(_MD("set_bg_color","color"),&Environment::set_bg_color); + ObjectTypeDB::bind_method(_MD("set_bg_energy","energy"),&Environment::set_bg_energy); + ObjectTypeDB::bind_method(_MD("set_canvas_max_layer","layer"),&Environment::set_canvas_max_layer); + ObjectTypeDB::bind_method(_MD("set_ambient_light_color","color"),&Environment::set_ambient_light_color); + ObjectTypeDB::bind_method(_MD("set_ambient_light_energy","energy"),&Environment::set_ambient_light_energy); + ObjectTypeDB::bind_method(_MD("set_ambient_light_skybox_energy","energy"),&Environment::set_ambient_light_skybox_energy); + + + ObjectTypeDB::bind_method(_MD("get_background"),&Environment::get_background); + ObjectTypeDB::bind_method(_MD("get_skybox:CubeMap"),&Environment::get_skybox); + ObjectTypeDB::bind_method(_MD("get_skybox_scale"),&Environment::get_skybox_scale); + ObjectTypeDB::bind_method(_MD("get_bg_color"),&Environment::get_bg_color); + ObjectTypeDB::bind_method(_MD("get_bg_energy"),&Environment::get_bg_energy); + ObjectTypeDB::bind_method(_MD("get_canvas_max_layer"),&Environment::get_canvas_max_layer); + ObjectTypeDB::bind_method(_MD("get_ambient_light_color"),&Environment::get_ambient_light_color); + ObjectTypeDB::bind_method(_MD("get_ambient_light_energy"),&Environment::get_ambient_light_energy); + ObjectTypeDB::bind_method(_MD("get_ambient_light_skybox_energy"),&Environment::get_ambient_light_skybox_energy); + + + ADD_PROPERTY(PropertyInfo(Variant::INT,"background/mode",PROPERTY_HINT_ENUM,"Clear Color,Custom Color,Skybox,Canvas,Keep"),_SCS("set_background"),_SCS("get_background") ); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"background/skybox",PROPERTY_HINT_RESOURCE_TYPE,"CubeMap"),_SCS("set_skybox"),_SCS("get_skybox") ); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"background/skybox_scale",PROPERTY_HINT_RANGE,"0,32,0.01"),_SCS("set_skybox_scale"),_SCS("get_skybox_scale") ); + ADD_PROPERTY(PropertyInfo(Variant::COLOR,"background/color"),_SCS("set_bg_color"),_SCS("get_bg_color") ); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"background/energy",PROPERTY_HINT_RANGE,"0,16,0.01"),_SCS("set_bg_energy"),_SCS("get_bg_energy") ); + ADD_PROPERTY(PropertyInfo(Variant::INT,"background/canvas_max_layer",PROPERTY_HINT_RANGE,"-1000,1000,1"),_SCS("set_canvas_max_layer"),_SCS("get_canvas_max_layer") ); + ADD_PROPERTY(PropertyInfo(Variant::COLOR,"ambient_light/color"),_SCS("set_ambient_light_color"),_SCS("get_ambient_light_color") ); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"ambient_light/energy",PROPERTY_HINT_RANGE,"0,16,0.01"),_SCS("set_ambient_light_energy"),_SCS("get_ambient_light_energy") ); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"ambient_light/skybox_energy",PROPERTY_HINT_RANGE,"0,16,0.01"),_SCS("set_ambient_light_skybox_energy"),_SCS("get_ambient_light_skybox_energy") ); + + GLOBAL_DEF("rendering/skybox/irradiance_cube_resolution",256); + GLOBAL_DEF("rendering/skybox/radiance_cube_resolution",64); + + BIND_CONSTANT(BG_KEEP); + BIND_CONSTANT(BG_CLEAR_COLOR); + BIND_CONSTANT(BG_COLOR); + BIND_CONSTANT(BG_SKYBOX); + BIND_CONSTANT(BG_CANVAS); + BIND_CONSTANT(BG_MAX); + BIND_CONSTANT(GLOW_BLEND_MODE_ADDITIVE); + BIND_CONSTANT(GLOW_BLEND_MODE_SCREEN); + BIND_CONSTANT(GLOW_BLEND_MODE_SOFTLIGHT); + BIND_CONSTANT(GLOW_BLEND_MODE_DISABLED); } Environment::Environment() { + bg_mode=BG_CLEAR_COLOR; + bg_energy=1.0; + bg_canvas_max_layer=0; + ambient_energy=1.0; + ambient_skybox_energy=0; + + environment = VS::get_singleton()->environment_create(); } diff --git a/scene/resources/environment.h b/scene/resources/environment.h index f8ea0cb36f0..0435ffc6cb8 100644 --- a/scene/resources/environment.h +++ b/scene/resources/environment.h @@ -31,28 +31,80 @@ #include "resource.h" #include "servers/visual_server.h" +#include "scene/resources/texture.h" class Environment : public Resource { OBJ_TYPE(Environment,Resource); public: + enum BGMode { + + BG_CLEAR_COLOR, + BG_COLOR, + BG_SKYBOX, + BG_CANVAS, + BG_KEEP, + BG_MAX + }; + + enum GlowBlendMode { + GLOW_BLEND_MODE_ADDITIVE, + GLOW_BLEND_MODE_SCREEN, + GLOW_BLEND_MODE_SOFTLIGHT, + GLOW_BLEND_MODE_DISABLED, + }; private: - - RID environment; + BGMode bg_mode; + Ref bg_skybox; + float bg_skybox_scale; + Color bg_color; + float bg_energy; + int bg_canvas_max_layer; + Color ambient_color; + float ambient_energy; + float ambient_skybox_energy; + protected: static void _bind_methods(); + virtual void _validate_property(PropertyInfo& property) const; + public: + + void set_background(BGMode p_bg); + void set_skybox(const Ref& p_skybox); + void set_skybox_scale(float p_scale); + void set_bg_color(const Color& p_color); + void set_bg_energy(float p_energy); + void set_canvas_max_layer(int p_max_layer); + void set_ambient_light_color(const Color& p_color); + void set_ambient_light_energy(float p_energy); + void set_ambient_light_skybox_energy(float p_energy); + + BGMode get_background() const; + Ref get_skybox() const; + float get_skybox_scale() const; + Color get_bg_color() const; + float get_bg_energy() const; + int get_canvas_max_layer() const; + Color get_ambient_light_color() const; + float get_ambient_light_energy() const; + float get_ambient_light_skybox_energy() const; + + virtual RID get_rid() const; Environment(); ~Environment(); }; +VARIANT_ENUM_CAST(Environment::BGMode) +VARIANT_ENUM_CAST(Environment::GlowBlendMode) + #endif // ENVIRONMENT_H diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index d3f27687caf..81cdcf6a25e 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -39,6 +39,26 @@ class RasterizerScene { public: + /* ENVIRONMENT API */ + + virtual RID environment_create()=0; + + virtual void environment_set_background(RID p_env,VS::EnvironmentBG p_bg)=0; + virtual void environment_set_skybox(RID p_env,RID p_skybox,int p_radiance_size,int p_irradiance_size)=0; + virtual void environment_set_skybox_scale(RID p_env,float p_scale)=0; + virtual void environment_set_bg_color(RID p_env,const Color& p_color)=0; + virtual void environment_set_bg_energy(RID p_env,float p_energy)=0; + virtual void environment_set_canvas_max_layer(RID p_env,int p_max_layer)=0; + virtual void environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy=1.0,float p_skybox_energy=0.0)=0; + + virtual void environment_set_glow(RID p_env,bool p_enable,int p_radius,float p_intensity,float p_strength,float p_bloom_treshold,VS::EnvironmentGlowBlendMode p_blend_mode)=0; + virtual void environment_set_fog(RID p_env,bool p_enable,float p_begin,float p_end,RID p_gradient_texture)=0; + + virtual void environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,VS::EnvironmentToneMapper p_tone_mapper)=0; + virtual void environment_set_brightness(RID p_env,bool p_enable,float p_brightness)=0; + virtual void environment_set_contrast(RID p_env,bool p_enable,float p_contrast)=0; + virtual void environment_set_saturation(RID p_env,bool p_enable,float p_saturation)=0; + virtual void environment_set_color_correction(RID p_env,bool p_enable,RID p_ramp)=0; struct InstanceBase : RID_Data { @@ -126,6 +146,7 @@ public: virtual void texture_debug_usage(List *r_info)=0; + virtual RID texture_create_pbr_cubemap(RID p_source,VS::PBRCubeMapMode p_mode,int p_resolution=-1) const=0; /* SHADER API */ diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 62d45f8206d..a2502e89f9d 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -620,6 +620,7 @@ public: BIND1RC(uint32_t,texture_get_width,RID) BIND1RC(uint32_t,texture_get_height,RID) BIND3(texture_set_size_override,RID,int,int) + BIND3RC(RID,texture_create_pbr_cubemap,RID,PBRCubeMapMode,int) @@ -848,15 +849,17 @@ public: #undef BINDBASE //from now on, calls forwarded to this singleton -#define BINDBASE VSG::scene +#define BINDBASE VSG::scene_render BIND0R(RID,environment_create) BIND2(environment_set_background,RID ,EnvironmentBG ) - BIND3(environment_set_skybox,RID,RID ,float ) + BIND4(environment_set_skybox,RID,RID ,int,int ) + BIND2(environment_set_skybox_scale,RID,float) BIND2(environment_set_bg_color,RID,const Color& ) + BIND2(environment_set_bg_energy,RID,float ) BIND2(environment_set_canvas_max_layer,RID,int ) - BIND3(environment_set_ambient_light,RID,const Color& ,float ) + BIND4(environment_set_ambient_light,RID,const Color& ,float,float ) BIND7(environment_set_glow,RID,bool ,int ,float ,float ,float ,EnvironmentGlowBlendMode ) BIND5(environment_set_fog,RID,bool ,float ,float ,RID ) @@ -871,6 +874,9 @@ public: /* SCENARIO API */ +#undef BINDBASE +#define BINDBASE VSG::scene + BIND0R(RID,scenario_create) BIND2(scenario_set_debug,RID,ScenarioDebugMode ) diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index a3b1d76fb8e..8fdf3d160d0 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -69,54 +69,6 @@ void VisualServerScene::camera_set_use_vertical_aspect(RID p_camera,bool p_enabl } - -/* ENVIRONMENT API */ - -RID VisualServerScene::environment_create(){ - - return RID(); -} - -void VisualServerScene::environment_set_background(RID p_env,VS::EnvironmentBG p_bg){ - -} -void VisualServerScene::environment_set_skybox(RID p_env,RID p_skybox,float p_energy){ - -} -void VisualServerScene::environment_set_bg_color(RID p_env,const Color& p_color){ - -} -void VisualServerScene::environment_set_canvas_max_layer(RID p_env,int p_max_layer){ - -} -void VisualServerScene::environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy){ - -} - -void VisualServerScene::environment_set_glow(RID p_env,bool p_enable,int p_radius,float p_intensity,float p_strength,float p_bloom_treshold,VS::EnvironmentGlowBlendMode p_blend_mode){ - -} -void VisualServerScene::environment_set_fog(RID p_env,bool p_enable,float p_begin,float p_end,RID p_gradient_texture){ - -} - -void VisualServerScene::environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,VS::EnvironmentToneMapper p_tone_mapper){ - -} -void VisualServerScene::environment_set_brightness(RID p_env,bool p_enable,float p_brightness){ - -} -void VisualServerScene::environment_set_contrast(RID p_env,bool p_enable,float p_contrast){ - -} -void VisualServerScene::environment_set_saturation(RID p_env,bool p_enable,float p_saturation){ - -} -void VisualServerScene::environment_set_color_correction(RID p_env,bool p_enable,RID p_ramp){ - -} - - /* SCENARIO API */ diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index ceec4af5989..515d52db7bc 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -139,25 +139,6 @@ public: }; */ - /* ENVIRONMENT API */ - - virtual RID environment_create(); - - virtual void environment_set_background(RID p_env,VS::EnvironmentBG p_bg); - virtual void environment_set_skybox(RID p_env,RID p_skybox,float p_energy=1.0); - virtual void environment_set_bg_color(RID p_env,const Color& p_color); - virtual void environment_set_canvas_max_layer(RID p_env,int p_max_layer); - virtual void environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy=1.0); - - virtual void environment_set_glow(RID p_env,bool p_enable,int p_radius,float p_intensity,float p_strength,float p_bloom_treshold,VS::EnvironmentGlowBlendMode p_blend_mode); - virtual void environment_set_fog(RID p_env,bool p_enable,float p_begin,float p_end,RID p_gradient_texture); - - virtual void environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,VS::EnvironmentToneMapper p_tone_mapper); - virtual void environment_set_brightness(RID p_env,bool p_enable,float p_brightness); - virtual void environment_set_contrast(RID p_env,bool p_enable,float p_contrast); - virtual void environment_set_saturation(RID p_env,bool p_enable,float p_saturation); - virtual void environment_set_color_correction(RID p_env,bool p_enable,RID p_ramp); - /* SCENARIO API */ diff --git a/servers/visual_server.h b/servers/visual_server.h index eb20355efba..11828c7d265 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -125,6 +125,13 @@ public: virtual void texture_set_shrink_all_x2_on_set_data(bool p_enable)=0; + enum PBRCubeMapMode { + PBR_CUBEMAP_RADIANCE, + PBR_CUBEMAP_IRRADIANCE, + }; + + virtual RID texture_create_pbr_cubemap(RID p_source,PBRCubeMapMode p_mode,int p_resolution=-1) const=0; + struct TextureInfo { RID texture; Size2 size; @@ -478,18 +485,21 @@ public: enum EnvironmentBG { - ENV_BG_KEEP, + ENV_BG_CLEAR_COLOR, ENV_BG_COLOR, ENV_BG_SKYBOX, ENV_BG_CANVAS, + ENV_BG_KEEP, ENV_BG_MAX }; virtual void environment_set_background(RID p_env,EnvironmentBG p_bg)=0; - virtual void environment_set_skybox(RID p_env,RID p_skybox,float p_energy=1.0)=0; + virtual void environment_set_skybox(RID p_env,RID p_skybox,int p_radiance_size,int p_irradiance_size)=0; + virtual void environment_set_skybox_scale(RID p_env,float p_scale)=0; virtual void environment_set_bg_color(RID p_env,const Color& p_color)=0; + virtual void environment_set_bg_energy(RID p_env,float p_energy)=0; virtual void environment_set_canvas_max_layer(RID p_env,int p_max_layer)=0; - virtual void environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy=1.0)=0; + virtual void environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy=1.0,float p_skybox_energy=0.0)=0; //set default SSAO options //set default SSR options