Ejemplo n.º 1
0
func main() {
	app := example.Open()
	defer app.Close()
	bgfx.Init()
	defer bgfx.Shutdown()

	bgfx.Reset(app.Width, app.Height, bgfx.ResetVSync)
	bgfx.SetDebug(bgfx.DebugText)
	bgfx.SetViewClear(
		0,
		bgfx.ClearColor|bgfx.ClearDepth,
		0x303030ff,
		1.0,
		0,
	)

	instancingSupported := bgfx.Caps().Supported&bgfx.CapsInstancing != 0

	var vd bgfx.VertexDecl
	vd.Begin()
	vd.Add(bgfx.AttribPosition, 3, bgfx.AttribTypeFloat, false, false)
	vd.Add(bgfx.AttribNormal, 4, bgfx.AttribTypeUint8, true, true)
	vd.Add(bgfx.AttribTangent, 4, bgfx.AttribTypeUint8, true, true)
	vd.Add(bgfx.AttribTexcoord0, 2, bgfx.AttribTypeInt16, true, true)
	vd.End()
	example.CalculateTangents(vertices, len(vertices), vd, indices)

	vb := bgfx.CreateVertexBuffer(vertices, vd)
	defer bgfx.DestroyVertexBuffer(vb)
	ib := bgfx.CreateIndexBuffer(indices)
	defer bgfx.DestroyIndexBuffer(ib)

	const numLights = 4
	uTexColor := bgfx.CreateUniform("u_texColor", bgfx.Uniform1iv, 1)
	uTexNormal := bgfx.CreateUniform("u_texNormal", bgfx.Uniform1iv, 1)
	uLightPosRadius := bgfx.CreateUniform("u_lightPosRadius", bgfx.Uniform4fv, numLights)
	uLightRgbInnerR := bgfx.CreateUniform("u_lightRgbInnerR", bgfx.Uniform4fv, numLights)

	vsbump := "vs_bump"
	if instancingSupported {
		vsbump = "vs_bump_instanced"
	}
	prog := assets.LoadProgram(vsbump, "fs_bump")
	defer bgfx.DestroyProgram(prog)

	textureColor := assets.LoadTexture("fieldstone-rgba.dds", 0)
	textureNormal := assets.LoadTexture("fieldstone-n.dds", 0)

	for app.Continue() {
		var (
			eye = [3]float32{0, 0, -7.0}
			at  = [3]float32{0, 0, 0}
			up  = [3]float32{1, 0, 0}
		)
		view := mat4.LookAtLH(eye, at, up)
		proj := mat4.PerspectiveLH(
			cgm.ToRadians(60),
			float32(app.Width)/float32(app.Height),
			0.1, 100.0,
		)
		bgfx.SetViewTransform(0, view, proj)
		bgfx.SetViewRect(0, 0, 0, app.Width, app.Height)
		bgfx.DebugTextClear()
		bgfx.DebugTextPrintf(0, 1, 0x4f, app.Title)
		bgfx.DebugTextPrintf(0, 2, 0x6f, "Description: Loading textures.")
		bgfx.DebugTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", app.DeltaTime*1000.0)
		bgfx.Submit(0)

		const halfPi = math.Pi / 2
		var lightPosRadius [4][4]float32
		for i := 0; i < numLights; i++ {
			fi := float32(i)
			lightPosRadius[i][0] = float32(math.Sin(float64(app.Time*(0.1+fi*0.17)+fi*halfPi*1.37)) * 3.0)
			lightPosRadius[i][1] = float32(math.Cos(float64(app.Time*(0.2+fi*0.29)+fi*halfPi*1.49)) * 3.0)
			lightPosRadius[i][2] = -2.5
			lightPosRadius[i][3] = 3.0
		}
		bgfx.SetUniform(uLightPosRadius, &lightPosRadius, numLights)

		lightRgbInnerR := [4][4]float32{
			{1.0, 0.7, 0.2, 0.8},
			{0.7, 0.2, 1.0, 0.8},
			{0.2, 1.0, 0.7, 0.8},
			{1.0, 0.4, 0.2, 0.8},
		}
		bgfx.SetUniform(uLightRgbInnerR, &lightRgbInnerR, numLights)

		if instancingSupported {
			for y := 0; y < 3; y++ {
				const numInstances = 3
				const instanceStride = 64
				idb := bgfx.AllocInstanceDataBuffer(numInstances, instanceStride)
				for x := 0; x < 3; x++ {
					mtx := mat4.RotateXYZ(
						cgm.Radians(app.Time)*0.023+cgm.Radians(x)*0.21,
						cgm.Radians(app.Time)*0.03+cgm.Radians(y)*0.37,
						0,
					)
					mtx[12] = -3 + float32(x)*3
					mtx[13] = -3 + float32(y)*3
					mtx[14] = 0
					binary.Write(&idb, binary.LittleEndian, mtx)
				}
				bgfx.SetInstanceDataBuffer(idb)
				bgfx.SetProgram(prog)
				bgfx.SetVertexBuffer(vb)
				bgfx.SetIndexBuffer(ib)
				bgfx.SetTexture(0, uTexColor, textureColor)
				bgfx.SetTexture(1, uTexNormal, textureNormal)
				bgfx.SetState(bgfx.StateDefault & (^bgfx.StateCullMask))
				bgfx.Submit(0)
			}
		} else {
			for y := 0; y < 3; y++ {
				for x := 0; x < 3; x++ {
					mtx := mat4.RotateXYZ(
						cgm.Radians(app.Time)*0.023+cgm.Radians(x)*0.21,
						cgm.Radians(app.Time)*0.03+cgm.Radians(y)*0.37,
						0,
					)
					mtx[12] = -3 + float32(x)*3
					mtx[13] = -3 + float32(y)*3
					mtx[14] = 0

					bgfx.SetTransform([16]float32(mtx))
					bgfx.SetProgram(prog)
					bgfx.SetVertexBuffer(vb)
					bgfx.SetIndexBuffer(ib)
					bgfx.SetTexture(0, uTexColor, textureColor)
					bgfx.SetTexture(1, uTexNormal, textureNormal)
					bgfx.SetState(bgfx.StateDefault & (^bgfx.StateCullMask))
					bgfx.Submit(0)
				}
			}
		}
		bgfx.Frame()
	}
}
Ejemplo n.º 2
0
func main() {
	app := example.Open()
	defer app.Close()
	bgfx.Init()
	defer bgfx.Shutdown()

	bgfx.Reset(app.Width, app.Height, bgfx.ResetVSync)
	bgfx.SetDebug(bgfx.DebugText)
	bgfx.SetViewClear(
		0,
		bgfx.ClearColor|bgfx.ClearDepth,
		0x303030ff,
		1.0,
		0,
	)

	caps := bgfx.Caps()
	originBottomLeft := false
	switch caps.RendererType {
	case bgfx.RendererTypeDirect3D9:
		texelHalf = 0.5
	case bgfx.RendererTypeOpenGL, bgfx.RendererTypeOpenGLES:
		originBottomLeft = true
	}

	var decl bgfx.VertexDecl
	decl.Begin()
	decl.Add(bgfx.AttribPosition, 3, bgfx.AttribTypeFloat, false, false)
	decl.Add(bgfx.AttribColor0, 4, bgfx.AttribTypeUint8, true, false)
	decl.Add(bgfx.AttribTexcoord0, 2, bgfx.AttribTypeFloat, false, false)
	decl.End()

	var (
		skyProg     = assets.LoadProgram("vs_hdr_skybox", "fs_hdr_skybox")
		lumProg     = assets.LoadProgram("vs_hdr_lum", "fs_hdr_lum")
		lumAvgProg  = assets.LoadProgram("vs_hdr_lumavg", "fs_hdr_lumavg")
		blurProg    = assets.LoadProgram("vs_hdr_blur", "fs_hdr_blur")
		brightProg  = assets.LoadProgram("vs_hdr_bright", "fs_hdr_bright")
		meshProg    = assets.LoadProgram("vs_hdr_mesh", "fs_hdr_mesh")
		tonemapProg = assets.LoadProgram("vs_hdr_tonemap", "fs_hdr_tonemap")
	)
	defer bgfx.DestroyProgram(skyProg)
	defer bgfx.DestroyProgram(lumProg)
	defer bgfx.DestroyProgram(lumAvgProg)
	defer bgfx.DestroyProgram(blurProg)
	defer bgfx.DestroyProgram(brightProg)
	defer bgfx.DestroyProgram(meshProg)
	defer bgfx.DestroyProgram(tonemapProg)

	var (
		uTime     = bgfx.CreateUniform("u_time", bgfx.Uniform1f, 1)
		uTexCube  = bgfx.CreateUniform("u_texCube", bgfx.Uniform1i, 1)
		uTexColor = bgfx.CreateUniform("u_texColor", bgfx.Uniform1i, 1)
		uTexLum   = bgfx.CreateUniform("u_texLum", bgfx.Uniform1i, 1)
		uTexBlur  = bgfx.CreateUniform("u_texBlur", bgfx.Uniform1i, 1)
		uMtx      = bgfx.CreateUniform("u_mtx", bgfx.Uniform4x4fv, 1)
		uTonemap  = bgfx.CreateUniform("u_tonemap", bgfx.Uniform4fv, 1)
		uOffset   = bgfx.CreateUniform("u_offset", bgfx.Uniform4fv, 16)
	)
	defer bgfx.DestroyUniform(uTime)
	defer bgfx.DestroyUniform(uTexCube)
	defer bgfx.DestroyUniform(uTexColor)
	defer bgfx.DestroyUniform(uTexLum)
	defer bgfx.DestroyUniform(uTexBlur)
	defer bgfx.DestroyUniform(uMtx)
	defer bgfx.DestroyUniform(uTonemap)
	defer bgfx.DestroyUniform(uOffset)

	mesh := assets.LoadMesh("bunny")
	defer mesh.Unload()

	uffizi := assets.LoadTexture("uffizi.dds", bgfx.TextureUClamp|bgfx.TextureVClamp|bgfx.TextureWClamp)
	defer bgfx.DestroyTexture(uffizi)

	fbtextures := []bgfx.Texture{
		bgfx.CreateTexture2D(app.Width, app.Height, 1, bgfx.TextureFormatBGRA8, bgfx.TextureRT|bgfx.TextureUClamp|bgfx.TextureVClamp, nil),
		bgfx.CreateTexture2D(app.Width, app.Height, 1, bgfx.TextureFormatD16, bgfx.TextureRTBufferOnly, nil),
	}
	fb := bgfx.CreateFrameBufferFromTextures(fbtextures, true)
	lum := [5]bgfx.FrameBuffer{
		bgfx.CreateFrameBuffer(128, 128, bgfx.TextureFormatBGRA8, 0),
		bgfx.CreateFrameBuffer(64, 64, bgfx.TextureFormatBGRA8, 0),
		bgfx.CreateFrameBuffer(16, 16, bgfx.TextureFormatBGRA8, 0),
		bgfx.CreateFrameBuffer(4, 4, bgfx.TextureFormatBGRA8, 0),
		bgfx.CreateFrameBuffer(1, 1, bgfx.TextureFormatBGRA8, 0),
	}
	bright := bgfx.CreateFrameBuffer(app.Width/2, app.Height/2, bgfx.TextureFormatBGRA8, 0)
	blur := bgfx.CreateFrameBuffer(app.Width/8, app.Height/8, bgfx.TextureFormatBGRA8, 0)
	// defer in closure to capture these by reference since we destroy
	// and recreate these when the window resizes.
	defer func() {
		for _, l := range lum {
			bgfx.DestroyFrameBuffer(l)
		}
		bgfx.DestroyFrameBuffer(fb)
		bgfx.DestroyFrameBuffer(bright)
		bgfx.DestroyFrameBuffer(blur)
	}()

	const (
		speed      = 0.37
		middleGray = 0.18
		white      = 1.1
		threshold  = 1.5
	)
	var (
		prevWidth  = app.Width
		prevHeight = app.Height
	)
	for app.Continue() {
		if prevWidth != app.Width || prevHeight != app.Height {
			prevWidth = app.Width
			prevHeight = app.Height
			bgfx.DestroyFrameBuffer(fb)
			bgfx.DestroyFrameBuffer(blur)
			bgfx.DestroyFrameBuffer(bright)
			fbtextures[0] = bgfx.CreateTexture2D(app.Width, app.Height, 1, bgfx.TextureFormatBGRA8, bgfx.TextureRT|bgfx.TextureUClamp|bgfx.TextureVClamp, nil)
			fbtextures[1] = bgfx.CreateTexture2D(app.Width, app.Height, 1, bgfx.TextureFormatD16, bgfx.TextureRTBufferOnly, nil)
			fb = bgfx.CreateFrameBufferFromTextures(fbtextures, true)
			bright = bgfx.CreateFrameBuffer(app.Width/2, app.Height/2, bgfx.TextureFormatBGRA8, 0)
			blur = bgfx.CreateFrameBuffer(app.Width/8, app.Height/8, bgfx.TextureFormatBGRA8, 0)
		}

		bgfx.DebugTextClear()
		bgfx.DebugTextPrintf(0, 1, 0x4f, app.Title)
		bgfx.DebugTextPrintf(0, 2, 0x6f, "Description: Using multiple views and render targets.")
		bgfx.DebugTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", app.DeltaTime*1000.0)

		bgfx.SetUniform(uTime, &app.Time, 1)

		for i := 0; i < 6; i++ {
			bgfx.SetViewRect(bgfx.ViewID(i), 0, 0, app.Width, app.Height)
		}
		bgfx.SetViewFrameBuffer(0, fb)
		bgfx.SetViewFrameBuffer(1, fb)

		bgfx.SetViewRect(2, 0, 0, 128, 128)
		bgfx.SetViewFrameBuffer(2, lum[0])
		bgfx.SetViewRect(3, 0, 0, 64, 64)
		bgfx.SetViewFrameBuffer(3, lum[1])
		bgfx.SetViewRect(4, 0, 0, 16, 16)
		bgfx.SetViewFrameBuffer(4, lum[2])
		bgfx.SetViewRect(5, 0, 0, 4, 4)
		bgfx.SetViewFrameBuffer(5, lum[3])
		bgfx.SetViewRect(6, 0, 0, 1, 1)
		bgfx.SetViewFrameBuffer(6, lum[4])

		bgfx.SetViewRect(7, 0, 0, app.Width/2, app.Height/2)
		bgfx.SetViewFrameBuffer(7, bright)

		bgfx.SetViewRect(8, 0, 0, app.Width/8, app.Height/8)
		bgfx.SetViewFrameBuffer(8, blur)

		bgfx.SetViewRect(9, 0, 0, app.Width, app.Height)

		view := mat4.Identity()
		proj := mat4.OrthoLH(0, 1, 1, 0, 0, 100)
		for i := 0; i < 10; i++ {
			bgfx.SetViewTransform(bgfx.ViewID(i), view, proj)
		}

		var (
			eye = [3]float32{0, 1, -2.5}
			at  = [3]float32{0, 1, 0}
			up  = [3]float32{0, 1, 0}
			mtx = mat4.RotateXYZ(0, cgm.Radians(app.Time)*0.37, 0)
		)
		eye = mat4.Mul3(mtx, eye)
		view = mat4.LookAtLH(eye, at, up)
		proj = mat4.PerspectiveLH(
			cgm.ToRadians(60),
			float32(app.Width)/float32(app.Height),
			0.1, 100,
		)
		bgfx.SetViewTransform(1, view, proj)
		bgfx.SetUniform(uMtx, &mtx, 1)

		// Render skybox into view 0
		bgfx.SetTexture(0, uTexCube, uffizi)
		bgfx.SetProgram(skyProg)
		bgfx.SetState(bgfx.StateRGBWrite | bgfx.StateAlphaWrite)
		screenSpaceQuad(decl, float32(app.Width), float32(app.Height), true)
		bgfx.Submit(0)

		// Render mesh into view 1
		bgfx.SetTexture(0, uTexCube, uffizi)
		mesh.Submit(1, meshProg, mat4.Identity(), 0)

		// Calculate luminance.
		setOffsets2x2Lum(uOffset, 128, 128)
		bgfx.SetTexture(0, uTexColor, fbtextures[0])
		bgfx.SetProgram(lumProg)
		bgfx.SetState(bgfx.StateRGBWrite | bgfx.StateAlphaWrite)
		screenSpaceQuad(decl, 128, 128, originBottomLeft)
		bgfx.Submit(2)

		// Downscale luminance 0.
		setOffsets4x4Lum(uOffset, 128, 128)
		bgfx.SetTextureFromFrameBuffer(0, uTexColor, lum[0])
		bgfx.SetProgram(lumAvgProg)
		bgfx.SetState(bgfx.StateRGBWrite | bgfx.StateAlphaWrite)
		screenSpaceQuad(decl, 64, 64, originBottomLeft)
		bgfx.Submit(3)

		// Downscale luminance 1.
		setOffsets4x4Lum(uOffset, 64, 64)
		bgfx.SetTextureFromFrameBuffer(0, uTexColor, lum[1])
		bgfx.SetProgram(lumAvgProg)
		bgfx.SetState(bgfx.StateRGBWrite | bgfx.StateAlphaWrite)
		screenSpaceQuad(decl, 16, 16, originBottomLeft)
		bgfx.Submit(4)

		// Downscale luminance 2.
		setOffsets4x4Lum(uOffset, 16, 16)
		bgfx.SetTextureFromFrameBuffer(0, uTexColor, lum[2])
		bgfx.SetProgram(lumAvgProg)
		bgfx.SetState(bgfx.StateRGBWrite | bgfx.StateAlphaWrite)
		screenSpaceQuad(decl, 4, 4, originBottomLeft)
		bgfx.Submit(5)

		// Downscale luminance 3.
		setOffsets4x4Lum(uOffset, 4, 4)
		bgfx.SetTextureFromFrameBuffer(0, uTexColor, lum[3])
		bgfx.SetProgram(lumAvgProg)
		bgfx.SetState(bgfx.StateRGBWrite | bgfx.StateAlphaWrite)
		screenSpaceQuad(decl, 1, 1, originBottomLeft)
		bgfx.Submit(6)

		tonemap := [4]float32{middleGray, white * white, threshold, 0}
		bgfx.SetUniform(uTonemap, &tonemap, 1)

		// Bright pass threshold is tonemap[3]
		setOffsets4x4Lum(uOffset, app.Width/2, app.Height/2)
		bgfx.SetTexture(0, uTexColor, fbtextures[0])
		bgfx.SetTextureFromFrameBuffer(1, uTexLum, lum[4])
		bgfx.SetProgram(brightProg)
		bgfx.SetState(bgfx.StateRGBWrite | bgfx.StateAlphaWrite)
		screenSpaceQuad(decl, float32(app.Width/2), float32(app.Height/2), originBottomLeft)
		bgfx.Submit(7)

		// Blur pass vertically
		bgfx.SetTextureFromFrameBuffer(0, uTexColor, bright)
		bgfx.SetProgram(blurProg)
		bgfx.SetState(bgfx.StateRGBWrite | bgfx.StateAlphaWrite)
		screenSpaceQuad(decl, float32(app.Width/8), float32(app.Height/8), originBottomLeft)
		bgfx.Submit(8)

		// Blur pass horizontally, do tonemapping and combine.
		bgfx.SetTexture(0, uTexColor, fbtextures[0])
		bgfx.SetTextureFromFrameBuffer(1, uTexLum, lum[4])
		bgfx.SetTextureFromFrameBuffer(2, uTexBlur, blur)
		bgfx.SetProgram(tonemapProg)
		bgfx.SetState(bgfx.StateRGBWrite | bgfx.StateAlphaWrite)
		screenSpaceQuad(decl, float32(app.Width), float32(app.Height), originBottomLeft)
		bgfx.Submit(9)

		bgfx.Frame()
	}
}
Ejemplo n.º 3
0
func main() {
	app := example.Open()
	defer app.Close()
	bgfx.Init()
	defer bgfx.Shutdown()
	bgfx.Reset(app.Width, app.Height, bgfx.ResetVSync)
	bgfx.SetDebug(bgfx.DebugText)
	bgfx.SetViewClear(
		0,
		bgfx.ClearColor|bgfx.ClearDepth,
		0x303030ff,
		1.0,
		0,
	)

	var (
		uTexColor   = bgfx.CreateUniform("u_texColor", bgfx.Uniform1iv, 1)
		uStipple    = bgfx.CreateUniform("u_stipple", bgfx.Uniform3fv, 1)
		uTexStipple = bgfx.CreateUniform("u_texStipple", bgfx.Uniform1iv, 1)
	)
	defer bgfx.DestroyUniform(uTexColor)
	defer bgfx.DestroyUniform(uStipple)
	defer bgfx.DestroyUniform(uTexStipple)

	prog := assets.LoadProgram("vs_tree", "fs_tree")
	defer bgfx.DestroyProgram(prog)

	textureLeafs := assets.LoadTexture("leafs1.dds", 0)
	textureBark := assets.LoadTexture("bark1.dds", 0)
	defer bgfx.DestroyTexture(textureLeafs)
	defer bgfx.DestroyTexture(textureBark)

	stippleData := make([]byte, 8*4)
	for i, v := range knightTour {
		stippleData[(v.Y*8 + v.X)] = byte(i * 4)
	}
	textureStipple := bgfx.CreateTexture2D(8, 4, 1, bgfx.TextureFormatR8,
		bgfx.TextureMinPoint|bgfx.TextureMagPoint, stippleData)
	defer bgfx.DestroyTexture(textureStipple)

	meshTop := [3]assets.Mesh{
		assets.LoadMesh("tree1b_lod0_1"),
		assets.LoadMesh("tree1b_lod1_1"),
		assets.LoadMesh("tree1b_lod2_1"),
	}
	meshTrunk := [3]assets.Mesh{
		assets.LoadMesh("tree1b_lod0_2"),
		assets.LoadMesh("tree1b_lod1_2"),
		assets.LoadMesh("tree1b_lod2_2"),
	}
	for _, m := range meshTop {
		defer m.Unload()
	}
	for _, m := range meshTrunk {
		defer m.Unload()
	}

	var (
		stateCommon      = bgfx.StateRGBWrite | bgfx.StateAlphaWrite | bgfx.StateDepthTestLess | bgfx.StateCullCCW | bgfx.StateMSAA
		stateTransparent = stateCommon | bgfx.StateBlendAlpha()
		stateOpaque      = stateCommon | bgfx.StateDepthWrite

		transitions     = true
		transitionFrame = 0
		currLOD         = 0
		targetLOD       = 0
	)

	for app.Continue() {
		bgfx.SetViewRect(0, 0, 0, app.Width, app.Height)
		bgfx.Submit(0)
		bgfx.DebugTextClear()
		bgfx.DebugTextPrintf(0, 1, 0x4f, app.Title)
		bgfx.DebugTextPrintf(0, 2, 0x6f, "Description: Mesh LOD transitions.")
		bgfx.DebugTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", app.DeltaTime*1000.0)

		var (
			currentLODframe = 32
			mainLOD         = targetLOD
			distance        = float32(math.Cos(float64(app.Time))*2 + 4.0)
		)
		if transitions {
			currentLODframe = 32 - transitionFrame
			mainLOD = currLOD
		}
		stipple := [3]float32{
			0,
			-1,
			(float32(currentLODframe) * 4 / 255) - (1.0 / 255),
		}
		stippleInv := [3]float32{
			31.0 * 4 / 255,
			1,
			(float32(transitionFrame) * 4 / 255) - (1.0 / 255),
		}

		var (
			eye = [3]float32{0, 1, -distance}
			at  = [3]float32{0, 1, 0}
			up  = [3]float32{0, 1, 0}
		)
		view := mat4.LookAtLH(eye, at, up)
		proj := mat4.PerspectiveLH(
			cgm.ToRadians(60),
			float32(app.Width)/float32(app.Height),
			0.1, 100,
		)
		mtx := mat4.Scale(0.1, 0.1, 0.1)
		bgfx.SetViewTransform(0, view, proj)

		bgfx.SetTexture(0, uTexColor, textureBark)
		bgfx.SetTexture(1, uTexStipple, textureStipple)
		bgfx.SetUniform(uStipple, &stipple, 1)
		meshTrunk[mainLOD].Submit(0, prog, mtx, stateOpaque)

		bgfx.SetTexture(0, uTexColor, textureLeafs)
		bgfx.SetTexture(1, uTexStipple, textureStipple)
		bgfx.SetUniform(uStipple, &stipple, 1)
		meshTop[mainLOD].Submit(0, prog, mtx, stateTransparent)

		if transitions && transitionFrame != 0 {
			bgfx.SetTexture(0, uTexColor, textureBark)
			bgfx.SetTexture(1, uTexStipple, textureStipple)
			bgfx.SetUniform(uStipple, &stippleInv, 1)
			meshTrunk[targetLOD].Submit(0, prog, mtx, stateOpaque)

			bgfx.SetTexture(0, uTexColor, textureLeafs)
			bgfx.SetTexture(1, uTexStipple, textureStipple)
			bgfx.SetUniform(uStipple, &stippleInv, 1)
			meshTop[targetLOD].Submit(0, prog, mtx, stateTransparent)
		}

		lod := 0
		if distance > 2.5 {
			lod = 1
		}
		if distance > 5.0 {
			lod = 2
		}
		if targetLOD != lod && targetLOD == currLOD {
			targetLOD = lod
		}
		if currLOD != targetLOD {
			transitionFrame++
		}
		if transitionFrame > 32 {
			currLOD = targetLOD
			transitionFrame = 0
		}

		bgfx.Frame()
	}
}