Пример #1
0
//LoadPng tries to load a png file from hard drive and upload it to the GPU.
func LoadPng(file string) (gl2.Texture2D, error) {
	imgFile, err := os.Open(file)
	if err != nil {
		return 0, nil
	}
	defer imgFile.Close()
	img, _, err := image.Decode(imgFile)
	if err != nil {
		return 0, nil
	}

	rgba := image.NewRGBA(img.Bounds())
	if rgba.Stride != rgba.Rect.Size().X*4 {
		return 0, fmt.Errorf("unsupported stride")
	}
	draw.Draw(rgba, rgba.Bounds(), img, image.Point{0, 0}, draw.Src)

	texture := gl2.GenTexture2D()
	gl.ActiveTexture(gl2.TEXTURE0)
	texture.Bind()
	defer texture.Unbind()
	texture.MinFilter(gl2.LINEAR)
	texture.MagFilter(gl2.LINEAR)
	texture.WrapS(gl2.CLAMP_TO_EDGE)
	texture.WrapT(gl2.CLAMP_TO_EDGE)
	texture.TexImage2D(0, gl2.RGBA, int32(rgba.Rect.Size().X), int32(rgba.Rect.Size().Y), 0, gl2.RGBA, gl2.UNSIGNED_BYTE, gl.Ptr(rgba.Pix))

	return texture, nil
}
Пример #2
0
//GenRGBTexture2D is a utility function to generate an empty 2D textures of size (width,height), internal format RGB adn data type UNSIGNED_BYTE
func GenRGBTexture2D(width, height int32) gl.Texture2D {
	tex := gl.GenTexture2D()
	tex.Bind()
	tex.MinFilter(gl.LINEAR)
	tex.MagFilter(gl.LINEAR)
	tex.WrapS(gl.CLAMP_TO_EDGE)
	tex.WrapT(gl.CLAMP_TO_EDGE)
	tex.TexImage2D(0, gl.RGB, width, height, 0, gl.RGB, gl.UNSIGNED_BYTE, nil)
	return tex
}
Пример #3
0
//GenDepthTexture is a utility function to generate a depth Texture2D
func GenDepthTexture(width, height int32) gl2.Texture2D {
	tex := gl2.GenTexture2D()
	tex.Bind()
	defer tex.Unbind()
	tex.MinFilter(gl2.NEAREST)
	tex.MagFilter(gl2.NEAREST)
	tex.WrapS(gl2.CLAMP_TO_EDGE)
	tex.WrapT(gl2.CLAMP_TO_EDGE)
	tex.TexImage2D(0, gl.DEPTH_COMPONENT, width, height, 0, gl.DEPTH_COMPONENT, gl.FLOAT, nil)
	return tex
}
Пример #4
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
}
Пример #5
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
}