Browse Source

Added support for spherical sky/env maps.

Mark Sibly 7 years ago
parent
commit
38ce235416

+ 11 - 7
modules/mojo/graphics/shader.monkey2

@@ -130,20 +130,24 @@ Class GLProgram
 			For Local u:=Eachin _uniforms[i]
 			
 				Select u.type
+				Case GL_BOOL
+
+					glUniform1i( u.location,ublock.GetInt( u.uniformId ) )
+
 				Case GL_INT
-				
+
 					glUniform1i( u.location,ublock.GetInt( u.uniformId ) )
-					
+
 				Case GL_FLOAT
-				
+
 					glUniform1f( u.location,ublock.GetFloat( u.uniformId ) )
-					
+
 				Case GL_FLOAT_VEC2
-				
+
 					glUniform2fv( u.location,1,ublock.GetVec2fv( u.uniformId ) )
-					
+
 				Case GL_FLOAT_VEC3
-				
+
 					glUniform3fv( u.location,1,ublock.GetVec3fv( u.uniformId ) )
 					
 				Case GL_FLOAT_VEC4

+ 25 - 16
modules/mojo/graphics/texture.monkey2

@@ -93,12 +93,14 @@ Function ClearTexImage2D( glTarget:GLenum,width:Int,height:Int,format:PixelForma
 	glCheck()
 End
 
-Function UploadTexImage2D( glTarget:GLenum,image:Pixmap,mipmap:Bool,envface:Bool )
+Function UploadTexImage2D( glTarget:GLenum,image:Pixmap,mipmap:Bool,envmap:Bool )
 	
 	glCheck()
 	
 	Local format:=image.Format
 	
+	If envmap Assert( format=PixelFormat.RGBA8 )
+	
 	Local gliformat:=glInternalFormat( format )
 	Local glformat:=glFormat( format )
 	Local gltype:=glType( format )
@@ -109,10 +111,10 @@ Function UploadTexImage2D( glTarget:GLenum,image:Pixmap,mipmap:Bool,envface:Bool
 		
 		Local width:=image.Width,height:=image.Height
 
-		If envface		
+		If envmap
+			'write miplevel to alpha for envmaps
 			For Local y:=0 until height
 				Local p:=image.PixelPtr( 0,y )
-				'write miplevel to alpha!
 				For Local x:=0 Until width
 					p[x*4+3]=mip
 				Next
@@ -133,14 +135,16 @@ Function UploadTexImage2D( glTarget:GLenum,image:Pixmap,mipmap:Bool,envface:Bool
 		
 		glFlush() 'macos nvidia bug!
 		
-		If Not mipmap Or Not envface Exit
+		If Not mipmap Or Not envmap Exit
+		
+		If width=1 And height=1 Exit
 		
-		If image.Width=1 And image.Height=1 Exit
 		image=image.MipHalve()
+		
 		mip+=1
 	Forever
 	
-	If mipmap And Not envface glGenerateMipmap( glTarget )
+	If mipmap And Not envmap glGenerateMipmap( glTarget )
 	
 	glCheck()
 End
@@ -169,9 +173,11 @@ Enum TextureFlags
 	
 	Dynamic=		$0100
 	Cubemap=		$0200
+	Envmap=			$0400
 	
 	WrapST=			WrapS|WrapT
 	FilterMipmap=	Filter|Mipmap
+	CubeEnvmap=		Cubemap|Envmap
 End
 
 #rem monketdoc @hidden
@@ -206,12 +212,12 @@ Class Texture Extends Resource
 		
 		If flags & TextureFlags.Cubemap
 
-			'Nasty: cubemap mips always have mip level in alpha channel for env maps
+			'Nasty: envmap mips need mip level in the alpha channel for env maps
 			'
-			If flags & TextureFlags.Mipmap And pixmap.Format<>PixelFormat.RGBA8
-				
-				pixmap=pixmap.Convert( PixelFormat.RGBA8 )
-			Endif
+			'If flags & TextureFlags.Envmap And pixmap.Format<>PixelFormat.RGBA8
+			'	
+			'	pixmap=pixmap.Convert( PixelFormat.RGBA8 )
+			'Endif
 
 			Local size:=pixmap.Size
 			
@@ -328,8 +334,11 @@ Class Texture Extends Resource
 	End
 
 	Function Load:Texture( path:String,flags:TextureFlags=TextureFlags.FilterMipmap,flipNormalY:Bool=False )
+		
+		Local format:=PixelFormat.Unknown
+		If flags & TextureFlags.Envmap format=PixelFormat.RGBA8
 
-		Local pixmap:=Pixmap.Load( path,,True )
+		Local pixmap:=Pixmap.Load( path,format,True )
 		If Not pixmap Return Null
 		
 		If flipNormalY
@@ -512,11 +521,13 @@ Class Texture Extends Resource
 			
 			Local mipmap:=(_flags & TextureFlags.Mipmap)<>0
 				
+			Local envmap:=(_flags & TextureFlags.Envmap)<>0
+				
 			Select _glTarget
 			Case GL_TEXTURE_2D
 				
 				If _managed
-					UploadTexImage2D( _glTarget,_managed,mipmap,False )
+					UploadTexImage2D( _glTarget,_managed,mipmap,envmap )
 					_dirty&=~Dirty.Mipmaps
 				else
 					ClearTexImage2D( _glTarget,_size.x,_size.y,_format,Color.Black )
@@ -525,12 +536,10 @@ Class Texture Extends Resource
 					
 			Case GL_TEXTURE_CUBE_MAP
 				
-				Local envface:=mipmap
-				
 				If _cubeFaces[0]._managed
 					For Local i:=0 Until 6
 						Local face:=_cubeFaces[i]
-						UploadTexImage2D( face._glTarget,face._managed,mipmap,envface )
+						UploadTexImage2D( face._glTarget,face._managed,mipmap,envmap )
 					Next
 					_dirty&=~Dirty.Mipmaps
 				Else

+ 7 - 0
modules/mojo3d/assets/shaders/imports/pbr.glsl

@@ -101,6 +101,9 @@ void emitPbrFragment( vec4 color,vec3 ambient,vec3 emissive,float metalness,floa
 	vec3 vvec=normalize( -v_Position );
 	float ndotv=max( dot( normal,vvec ),0.0 );
 	
+	vec3 ambEnv=sampleEnv( reflect( v_Position,normal ),roughness );
+	
+	/*
 	vec3 rvec=r_EnvMatrix * reflect( v_Position,normal );
 
 	float lod=textureCube( r_EnvTexture,rvec,r_EnvTextureMaxLod ).a * 255.0 - r_EnvTextureMaxLod;
@@ -110,6 +113,7 @@ void emitPbrFragment( vec4 color,vec3 ambient,vec3 emissive,float metalness,floa
 //	if( lod==0.0 ) lod=textureCube( r_EnvTexture,rvec,r_EnvTextureMaxLod ).a * 255.0 - r_EnvTextureMaxLod;
 
 	vec3 ambEnv=pow( textureCube( r_EnvTexture,rvec,max( roughness*r_EnvTextureMaxLod-lod,0.0 ) ).rgb,vec3( 2.2 ) ) * r_EnvColor.rgb;
+	*/
 
 	vec3 fschlick0=specular + (1.0-specular) * pow( 1.0-ndotv,5.0 ) * glosiness;
 
@@ -152,6 +156,8 @@ void emitPbrFragment( vec4 color,vec3 ambient,vec3 emissive,float metalness,floa
 	
 #if MX2_AMBIENTPASS
 	//ambient color
+	vec3 ambEnv=sampleEnv( reflect( v_Position,normal ),roughness );
+/*	
 	vec3 rvec=r_EnvMatrix * reflect( v_Position,normal );
 	
 	float lod=textureCube( r_EnvTexture,rvec,r_EnvTextureMaxLod ).a * 255.0 - r_EnvTextureMaxLod;
@@ -161,6 +167,7 @@ void emitPbrFragment( vec4 color,vec3 ambient,vec3 emissive,float metalness,floa
 //	if( lod==0.0 ) lod=textureCube( r_EnvTexture,rvec,r_EnvTextureMaxLod ).a * 255.0 - r_EnvTextureMaxLod;
 
 	vec3 ambEnv=pow( textureCube( r_EnvTexture,rvec,max( roughness*r_EnvTextureMaxLod-lod,0.0 ) ).rgb,vec3( 2.2 ) ) * r_EnvColor.rgb;
+*/
 	
 	vec3 fschlick0=specular + (1.0-specular) * pow( 1.0-ndotv,5.0 ) * glosiness;
 	

+ 37 - 2
modules/mojo3d/assets/shaders/imports/std.glsl

@@ -43,15 +43,26 @@
 #define MX2_BUMPMAPPED			((MX2_ATTRIBMASK & 32)==32)
 #define MX2_BONED				((MX2_ATTRIBMASK & 192)==192)
 
+//***** CONSTS *****
+//
+const float pi=3.1415926535897932384626433832795;
+
 //***** RENDER *****
 //
 uniform float r_Time;
 uniform vec4 r_AmbientDiffuse;
-uniform samplerCube r_SkyTexture;
-uniform samplerCube r_EnvTexture;
+
+uniform samplerCube r_SkyTextureCube;
+uniform sampler2D r_SkyTexture2D;
+uniform bool r_SkyCube;
+
+uniform samplerCube r_EnvTextureCube;
+uniform sampler2D r_EnvTexture2D;
+uniform bool r_EnvCube;
 uniform float r_EnvTextureMaxLod;
 uniform vec4 r_EnvColor;
 uniform mat3 r_EnvMatrix;
+
 uniform float r_DepthNear;
 uniform float r_DepthFar;
 uniform float r_FogNear;
@@ -326,6 +337,30 @@ float shadowColor( vec3 position ){
 
 #endif
 
+vec3 sampleEnv( vec3 viewVec,float roughness ){
+
+	vec3 tv=r_EnvMatrix * viewVec;
+
+	if( r_EnvCube ){
+		
+		float lod=textureCube( r_EnvTextureCube,tv,r_EnvTextureMaxLod ).a * 255.0 - r_EnvTextureMaxLod;
+		if( lod>0.0 ) lod=textureCube( r_EnvTextureCube,tv ).a * 255.0;
+	
+		return pow( textureCube( r_EnvTextureCube,tv,max( roughness*r_EnvTextureMaxLod-lod,0.0 ) ).rgb,vec3( 2.2 ) ) * r_EnvColor.rgb;
+		
+	}else{
+
+		float p=-atan( tv.y,sqrt( tv.x*tv.x+tv.z*tv.z ) ) / (pi/2.0);
+		float y=atan( tv.x,tv.z ) / pi;
+		
+		vec2 tc=vec2( y,p ) *0.5 + 0.5;
+
+		float lod=texture2D( r_EnvTexture2D,tc,r_EnvTextureMaxLod ).a * 255.0 - r_EnvTextureMaxLod;
+		if( lod>0.0 ) lod=texture2D( r_EnvTexture2D,tc ).a * 255.0;
+	
+		return pow( texture2D( r_EnvTexture2D,tc,max( roughness*r_EnvTextureMaxLod-lod,0.0 ) ).rgb,vec3( 2.2 ) ) * r_EnvColor.rgb;
+	}
+}
 
 #if MX2_FORWARDPASS
 

+ 17 - 2
modules/mojo3d/assets/shaders/misc/skybox.glsl

@@ -15,10 +15,25 @@ void main(){
 void main(){
 
 	vec4 clip=r_InverseProjectionMatrix * vec4( v_ClipPosition,1.0,1.0 );
-
+	
 	vec3 tv=r_EnvMatrix * (clip.xyz/clip.w);
 	
-	vec3 frag=pow( textureCube( r_SkyTexture,tv ).rgb,vec3( 2.2 ) );
+	vec3 frag;
+
+	if( r_SkyCube ){
+
+		frag=pow( textureCube( r_SkyTextureCube,tv ).rgb,vec3( 2.2 ) );
+
+	}else{
+		
+		float p=-atan( tv.y,sqrt( tv.x*tv.x+tv.z*tv.z ) ) / (pi/2.0) * 0.5 + 0.5;
+		
+		float y=atan( tv.x,tv.z ) / pi * 0.5 + 0.5;
+		
+		frag=pow( texture2D( r_SkyTexture2D,vec2( y,p ) ).rgb,vec3( 2.2 ) );
+		
+//		frag=vec3( p,p,p );//y,y,y );
+	}
 	
 #if MX2_DEFERREDRENDERER
 	gl_FragData[0]=vec4( frag,1.0 );					//accum

+ 26 - 9
modules/mojo3d/render/renderer.monkey2

@@ -980,22 +980,39 @@ When a new renderer is created, the config setting `MOJO3D\_RENDERER` can be use
 		
 		_scene=scene
 		
-		_runiforms.SetTexture( "SkyTexture",_scene.SkyTexture )
+		Local sky:=_scene.SkyTexture
+		
+		If sky
+			If sky.Flags & TextureFlags.Cubemap
+				_runiforms.SetTexture( "SkyTextureCube",sky )
+				_runiforms.SetTexture( "SkyTexture2D",_whiteTexture )
+				_runiforms.SetInt( "SkyCube",1 )
+			Else
+				_runiforms.SetTexture( "SkyTextureCube",_whiteCubeTexture )
+				_runiforms.SetTexture( "SkyTexture2D",sky )
+				_runiforms.SetInt( "SkyCube",0 )
+			Endif
+		Else
+			_runiforms.SetTexture( "SkyTextureCube",Null )
+			_runiforms.SetTexture( "SkyTexture2D",Null )
+		Endif
+				
 		_runiforms.SetColor( "ClearColor",_scene.ClearColor )
 		_runiforms.SetColor( "AmbientDiffuse",_scene.AmbientLight )
 		
-		Local env:Texture
+		Local env:=(_scene.EnvTexture ?Else _scene.SkyTexture) ?Else _defaultEnv
 		
-		If _scene.EnvTexture
-			env=_scene.EnvTexture
-		ElseIf _scene.SkyTexture
-			env=_scene.SkyTexture
+		If env.Flags & TextureFlags.Cubemap
+			_runiforms.SetTexture( "EnvTextureCube",env )
+			_runiforms.SetTexture( "EnvTexture2D",_whiteTexture )
+			_runiforms.SetInt( "EnvCube",1 )
 		Else
-			env=_defaultEnv
+			_runiforms.SetTexture( "EnvTextureCube",_whiteCubeTexture )
+			_runiforms.SetTexture( "EnvTexture2D",env )
+			_runiforms.SetInt( "EnvCube",0 )
 		Endif
 		
-		_runiforms.SetTexture( "EnvTexture",env )
-		_runiforms.SetFloat( "EnvTextureMaxLod",Log2( env.Size.x ) )
+		_runiforms.SetFloat( "EnvTextureMaxLod",Log2( env.Size.y ) )
 		_runiforms.SetColor( "EnvColor",_scene.EnvColor )
 		
 		_runiforms.SetColor( "FogColor",_scene.FogColor )

+ 1 - 1
modules/mojo3d/tests/pbrspheres.monkey2

@@ -30,7 +30,7 @@ Class MyWindow Extends Window
 		
 		_scene=New Scene
 		
-		_scene.SkyTexture=Texture.Load( "asset::miramar-skybox.jpg",TextureFlags.FilterMipmap|TextureFlags.Cubemap )
+		_scene.SkyTexture=Texture.Load( "asset::miramar-skybox.jpg",TextureFlags.FilterMipmap|TextureFlags.Cubemap|TextureFlags.Envmap )
 		
 		'create camera
 		'

+ 18 - 2
modules/std/graphics/pixmap.monkey2

@@ -421,9 +421,25 @@ Class Pixmap Extends Resource
 	#end
 	Method MipHalve:Pixmap()
 		
-		DebugAssert( Width&1=0 And Height&1=0 )
+		If Width=1 And Height=1 Return Null
 		
-		Local dst:=New Pixmap( Width/2,Height/2,Format )
+		Local dst:=New Pixmap( Max( Width/2,1 ),Max( Height/2,1 ),Format )
+		
+		If Width=1
+			For Local y:=0 Until dst.Height
+				Local c0:=GetPixel( 0,y*2 )
+				Local c1:=GetPixel( 0,y*2+1 )
+				dst.SetPixel( 0,y,(c0+c1)*0.5 )
+			Next
+			Return dst
+		Else If Height=1
+			For Local x:=0 Until dst.Width
+				Local c0:=GetPixel( x*2,0 )
+				Local c1:=GetPixel( x*2+1,0 )
+				dst.SetPixel( x,0,(c0+c1)*0.5 )
+			Next
+			Return dst
+		Endif
 
 		Select _format
 		Case PixelFormat.RGBA8