예제 #1
0
//NewShadowFBO will create a new FBO, a new depth texture and the program needed to generate shadow map
//currently not optimized, we should probably reuse the FBO and absolutely reuse the program.
func NewShadowFBO(width, height int32) (*ShadowFBO, error) {
	sfbo := ShadowFBO{}
	fbo := gl2.GenFramebuffer()
	sfbo.width, sfbo.height = width, height
	sfbo.framebuffer = fbo
	fbo.Bind(gl2.FRAMEBUFFER)
	defer fbo.Unbind(gl2.FRAMEBUFFER)

	shadowtex := gl2.GenTexture2D()
	sfbo.texture = shadowtex
	shadowtex.Bind()
	defer shadowtex.Unbind()
	shadowtex.TexParameteriv(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
	shadowtex.TexParameteriv(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
	shadowtex.TexParameteriv(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
	shadowtex.TexParameteriv(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
	shadowtex.TexParameteriv(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE)
	shadowtex.TexParameteriv(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_FUNC, gl.LEQUAL)
	shadowtex.TexImage2D(0, gl.DEPTH_COMPONENT16, width, height, 0, gl.DEPTH_COMPONENT, gl.FLOAT, nil)

	fbo.Texture(gl2.FRAMEBUFFER, gl2.DEPTH_ATTACHMENT, shadowtex, 0 /*level*/)

	fbo.DrawBuffer(gl2.NONE)
	fbo.ReadBuffer(gl2.NONE)

	if gl.CheckFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE {
		return &sfbo, errors.New("framebuffer incomplete")
	}

	vs, err := CompileShader(_shadowFboVertexShader, gl2.VERTEX_SHADER)
	if err != nil {
		return &sfbo, err
	}
	defer vs.Delete()
	fs, err := CompileShader(_shadowFboFragmentShader, gl2.FRAGMENT_SHADER)
	if err != nil {
		return &sfbo, err
	}
	defer fs.Delete()
	prog, err := NewProgram(vs, fs)
	if err != nil {
		return &sfbo, err
	}
	sfbo.program = prog
	prog.Use()
	sfbo.mvpUni = prog.GetUniformLocation("mvp")

	return &sfbo, nil
}
예제 #2
0
//NewPostProcessFramebuffer creates a new PostProcessFramebuffer and allocated all the ressources.
//You do not control the vertex shader but you can give a fragment shader. The fragment shader must have the following uniforms:
//	-resolution: float vec2, representing the size of the texture
//	-time: float, glfw time since the begining of the program
//	-tex: sampler2D, the input texture to this post process pass
func NewPostProcessFramebuffer(width, height int32, fragmentSource string) (*PostProcessFramebuffer, error) {
	ppf := PostProcessFramebuffer{}
	vs, err := CompileShader(_fullscreenVertexShader, gl2.VERTEX_SHADER)
	if err != nil {
		return &ppf, err
	}
	defer vs.Delete()
	fs, err := CompileShader(fragmentSource, gl2.FRAGMENT_SHADER)
	if err != nil {
		return &ppf, err
	}
	defer fs.Delete()
	prog, err := NewProgram(vs, fs)
	if err != nil {
		return &ppf, err
	}
	ppf.Prog = prog
	prog.Use()
	res := prog.GetUniformLocation("resolution")
	ppf.source = prog.GetUniformLocation("tex")

	res.Uniform2f(float32(width), float32(height))

	ppf.time = prog.GetUniformLocation("time")

	ppf.Fb = gl2.GenFramebuffer()
	ppf.Tex = GenRGBTexture2D(width, height)

	ppf.Fb.Bind(gl2.FRAMEBUFFER)
	defer ppf.Fb.Unbind(gl2.FRAMEBUFFER)

	ppf.Fb.Texture(gl2.FRAMEBUFFER, gl2.COLOR_ATTACHMENT0, ppf.Tex, 0)
	ppf.Fb.DrawBuffers(gl2.COLOR_ATTACHMENT0)

	if gl.CheckFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE {
		return &ppf, errors.New("framebuffer incomplete")
	}
	return &ppf, nil
}
예제 #3
0
//NewGBuffer will create a new geometry buffer and allocate all the resources required
func NewGBuffer(width, height int32) (gbuffer GBuffer, err error) {
	const (
		_gbufferVertexShaderSource = `#version 330
uniform mat4 M;
uniform mat4 MVP;

layout (location=0) in vec3 vert;
layout (location=1) in vec2 vertTexCoord;
layout (location=2) in vec3 vertNormal;

out vec2 fragTexCoord;
out vec3 normal;
out vec3 world_pos;

void main() {
	normal = vertNormal;
	fragTexCoord = vertTexCoord;
	world_pos=(M*vec4(vert,1)).xyz;
	gl_Position = MVP * vec4(vert, 1);
}
` + "\x00"

		_gbufferFragmentShaderSource = `#version 330
uniform sampler2D diffuse;
uniform mat4 N;

in vec2 fragTexCoord;
in vec3 normal;
in vec3 world_pos;
layout (location=0) out vec3 outColor;
layout (location=1) out vec3 outNormal;
layout (location=2) out vec3 outPosition;
void main() {
	outColor = texture(diffuse, fragTexCoord).rgb;
	outNormal = (N*vec4(normal,1)).xyz;
	outPosition = world_pos;
}
` + "\x00"

		//shouldnt be there
		_gbufferAggregateFragmentShader = `#version 330
#define MAX_POINT_LIGHT 8
#define MIN_LUX 0.3

//GBuffer textures
uniform sampler2D diffusetex;
uniform sampler2D normaltex;
uniform sampler2D postex;
uniform sampler2D depthtex;

//cook
uniform float roughnessValue;
uniform float F0;
uniform float k;

//Lights
uniform int NUM_POINT_LIGHT;
uniform vec3 point_light_pos[MAX_POINT_LIGHT];
uniform vec3 point_light_color[MAX_POINT_LIGHT];

//Shadows
uniform sampler2DShadow shadowmap;
uniform mat4 shadowmat;

//View
uniform vec3 cam_pos;

in vec2 uv;

layout (location=0) out vec4 outColor;

void main(){
	vec3 normal = normalize(texture(normaltex, uv).xyz);
	vec3 world_position = texture(postex, uv).xyz;

	vec4 shadowcoord = shadowmat*vec4(world_position, 1);
	shadowcoord.z+=0.005;
	float shadow = texture(shadowmap, shadowcoord.xyz,0);

	//////cook torrance

	//material values
	vec3 lightColor = vec3(0.9,0.1,0.1);

	vec3 world_pos = texture(postex, uv).xyz;
	vec3 lightDir = point_light_pos[0]-world_pos;

	float NdL = max(dot(normal, lightDir), 0);

	float lux = shadow;
	if(shadow > 0){
		float specular = 0.0;
		if(NdL > 0.0){
			vec3 eyeDir = normalize(cam_pos-world_pos);

			vec3 halfVec = normalize(lightDir+eyeDir);
			float NdH = max(0,dot(normal,halfVec));
			float NdV = max(0,dot(normal, eyeDir));
			float VdH = max(0,dot(eyeDir, halfVec));
			float mSqu = roughnessValue*roughnessValue;

			float NH2 = 2.0*NdH;
			float geoAtt = min(1.0,min((NH2*NdV)/VdH,(NH2*NdL)/VdH));
			float roughness = (1.0 / ( 4.0 * mSqu * pow(NdH, 4.0)))*exp((NdH * NdH - 1.0) / (mSqu * NdH * NdH));
			float fresnel = pow(1.0 - VdH, 5.0)*(1.0 - F0)+F0;
			specular = (fresnel*geoAtt*roughness)/(NdV*NdL*3.14);
		}
		lux=NdL * (k + specular * (1.0 - k));
	}
	if(lux < MIN_LUX){
		lux=MIN_LUX;
	}
	outColor = texture(diffusetex, uv)*lux;
}
` + "\x00"
	)

	gbuffer.width, gbuffer.height = width, height
	fb := gl2.GenFramebuffer()
	fb.Bind(gl2.FRAMEBUFFER)
	defer fb.Unbind(gl2.FRAMEBUFFER)
	gbuffer.framebuffer = fb

	depthtex := gl2.GenTexture2D()
	depthtex.Bind()
	depthtex.MinFilter(gl2.NEAREST)
	depthtex.MagFilter(gl2.NEAREST)
	depthtex.WrapS(gl2.CLAMP_TO_EDGE)
	depthtex.WrapT(gl2.CLAMP_TO_EDGE)
	depthtex.TexImage2D(0, gl2.DEPTH24_STENCIL8, width, height, 0, gl2.DEPTH_STENCIL, gl2.UNSIGNED_INT_24_8, nil)

	diffuseTex := gl2.GenTexture2D()
	diffuseTex.Bind()
	diffuseTex.MinFilter(gl2.LINEAR)
	diffuseTex.MagFilter(gl2.LINEAR)
	diffuseTex.WrapS(gl2.CLAMP_TO_EDGE)
	diffuseTex.WrapT(gl2.CLAMP_TO_EDGE)
	diffuseTex.TexImage2D(0, gl2.RGB16F, width, height, 0, gl2.RGBA, gl2.FLOAT, nil)

	normalTex := gl2.GenTexture2D()
	normalTex.Bind()
	normalTex.MinFilter(gl2.LINEAR)
	normalTex.MagFilter(gl2.LINEAR)
	normalTex.WrapS(gl2.CLAMP_TO_EDGE)
	normalTex.WrapT(gl2.CLAMP_TO_EDGE)
	normalTex.TexImage2D(0, gl2.RGB16F, width, height, 0, gl2.RGB, gl2.FLOAT, nil)

	positionTex := gl2.GenTexture2D()
	positionTex.Bind()
	positionTex.MinFilter(gl2.LINEAR)
	positionTex.MagFilter(gl2.LINEAR)
	positionTex.WrapS(gl2.CLAMP_TO_EDGE)
	positionTex.WrapT(gl2.CLAMP_TO_EDGE)
	positionTex.TexImage2D(0, gl2.RGB16F, width, height, 0, gl2.RGB, gl2.FLOAT, nil)

	fb.DrawBuffers(gl2.COLOR_ATTACHMENT0, gl2.COLOR_ATTACHMENT1, gl2.COLOR_ATTACHMENT2)

	fb.Texture(gl2.FRAMEBUFFER, gl2.COLOR_ATTACHMENT0, diffuseTex, 0 /*level*/)
	fb.Texture(gl2.FRAMEBUFFER, gl2.COLOR_ATTACHMENT1, normalTex, 0 /*level*/)
	fb.Texture(gl2.FRAMEBUFFER, gl2.COLOR_ATTACHMENT2, positionTex, 0 /*level*/)
	fb.Texture(gl2.FRAMEBUFFER, gl2.DEPTH_STENCIL_ATTACHMENT, depthtex, 0 /*level*/)

	gbuffer.DiffuseTex = diffuseTex
	gbuffer.NormalTex = normalTex
	gbuffer.PositionTex = positionTex
	gbuffer.DepthTex = depthtex

	vs, err := CompileShader(_gbufferVertexShaderSource, gl2.VERTEX_SHADER)
	if err != nil {
		return
	}
	fs, err := CompileShader(_gbufferFragmentShaderSource, gl2.FRAGMENT_SHADER)
	if err != nil {
		return
	}
	prog, err := NewProgram(vs, fs)
	if err != nil {
		return
	}
	gbuffer.program = prog

	prog.Use()
	defer prog.Unuse()
	gbuffer.PUni = prog.GetUniformLocation("P")
	gbuffer.VUni = prog.GetUniformLocation("V")
	gbuffer.MUni = prog.GetUniformLocation("M")
	gbuffer.NUni = prog.GetUniformLocation("N")
	gbuffer.MVPUni = prog.GetUniformLocation("MVP")
	gbuffer.DiffuseUni = prog.GetUniformLocation("diffuse")
	//shadow map

	prog.BindFragDataLocation(0, "")
	prog.BindFragDataLocation(1, "")
	prog.BindFragDataLocation(2, "")

	//Aggregated fb and textures, essentially a special post process effect
	aggfb := AggregateFB{}
	gbuffer.AggregateFramebuffer = aggfb

	avs, err := CompileShader(_fullscreenVertexShader, gl2.VERTEX_SHADER)
	if err != nil {
		return
	}
	afs, err := CompileShader(_gbufferAggregateFragmentShader, gl2.FRAGMENT_SHADER)
	if err != nil {
		return
	}
	aprog, err := NewProgram(avs, afs)
	if err != nil {
		return
	}
	aggfb.program = aprog

	aggfb.framebuffer = gl2.GenFramebuffer()
	aggfb.framebuffer.Bind(gl2.FRAMEBUFFER)

	aggfb.Out = gl2.GenTexture2D()
	aggfb.Out.Bind()
	aggfb.Out.MinFilter(gl2.LINEAR)
	aggfb.Out.MagFilter(gl2.LINEAR)
	aggfb.Out.WrapS(gl2.CLAMP_TO_EDGE)
	aggfb.Out.WrapT(gl2.CLAMP_TO_EDGE)
	aggfb.Out.TexImage2D(0, gl2.RGBA16F, width, height, 0, gl2.RGB, gl2.FLOAT, nil)

	aggfb.DiffUni = aprog.GetUniformLocation("diffusetex")
	aggfb.NormalUni = aprog.GetUniformLocation("normaltex")
	aggfb.PosUni = aprog.GetUniformLocation("postex")
	aggfb.DepthUni = aprog.GetUniformLocation("depthtex")
	gbuffer.ShadowMapUni = aprog.GetUniformLocation("shadowmap")
	gbuffer.ShadowMatUni = aprog.GetUniformLocation("shadowmat")

	gbuffer.NumPointLightUni = aprog.GetUniformLocation("NUM_POINT_LIGHT")
	gbuffer.PointLightPosUni = aprog.GetUniformLocation("point_light_pos")
	gbuffer.PointLightColUni = aprog.GetUniformLocation("point_light_color")
	gbuffer.CamPosUni = aprog.GetUniformLocation("cam_pos")

	//test data for cook torrance shader
	gbuffer.CookRoughnessValue = aprog.GetUniformLocation("roughnessValue")
	gbuffer.CookF0 = aprog.GetUniformLocation("F0")
	gbuffer.CookK = aprog.GetUniformLocation("k")

	aggfb.framebuffer.DrawBuffers(gl2.COLOR_ATTACHMENT0)
	aggfb.framebuffer.Texture(gl2.FRAMEBUFFER, gl2.COLOR_ATTACHMENT0, aggfb.Out, 0)

	gbuffer.AggregateFramebuffer = aggfb
	return
}