leonsal преди 8 години
родител
ревизия
d22e286164
променени са 6 файла, в които са добавени 454 реда и са изтрити 215 реда
  1. 7 2
      material/material.go
  2. 18 18
      material/pbr_mr.go
  3. 52 0
      renderer/shaders/physical_fragment.glsl
  4. 43 0
      renderer/shaders/physical_vertex.glsl
  5. 292 190
      renderer/shaders/sources.go
  6. 42 5
      renderer/shaman.go

+ 7 - 2
material/material.go

@@ -98,7 +98,6 @@ func (mat *Material) Init() *Material {
 	mat.lineWidth = 1.0
 	mat.polyOffsetFactor = 0
 	mat.polyOffsetUnits = 0
-	mat.defines = make(map[string]string)
 	mat.textures = make([]*texture.Texture2D, 0)
 
 	return mat
@@ -222,6 +221,9 @@ func (mat *Material) SetPolygonOffset(factor, units float32) {
 // passed to this material shader.
 func (mat *Material) SetShaderDefine(name, value string) {
 
+	if mat.defines == nil {
+		mat.defines = make(map[string]string)
+	}
 	mat.defines[name] = value
 }
 
@@ -229,10 +231,13 @@ func (mat *Material) SetShaderDefine(name, value string) {
 // are passed to this material shader.
 func (mat *Material) UnsetShaderDefine(name string) {
 
+	if mat.defines == nil {
+		return
+	}
 	delete(mat.defines, name)
 }
 
-// ShaderDefines returns a map with the shader defines.
+// ShaderDefines returns this material map of shader defines.
 func (mat *Material) ShaderDefines() map[string]string {
 
 	return mat.defines

+ 18 - 18
material/pbr_mr.go

@@ -12,8 +12,8 @@ import (
 	"github.com/g3n/engine/texture"
 )
 
-// PbrMr is a physically based rendered material which uses the metallic-roughness model.
-type PbrMr struct {
+// Physical is a physically based rendered material which uses the metallic-roughness model.
+type Physical struct {
 	Material                                // Embedded material
 	baseColorTex         *texture.Texture2D // Optional base color texture
 	metallicRoughnessTex *texture.Texture2D // Optional metallic-roughness
@@ -30,14 +30,14 @@ type PbrMr struct {
 }
 
 // Number of glsl shader vec4 elements used by uniform data
-const pbrMrVec4Count = 3
+const physicalVec4Count = 3
 
-// NewPbrMr creates and returns a pointer to a new PbrMr material.
-func NewPbrMr() *PbrMr {
+// NewPhysical creates and returns a pointer to a new Physical material.
+func NewPhysical() *Physical {
 
-	m := new(PbrMr)
+	m := new(Physical)
 	m.Material.Init()
-	m.SetShader("pbr_mr")
+	m.SetShader("physical")
 
 	// Creates uniform and set defaulf values
 	m.uni.Init("Material")
@@ -51,7 +51,7 @@ func NewPbrMr() *PbrMr {
 // SetBaseColorFactor sets this material base color.
 // Its default value is {1,1,1,1}.
 // Returns pointer to this updated material.
-func (m *PbrMr) SetBaseColorFactor(c *math32.Color4) *PbrMr {
+func (m *Physical) SetBaseColorFactor(c *math32.Color4) *Physical {
 
 	m.udata.baseColorFactor = *c
 	return m
@@ -59,7 +59,7 @@ func (m *PbrMr) SetBaseColorFactor(c *math32.Color4) *PbrMr {
 
 // SetBaseColorTexture sets this material optional texture base color.
 // Returns pointer to this updated material.
-func (m *PbrMr) SetBaseColorTexture(tex *texture.Texture2D) *PbrMr {
+func (m *Physical) SetBaseColorTexture(tex *texture.Texture2D) *Physical {
 
 	m.baseColorTex = tex
 	if m.baseColorTex != nil {
@@ -74,7 +74,7 @@ func (m *PbrMr) SetBaseColorTexture(tex *texture.Texture2D) *PbrMr {
 // SetEmissiveFactor sets the emissive color of the material.
 // Its default is {0, 0, 0}.
 // Returns pointer to this updated material.
-func (m *PbrMr) SetEmissiveFactor(c *math32.Color) *PbrMr {
+func (m *Physical) SetEmissiveFactor(c *math32.Color) *Physical {
 
 	m.udata.emissiveFactor.R = c.R
 	m.udata.emissiveFactor.G = c.G
@@ -85,7 +85,7 @@ func (m *PbrMr) SetEmissiveFactor(c *math32.Color) *PbrMr {
 // SetMetallicFactor sets this material metallic factor.
 // Its default value is 1.0
 // Returns pointer to this updated material.
-func (m *PbrMr) SetMetallicFactor(v float32) *PbrMr {
+func (m *Physical) SetMetallicFactor(v float32) *Physical {
 
 	m.udata.metallicFactor = v
 	return m
@@ -93,7 +93,7 @@ func (m *PbrMr) SetMetallicFactor(v float32) *PbrMr {
 
 // SetMetallicRoughnessTexture sets this material optional metallic-roughness texture.
 // Returns pointer to this updated material.
-func (m *PbrMr) SetMetallicRoughnessTexture(tex *texture.Texture2D) *PbrMr {
+func (m *Physical) SetMetallicRoughnessTexture(tex *texture.Texture2D) *Physical {
 
 	m.metallicRoughnessTex = tex
 	if m.metallicRoughnessTex != nil {
@@ -107,7 +107,7 @@ func (m *PbrMr) SetMetallicRoughnessTexture(tex *texture.Texture2D) *PbrMr {
 
 // SetNormalTexture sets this material optional normal texture.
 // Returns pointer to this updated material.
-func (m *PbrMr) SetNormalTexture(tex *texture.Texture2D) *PbrMr {
+func (m *Physical) SetNormalTexture(tex *texture.Texture2D) *Physical {
 
 	m.normalTex = tex
 	if m.normalTex != nil {
@@ -121,7 +121,7 @@ func (m *PbrMr) SetNormalTexture(tex *texture.Texture2D) *PbrMr {
 
 // SetOcclusionTexture sets this material optional occlusion texture.
 // Returns pointer to this updated material.
-func (m *PbrMr) SetOcclusionTexture(tex *texture.Texture2D) *PbrMr {
+func (m *Physical) SetOcclusionTexture(tex *texture.Texture2D) *Physical {
 
 	m.occlusionTex = tex
 	if m.occlusionTex != nil {
@@ -135,7 +135,7 @@ func (m *PbrMr) SetOcclusionTexture(tex *texture.Texture2D) *PbrMr {
 
 // SetEmissiveTexture sets this material optional emissive texture.
 // Returns pointer to this updated material.
-func (m *PbrMr) SetEmissiveTexture(tex *texture.Texture2D) *PbrMr {
+func (m *Physical) SetEmissiveTexture(tex *texture.Texture2D) *Physical {
 
 	m.emissiveTex = tex
 	if m.emissiveTex != nil {
@@ -150,18 +150,18 @@ func (m *PbrMr) SetEmissiveTexture(tex *texture.Texture2D) *PbrMr {
 // SetRoughnessFactor sets this material roughness factor.
 // Its default value is 1.0
 // Returns pointer to this updated material.
-func (m *PbrMr) SetRoughnessFactor(v float32) *PbrMr {
+func (m *Physical) SetRoughnessFactor(v float32) *Physical {
 
 	m.udata.roughnessFactor = v
 	return m
 }
 
 // RenderSetup transfer this material uniforms and textures to the shader
-func (m *PbrMr) RenderSetup(gl *gls.GLS) {
+func (m *Physical) RenderSetup(gl *gls.GLS) {
 
 	m.Material.RenderSetup(gl)
 	location := m.uni.Location(gl)
-	gl.Uniform4fvUP(location, pbrMrVec4Count, unsafe.Pointer(&m.udata))
+	gl.Uniform4fvUP(location, physicalVec4Count, unsafe.Pointer(&m.udata))
 
 	// Transfer optional textures
 	if m.baseColorTex != nil {

+ 52 - 0
renderer/shaders/physical_fragment.glsl

@@ -0,0 +1,52 @@
+//
+// Physical material fragment shader
+//
+
+// Inputs from vertex shader
+in vec4 Position;       // Vertex position in camera coordinates.
+in vec3 Normal;         // Vertex normal in camera coordinates.
+in vec3 CamDir;         // Direction from vertex to camera
+in vec2 FragTexcoord;
+
+#include <lights>
+#include <material>
+#include <phong_model>
+
+// Final fragment color
+out vec4 FragColor;
+
+void main() {
+
+    // Mix material color with textures colors
+    vec4 texMixed = vec4(1);
+    vec4 texColor;
+    #if MAT_TEXTURES==1
+        MIX_TEXTURE(0)
+    #elif MAT_TEXTURES==2
+        MIX_TEXTURE(0)
+        MIX_TEXTURE(1)
+    #elif MAT_TEXTURES==3
+        MIX_TEXTURE(0)
+        MIX_TEXTURE(1)
+        MIX_TEXTURE(2)
+    #endif
+
+    // Combine material with texture colors
+    vec4 matDiffuse = vec4(MatDiffuseColor, MatOpacity) * texMixed;
+    vec4 matAmbient = vec4(MatAmbientColor, MatOpacity) * texMixed;
+
+    // Inverts the fragment normal if not FrontFacing
+    vec3 fragNormal = Normal;
+    if (!gl_FrontFacing) {
+        fragNormal = -fragNormal;
+    }
+
+    // Calculates the Ambient+Diffuse and Specular colors for this fragment using the Phong model.
+    vec3 Ambdiff, Spec;
+    phongModel(Position, fragNormal, CamDir, vec3(matAmbient), vec3(matDiffuse), Ambdiff, Spec);
+
+    // Final fragment color
+    FragColor = min(vec4(Ambdiff + Spec, matDiffuse.a), vec4(1.0));
+}
+
+

+ 43 - 0
renderer/shaders/physical_vertex.glsl

@@ -0,0 +1,43 @@
+//
+// Physical maiterial vertex shader
+//
+#include <attributes>
+
+// Model uniforms
+uniform mat4 ModelViewMatrix;
+uniform mat3 NormalMatrix;
+uniform mat4 MVP;
+
+#include <material>
+
+// Output variables for Fragment shader
+out vec4 Position;
+out vec3 Normal;
+out vec3 CamDir;
+out vec2 FragTexcoord;
+
+void main() {
+
+    // Transform this vertex position to camera coordinates.
+    Position = ModelViewMatrix * vec4(VertexPosition, 1.0);
+
+    // Transform this vertex normal to camera coordinates.
+    Normal = normalize(NormalMatrix * VertexNormal);
+
+    // Calculate the direction vector from the vertex to the camera
+    // The camera is at 0,0,0
+    CamDir = normalize(-Position.xyz);
+
+    // Flips texture coordinate Y if requested.
+    vec2 texcoord = VertexTexcoord;
+#if MAT_TEXTURES>0
+    if (MatTexFlipY(0)) {
+        texcoord.y = 1 - texcoord.y;
+    }
+#endif
+    FragTexcoord = texcoord;
+
+    gl_Position = MVP * vec4(VertexPosition, 1.0);
+}
+
+

+ 292 - 190
renderer/shaders/sources.go

@@ -3,6 +3,19 @@
 // 'go generate' in this folder.
 package shaders
 
+const include_attributes_source = `//
+// Vertex attributes
+//
+layout(location = 0) in  vec3  VertexPosition;
+layout(location = 1) in  vec3  VertexNormal;
+layout(location = 2) in  vec3  VertexColor;
+layout(location = 3) in  vec2  VertexTexcoord;
+layout(location = 4) in  float VertexDistance;
+layout(location = 5) in  vec4  VertexTexoffsets;
+
+
+`
+
 const include_phong_model_source = `/***
  phong lighting model
  Parameters:
@@ -119,6 +132,49 @@ void phongModel(vec4 position, vec3 normal, vec3 camDir, vec3 matAmbient, vec3 m
 }
 
 
+`
+
+const include_lights_source = `//
+// Lights uniforms
+//
+
+// Ambient lights uniforms
+#if AMB_LIGHTS>0
+    uniform vec3 AmbientLightColor[AMB_LIGHTS];
+#endif
+
+// Directional lights uniform array. Each directional light uses 2 elements
+#if DIR_LIGHTS>0
+    uniform vec3 DirLight[2*DIR_LIGHTS];
+    // Macros to access elements inside the DirectionalLight uniform array
+    #define DirLightColor(a)		DirLight[2*a]
+    #define DirLightPosition(a)		DirLight[2*a+1]
+#endif
+
+// Point lights uniform array. Each point light uses 3 elements
+#if POINT_LIGHTS>0
+    uniform vec3 PointLight[3*POINT_LIGHTS];
+    // Macros to access elements inside the PointLight uniform array
+    #define PointLightColor(a)			PointLight[3*a]
+    #define PointLightPosition(a)		PointLight[3*a+1]
+    #define PointLightLinearDecay(a)	PointLight[3*a+2].x
+    #define PointLightQuadraticDecay(a)	PointLight[3*a+2].y
+#endif
+
+#if SPOT_LIGHTS>0
+    // Spot lights uniforms. Each spot light uses 5 elements
+    uniform vec3  SpotLight[5*SPOT_LIGHTS];
+    
+    // Macros to access elements inside the PointLight uniform array
+    #define SpotLightColor(a)			SpotLight[5*a]
+    #define SpotLightPosition(a)		SpotLight[5*a+1]
+    #define SpotLightDirection(a)		SpotLight[5*a+2]
+    #define SpotLightAngularDecay(a)	SpotLight[5*a+3].x
+    #define SpotLightCutoffAngle(a)		SpotLight[5*a+3].y
+    #define SpotLightLinearDecay(a)		SpotLight[5*a+3].z
+    #define SpotLightQuadraticDecay(a)	SpotLight[5*a+4].x
+#endif
+
 `
 
 const include_material_source = `//
@@ -166,72 +222,129 @@ uniform vec3 Material[6];
 
 `
 
-const include_lights_source = `//
-// Lights uniforms
+const sprite_fragment_source = `//
+// Fragment shader for sprite
 //
 
-// Ambient lights uniforms
-#if AMB_LIGHTS>0
-    uniform vec3 AmbientLightColor[AMB_LIGHTS];
-#endif
+#include <material>
 
-// Directional lights uniform array. Each directional light uses 2 elements
-#if DIR_LIGHTS>0
-    uniform vec3 DirLight[2*DIR_LIGHTS];
-    // Macros to access elements inside the DirectionalLight uniform array
-    #define DirLightColor(a)		DirLight[2*a]
-    #define DirLightPosition(a)		DirLight[2*a+1]
-#endif
+// Inputs from vertex shader
+in vec3 Color;
+in vec2 FragTexcoord;
 
-// Point lights uniform array. Each point light uses 3 elements
-#if POINT_LIGHTS>0
-    uniform vec3 PointLight[3*POINT_LIGHTS];
-    // Macros to access elements inside the PointLight uniform array
-    #define PointLightColor(a)			PointLight[3*a]
-    #define PointLightPosition(a)		PointLight[3*a+1]
-    #define PointLightLinearDecay(a)	PointLight[3*a+2].x
-    #define PointLightQuadraticDecay(a)	PointLight[3*a+2].y
-#endif
+// Output
+out vec4 FragColor;
 
-#if SPOT_LIGHTS>0
-    // Spot lights uniforms. Each spot light uses 5 elements
-    uniform vec3  SpotLight[5*SPOT_LIGHTS];
-    
-    // Macros to access elements inside the PointLight uniform array
-    #define SpotLightColor(a)			SpotLight[5*a]
-    #define SpotLightPosition(a)		SpotLight[5*a+1]
-    #define SpotLightDirection(a)		SpotLight[5*a+2]
-    #define SpotLightAngularDecay(a)	SpotLight[5*a+3].x
-    #define SpotLightCutoffAngle(a)		SpotLight[5*a+3].y
-    #define SpotLightLinearDecay(a)		SpotLight[5*a+3].z
-    #define SpotLightQuadraticDecay(a)	SpotLight[5*a+4].x
+void main() {
+
+    // Combine all texture colors and opacity
+    vec4 texCombined = vec4(1);
+#if MAT_TEXTURES>0
+    for (int i = 0; i < {{.MatTexturesMax}}; i++) {
+        vec4 texcolor = texture(MatTexture[i], FragTexcoord * MatTexRepeat(i) + MatTexOffset(i));
+        if (i == 0) {
+            texCombined = texcolor;
+        } else {
+            texCombined = mix(texCombined, texcolor, texcolor.a);
+        }
+    }
 #endif
 
+    // Combine material color with texture
+    FragColor = min(vec4(Color, MatOpacity) * texCombined, vec4(1));
+}
+
 `
 
-const include_attributes_source = `//
-// Vertex attributes
+const sprite_vertex_source = `//
+// Vertex shader for sprites
 //
-layout(location = 0) in  vec3  VertexPosition;
-layout(location = 1) in  vec3  VertexNormal;
-layout(location = 2) in  vec3  VertexColor;
-layout(location = 3) in  vec2  VertexTexcoord;
-layout(location = 4) in  float VertexDistance;
-layout(location = 5) in  vec4  VertexTexoffsets;
 
+#include <attributes>
+
+// Input uniforms
+uniform mat4 MVP;
+
+#include <material>
+
+// Outputs for fragment shader
+out vec3 Color;
+out vec2 FragTexcoord;
+
+void main() {
+
+    // Applies transformation to vertex position
+    gl_Position = MVP * vec4(VertexPosition, 1.0);
+
+    // Outputs color
+    Color = MatDiffuseColor;
+
+    // Flips texture coordinate Y if requested.
+    vec2 texcoord = VertexTexcoord;
+#if MAT_TEXTURES>0
+    if (MatTexFlipY[0]) {
+        texcoord.y = 1 - texcoord.y;
+    }
+#endif
+    FragTexcoord = texcoord;
+}
 
 `
 
-const basic_fragment_source = `//
-// Fragment Shader template
+const point_vertex_source = `#include <attributes>
+
+// Model uniforms
+uniform mat4 MVP;
+
+// Material uniforms
+#include <material>
+
+// Outputs for fragment shader
+out vec3 Color;
+flat out mat2 Rotation;
+
+void main() {
+
+    // Rotation matrix for fragment shader
+    float rotSin = sin(MatPointRotationZ);
+    float rotCos = cos(MatPointRotationZ);
+    Rotation = mat2(rotCos, rotSin, - rotSin, rotCos);
+
+    // Sets the vertex position
+    vec4 pos = MVP * vec4(VertexPosition, 1.0);
+    gl_Position = pos;
+
+    // Sets the size of the rasterized point decreasing with distance
+    gl_PointSize = (1.0 - pos.z / pos.w) * MatPointSize;
+
+    // Outputs color
+    Color = MatEmissiveColor;
+}
+
+`
+
+const panel_vertex_source = `//
+// Vertex shader panel
 //
+#include <attributes>
+
+// Model uniforms
+uniform mat4 ModelMatrix;
+
+// Outputs for fragment shader
+out vec2 FragTexcoord;
 
-in vec3 Color;
-out vec4 FragColor;
 
 void main() {
 
-    FragColor = vec4(Color, 1.0);
+    // Always flip texture coordinates
+    vec2 texcoord = VertexTexcoord;
+    texcoord.y = 1 - texcoord.y;
+    FragTexcoord = texcoord;
+
+    // Set position
+    vec4 pos = vec4(VertexPosition.xyz, 1);
+    gl_Position = ModelMatrix * pos;
 }
 
 `
@@ -282,64 +395,102 @@ void main() {
 
 `
 
-const panel_vertex_source = `//
-// Vertex shader panel
+const standard_vertex_source = `//
+// Vertex shader standard
 //
 #include <attributes>
 
 // Model uniforms
-uniform mat4 ModelMatrix;
+uniform mat4 ModelViewMatrix;
+uniform mat3 NormalMatrix;
+uniform mat4 MVP;
 
-// Outputs for fragment shader
-out vec2 FragTexcoord;
+#include <lights>
+#include <material>
+#include <phong_model>
 
 
+// Outputs for the fragment shader.
+out vec3 ColorFrontAmbdiff;
+out vec3 ColorFrontSpec;
+out vec3 ColorBackAmbdiff;
+out vec3 ColorBackSpec;
+out vec2 FragTexcoord;
+
 void main() {
 
-    // Always flip texture coordinates
+    // Transform this vertex normal to camera coordinates.
+    vec3 normal = normalize(NormalMatrix * VertexNormal);
+
+    // Calculate this vertex position in camera coordinates
+    vec4 position = ModelViewMatrix * vec4(VertexPosition, 1.0);
+
+    // Calculate the direction vector from the vertex to the camera
+    // The camera is at 0,0,0
+    vec3 camDir = normalize(-position.xyz);
+
+    // Calculates the vertex Ambient+Diffuse and Specular colors using the Phong model
+    // for the front and back
+    phongModel(position,  normal, camDir, MatAmbientColor, MatDiffuseColor, ColorFrontAmbdiff, ColorFrontSpec);
+    phongModel(position, -normal, camDir, MatAmbientColor, MatDiffuseColor, ColorBackAmbdiff, ColorBackSpec);
+
     vec2 texcoord = VertexTexcoord;
-    texcoord.y = 1 - texcoord.y;
+#if MAT_TEXTURES > 0
+    // Flips texture coordinate Y if requested.
+    if (MatTexFlipY(0)) {
+        texcoord.y = 1 - texcoord.y;
+    }
+#endif
     FragTexcoord = texcoord;
 
-    // Set position
-    vec4 pos = vec4(VertexPosition.xyz, 1);
-    gl_Position = ModelMatrix * pos;
+    gl_Position = MVP * vec4(VertexPosition, 1.0);
 }
 
 `
 
-const sprite_fragment_source = `//
-// Fragment shader for sprite
+const physical_vertex_source = `//
+// Physical maiterial vertex shader
 //
+#include <attributes>
 
-#include <material>
+// Model uniforms
+uniform mat4 ModelViewMatrix;
+uniform mat3 NormalMatrix;
+uniform mat4 MVP;
 
-// Inputs from vertex shader
-in vec3 Color;
-in vec2 FragTexcoord;
+#include <material>
 
-// Output
-out vec4 FragColor;
+// Output variables for Fragment shader
+out vec4 Position;
+out vec3 Normal;
+out vec3 CamDir;
+out vec2 FragTexcoord;
 
 void main() {
 
-    // Combine all texture colors and opacity
-    vec4 texCombined = vec4(1);
+    // Transform this vertex position to camera coordinates.
+    Position = ModelViewMatrix * vec4(VertexPosition, 1.0);
+
+    // Transform this vertex normal to camera coordinates.
+    Normal = normalize(NormalMatrix * VertexNormal);
+
+    // Calculate the direction vector from the vertex to the camera
+    // The camera is at 0,0,0
+    CamDir = normalize(-Position.xyz);
+
+    // Flips texture coordinate Y if requested.
+    vec2 texcoord = VertexTexcoord;
 #if MAT_TEXTURES>0
-    for (int i = 0; i < {{.MatTexturesMax}}; i++) {
-        vec4 texcolor = texture(MatTexture[i], FragTexcoord * MatTexRepeat(i) + MatTexOffset(i));
-        if (i == 0) {
-            texCombined = texcolor;
-        } else {
-            texCombined = mix(texCombined, texcolor, texcolor.a);
-        }
+    if (MatTexFlipY(0)) {
+        texcoord.y = 1 - texcoord.y;
     }
 #endif
+    FragTexcoord = texcoord;
 
-    // Combine material color with texture
-    FragColor = min(vec4(Color, MatOpacity) * texCombined, vec4(1));
+    gl_Position = MVP * vec4(VertexPosition, 1.0);
 }
 
+
 `
 
 const point_fragment_source = `#include <material>
@@ -386,6 +537,20 @@ void main() {
 
 `
 
+const basic_fragment_source = `//
+// Fragment Shader template
+//
+
+in vec3 Color;
+out vec4 FragColor;
+
+void main() {
+
+    FragColor = vec4(Color, 1.0);
+}
+
+`
+
 const phong_vertex_source = `//
 // Vertex Shader
 //
@@ -591,141 +756,75 @@ void main() {
 
 `
 
-const sprite_vertex_source = `//
-// Vertex shader for sprites
+const basic_vertex_source = `//
+// Vertex shader basic
 //
-
 #include <attributes>
 
-// Input uniforms
+// Model uniforms
 uniform mat4 MVP;
 
-#include <material>
-
-// Outputs for fragment shader
+// Final output color for fragment shader
 out vec3 Color;
-out vec2 FragTexcoord;
 
 void main() {
 
-    // Applies transformation to vertex position
+    Color = VertexColor;
     gl_Position = MVP * vec4(VertexPosition, 1.0);
-
-    // Outputs color
-    Color = MatDiffuseColor;
-
-    // Flips texture coordinate Y if requested.
-    vec2 texcoord = VertexTexcoord;
-#if MAT_TEXTURES>0
-    if (MatTexFlipY[0]) {
-        texcoord.y = 1 - texcoord.y;
-    }
-#endif
-    FragTexcoord = texcoord;
 }
 
+
 `
 
-const standard_vertex_source = `//
-// Vertex shader standard
+const physical_fragment_source = `//
+// Physical material fragment shader
 //
-#include <attributes>
 
-// Model uniforms
-uniform mat4 ModelViewMatrix;
-uniform mat3 NormalMatrix;
-uniform mat4 MVP;
+// Inputs from vertex shader
+in vec4 Position;       // Vertex position in camera coordinates.
+in vec3 Normal;         // Vertex normal in camera coordinates.
+in vec3 CamDir;         // Direction from vertex to camera
+in vec2 FragTexcoord;
 
 #include <lights>
 #include <material>
 #include <phong_model>
 
-
-// Outputs for the fragment shader.
-out vec3 ColorFrontAmbdiff;
-out vec3 ColorFrontSpec;
-out vec3 ColorBackAmbdiff;
-out vec3 ColorBackSpec;
-out vec2 FragTexcoord;
+// Final fragment color
+out vec4 FragColor;
 
 void main() {
 
-    // Transform this vertex normal to camera coordinates.
-    vec3 normal = normalize(NormalMatrix * VertexNormal);
-
-    // Calculate this vertex position in camera coordinates
-    vec4 position = ModelViewMatrix * vec4(VertexPosition, 1.0);
-
-    // Calculate the direction vector from the vertex to the camera
-    // The camera is at 0,0,0
-    vec3 camDir = normalize(-position.xyz);
+    // Mix material color with textures colors
+    vec4 texMixed = vec4(1);
+    vec4 texColor;
+    #if MAT_TEXTURES==1
+        MIX_TEXTURE(0)
+    #elif MAT_TEXTURES==2
+        MIX_TEXTURE(0)
+        MIX_TEXTURE(1)
+    #elif MAT_TEXTURES==3
+        MIX_TEXTURE(0)
+        MIX_TEXTURE(1)
+        MIX_TEXTURE(2)
+    #endif
 
-    // Calculates the vertex Ambient+Diffuse and Specular colors using the Phong model
-    // for the front and back
-    phongModel(position,  normal, camDir, MatAmbientColor, MatDiffuseColor, ColorFrontAmbdiff, ColorFrontSpec);
-    phongModel(position, -normal, camDir, MatAmbientColor, MatDiffuseColor, ColorBackAmbdiff, ColorBackSpec);
+    // Combine material with texture colors
+    vec4 matDiffuse = vec4(MatDiffuseColor, MatOpacity) * texMixed;
+    vec4 matAmbient = vec4(MatAmbientColor, MatOpacity) * texMixed;
 
-    vec2 texcoord = VertexTexcoord;
-#if MAT_TEXTURES > 0
-    // Flips texture coordinate Y if requested.
-    if (MatTexFlipY(0)) {
-        texcoord.y = 1 - texcoord.y;
+    // Inverts the fragment normal if not FrontFacing
+    vec3 fragNormal = Normal;
+    if (!gl_FrontFacing) {
+        fragNormal = -fragNormal;
     }
-#endif
-    FragTexcoord = texcoord;
-
-    gl_Position = MVP * vec4(VertexPosition, 1.0);
-}
-
-`
-
-const point_vertex_source = `#include <attributes>
-
-// Model uniforms
-uniform mat4 MVP;
-
-// Material uniforms
-#include <material>
 
-// Outputs for fragment shader
-out vec3 Color;
-flat out mat2 Rotation;
-
-void main() {
-
-    // Rotation matrix for fragment shader
-    float rotSin = sin(MatPointRotationZ);
-    float rotCos = cos(MatPointRotationZ);
-    Rotation = mat2(rotCos, rotSin, - rotSin, rotCos);
-
-    // Sets the vertex position
-    vec4 pos = MVP * vec4(VertexPosition, 1.0);
-    gl_Position = pos;
-
-    // Sets the size of the rasterized point decreasing with distance
-    gl_PointSize = (1.0 - pos.z / pos.w) * MatPointSize;
-
-    // Outputs color
-    Color = MatEmissiveColor;
-}
-
-`
-
-const basic_vertex_source = `//
-// Vertex shader basic
-//
-#include <attributes>
-
-// Model uniforms
-uniform mat4 MVP;
-
-// Final output color for fragment shader
-out vec3 Color;
-
-void main() {
+    // Calculates the Ambient+Diffuse and Specular colors for this fragment using the Phong model.
+    vec3 Ambdiff, Spec;
+    phongModel(Position, fragNormal, CamDir, vec3(matAmbient), vec3(matDiffuse), Ambdiff, Spec);
 
-    Color = VertexColor;
-    gl_Position = MVP * vec4(VertexPosition, 1.0);
+    // Final fragment color
+    FragColor = min(vec4(Ambdiff + Spec, matDiffuse.a), vec4(1.0));
 }
 
 
@@ -734,27 +833,29 @@ void main() {
 // Maps include name with its source code
 var includeMap = map[string]string{
 
+	"attributes":  include_attributes_source,
 	"phong_model": include_phong_model_source,
-	"material":    include_material_source,
 	"lights":      include_lights_source,
-	"attributes":  include_attributes_source,
+	"material":    include_material_source,
 }
 
 // Maps shader name with its source code
 var shaderMap = map[string]string{
 
-	"basic_fragment":    basic_fragment_source,
-	"standard_fragment": standard_fragment_source,
-	"panel_vertex":      panel_vertex_source,
 	"sprite_fragment":   sprite_fragment_source,
+	"sprite_vertex":     sprite_vertex_source,
+	"point_vertex":      point_vertex_source,
+	"panel_vertex":      panel_vertex_source,
+	"standard_fragment": standard_fragment_source,
+	"standard_vertex":   standard_vertex_source,
+	"physical_vertex":   physical_vertex_source,
 	"point_fragment":    point_fragment_source,
+	"basic_fragment":    basic_fragment_source,
 	"phong_vertex":      phong_vertex_source,
 	"panel_fragment":    panel_fragment_source,
 	"phong_fragment":    phong_fragment_source,
-	"sprite_vertex":     sprite_vertex_source,
-	"standard_vertex":   standard_vertex_source,
-	"point_vertex":      point_vertex_source,
 	"basic_vertex":      basic_vertex_source,
+	"physical_fragment": physical_fragment_source,
 }
 
 // Maps program name with Proginfo struct with shaders names
@@ -763,6 +864,7 @@ var programMap = map[string]ProgramInfo{
 	"basic":    {"basic_vertex", "basic_fragment", ""},
 	"panel":    {"panel_vertex", "panel_fragment", ""},
 	"phong":    {"phong_vertex", "phong_fragment", ""},
+	"physical": {"physical_vertex", "physical_fragment", ""},
 	"point":    {"point_vertex", "point_fragment", ""},
 	"sprite":   {"sprite_vertex", "sprite_fragment", ""},
 	"standard": {"standard_vertex", "standard_fragment", ""},

+ 42 - 5
renderer/shaman.go

@@ -121,7 +121,8 @@ func (sm *Shaman) AddProgram(name, vertexName, fragName string, others ...string
 func (sm *Shaman) SetProgram(s *ShaderSpecs) (bool, error) {
 
 	// Checks material use lights bit mask
-	specs := *s
+	var specs ShaderSpecs
+	specs.copy(s)
 	if (specs.UseLights & material.UseLightAmbient) == 0 {
 		specs.AmbientLightsMax = 0
 	}
@@ -136,13 +137,13 @@ func (sm *Shaman) SetProgram(s *ShaderSpecs) (bool, error) {
 	}
 
 	// If current shader specs are the same as the specified specs, nothing to do.
-	if sm.specs.Compare(&specs) {
+	if sm.specs.compare(&specs) {
 		return false, nil
 	}
 
 	// Search for compiled program with the specified specs
 	for _, pinfo := range sm.programs {
-		if pinfo.specs.Compare(&specs) {
+		if pinfo.specs.compare(&specs) {
 			sm.gs.UseProgram(pinfo.program)
 			sm.specs = specs
 			return true, nil
@@ -282,8 +283,20 @@ func (sm *Shaman) preprocess(source string, defines map[string]string) (string,
 	return prefix + newSource, nil
 }
 
+// copy copies other spec into this
+func (ss *ShaderSpecs) copy(other *ShaderSpecs) {
+
+	*ss = *other
+	if other.Defines != nil {
+		ss.Defines = make(map[string]string)
+		for k, v := range other.Defines {
+			ss.Defines[k] = v
+		}
+	}
+}
+
 // Compare compares two shaders specifications structures
-func (ss *ShaderSpecs) Compare(other *ShaderSpecs) bool {
+func (ss *ShaderSpecs) compare(other *ShaderSpecs) bool {
 
 	if ss.Name != other.Name {
 		return false
@@ -295,8 +308,32 @@ func (ss *ShaderSpecs) Compare(other *ShaderSpecs) bool {
 		ss.DirLightsMax == other.DirLightsMax &&
 		ss.PointLightsMax == other.PointLightsMax &&
 		ss.SpotLightsMax == other.SpotLightsMax &&
-		ss.MatTexturesMax == other.MatTexturesMax {
+		ss.MatTexturesMax == other.MatTexturesMax &&
+		ss.compareDefines(other) {
+		return true
+	}
+	return false
+}
+
+// compareDefines compares two shaders specification define maps.
+func (ss *ShaderSpecs) compareDefines(other *ShaderSpecs) bool {
+
+	if ss.Defines == nil && other.Defines == nil {
+		return true
+	}
+	if ss.Defines != nil && other.Defines != nil {
+		if len(ss.Defines) != len(other.Defines) {
+			return false
+		}
+		for k, _ := range ss.Defines {
+			v1, ok1 := ss.Defines[k]
+			v2, ok2 := other.Defines[k]
+			if v1 != v2 || ok1 != ok2 {
+				return false
+			}
+		}
 		return true
 	}
+	// One is nil and the other is not nil
 	return false
 }