render: move render_world_helper, remove chunks drawn behind view
This commit is contained in:
		| @@ -145,6 +145,12 @@ func (g *Game) Init(win *glfw.Window) { | ||||
|  | ||||
| 					g.fullscreen = true | ||||
| 				} | ||||
| 				win.MakeContextCurrent() | ||||
| 				glfw.SwapInterval(1) | ||||
| 			} | ||||
|  | ||||
| 			if key == glfw.KeyF3 { | ||||
| 				io.ShowDebugInfo = !io.ShowDebugInfo | ||||
| 			} | ||||
| 		} | ||||
| 	}) | ||||
| @@ -225,6 +231,8 @@ func (g *Game) Update(win *glfw.Window, delta time.Duration) { | ||||
| 	g.player.Update(g.world, delta) | ||||
|  | ||||
| 	g.view.LookAt(g.player.EyePosition().ToFloat32(), g.rotY, itype.Degrees(g.rotZ)) | ||||
| 	io.ViewPos = g.player.EyePosition() | ||||
| 	io.ViewDir = itype.Vec3d(mgl64.Rotate3DY(float64(g.rotY.Radians())).Mul3(mgl64.Rotate3DZ(float64(itype.Degrees(g.rotZ)))).Mul3x1(mgl64.Vec3{1, 0, 0})) | ||||
|  | ||||
| 	render.Framewire.PushBox(g.player.WorldHitbox().ToFloat32(), color.White) | ||||
|  | ||||
|   | ||||
| @@ -4,4 +4,10 @@ import "edgaru089.ml/go/gl01/internal/util/itype" | ||||
|  | ||||
| var ( | ||||
| 	DisplaySize itype.Vec2i // Size of the window viewport in pixels. | ||||
|  | ||||
| 	// Directions are not always normalized. | ||||
| 	ViewPos, ViewDir     itype.Vec3d // Position and Direction of the player view. | ||||
| 	RenderPos, RenderDir itype.Vec3d // Position and Direction of view for the current render pass. Might be different for e.g. lighting passes | ||||
|  | ||||
| 	ShowDebugInfo bool // Show debug info (F3 screen)? | ||||
| ) | ||||
|   | ||||
							
								
								
									
										23
									
								
								internal/render/drawtexture.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								internal/render/drawtexture.frag
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| #version 330 | ||||
|  | ||||
| #define DrawTextureChannels_R (1<<0) | ||||
| #define DrawTextureChannels_G (1<<1) | ||||
| #define DrawTextureChannels_B (1<<2) | ||||
| #define DrawTextureChannels_A (1<<3) | ||||
|  | ||||
| uniform float valueMin, valueMax; | ||||
| uniform int channels; | ||||
|  | ||||
| uniform sampler2D tex; | ||||
|  | ||||
| in vec2 fragVert; | ||||
| in vec2 fragTexCoord; | ||||
|  | ||||
| out vec4 outputColor; | ||||
|  | ||||
|  | ||||
| void main() { | ||||
|  | ||||
| 	outputColor = vec4(0, 0, 0, 1); | ||||
|  | ||||
| } | ||||
							
								
								
									
										17
									
								
								internal/render/drawtexture.vert
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								internal/render/drawtexture.vert
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| #version 330 | ||||
|  | ||||
| uniform vec2 onScreenPos, onScreenSize; | ||||
|  | ||||
| layout (location = 0) in vec2 vert; | ||||
| layout (location = 1) in vec2 texCoord; | ||||
|  | ||||
| out vec2 fragVert; | ||||
| out vec2 fragTexCoord; | ||||
|  | ||||
|  | ||||
| void main() { | ||||
| 	gl_Position = vec4(onScreenPos + onScreenSize * texCoord, 1, 0); | ||||
| 	fragVert = texCoord * 2 - vec2(1, 1); | ||||
| 	fragTexCoord = texCoord; | ||||
| } | ||||
|  | ||||
| @@ -138,6 +138,8 @@ func (r *WorldRenderer) ResizeDisplay(newSize itype.Vec2i) { | ||||
| var sun = [3]float32{0.2, 0.4, 0.3} | ||||
|  | ||||
| func (r *WorldRenderer) Render(world *world.World, view *View) { | ||||
| 	io.RenderPos = io.ViewPos | ||||
| 	io.RenderDir = io.ViewDir | ||||
|  | ||||
| 	// re-generate the G-buffers if the display size changed | ||||
| 	if r.lastDisplaySize != io.DisplaySize { | ||||
| @@ -169,12 +171,18 @@ func (r *WorldRenderer) Render(world *world.World, view *View) { | ||||
| 	lightProjection := mgl32.Ortho(-50, 50, -50, 50, 1, 100) | ||||
| 	lightspace := lightProjection.Mul4(lightView) | ||||
|  | ||||
| 	io.RenderPos = lightPos.ToFloat64() | ||||
| 	io.RenderDir = view.EyePos.Add(lightPos.Negative()).ToFloat64() | ||||
|  | ||||
| 	r.depthmap.shader.UseProgram() | ||||
| 	r.depthmap.shader.SetUniformMat4("lightspace", lightspace) | ||||
|  | ||||
| 	world.Render() | ||||
|  | ||||
| 	// 2. Geometry pass, render to G-buffer | ||||
| 	io.RenderPos = io.ViewPos | ||||
| 	io.RenderDir = io.ViewDir | ||||
|  | ||||
| 	gl.Viewport(0, 0, int32(r.lastDisplaySize[0]), int32(r.lastDisplaySize[1])) | ||||
| 	gl.BindFramebuffer(gl.FRAMEBUFFER, r.gbuffer.fbo) | ||||
| 	gl.ClearColor(0, 0, 0, 1) | ||||
| @@ -202,5 +210,11 @@ func (r *WorldRenderer) Render(world *world.World, view *View) { | ||||
| 	r.shader.SetUniformVec4f("fogColor", itype.Vec4f{0.6, 0.8, 1.0, 1.0}) | ||||
| 	r.shader.SetUniformVec3f("sun", normalSun) | ||||
|  | ||||
| 	r.drawScreenQuad() | ||||
| 	DrawScreenQuad() | ||||
|  | ||||
| 	// Show G-buffers? | ||||
| 	/*if io.ShowDebugInfo { | ||||
| 		DrawTexture(r.gbuffer.pos, itype.Rectf{0.5, 0.5, 0.5, 0.5}, DrawTextureChannels_R|DrawTextureChannels_G|DrawTextureChannels_B, 0, 32) | ||||
| 		DrawTexture(r.gbuffer.depth, itype.Rectf{0.5, 0, 0.5, 0.5}, DrawTextureChannels_R, 0, 1) | ||||
| 	}*/ | ||||
| } | ||||
|   | ||||
| @@ -1,54 +0,0 @@ | ||||
| package render | ||||
|  | ||||
| import ( | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"github.com/go-gl/gl/all-core/gl" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	screenQuadVerts = []float32{ | ||||
| 		-1, -1, | ||||
| 		0, 0, | ||||
| 		1, -1, | ||||
| 		1, 0, | ||||
| 		1, 1, | ||||
| 		1, 1, | ||||
| 		-1, -1, | ||||
| 		0, 0, | ||||
| 		1, 1, | ||||
| 		1, 1, | ||||
| 		-1, 1, | ||||
| 		0, 1, | ||||
| 	} | ||||
| 	screenQuadVAO uint32 | ||||
| 	screenQuadVBO uint32 | ||||
| ) | ||||
|  | ||||
| func initScreenQuad() { | ||||
| 	gl.GenBuffers(1, &screenQuadVBO) | ||||
| 	gl.BindBuffer(gl.ARRAY_BUFFER, screenQuadVBO) | ||||
| 	gl.BufferData(gl.ARRAY_BUFFER, int(unsafe.Sizeof(float32(0)))*len(screenQuadVerts), gl.Ptr(screenQuadVerts), gl.STATIC_DRAW) | ||||
|  | ||||
| 	gl.GenVertexArrays(1, &screenQuadVAO) | ||||
| 	gl.BindVertexArray(screenQuadVAO) | ||||
|  | ||||
| 	gl.VertexAttribPointer(0, 2, gl.FLOAT, false, int32(4*unsafe.Sizeof(float32(0))), gl.PtrOffset(0)) | ||||
| 	gl.VertexAttribPointer(1, 2, gl.FLOAT, false, int32(4*unsafe.Sizeof(float32(0))), gl.PtrOffset(int(2*unsafe.Sizeof(float32(0))))) | ||||
| 	gl.EnableVertexAttribArray(0) | ||||
| 	gl.EnableVertexAttribArray(1) | ||||
| } | ||||
|  | ||||
| // drawScreenQuad draws a Quad covering the entire screen. | ||||
| // | ||||
| // Attribute: vert:     [ -1.0 --> 1.0] | ||||
| func (r *WorldRenderer) drawScreenQuad() { | ||||
| 	if screenQuadVAO == 0 { | ||||
| 		initScreenQuad() | ||||
| 	} | ||||
|  | ||||
| 	gl.Disable(gl.DEPTH_TEST) | ||||
| 	gl.Disable(gl.CULL_FACE) | ||||
| 	gl.BindVertexArray(screenQuadVAO) | ||||
| 	gl.DrawArrays(gl.TRIANGLES, 0, 6) | ||||
| } | ||||
							
								
								
									
										122
									
								
								internal/render/screenquad.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								internal/render/screenquad.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,122 @@ | ||||
| package render | ||||
|  | ||||
| import ( | ||||
| 	_ "embed" | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"edgaru089.ml/go/gl01/internal/util/itype" | ||||
| 	"github.com/go-gl/gl/all-core/gl" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	screenQuadVerts = []float32{ | ||||
| 		-1, -1, | ||||
| 		0, 0, | ||||
| 		1, -1, | ||||
| 		1, 0, | ||||
| 		1, 1, | ||||
| 		1, 1, | ||||
| 		-1, -1, | ||||
| 		0, 0, | ||||
| 		1, 1, | ||||
| 		1, 1, | ||||
| 		-1, 1, | ||||
| 		0, 1, | ||||
| 	} | ||||
| 	screenQuadVAO uint32 | ||||
| 	screenQuadVBO uint32 | ||||
|  | ||||
| 	drawTextureShader *Shader // Shader for dumping textures to screen | ||||
| ) | ||||
|  | ||||
| func initScreenQuad() { | ||||
| 	gl.GenBuffers(1, &screenQuadVBO) | ||||
| 	gl.BindBuffer(gl.ARRAY_BUFFER, screenQuadVBO) | ||||
| 	gl.BufferData(gl.ARRAY_BUFFER, int(unsafe.Sizeof(float32(0)))*len(screenQuadVerts), gl.Ptr(screenQuadVerts), gl.STATIC_DRAW) | ||||
|  | ||||
| 	gl.GenVertexArrays(1, &screenQuadVAO) | ||||
| 	gl.BindVertexArray(screenQuadVAO) | ||||
|  | ||||
| 	gl.VertexAttribPointer(0, 2, gl.FLOAT, false, int32(4*unsafe.Sizeof(float32(0))), gl.PtrOffset(0)) | ||||
| 	gl.VertexAttribPointer(1, 2, gl.FLOAT, false, int32(4*unsafe.Sizeof(float32(0))), gl.PtrOffset(int(2*unsafe.Sizeof(float32(0))))) | ||||
| 	gl.EnableVertexAttribArray(0) | ||||
| 	gl.EnableVertexAttribArray(1) | ||||
| } | ||||
|  | ||||
| // DrawScreenQuad draws a Quad covering the entire screen with the current binding shader. | ||||
| // | ||||
| // Attribute: (location=0) vert:     [ -1.0 --> 1.0] | ||||
| //            (location=1) texCoord: [ 0    --> 1] | ||||
| func DrawScreenQuad() { | ||||
| 	if screenQuadVAO == 0 { | ||||
| 		initScreenQuad() | ||||
| 	} | ||||
|  | ||||
| 	gl.Disable(gl.DEPTH_TEST) | ||||
| 	gl.Disable(gl.CULL_FACE) | ||||
| 	gl.BindVertexArray(screenQuadVAO) | ||||
| 	gl.DrawArrays(gl.TRIANGLES, 0, 6) | ||||
| } | ||||
|  | ||||
| // DrawTextureChannels specifies the channels in RGBA to be drawn. | ||||
| type DrawTextureChannels int | ||||
|  | ||||
| const ( | ||||
| 	DrawTextureChannels_R DrawTextureChannels = 1 << iota | ||||
| 	DrawTextureChannels_G | ||||
| 	DrawTextureChannels_B | ||||
| 	DrawTextureChannels_A | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	//go:embed drawtexture.vert | ||||
| 	drawTextureShaderVert string | ||||
| 	//go:embed drawtexture.frag | ||||
| 	drawTextureShaderFrag string | ||||
| ) | ||||
|  | ||||
| func initDrawTexture() { | ||||
| 	var err error | ||||
| 	drawTextureShader, err = NewShader(drawTextureShaderVert, drawTextureShaderFrag) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
|  | ||||
| 	gl.BindFragDataLocation(drawTextureShader.Handle(), 0, gl.Str("outputColor\x00")) | ||||
| } | ||||
|  | ||||
| // DrawTexture dumps the contents of a Texture onto the portion of the screen. | ||||
| // It disables depth test and cull face. | ||||
| // | ||||
| // onScreen is specified in [-1, 1] size. | ||||
| // | ||||
| // If only one channel is specified, that channel is drawn in black and white. | ||||
| // Otherwise, R/G/B are drawn in their specified channels and A is ignored. | ||||
| // | ||||
| // The texture values from vauleRange is mapped to [0, 1] linearly. | ||||
| // | ||||
| // TODO: This does not work. Maybe something wrong with the shaders or blending | ||||
| func DrawTexture(texture uint32, onScreen itype.Rectf, channels DrawTextureChannels, valueMin, valueMax float32) { | ||||
| 	if screenQuadVAO == 0 { | ||||
| 		initScreenQuad() | ||||
| 	} | ||||
| 	if drawTextureShader == nil { | ||||
| 		initDrawTexture() | ||||
| 	} | ||||
|  | ||||
| 	drawTextureShader.UseProgram() | ||||
|  | ||||
| 	drawTextureShader.SetUniformVec2f("onScreenPos", onScreen.MinPoint()) | ||||
| 	drawTextureShader.SetUniformVec2f("onScreenSize", onScreen.Size()) | ||||
| 	drawTextureShader.SetUniformFloat("valueMin", valueMin) | ||||
| 	drawTextureShader.SetUniformFloat("valueMax", valueMax) | ||||
| 	drawTextureShader.SetUniformInt("channels", int32(channels)) | ||||
| 	drawTextureShader.SetUniformTextureHandle("tex", texture) | ||||
|  | ||||
| 	drawTextureShader.BindTextures() | ||||
|  | ||||
| 	gl.Disable(gl.DEPTH_TEST) | ||||
| 	gl.Disable(gl.CULL_FACE) | ||||
| 	gl.BindVertexArray(screenQuadVAO) | ||||
| 	gl.DrawArrays(gl.TRIANGLES, 0, 6) | ||||
| } | ||||
| @@ -66,6 +66,11 @@ func NewTextureRGBA(image *image.RGBA) *Texture { | ||||
| 	return &Texture{tex: tex} | ||||
| } | ||||
|  | ||||
| // NewTextureFromHandle creates a new *Texture from an existing OpenGL handle. | ||||
| func NewTextureFromHandle(handle uint32) *Texture { | ||||
| 	return &Texture{tex: handle} | ||||
| } | ||||
|  | ||||
| // updateFilters updates the MIN/MAG_FILTER parameters of the texture based on t.smooth and t.hasMipmap. | ||||
| // | ||||
| // It does not bind the texture; the caller has to do that | ||||
|   | ||||
| @@ -14,12 +14,36 @@ type Rectf struct { | ||||
| 	Width, Height float32 | ||||
| } | ||||
|  | ||||
| func (r Rectf) MinPoint() Vec2f { | ||||
| 	return Vec2f{r.Left, r.Top} | ||||
| } | ||||
|  | ||||
| func (r Rectf) MaxPoint() Vec2f { | ||||
| 	return Vec2f{r.Left + r.Width, r.Top + r.Height} | ||||
| } | ||||
|  | ||||
| func (r Rectf) Size() Vec2f { | ||||
| 	return Vec2f{r.Width, r.Height} | ||||
| } | ||||
|  | ||||
| // Rectd is a 2D rectangle with float64 coordinates. | ||||
| type Rectd struct { | ||||
| 	Left, Top     float64 | ||||
| 	Width, Height float64 | ||||
| } | ||||
|  | ||||
| func (r Rectd) MinPoint() Vec2d { | ||||
| 	return Vec2d{r.Left, r.Top} | ||||
| } | ||||
|  | ||||
| func (r Rectd) MaxPoint() Vec2d { | ||||
| 	return Vec2d{r.Left + r.Width, r.Top + r.Height} | ||||
| } | ||||
|  | ||||
| func (r Rectd) Size() Vec2d { | ||||
| 	return Vec2d{r.Width, r.Height} | ||||
| } | ||||
|  | ||||
| // Boxi is a 3D box with int coordinates. | ||||
| type Boxi struct { | ||||
| 	OffX, OffY, OffZ    int | ||||
|   | ||||
| @@ -79,6 +79,10 @@ func (v Vec2f) ToFloat64() Vec2d { | ||||
| // Vec3f is a three-element float vector | ||||
| type Vec3f [3]float32 | ||||
|  | ||||
| func (v Vec3f) Negative() Vec3f { | ||||
| 	return Vec3f{-v[0], -v[1], -v[2]} | ||||
| } | ||||
|  | ||||
| func (v Vec3f) Add(add Vec3f) Vec3f { | ||||
| 	return Vec3f{v[0] + add[0], v[1] + add[1], v[2] + add[2]} | ||||
| } | ||||
|   | ||||
| @@ -6,6 +6,7 @@ import ( | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"edgaru089.ml/go/gl01/internal/asset" | ||||
| 	"edgaru089.ml/go/gl01/internal/io" | ||||
| 	"edgaru089.ml/go/gl01/internal/util/itype" | ||||
| 	"github.com/go-gl/gl/all-core/gl" | ||||
| ) | ||||
| @@ -67,14 +68,45 @@ func (c *Chunk) updateRender() { | ||||
|  | ||||
| 	select { | ||||
| 	case vert := <-c.vertUpdate: | ||||
| 		log.Printf("Chunk [%d,%d]: received len=%d", c.X, c.Z, len(vert)) | ||||
| 		gl.BufferData(gl.ARRAY_BUFFER, int(unsafe.Sizeof(Vertex{}))*len(vert), gl.Ptr(vert), gl.DYNAMIC_DRAW) | ||||
| 		c.vbolen = len(vert) | ||||
| 	default: // do nothing | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var checkViewOffset = []itype.Vec3d{ | ||||
| 	{0, 0, 0}, | ||||
| 	{ChunkSizeX, 0, 0}, | ||||
| 	{0, 0, ChunkSizeZ}, | ||||
| 	{ChunkSizeX, 0, ChunkSizeZ}, | ||||
| 	{0, ChunkSizeY, 0}, | ||||
| 	{ChunkSizeX, ChunkSizeY, 0}, | ||||
| 	{0, ChunkSizeY, ChunkSizeZ}, | ||||
| 	{ChunkSizeX, ChunkSizeY, ChunkSizeZ}, | ||||
| } | ||||
|  | ||||
| // checkView checks if the chunk is in the front-facing direction of the view. | ||||
| func (c *Chunk) checkView(from, facing itype.Vec3d) bool { | ||||
| 	off := itype.Vec3d{ | ||||
| 		float64(c.X * ChunkSizeX), | ||||
| 		0, | ||||
| 		float64(c.Z * ChunkSizeZ), | ||||
| 	} | ||||
|  | ||||
| 	for _, check := range checkViewOffset { | ||||
| 		ok := off.Add(check).Add(from.Negative()).Dot(facing) > 0 | ||||
| 		if ok { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (c *Chunk) Render() { | ||||
| 	if !c.checkView(io.ViewPos, io.ViewDir) || !c.checkView(io.RenderPos, io.RenderDir) { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	c.Bind() | ||||
| 	c.updateRender() | ||||
| 	gl.DrawArrays(gl.TRIANGLES, 0, int32(c.vbolen)) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user