Преглед на файлове

Several fixes related to PBR and Environment

Juan Linietsky преди 8 години
родител
ревизия
5567e898d1

+ 2 - 2
core/io/image_loader.cpp

@@ -43,7 +43,7 @@ bool ImageFormatLoader::recognize(const String &p_extension) const {
 	return false;
 }
 
-Error ImageLoader::load_image(String p_file, Ref<Image> p_image, FileAccess *p_custom) {
+Error ImageLoader::load_image(String p_file, Ref<Image> p_image, FileAccess *p_custom, bool p_force_linear) {
 	ERR_FAIL_COND_V(p_image.is_null(), ERR_INVALID_PARAMETER);
 
 	FileAccess *f = p_custom;
@@ -62,7 +62,7 @@ Error ImageLoader::load_image(String p_file, Ref<Image> p_image, FileAccess *p_c
 
 		if (!loader[i]->recognize(extension))
 			continue;
-		Error err = loader[i]->load_image(p_image, f);
+		Error err = loader[i]->load_image(p_image, f, p_force_linear);
 
 		if (err != ERR_FILE_UNRECOGNIZED) {
 

+ 2 - 2
core/io/image_loader.h

@@ -56,7 +56,7 @@ class ImageFormatLoader {
 	friend class ImageLoader;
 
 protected:
-	virtual Error load_image(Ref<Image> p_image, FileAccess *p_fileaccess) = 0;
+	virtual Error load_image(Ref<Image> p_image, FileAccess *p_fileaccess, bool p_force_linear) = 0;
 	virtual void get_recognized_extensions(List<String> *p_extensions) const = 0;
 	bool recognize(const String &p_extension) const;
 
@@ -75,7 +75,7 @@ class ImageLoader {
 
 protected:
 public:
-	static Error load_image(String p_file, Ref<Image> p_image, FileAccess *p_custom = NULL);
+	static Error load_image(String p_file, Ref<Image> p_image, FileAccess *p_custom = NULL, bool p_force_linear = false);
 	static void get_recognized_extensions(List<String> *p_extensions);
 	static bool recognize(const String &p_extension);
 

+ 6 - 3
drivers/gles3/rasterizer_scene_gles3.cpp

@@ -2120,7 +2120,7 @@ void RasterizerSceneGLES3::_add_geometry(RasterizerStorageGLES3::Geometry *p_geo
 	}
 }
 
-void RasterizerSceneGLES3::_draw_sky(RasterizerStorageGLES3::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_scale) {
+void RasterizerSceneGLES3::_draw_sky(RasterizerStorageGLES3::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_scale, float p_energy) {
 
 	if (!p_sky)
 		return;
@@ -2188,13 +2188,16 @@ void RasterizerSceneGLES3::_draw_sky(RasterizerStorageGLES3::Sky *p_sky, const C
 	glBindVertexArray(state.sky_array);
 
 	storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_PANORAMA, true);
+	storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_MULTIPLIER, true);
 	storage->shaders.copy.bind();
+	storage->shaders.copy.set_uniform(CopyShaderGLES3::MULTIPLIER, p_energy);
 
 	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 
 	glBindVertexArray(0);
 	glColorMask(1, 1, 1, 1);
 
+	storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_MULTIPLIER, false);
 	storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_PANORAMA, false);
 }
 
@@ -3885,7 +3888,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const
 			glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.fbo); //switch to alpha fbo for sky, only diffuse/ambient matters
 		*/
 
-		_draw_sky(sky, p_cam_projection, p_cam_transform, storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP], env->sky_scale);
+		_draw_sky(sky, p_cam_projection, p_cam_transform, storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP], env->sky_scale, env->bg_energy);
 	}
 
 	//_render_list_forward(&alpha_render_list,camera_transform,camera_transform_inverse,camera_projection,false,fragment_lighting,true);
@@ -4832,7 +4835,7 @@ void RasterizerSceneGLES3::initialize() {
 		glGenTextures(1, &e.color);
 		glBindTexture(GL_TEXTURE_2D, e.color);
 #ifdef IPHONE_ENABLED
-		///@TODO ugly hack to get around iOS not supporting 32bit single channel floating point textures...  
+		///@TODO ugly hack to get around iOS not supporting 32bit single channel floating point textures...
 		glTexImage2D(GL_TEXTURE_2D, 0, GL_R16F, max_exposure_shrink_size, max_exposure_shrink_size, 0, GL_RED, GL_FLOAT, NULL);
 #else
 		glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, max_exposure_shrink_size, max_exposure_shrink_size, 0, GL_RED, GL_FLOAT, NULL);

+ 1 - 3
drivers/gles3/rasterizer_scene_gles3.h

@@ -131,8 +131,6 @@ public:
 		struct EnvironmentRadianceUBO {
 
 			float transform[16];
-			float box_min[4]; //unused for now
-			float box_max[4];
 			float ambient_contribution;
 
 		} env_radiance_data;
@@ -700,7 +698,7 @@ public:
 
 	_FORCE_INLINE_ void _add_geometry(RasterizerStorageGLES3::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner, int p_material, bool p_shadow);
 
-	void _draw_sky(RasterizerStorageGLES3::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_scale);
+	void _draw_sky(RasterizerStorageGLES3::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_scale, float p_energy);
 
 	void _setup_environment(Environment *env, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform);
 	void _setup_directional_light(int p_index, const Transform &p_camera_inverse_transformm, bool p_use_shadows);

+ 3 - 1
drivers/gles3/rasterizer_storage_gles3.cpp

@@ -5553,7 +5553,7 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) {
 	Image::Format image_format;
 
 	bool hdr = rt->flags[RENDER_TARGET_HDR] && config.hdr_supported;
-	hdr = false;
+	//hdr = false;
 
 	if (!hdr || rt->flags[RENDER_TARGET_NO_3D]) {
 
@@ -6403,6 +6403,8 @@ void RasterizerStorageGLES3::initialize() {
 	config.etc2_supported = true;
 	config.hdr_supported = false;
 #endif
+
+	print_line("hdr supported: " + itos(config.hdr_supported));
 	config.pvrtc_supported = config.extensions.has("GL_IMG_texture_compression_pvrtc");
 	config.srgb_decode_supported = config.extensions.has("GL_EXT_texture_sRGB_decode");
 

+ 8 - 1
drivers/gles3/shaders/copy.glsl

@@ -45,6 +45,11 @@ uniform samplerCube source_cube; //texunit:0
 uniform sampler2D source; //texunit:0
 #endif
 
+
+#ifdef USE_MULTIPLIER
+uniform float multiplier;
+#endif
+
 #ifdef USE_PANORAMA
 
 vec4 texturePanorama(vec3 normal,sampler2D pano ) {
@@ -130,7 +135,9 @@ void main() {
 	color+=texture( source,  uv_interp+vec2( 0.0,-2.0)*pixel_size )*0.06136;
 #endif
 
-
+#ifdef USE_MULTIPLIER
+	color.rgb*=multiplier;
+#endif
 	frag_color = color;
 }
 

+ 29 - 24
drivers/gles3/shaders/scene.glsl

@@ -380,8 +380,6 @@ uniform sampler2D radiance_map; //texunit:-2
 layout(std140) uniform Radiance { //ubo:2
 
 	mat4 radiance_inverse_xform;
-	vec3 radiance_box_min;
-	vec3 radiance_box_max;
 	float radiance_ambient_contribution;
 
 };
@@ -1133,6 +1131,23 @@ void gi_probes_compute(vec3 pos, vec3 normal, float roughness, vec3 specular, in
 
 #endif
 
+vec3 textureDualParabolod(sampler2D p_tex, vec3 p_vec,float p_lod) {
+
+	vec3 norm = normalize(p_vec);
+	float y_ofs=0.0;
+	if (norm.z>=0.0) {
+
+		norm.z+=1.0;
+		y_ofs+=0.5;
+	} else {
+		norm.z=1.0 - norm.z;
+		norm.y=-norm.y;
+	}
+
+	norm.xy/=norm.z;
+	norm.xy=norm.xy * vec2(0.5,0.25) + vec2(0.5,0.25+y_ofs);
+	return textureLod(p_tex, norm.xy, p_lod).xyz;
+}
 
 void main() {
 
@@ -1264,6 +1279,8 @@ FRAGMENT_SHADER_CODE
 	float ndotv = clamp(dot(normal,eye_vec),0.0,1.0);
 
 	vec2 brdf = texture(brdf_texture, vec2(roughness, ndotv)).xy;
+	brdf.x=1.0;
+	brdf.y=0.0;
 #endif
 
 #ifdef USE_RADIANCE_MAP
@@ -1274,28 +1291,15 @@ FRAGMENT_SHADER_CODE
 		{
 
 
-
-			float lod = roughness * 5.0;
+#define RADIANCE_MAX_LOD 5.0
+			float lod = roughness * RADIANCE_MAX_LOD;
 
 			{ //read radiance from dual paraboloid
 
 				vec3 ref_vec = reflect(-eye_vec,normal); //2.0 * ndotv * normal - view; // reflect(v, n);
-				ref_vec=normalize((radiance_inverse_xform * vec4(ref_vec,0.0)).xyz);
-
-				vec3 norm = normalize(ref_vec);
-				float y_ofs=0.0;
-				if (norm.z>=0.0) {
-
-					norm.z+=1.0;
-					y_ofs+=0.5;
-				} else {
-					norm.z=1.0 - norm.z;
-					norm.y=-norm.y;
-				}
-
-				norm.xy/=norm.z;
-				norm.xy=norm.xy * vec2(0.5,0.25) + vec2(0.5,0.25+y_ofs);
-				specular_light = textureLod(radiance_map, norm.xy, lod).xyz * brdf.x + brdf.y;
+				ref_vec=normalize((radiance_inverse_xform * vec4(ref_vec,0.0)).xyz);				
+				vec3 radiance = textureDualParabolod(radiance_map,ref_vec,lod) * bg_energy;
+				specular_light = radiance * brdf.x + brdf.y;
 
 			}
 			//no longer a cubemap
@@ -1305,11 +1309,11 @@ FRAGMENT_SHADER_CODE
 
 		{
 
-			/*vec3 ambient_dir=normalize((radiance_inverse_xform * vec4(normal,0.0)).xyz);
-			vec3 env_ambient=textureLod(radiance_cube, ambient_dir, 5.0).xyz;
+			vec3 ambient_dir=normalize((radiance_inverse_xform * vec4(normal,0.0)).xyz);
+			vec3 env_ambient=textureDualParabolod(radiance_map,ambient_dir,RADIANCE_MAX_LOD) * bg_energy;
 
-			ambient_light=mix(ambient_light_color.rgb,env_ambient,radiance_ambient_contribution);*/
-			ambient_light=vec3(0.0,0.0,0.0);
+			ambient_light=mix(ambient_light_color.rgb,env_ambient,radiance_ambient_contribution);
+			//ambient_light=vec3(0.0,0.0,0.0);
 		}
 	}
 
@@ -1322,6 +1326,7 @@ FRAGMENT_SHADER_CODE
 	}
 #endif
 
+	ambient_light*=ambient_energy;
 
 #ifdef USE_LIGHT_DIRECTIONAL
 

+ 1 - 1
drivers/png/image_loader_png.cpp

@@ -201,7 +201,7 @@ Error ImageLoaderPNG::_load_image(void *rf_up, png_rw_ptr p_func, Ref<Image> p_i
 	return OK;
 }
 
-Error ImageLoaderPNG::load_image(Ref<Image> p_image, FileAccess *f) {
+Error ImageLoaderPNG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear) {
 
 	Error err = _load_image(f, _read_png_data, p_image);
 	f->close();

+ 1 - 1
drivers/png/image_loader_png.h

@@ -43,7 +43,7 @@ class ImageLoaderPNG : public ImageFormatLoader {
 
 public:
 	static Error _load_image(void *rf_up, png_rw_ptr p_func, Ref<Image> p_image);
-	virtual Error load_image(Ref<Image> p_image, FileAccess *f);
+	virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear);
 	virtual void get_recognized_extensions(List<String> *p_extensions) const;
 	ImageLoaderPNG();
 };

+ 1 - 1
editor/editor_node.cpp

@@ -1380,7 +1380,7 @@ void EditorNode::_property_editor_back() {
 
 void EditorNode::_save_default_environment() {
 
-	Ref<Environment> fallback = get_scene_root()->get_world()->get_fallback_environment();
+	Ref<Environment> fallback = get_tree()->get_root()->get_world()->get_fallback_environment();
 
 	if (fallback.is_valid() && fallback->get_path().is_resource_file()) {
 		Map<RES, bool> processed;

+ 3 - 1
editor/import/resource_importer_texture.cpp

@@ -177,6 +177,7 @@ void ResourceImporterTexture::get_import_options(List<ImportOption> *r_options,
 	r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "flags/srgb", PROPERTY_HINT_ENUM, "Disable,Enable,Detect"), 2));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/fix_alpha_border"), p_preset != PRESET_3D ? true : false));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/premult_alpha"), true));
+	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/HDR_as_SRGB"), false));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "stream"), false));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "size_limit", PROPERTY_HINT_RANGE, "0,4096,1"), 0));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "detect_3d"), p_preset == PRESET_DETECT));
@@ -327,10 +328,11 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
 	bool stream = p_options["stream"];
 	int size_limit = p_options["size_limit"];
 	bool force_rgbe = int(p_options["compress/hdr_mode"]) == 1;
+	bool hdr_as_srgb = p_options["process/HDR_as_SRGB"];
 
 	Ref<Image> image;
 	image.instance();
-	Error err = ImageLoader::load_image(p_source_file, image);
+	Error err = ImageLoader::load_image(p_source_file, image, NULL, hdr_as_srgb);
 	if (err != OK)
 		return err;
 

+ 17 - 7
modules/hdr/image_loader_hdr.cpp

@@ -34,17 +34,23 @@
 
 #include "thirdparty/tinyexr/tinyexr.h"
 
-Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f) {
+Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear) {
 
 	String header = f->get_token();
 
 	print_line("HEADER: " + header);
-	ERR_FAIL_COND_V(header != "#?RADIANCE", ERR_FILE_UNRECOGNIZED);
-
-	String format = f->get_token();
-	print_line("FORMAT: " + format);
-
-	ERR_FAIL_COND_V(format != "FORMAT=32-bit_rle_rgbe", ERR_FILE_UNRECOGNIZED);
+	ERR_FAIL_COND_V(header != "#?RADIANCE" && header != "#?RGBE", ERR_FILE_UNRECOGNIZED);
+
+	while (true) {
+		String format = f->get_token();
+		ERR_FAIL_COND_V(f->eof_reached(), ERR_FILE_UNRECOGNIZED);
+		if (format.begins_with("FORMAT=") && format != "FORMAT=32-bit_rle_rgbe") {
+			ERR_EXPLAIN("Only 32-bit_rle_rgbe is supported for .hdr files.");
+			return ERR_FILE_UNRECOGNIZED;
+		}
+		if (format == "FORMAT=32-bit_rle_rgbe")
+			break;
+	}
 
 	String token = f->get_token();
 
@@ -132,6 +138,10 @@ Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f) {
 					ptr[1] * exp / 255.0,
 					ptr[2] * exp / 255.0);
 
+			if (p_force_linear) {
+				c = c.to_linear();
+			}
+
 			*(uint32_t *)ptr = c.to_rgbe9995();
 			ptr += 4;
 		}

+ 1 - 1
modules/hdr/image_loader_hdr.h

@@ -38,7 +38,7 @@
 class ImageLoaderHDR : public ImageFormatLoader {
 
 public:
-	virtual Error load_image(Ref<Image> p_image, FileAccess *f);
+	virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear);
 	virtual void get_recognized_extensions(List<String> *p_extensions) const;
 	ImageLoaderHDR();
 };

+ 1 - 1
modules/jpg/image_loader_jpegd.cpp

@@ -89,7 +89,7 @@ Error jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p
 	return OK;
 }
 
-Error ImageLoaderJPG::load_image(Ref<Image> p_image, FileAccess *f) {
+Error ImageLoaderJPG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear) {
 
 	PoolVector<uint8_t> src_image;
 	int src_image_len = f->get_len();

+ 1 - 1
modules/jpg/image_loader_jpegd.h

@@ -38,7 +38,7 @@
 class ImageLoaderJPG : public ImageFormatLoader {
 
 public:
-	virtual Error load_image(Ref<Image> p_image, FileAccess *f);
+	virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear);
 	virtual void get_recognized_extensions(List<String> *p_extensions) const;
 	ImageLoaderJPG();
 };

+ 12 - 4
modules/tinyexr/image_loader_tinyexr.cpp

@@ -34,7 +34,7 @@
 
 #include "thirdparty/tinyexr/tinyexr.h"
 
-Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f) {
+Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear) {
 
 	PoolVector<uint8_t> src_image;
 	int src_image_len = f->get_len();
@@ -133,9 +133,17 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f) {
 		// Assume `out_rgba` have enough memory allocated.
 		for (int i = 0; i < exr_image.width * exr_image.height; i++) {
 
-			*iw++ = Math::make_half_float(reinterpret_cast<float **>(exr_image.images)[idxR][i]);
-			*iw++ = Math::make_half_float(reinterpret_cast<float **>(exr_image.images)[idxG][i]);
-			*iw++ = Math::make_half_float(reinterpret_cast<float **>(exr_image.images)[idxB][i]);
+			Color color(
+					reinterpret_cast<float **>(exr_image.images)[idxR][i],
+					reinterpret_cast<float **>(exr_image.images)[idxG][i],
+					reinterpret_cast<float **>(exr_image.images)[idxB][i]);
+
+			if (p_force_linear)
+				color = color.to_linear();
+
+			*iw++ = Math::make_half_float(color.r);
+			*iw++ = Math::make_half_float(color.g);
+			*iw++ = Math::make_half_float(color.b);
 
 			if (idxA > 0) {
 				*iw++ = Math::make_half_float(reinterpret_cast<float **>(exr_image.images)[idxA][i]);

+ 1 - 1
modules/tinyexr/image_loader_tinyexr.h

@@ -38,7 +38,7 @@
 class ImageLoaderTinyEXR : public ImageFormatLoader {
 
 public:
-	virtual Error load_image(Ref<Image> p_image, FileAccess *f);
+	virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear);
 	virtual void get_recognized_extensions(List<String> *p_extensions) const;
 	ImageLoaderTinyEXR();
 };

+ 1 - 1
modules/webp/image_loader_webp.cpp

@@ -115,7 +115,7 @@ static Ref<Image> _webp_lossy_unpack(const PoolVector<uint8_t> &p_buffer) {
 	return img;
 }
 
-Error ImageLoaderWEBP::load_image(Ref<Image> p_image, FileAccess *f) {
+Error ImageLoaderWEBP::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear) {
 
 	uint32_t size = f->get_len();
 	PoolVector<uint8_t> src_image;

+ 1 - 1
modules/webp/image_loader_webp.h

@@ -38,7 +38,7 @@
 class ImageLoaderWEBP : public ImageFormatLoader {
 
 public:
-	virtual Error load_image(Ref<Image> p_image, FileAccess *f);
+	virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear);
 	virtual void get_recognized_extensions(List<String> *p_extensions) const;
 	ImageLoaderWEBP();
 };

+ 38 - 38
scene/resources/environment.cpp

@@ -266,19 +266,19 @@ Ref<Texture> Environment::get_adjustment_color_correction() const {
 
 void Environment::_validate_property(PropertyInfo &property) const {
 
-	if (property.name == "background/sky" || property.name == "background/sky_scale" || property.name == "ambient_light/sky_contribution") {
+	if (property.name == "background_sky" || property.name == "background_sky_scale" || property.name == "ambient_light/sky_contribution") {
 		if (bg_mode != BG_SKY) {
 			property.usage = PROPERTY_USAGE_NOEDITOR;
 		}
 	}
 
-	if (property.name == "background/color") {
+	if (property.name == "background_color") {
 		if (bg_mode != BG_COLOR) {
 			property.usage = PROPERTY_USAGE_NOEDITOR;
 		}
 	}
 
-	if (property.name == "background/canvas_max_layer") {
+	if (property.name == "background_canvas_max_layer") {
 		if (bg_mode != BG_CANVAS) {
 			property.usage = PROPERTY_USAGE_NOEDITOR;
 		}
@@ -695,6 +695,41 @@ void Environment::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "ambient_light_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_ambient_light_energy", "get_ambient_light_energy");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "ambient_light_sky_contribution", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_ambient_light_sky_contribution", "get_ambient_light_sky_contribution");
 
+	ClassDB::bind_method(D_METHOD("set_tonemapper", "mode"), &Environment::set_tonemapper);
+	ClassDB::bind_method(D_METHOD("get_tonemapper"), &Environment::get_tonemapper);
+
+	ClassDB::bind_method(D_METHOD("set_tonemap_exposure", "exposure"), &Environment::set_tonemap_exposure);
+	ClassDB::bind_method(D_METHOD("get_tonemap_exposure"), &Environment::get_tonemap_exposure);
+
+	ClassDB::bind_method(D_METHOD("set_tonemap_white", "white"), &Environment::set_tonemap_white);
+	ClassDB::bind_method(D_METHOD("get_tonemap_white"), &Environment::get_tonemap_white);
+
+	ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure", "auto_exposure"), &Environment::set_tonemap_auto_exposure);
+	ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure"), &Environment::get_tonemap_auto_exposure);
+
+	ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_max", "exposure_max"), &Environment::set_tonemap_auto_exposure_max);
+	ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_max"), &Environment::get_tonemap_auto_exposure_max);
+
+	ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_min", "exposure_min"), &Environment::set_tonemap_auto_exposure_min);
+	ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_min"), &Environment::get_tonemap_auto_exposure_min);
+
+	ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_speed", "exposure_speed"), &Environment::set_tonemap_auto_exposure_speed);
+	ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_speed"), &Environment::get_tonemap_auto_exposure_speed);
+
+	ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_grey", "exposure_grey"), &Environment::set_tonemap_auto_exposure_grey);
+	ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_grey"), &Environment::get_tonemap_auto_exposure_grey);
+
+	ADD_GROUP("Tonemap", "tonemap_");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "tonemap_mode", PROPERTY_HINT_ENUM, "Linear,Reindhart,Filmic,Aces"), "set_tonemapper", "get_tonemapper");
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "tonemap_exposure", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_exposure", "get_tonemap_exposure");
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "tonemap_white", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_white", "get_tonemap_white");
+	ADD_GROUP("Auto Exposure", "auto_exposure_");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_exposure_enabled"), "set_tonemap_auto_exposure", "get_tonemap_auto_exposure");
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "auto_exposure_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_tonemap_auto_exposure_grey", "get_tonemap_auto_exposure_grey");
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "auto_exposure_min_luma", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_auto_exposure_min", "get_tonemap_auto_exposure_min");
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "auto_exposure_max_luma", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_auto_exposure_max", "get_tonemap_auto_exposure_max");
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "auto_exposure_speed", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_tonemap_auto_exposure_speed", "get_tonemap_auto_exposure_speed");
+
 	ClassDB::bind_method(D_METHOD("set_ssr_enabled", "enabled"), &Environment::set_ssr_enabled);
 	ClassDB::bind_method(D_METHOD("is_ssr_enabled"), &Environment::is_ssr_enabled);
 
@@ -852,41 +887,6 @@ void Environment::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "glow_hdr_scale", PROPERTY_HINT_RANGE, "0.0,4.0,0.01"), "set_glow_hdr_bleed_scale", "get_glow_hdr_bleed_scale");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "glow_bicubic_upscale"), "set_glow_bicubic_upscale", "is_glow_bicubic_upscale_enabled");
 
-	ClassDB::bind_method(D_METHOD("set_tonemapper", "mode"), &Environment::set_tonemapper);
-	ClassDB::bind_method(D_METHOD("get_tonemapper"), &Environment::get_tonemapper);
-
-	ClassDB::bind_method(D_METHOD("set_tonemap_exposure", "exposure"), &Environment::set_tonemap_exposure);
-	ClassDB::bind_method(D_METHOD("get_tonemap_exposure"), &Environment::get_tonemap_exposure);
-
-	ClassDB::bind_method(D_METHOD("set_tonemap_white", "white"), &Environment::set_tonemap_white);
-	ClassDB::bind_method(D_METHOD("get_tonemap_white"), &Environment::get_tonemap_white);
-
-	ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure", "auto_exposure"), &Environment::set_tonemap_auto_exposure);
-	ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure"), &Environment::get_tonemap_auto_exposure);
-
-	ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_max", "exposure_max"), &Environment::set_tonemap_auto_exposure_max);
-	ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_max"), &Environment::get_tonemap_auto_exposure_max);
-
-	ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_min", "exposure_min"), &Environment::set_tonemap_auto_exposure_min);
-	ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_min"), &Environment::get_tonemap_auto_exposure_min);
-
-	ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_speed", "exposure_speed"), &Environment::set_tonemap_auto_exposure_speed);
-	ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_speed"), &Environment::get_tonemap_auto_exposure_speed);
-
-	ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_grey", "exposure_grey"), &Environment::set_tonemap_auto_exposure_grey);
-	ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_grey"), &Environment::get_tonemap_auto_exposure_grey);
-
-	ADD_GROUP("Tonemap", "tonemap_");
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "tonemap_mode", PROPERTY_HINT_ENUM, "Linear,Reindhart,Filmic,Aces"), "set_tonemapper", "get_tonemapper");
-	ADD_PROPERTY(PropertyInfo(Variant::REAL, "tonemap_exposure", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_exposure", "get_tonemap_exposure");
-	ADD_PROPERTY(PropertyInfo(Variant::REAL, "tonemap_white", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_white", "get_tonemap_white");
-	ADD_GROUP("Auto Exposure", "auto_exposure_");
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_expoure_enabled"), "set_tonemap_auto_exposure", "get_tonemap_auto_exposure");
-	ADD_PROPERTY(PropertyInfo(Variant::REAL, "auto_expoure_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_tonemap_auto_exposure_grey", "get_tonemap_auto_exposure_grey");
-	ADD_PROPERTY(PropertyInfo(Variant::REAL, "auto_expoure_min_luma", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_auto_exposure_min", "get_tonemap_auto_exposure_min");
-	ADD_PROPERTY(PropertyInfo(Variant::REAL, "auto_expoure_max_luma", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_auto_exposure_max", "get_tonemap_auto_exposure_max");
-	ADD_PROPERTY(PropertyInfo(Variant::REAL, "auto_expoure_speed", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_tonemap_auto_exposure_speed", "get_tonemap_auto_exposure_speed");
-
 	ClassDB::bind_method(D_METHOD("set_adjustment_enable", "enabled"), &Environment::set_adjustment_enable);
 	ClassDB::bind_method(D_METHOD("is_adjustment_enabled"), &Environment::is_adjustment_enabled);
 

+ 3 - 3
scene/resources/material.cpp

@@ -510,7 +510,7 @@ void SpatialMaterial::_update_shader() {
 	} else {
 		code += "\tvec4 specular_tex = texture(texture_specular,UV);\n";
 		code += "\tSPECULAR = vec3(ALBEDO.rgb * metalness * specular_tex.r);\n";
-		code += "\tROUGHNESS = specular_tex.a * roughness;\n";
+		code += "\tROUGHNESS = specular_tex.g * roughness;\n";
 	}
 
 	code += "}\n";
@@ -888,10 +888,10 @@ void SpatialMaterial::_validate_property(PropertyInfo &property) const {
 	_validate_feature("refraction", FEATURE_REFRACTION, property);
 	_validate_feature("detail", FEATURE_DETAIL, property);
 
-	if (property.name == "specular/color" && specular_mode == SPECULAR_MODE_METALLIC) {
+	if (property.name == "specular_color" && specular_mode == SPECULAR_MODE_METALLIC) {
 		property.usage = 0;
 	}
-	if (property.name == "specular/metalness" && specular_mode == SPECULAR_MODE_SPECULAR) {
+	if (property.name == "specular_metalness" && specular_mode == SPECULAR_MODE_SPECULAR) {
 		property.usage = 0;
 	}