From fea09c5012e5ea7edd6382ef520f82124bbbd1e3 Mon Sep 17 00:00:00 2001 From: Edgaru089 Date: Sat, 29 Jan 2022 00:43:11 +0800 Subject: [PATCH] semi-transparent water rendering (TODO) --- internal/asset/shader.go | 32 +++--- .../geometry.frag} | 0 .../geometry.vert} | 0 .../shader/{world.frag => world/output.frag} | 2 +- .../shader/{world.vert => world/output.vert} | 0 .../shadowmap.frag} | 0 .../shadowmap.vert} | 0 internal/asset/shader/world/water.frag | 93 ++++++++++++++++++ internal/asset/shader/world/water.vert | 26 +++++ internal/entity/.physics.go.swp | Bin 0 -> 20480 bytes internal/entity/physics.go | 36 +------ internal/game/logic.go | 4 +- internal/render/render_world.go | 48 ++++++++- internal/world/block.go | 3 +- internal/world/blocks/water.go | 8 +- internal/world/chunk.go | 2 +- internal/world/render.go | 56 +++++++++-- internal/world/world.go | 8 ++ 18 files changed, 250 insertions(+), 68 deletions(-) rename internal/asset/shader/{world.geometry.frag => world/geometry.frag} (100%) rename internal/asset/shader/{world.geometry.vert => world/geometry.vert} (100%) rename internal/asset/shader/{world.frag => world/output.frag} (97%) rename internal/asset/shader/{world.vert => world/output.vert} (100%) rename internal/asset/shader/{world.shadowmap.frag => world/shadowmap.frag} (100%) rename internal/asset/shader/{world.shadowmap.vert => world/shadowmap.vert} (100%) create mode 100644 internal/asset/shader/world/water.frag create mode 100644 internal/asset/shader/world/water.vert create mode 100644 internal/entity/.physics.go.swp diff --git a/internal/asset/shader.go b/internal/asset/shader.go index ed4e8bf..8a6ed21 100644 --- a/internal/asset/shader.go +++ b/internal/asset/shader.go @@ -2,23 +2,27 @@ package asset import _ "embed" -//go:embed shader/world.frag -var WorldShaderFrag string +var ( + //go:embed shader/world/output.frag + WorldShaderFrag string + //go:embed shader/world/output.vert + WorldShaderVert string -//go:embed shader/world.vert -var WorldShaderVert string + //go:embed shader/world/shadowmap.frag + WorldShaderShadowmapFrag string + //go:embed shader/world/shadowmap.vert + WorldShaderShadowmapVert string -//go:embed shader/world.shadowmap.frag -var WorldShaderShadowmapFrag string + //go:embed shader/world/geometry.frag + WorldShaderGeometryFrag string + //go:embed shader/world/geometry.vert + WorldShaderGeometryVert string -//go:embed shader/world.shadowmap.vert -var WorldShaderShadowmapVert string - -//go:embed shader/world.geometry.frag -var WorldShaderGeometryFrag string - -//go:embed shader/world.geometry.vert -var WorldShaderGeometryVert string + //go:embed shader/world/water.frag + WorldShaderWaterFrag string + //go:embed shader/world/water.vert + WorldShaderWaterVert string +) //go:embed shader/framewire.frag var FramewireShaderFrag string diff --git a/internal/asset/shader/world.geometry.frag b/internal/asset/shader/world/geometry.frag similarity index 100% rename from internal/asset/shader/world.geometry.frag rename to internal/asset/shader/world/geometry.frag diff --git a/internal/asset/shader/world.geometry.vert b/internal/asset/shader/world/geometry.vert similarity index 100% rename from internal/asset/shader/world.geometry.vert rename to internal/asset/shader/world/geometry.vert diff --git a/internal/asset/shader/world.frag b/internal/asset/shader/world/output.frag similarity index 97% rename from internal/asset/shader/world.frag rename to internal/asset/shader/world/output.frag index 3c36d34..a734769 100644 --- a/internal/asset/shader/world.frag +++ b/internal/asset/shader/world/output.frag @@ -24,7 +24,7 @@ out vec4 outputColor; const float gamma = 2.2; -const float ambient = 0.3, specularStrength = 0.5, specularShininess = 32; +const float ambient = 0.3, specularStrength = 0.08, specularShininess = 8; const float fogDensity = .00003; diff --git a/internal/asset/shader/world.vert b/internal/asset/shader/world/output.vert similarity index 100% rename from internal/asset/shader/world.vert rename to internal/asset/shader/world/output.vert diff --git a/internal/asset/shader/world.shadowmap.frag b/internal/asset/shader/world/shadowmap.frag similarity index 100% rename from internal/asset/shader/world.shadowmap.frag rename to internal/asset/shader/world/shadowmap.frag diff --git a/internal/asset/shader/world.shadowmap.vert b/internal/asset/shader/world/shadowmap.vert similarity index 100% rename from internal/asset/shader/world.shadowmap.vert rename to internal/asset/shader/world/shadowmap.vert diff --git a/internal/asset/shader/world/water.frag b/internal/asset/shader/world/water.frag new file mode 100644 index 0000000..d8b76b6 --- /dev/null +++ b/internal/asset/shader/world/water.frag @@ -0,0 +1,93 @@ +#version 330 + +uniform sampler2D tex; +uniform sampler2D shadowmap; +uniform vec3 viewPos; +uniform vec3 sun; +uniform vec4 fogColor; + +uniform float alpha; // Alpha of the semi-transparant layer + +// Fragment information +in vec4 fragPos; +in vec4 fragPosLightspace; +in vec3 fragNormal; +in vec2 fragTexCoord; +vec4 fragColor; + +out vec4 outputColor; + + +const float gamma = 2.2; + +const float ambient = 0.3, specularStrength = 1.6, specularShininess = 128; +const float fogDensity = .00003; + + +float finalpha; +float light; +vec4 texpixel, color; +void lightSun(); +float lightSunShadow(); +void lightPoint(int i); + + +void main() { + + fragColor = vec4(pow(texture(tex, fragTexCoord).rgb, vec3(gamma)), 1.0f); + + finalpha = alpha; + light = ambient; + + lightSun(); + + color += vec4(fragColor.rgb * light, 0.0f); + color.a = fragColor.a; + color.rgb = pow(color.rgb, vec3(1.0/gamma)); + + float z = gl_FragCoord.z / gl_FragCoord.w; + float fog = clamp(exp(-fogDensity * z * z), 0.2, 1); + + outputColor = mix(fogColor, color, fog) * finalpha; +} + +void lightSun() { + /* Diffuse */ + vec3 lightDir = sun; + float diffuse = max(dot(fragNormal, lightDir), 0.0f); + + /* Specular */ + vec3 viewDir = normalize(viewPos - fragPos.xyz); + vec3 reflectDir = reflect(-lightDir, fragNormal); + float specular = specularStrength * pow(max(dot(viewDir, reflectDir), 0.0), specularShininess); + if (specular > 1.0f) { + finalpha = min(finalpha + specular - 1.0f, 1.0f); + } + + float shadow = lightSunShadow(); + light += diffuse * shadow; + color += vec4(vec3(specular), 0.0f) * shadow; + finalpha = min(finalpha + 0.1f * shadow, 1.0f); +} + +float lightSunShadow() { + /* Shadow */ + float bias = max(0.0013 * (1.0 - dot(fragNormal, sun)), 0.0001); + vec3 projCoords = fragPosLightspace.xyz / fragPosLightspace.w; + projCoords = projCoords*0.5 + 0.5; + float closestDepth = texture(shadowmap, projCoords.xy).r; + float currentDepth = projCoords.z; + float shadow = 0; + + if (currentDepth > 1.0f || currentDepth < 0.0f) + return 1.0f; + + //vec2 texelSize = clamp((currentDepth+bias-closestDepth)*100.0f, 0.05f, 1.5f) / textureSize(shadowmap, 0); + vec2 texelSize = 0.4 / textureSize(shadowmap, 0); + for (int x=-4; x<=4; ++x) + for (int y=-4; y<=4; ++y) { + float pcfDepth = texture(shadowmap, projCoords.xy + vec2(x,y)*texelSize).r; + shadow += currentDepth-bias < pcfDepth ? 1.0f : 0.0f; + } + return min(shadow/81.0f, 1.0f); +} diff --git a/internal/asset/shader/world/water.vert b/internal/asset/shader/world/water.vert new file mode 100644 index 0000000..f6f917b --- /dev/null +++ b/internal/asset/shader/world/water.vert @@ -0,0 +1,26 @@ +#version 330 + +uniform mat4 projection; +uniform mat4 view; +uniform mat4 model; +uniform mat4 lightspace; + +layout (location = 0) in vec3 vert; +layout (location = 1) in vec3 normal; +layout (location = 2) in vec2 texCoord; +layout (location = 4) in float light; + +out vec4 fragPos; +out vec4 fragPosLightspace; +out vec3 fragNormal; +out vec2 fragTexCoord; + + +void main() { + fragTexCoord = texCoord; + fragPos = model * vec4(vert, 1); + fragPosLightspace = lightspace * fragPos; + fragNormal = normal; + gl_Position = projection * view * fragPos; +} + diff --git a/internal/entity/.physics.go.swp b/internal/entity/.physics.go.swp new file mode 100644 index 0000000000000000000000000000000000000000..594ecabaab3497e6dd71ffd2da55e78fb63a9f52 GIT binary patch literal 20480 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 WtC!{jy5x(<aBL4--5h+Lj literal 0 HcmV?d00001 diff --git a/internal/entity/physics.go b/internal/entity/physics.go index 07518d7..794001d 100644 --- a/internal/entity/physics.go +++ b/internal/entity/physics.go @@ -45,35 +45,6 @@ func (e *Entity) boxHitpoints(points []itype.Vec3d, hitbox itype.Boxd) []itype.V base.Add(itype.Vec3d{box.SizeX, 0, box.SizeZ}), base.Add(itype.Vec3d{box.SizeX, box.SizeY, box.SizeZ}), ) - /* - // add the surface points - // X+ and X- - for y := base[1] + HitpointMeshLen; y < base[1]+hitbox[1]; y += HitpointMeshLen { - for z := base[2] + HitpointMeshLen; z < base[2]+hitbox[2]; z += HitpointMeshLen { - points = append(points, - base.Addv(0, y, z), - base.Addv(box.SizeX, y, z), - ) - } - } - // Y+ and Y- - for x := base[0] + HitpointMeshLen; x < base[0]+hitbox[0]; x += HitpointMeshLen { - for z := base[2] + HitpointMeshLen; z < base[2]+hitbox[2]; z += HitpointMeshLen { - points = append(points, - base.Addv(x, 0, z), - base.Addv(x, box.SizeY, z), - ) - } - } - // Z+ and Z- - for x := base[0] + HitpointMeshLen; x < base[0]+hitbox[0]; x += HitpointMeshLen { - for y := base[1] + HitpointMeshLen; y < base[1]+hitbox[1]; y += HitpointMeshLen { - points = append(points, - base.Addv(x, y, 0), - base.Addv(x, y, box.SizeZ), - ) - } - }*/ return points } @@ -89,6 +60,7 @@ func pointStuck(point itype.Vec3d, w *world.World) bool { point.Floor(), block.Aux, block.Dataset, + w, ).Hitbox.Offset(blockid.ToFloat64()).Contains(point) } @@ -123,7 +95,7 @@ func (e *Entity) moveX(delta float64, hitbox itype.Boxd, w *world.World) { if block.Id == 0 { deltaDone = delta } else { // block.Id!=0 - app := world.GetBlockAppearance(blockid, block.Id, block.Aux, block.Dataset) + app := world.GetBlockAppearance(blockid, block.Id, block.Aux, block.Dataset, w) blockBox := app.Hitbox.Offset(blockid.ToFloat64()) if !app.NotSolid && blockBox.Contains(dest) { // Hit! hit = true @@ -176,7 +148,7 @@ func (e *Entity) moveY(delta float64, hitbox itype.Boxd, w *world.World) { if block.Id == 0 { deltaDone = delta } else { // block.Id!=0 - app := world.GetBlockAppearance(blockid, block.Id, block.Aux, block.Dataset) + app := world.GetBlockAppearance(blockid, block.Id, block.Aux, block.Dataset, w) blockBox := app.Hitbox.Offset(blockid.ToFloat64()) if !app.NotSolid && blockBox.Contains(dest) { // Hit! hit = true @@ -240,7 +212,7 @@ func (e *Entity) moveZ(delta float64, hitbox itype.Boxd, w *world.World) { if block.Id == 0 { deltaDone = delta } else { // block.Id!=0 - app := world.GetBlockAppearance(blockid, block.Id, block.Aux, block.Dataset) + app := world.GetBlockAppearance(blockid, block.Id, block.Aux, block.Dataset, w) blockBox := app.Hitbox.Offset(blockid.ToFloat64()) if !app.NotSolid && blockBox.Contains(dest) { // Hit! hit = true diff --git a/internal/game/logic.go b/internal/game/logic.go index db60f8d..2f3c349 100644 --- a/internal/game/logic.go +++ b/internal/game/logic.go @@ -47,8 +47,8 @@ func (g *Game) Init(win *glfw.Window) { var seed int64 = time.Now().Unix() gensync := make(chan struct{}) gensynccnt := 0 - for i := -8; i <= 8; i++ { - for j := -8; j <= 8; j++ { + for i := -4; i <= 4; i++ { + for j := -4; j <= 4; j++ { c := &world.Chunk{} g.world.SetChunk(i, j, c) go func() { diff --git a/internal/render/render_world.go b/internal/render/render_world.go index d225c24..3dd5098 100644 --- a/internal/render/render_world.go +++ b/internal/render/render_world.go @@ -33,6 +33,11 @@ type WorldRenderer struct { shader *Shader // Geometry pass shaders. } + water struct { + fbo uint32 + shader *Shader + } + shader *Shader // Deffered lighting pass shaders texture *Texture // World texture atlas } @@ -55,16 +60,23 @@ func (r *WorldRenderer) Init(w *world.World) (err error) { if err != nil { return err } + r.water.shader, err = NewShader(asset.WorldShaderWaterVert, asset.WorldShaderWaterFrag) + if err != nil { + return err + } asset.InitWorldTextureAtlas() r.texture = NewTextureRGBA(asset.WorldTextureAtlas.Image) r.texture.GenerateMipMap() r.gbuffer.shader.SetUniformTexture("tex", r.texture) + r.water.shader.SetUniformTexture("tex", r.texture) r.depthmap.shader.SetUniformMat4("model", mgl32.Ident4()) r.gbuffer.shader.SetUniformMat4("model", mgl32.Ident4()) + r.water.shader.SetUniformMat4("model", mgl32.Ident4()) // and view and projection uniforms not yet set gl.BindFragDataLocation(r.shader.Handle(), 0, gl.Str("outputColor\x00")) + gl.BindFragDataLocation(r.water.shader.Handle(), 0, gl.Str("outputColor\x00")) // generate the depthmap and depthmap FBO gl.GenFramebuffers(1, &r.depthmap.fbo) @@ -84,6 +96,7 @@ func (r *WorldRenderer) Init(w *world.World) (err error) { gl.ReadBuffer(gl.NONE) // attach the shadowmap to the shader r.shader.SetUniformTextureHandle("shadowmap", r.depthmap.tex) + r.water.shader.SetUniformTextureHandle("shadowmap", r.depthmap.tex) // generate G-buffer and friends gl.GenFramebuffers(1, &r.gbuffer.fbo) @@ -122,6 +135,13 @@ func (r *WorldRenderer) Init(w *world.World) (err error) { r.shader.SetUniformTextureHandle("gNorm", r.gbuffer.norm) r.shader.SetUniformTextureHandle("gColor", r.gbuffer.color) + // generate FBO for water rendering + gl.GenFramebuffers(1, &r.water.fbo) + gl.BindFramebuffer(gl.FRAMEBUFFER, r.water.fbo) + gl.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, r.gbuffer.depth) + gl.DrawBuffer(gl.BACK) + gl.ReadBuffer(gl.BACK) + gl.BindFramebuffer(gl.FRAMEBUFFER, 0) r.lastDisplaySize = io.DisplaySize @@ -136,6 +156,7 @@ func (r *WorldRenderer) ResizeDisplay(newSize itype.Vec2i) { } var sun = [3]float32{0.2, 0.4, 0.3} +var alpha float32 = 0.55 func (r *WorldRenderer) Render(world *world.World, view *View) { io.RenderPos = io.ViewPos @@ -149,13 +170,14 @@ func (r *WorldRenderer) Render(world *world.World, view *View) { gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA16F, int32(io.DisplaySize[0]), int32(io.DisplaySize[1]), 0, gl.RGBA, gl.FLOAT, nil) gl.BindTexture(gl.TEXTURE_2D, r.gbuffer.color) gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, int32(io.DisplaySize[0]), int32(io.DisplaySize[1]), 0, gl.RGBA, gl.UNSIGNED_BYTE, nil) - gl.BindRenderbuffer(gl.RENDERBUFFER, r.gbuffer.norm) + gl.BindRenderbuffer(gl.RENDERBUFFER, r.gbuffer.depth) gl.RenderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, int32(io.DisplaySize[0]), int32(io.DisplaySize[1])) r.lastDisplaySize = io.DisplaySize } imgui.SliderFloat3("Sun", &sun, -1, 1) normalSun := itype.Vec3f(sun).Normalize() + imgui.SliderFloat("Water Alpha", &alpha, 0, 1) gl.Enable(gl.CULL_FACE) gl.Enable(gl.DEPTH_TEST) @@ -178,6 +200,7 @@ func (r *WorldRenderer) Render(world *world.World, view *View) { r.depthmap.shader.SetUniformMat4("lightspace", lightspace) world.Render() + world.RenderWater() // 2. Geometry pass, render to G-buffer io.RenderPos = io.ViewPos @@ -201,10 +224,9 @@ func (r *WorldRenderer) Render(world *world.World, view *View) { gl.BindFramebuffer(gl.FRAMEBUFFER, 0) // 3. Render the actual output with deferred lighting - gl.Clear(gl.DEPTH_BUFFER_BIT) + gl.Disable(gl.DEPTH_TEST) r.shader.UseProgram() r.shader.BindTextures() - r.shader.SetUniformMat4("lightspace", lightspace) r.shader.SetUniformVec3f("viewPos", view.EyePos) r.shader.SetUniformVec4f("fogColor", itype.Vec4f{0.6, 0.8, 1.0, 1.0}) @@ -212,6 +234,26 @@ func (r *WorldRenderer) Render(world *world.World, view *View) { DrawScreenQuad() + // 4. Render water + gl.Enable(gl.DEPTH_TEST) + gl.DepthFunc(gl.LESS) + gl.Enable(gl.CULL_FACE) + gl.Enable(gl.BLEND) + gl.BlendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA) + gl.BlendEquation(gl.FUNC_ADD) + gl.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, r.gbuffer.depth) + r.water.shader.UseProgram() + r.water.shader.BindTextures() + + r.water.shader.SetUniformMat4("lightspace", lightspace) + r.water.shader.SetUniformMat4("view", view.View()) + r.water.shader.SetUniformMat4("projection", view.Perspective()) + r.water.shader.SetUniformVec3f("viewPos", view.EyePos) + r.water.shader.SetUniformVec3f("sun", normalSun) + r.water.shader.SetUniformFloat("alpha", alpha) + + world.RenderWater() + // 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) diff --git a/internal/world/block.go b/internal/world/block.go index b480bb9..af536e7 100644 --- a/internal/world/block.go +++ b/internal/world/block.go @@ -36,7 +36,8 @@ type BlockAppearance struct { data itype.Dataset, world *World, vertexArray []Vertex, - ) []Vertex + vertexArrayWater []Vertex, + ) (verts []Vertex, waters []Vertex) } // BlockBehaviour describes a kind of block of the same Major ID. diff --git a/internal/world/blocks/water.go b/internal/world/blocks/water.go index b9871ef..5ff8c67 100644 --- a/internal/world/blocks/water.go +++ b/internal/world/blocks/water.go @@ -10,7 +10,7 @@ type WaterBehaviour struct{} func (WaterBehaviour) Static() bool { return false } func (WaterBehaviour) RequireDataset() bool { return false } func (WaterBehaviour) RequireBlockUpdate() bool { return false } -func (b WaterBehaviour) Appearance(position itype.Vec3i, aux int, data itype.Dataset, w *world.World) world.BlockAppearance { +func (WaterBehaviour) Appearance(position itype.Vec3i, aux int, data itype.Dataset, w *world.World) world.BlockAppearance { return world.BlockAppearance{ Name: "water", Transparent: true, @@ -22,13 +22,13 @@ func (b WaterBehaviour) Appearance(position itype.Vec3i, aux int, data itype.Dat aux int, data itype.Dataset, w *world.World, - vertexArray []world.Vertex) []world.Vertex { + vertexArray []world.Vertex, vertsWater []world.Vertex) (verts, waters []world.Vertex) { if block := w.Block(position.Addv(0, 1, 0)); block.Id != Water { - return appendFace(itype.YPlus, position, "water.png", itype.Vec3f{0, -0.125, 0}, vertexArray) + return vertexArray, appendFace(itype.YPlus, position, "water.png", itype.Vec3f{0, -0.125, 0}, vertsWater) } - return vertexArray + return vertexArray, vertsWater }, } } diff --git a/internal/world/chunk.go b/internal/world/chunk.go index 4b3acff..553f141 100644 --- a/internal/world/chunk.go +++ b/internal/world/chunk.go @@ -25,7 +25,7 @@ type Chunk struct { vao, vbo uint32 vbolen int } - vertUpdate chan []Vertex + vertUpdate chan [2][]Vertex world *World } diff --git a/internal/world/render.go b/internal/world/render.go index 227beff..ca68a51 100644 --- a/internal/world/render.go +++ b/internal/world/render.go @@ -34,7 +34,21 @@ func (c *Chunk) InitRender() { gl.EnableVertexAttribArray(2) gl.EnableVertexAttribArray(3) - c.vertUpdate = make(chan []Vertex, 2) + gl.GenVertexArrays(1, &c.water.vao) + gl.BindVertexArray(c.water.vao) + gl.GenBuffers(1, &c.water.vbo) + gl.BindBuffer(gl.ARRAY_BUFFER, c.water.vbo) + + gl.VertexAttribPointer(0, 3, gl.FLOAT, false, int32(unsafe.Sizeof(Vertex{})), gl.PtrOffset(int(unsafe.Offsetof(Vertex{}.World)))) + gl.VertexAttribPointer(1, 3, gl.FLOAT, false, int32(unsafe.Sizeof(Vertex{})), gl.PtrOffset(int(unsafe.Offsetof(Vertex{}.Normal)))) + gl.VertexAttribPointer(2, 2, gl.FLOAT, false, int32(unsafe.Sizeof(Vertex{})), gl.PtrOffset(int(unsafe.Offsetof(Vertex{}.Texture)))) + gl.VertexAttribPointer(3, 1, gl.FLOAT, false, int32(unsafe.Sizeof(Vertex{})), gl.PtrOffset(int(unsafe.Offsetof(Vertex{}.Light)))) + gl.EnableVertexAttribArray(0) + gl.EnableVertexAttribArray(1) + gl.EnableVertexAttribArray(2) + gl.EnableVertexAttribArray(3) + + c.vertUpdate = make(chan [2][]Vertex, 2) c.renderChanged = true } @@ -42,6 +56,8 @@ func (c *Chunk) InitRender() { func (c *Chunk) FreeRender() { gl.DeleteVertexArrays(1, &c.vao) gl.DeleteBuffers(1, &c.vbo) + gl.DeleteVertexArrays(1, &c.water.vao) + gl.DeleteBuffers(1, &c.water.vbo) close(c.vertUpdate) } @@ -51,6 +67,12 @@ func (c *Chunk) Bind() { gl.BindBuffer(gl.ARRAY_BUFFER, c.vbo) } +// BindWater binds the semi-transparant layer of the renderer. +func (c *Chunk) BindWater() { + gl.BindVertexArray(c.water.vao) + gl.BindBuffer(gl.ARRAY_BUFFER, c.water.vbo) +} + // a global vertex array for VBO updates //var vertex []Vertex @@ -59,17 +81,21 @@ func (c *Chunk) updateRender() { if c.renderChanged { go func() { t := time.Now() - vert := c.AppendVertex([]Vertex{}) + vert, vertWater := c.appendVertex([]Vertex{}, []Vertex{}) log.Printf("Chunk [%d,%d]: UpdateRender: vertex len of %d*%d = %d in %dms", c.X, c.Z, unsafe.Sizeof(Vertex{}), len(vert), int(unsafe.Sizeof(Vertex{}))*len(vert), time.Since(t).Milliseconds()) - c.vertUpdate <- vert + c.vertUpdate <- [2][]Vertex{vert, vertWater} }() c.renderChanged = false } select { case vert := <-c.vertUpdate: - gl.BufferData(gl.ARRAY_BUFFER, int(unsafe.Sizeof(Vertex{}))*len(vert), gl.Ptr(vert), gl.DYNAMIC_DRAW) - c.vbolen = len(vert) + gl.BindBuffer(gl.ARRAY_BUFFER, c.vbo) + gl.BufferData(gl.ARRAY_BUFFER, int(unsafe.Sizeof(Vertex{}))*len(vert[0]), gl.Ptr(vert[0]), gl.DYNAMIC_DRAW) + gl.BindBuffer(gl.ARRAY_BUFFER, c.water.vbo) + gl.BufferData(gl.ARRAY_BUFFER, int(unsafe.Sizeof(Vertex{}))*len(vert[1]), gl.Ptr(vert[1]), gl.DYNAMIC_DRAW) + c.vbolen = len(vert[0]) + c.water.vbolen = len(vert[1]) default: // do nothing } } @@ -107,13 +133,23 @@ func (c *Chunk) Render() { return } - c.Bind() c.updateRender() + c.Bind() gl.DrawArrays(gl.TRIANGLES, 0, int32(c.vbolen)) } -// AppendVertex appends the chunk's global vertex into the array. -func (c *Chunk) AppendVertex(arr []Vertex) []Vertex { +func (c *Chunk) RenderWater() { + if !c.checkView(io.ViewPos, io.ViewDir) || !c.checkView(io.RenderPos, io.RenderDir) { + return + } + + c.updateRender() + c.BindWater() + gl.DrawArrays(gl.TRIANGLES, 0, int32(c.water.vbolen)) +} + +// appendVertex appends the chunk's global vertex into the array. +func (c *Chunk) appendVertex(arr, arrwater []Vertex) (fin, finwater []Vertex) { off := itype.Vec3i{ c.X * ChunkSizeX, 0, @@ -151,14 +187,14 @@ func (c *Chunk) AppendVertex(arr []Vertex) []Vertex { arr = c.appendFace(itype.ZPlus, itype.Vec3i{i, j, k}, app.Name+"_z+.png", arr) arr = c.appendFace(itype.ZMinus, itype.Vec3i{i, j, k}, app.Name+"_z-.png", arr) case CustomRendering: - arr = app.CustomRenderAppend(off.Addv(i, j, k), int(c.Aux[i][j][k]), nil, c.world, arr) + arr, arrwater = app.CustomRenderAppend(off.Addv(i, j, k), int(c.Aux[i][j][k]), nil, c.world, arr, arrwater) } } } } - return arr + return arr, arrwater } func (c *Chunk) appendFace(face itype.Direction, pos itype.Vec3i, texname string, arr []Vertex) []Vertex { diff --git a/internal/world/world.go b/internal/world/world.go index ad5fdc5..efb37ca 100644 --- a/internal/world/world.go +++ b/internal/world/world.go @@ -145,3 +145,11 @@ func (w *World) Render() { c.Render() } } + +// RenderWater calls DrawArrays drawing the semi-transparant layer of the world. +func (w *World) RenderWater() { + for _, c := range w.Chunks { + c.RenderWater() + } + +}