Преглед на файлове

Improve and simplify renderer

Daniel Salvadori преди 6 години
родител
ревизия
d166c58b29
променени са 1 файла, в които са добавени 193 реда и са изтрити 446 реда
  1. 193 446
      renderer/renderer.go

+ 193 - 446
renderer/renderer.go

@@ -15,32 +15,28 @@ import (
 	"sort"
 )
 
-// Renderer renders a 3D scene and/or a 2D GUI on the current window.
+// Renderer renders a scene containing 3D objects and/or 2D GUI elements.
 type Renderer struct {
-	gs           *gls.GLS
-	shaman       Shaman                     // Internal shader manager
-	stats        Stats                      // Renderer statistics
-	prevStats    Stats                      // Renderer statistics for previous frame
-	scene        core.INode                 // Node containing 3D scene to render
-	panelGui     gui.IPanel                 // Panel containing GUI to render
-	panel3D      gui.IPanel                 // Panel which contains the 3D scene
+	Shaman                      // Embedded shader manager
+	gs          *gls.GLS        // Reference to OpenGL state
+	rinfo       core.RenderInfo // Preallocated Render info
+	specs       ShaderSpecs     // Preallocated Shader specs
+	sortObjects bool            // Flag indicating whether objects should be sorted before rendering
+	stats       Stats           // Renderer statistics
+	prevStats   Stats           // Renderer statistics for previous frame
+
+	// Populated each frame
+	rgraphics    []*graphic.Graphic         // Array of rendered graphics
+	cgraphics    []*graphic.Graphic         // Array of culled graphics
+	grmatsOpaque []*graphic.GraphicMaterial // Array of rendered opaque graphic materials for scene
+	grmatsTransp []*graphic.GraphicMaterial // Array of rendered transparent graphic materials for scene
+	grmatsGui    []*graphic.GraphicMaterial // Array of rendered GUI graphic materials for scene
+	ipanels      []gui.IPanel               // Array of all top rendered IPanels (panels which are not children of other IPanels)
 	ambLights    []*light.Ambient           // Array of ambient lights for last scene
 	dirLights    []*light.Directional       // Array of directional lights for last scene
 	pointLights  []*light.Point             // Array of point
 	spotLights   []*light.Spot              // Array of spot lights for the scene
 	others       []core.INode               // Other nodes (audio, players, etc)
-	rgraphics    []*graphic.Graphic         // Array of rendered graphics
-	cgraphics    []*graphic.Graphic         // Array of rendered graphics
-	grmatsOpaque []*graphic.GraphicMaterial // Array of rendered opaque graphic materials for scene
-	grmatsTransp []*graphic.GraphicMaterial // Array of rendered transparent graphic materials for scene
-	rinfo        core.RenderInfo            // Preallocated Render info
-	specs        ShaderSpecs                // Preallocated Shader specs
-	sortObjects  bool                       // Flag indicating whether objects should be sorted before rendering
-	redrawGui    bool                       // Flag indicating the gui must be redrawn completely
-	rendered     bool                       // Flag indicating if anything was rendered
-	panList      []gui.IPanel               // list of panels to render
-	frameBuffers int                        // Number of frame buffers
-	frameCount   int                        // Current number of frame buffers to write
 }
 
 // Stats describes how many object types were rendered.
@@ -57,7 +53,8 @@ func NewRenderer(gs *gls.GLS) *Renderer {
 
 	r := new(Renderer)
 	r.gs = gs
-	r.shaman.Init(gs)
+	r.Shaman.Init(gs)
+	r.sortObjects = true
 
 	r.ambLights = make([]*light.Ambient, 0)
 	r.dirLights = make([]*light.Directional, 0)
@@ -68,65 +65,9 @@ func NewRenderer(gs *gls.GLS) *Renderer {
 	r.cgraphics = make([]*graphic.Graphic, 0)
 	r.grmatsOpaque = make([]*graphic.GraphicMaterial, 0)
 	r.grmatsTransp = make([]*graphic.GraphicMaterial, 0)
-	r.panList = make([]gui.IPanel, 0)
-	r.frameBuffers = 2
-	r.sortObjects = true
-	return r
-}
-
-// AddDefaultShaders adds to this renderer's shader manager all default
-// include chunks, shaders and programs statically registered.
-func (r *Renderer) AddDefaultShaders() error {
-
-	return r.shaman.AddDefaultShaders()
-}
-
-// AddChunk adds a shader chunk with the specified name and source code.
-func (r *Renderer) AddChunk(name, source string) {
-
-	r.shaman.AddChunk(name, source)
-}
-
-// AddShader adds a shader program with the specified name and source code.
-func (r *Renderer) AddShader(name, source string) {
-
-	r.shaman.AddShader(name, source)
-}
+	r.ipanels = make([]gui.IPanel, 0)
 
-// AddProgram adds the program with the specified name,
-// with associated vertex and fragment shaders (previously registered).
-func (r *Renderer) AddProgram(name, vertex, frag string, others ...string) {
-
-	r.shaman.AddProgram(name, vertex, frag, others...)
-}
-
-// SetGui sets the gui panel which contains the Gui to render.
-// If set to nil, no Gui will be rendered.
-func (r *Renderer) SetGui(gui gui.IPanel) {
-
-	r.panelGui = gui
-}
-
-// SetGuiPanel3D sets the gui panel inside which the 3D scene is shown.
-// This informs the renderer that the Gui elements over this panel
-// must be redrawn even if they didn't change.
-// This panel panel must not be renderable, otherwise it will cover the 3D scene.
-func (r *Renderer) SetGuiPanel3D(panel3D gui.IPanel) {
-
-	r.panel3D = panel3D
-}
-
-// Panel3D returns the current gui panel over the 3D scene.
-func (r *Renderer) Panel3D() gui.IPanel {
-
-	return r.panel3D
-}
-
-// SetScene sets the 3D scene to be rendered.
-// If set to nil, no 3D scene will be rendered.
-func (r *Renderer) SetScene(scene core.INode) {
-
-	r.scene = scene
+	return r
 }
 
 // Stats returns a copy of the statistics for the last frame.
@@ -148,44 +89,18 @@ func (r *Renderer) ObjectSorting() bool {
 	return r.sortObjects
 }
 
-// Render renders the previously set Scene and Gui using the specified camera.
-// Returns an indication if anything was rendered and an error.
-func (r *Renderer) Render(icam camera.ICamera) (bool, error) {
-
-	r.redrawGui = false
-	r.rendered = false
-	r.stats = Stats{}
-
-	// Renders the 3D scene
-	if r.scene != nil {
-		err := r.renderScene(r.scene, icam)
-		if err != nil {
-			return r.rendered, err
-		}
-	}
-	// Renders the Gui over the 3D scene
-	if r.panelGui != nil {
-		err := r.renderGui()
-		if err != nil {
-			return r.rendered, err
-		}
-	}
-	r.prevStats = r.stats
-	return r.rendered, nil
-}
-
-// renderScene renders the 3D scene using the specified camera.
-func (r *Renderer) renderScene(iscene core.INode, icam camera.ICamera) error {
+// Render renders the specified scene using the specified camera. Returns an an error.
+func (r *Renderer) Render(scene core.INode, cam camera.ICamera) error {
 
 	// Updates world matrices of all scene nodes
-	iscene.UpdateMatrixWorld()
-	scene := iscene.GetNode()
+	scene.UpdateMatrixWorld()
 
-	// Builds RenderInfo calls RenderSetup for all visible nodes
-	icam.ViewMatrix(&r.rinfo.ViewMatrix)
-	icam.ProjMatrix(&r.rinfo.ProjMatrix)
+	// Build RenderInfo
+	cam.ViewMatrix(&r.rinfo.ViewMatrix)
+	cam.ProjMatrix(&r.rinfo.ProjMatrix)
 
-	// Clear scene arrays
+	// Clear stats and scene arrays
+	r.stats = Stats{}
 	r.ambLights = r.ambLights[0:0]
 	r.dirLights = r.dirLights[0:0]
 	r.pointLights = r.pointLights[0:0]
@@ -195,82 +110,18 @@ func (r *Renderer) renderScene(iscene core.INode, icam camera.ICamera) error {
 	r.cgraphics = r.cgraphics[0:0]
 	r.grmatsOpaque = r.grmatsOpaque[0:0]
 	r.grmatsTransp = r.grmatsTransp[0:0]
+	r.ipanels = r.ipanels[0:0]
 
 	// Prepare for frustum culling
 	var proj math32.Matrix4
 	proj.MultiplyMatrices(&r.rinfo.ProjMatrix, &r.rinfo.ViewMatrix)
 	frustum := math32.NewFrustumFromMatrix(&proj)
 
-	// Internal function to classify a node and its children
-	var classifyNode func(inode core.INode)
-	classifyNode = func(inode core.INode) {
-
-		// If node not visible, ignore
-		node := inode.GetNode()
-		if !node.Visible() {
-			return
-		}
-
-		// Checks if node is a Graphic
-		igr, ok := inode.(graphic.IGraphic)
-		if ok {
-			if igr.Renderable() {
-
-				gr := igr.GetGraphic()
-
-				// Frustum culling
-				if igr.Cullable() {
-					mw := gr.MatrixWorld()
-					geom := igr.GetGeometry()
-					bb := geom.BoundingBox()
-					bb.ApplyMatrix4(&mw)
-					if frustum.IntersectsBox(&bb) {
-						// Append graphic to list of graphics to be rendered
-						r.rgraphics = append(r.rgraphics, gr)
-					} else {
-						// Append graphic to list of culled graphics
-						r.cgraphics = append(r.cgraphics, gr)
-					}
-				} else {
-					// Append graphic to list of graphics to be rendered
-					r.rgraphics = append(r.rgraphics, gr)
-				}
-			}
-			// Node is not a Graphic
-		} else {
-			// Checks if node is a Light
-			il, ok := inode.(light.ILight)
-			if ok {
-				switch l := il.(type) {
-				case *light.Ambient:
-					r.ambLights = append(r.ambLights, l)
-				case *light.Directional:
-					r.dirLights = append(r.dirLights, l)
-				case *light.Point:
-					r.pointLights = append(r.pointLights, l)
-				case *light.Spot:
-					r.spotLights = append(r.spotLights, l)
-				default:
-					panic("Invalid light type")
-				}
-				// Other nodes
-			} else {
-				r.others = append(r.others, inode)
-			}
-		}
-
-		// Classify node children
-		for _, ichild := range node.Children() {
-			classifyNode(ichild)
-		}
-	}
-
-	// Classify all scene nodes
-	classifyNode(scene)
-
+	// Classify scene and all scene nodes, culling renderable IGraphics which are fully outside of the camera frustum
+	r.classifyAndCull(scene, frustum)
 	//log.Debug("Rendered/Culled: %v/%v", len(r.grmats), len(r.cgrmats))
 
-	// Sets lights count in shader specs
+	// Set light counts in shader specs
 	r.specs.AmbientLightsMax = len(r.ambLights)
 	r.specs.DirLightsMax = len(r.dirLights)
 	r.specs.PointLightsMax = len(r.pointLights)
@@ -278,12 +129,11 @@ func (r *Renderer) renderScene(iscene core.INode, icam camera.ICamera) error {
 
 	// Pre-calculate MV and MVP matrices and compile lists of opaque and transparent graphic materials
 	for _, gr := range r.rgraphics {
-		// Calculate MV and MVP matrices for all graphics to be rendered
+		// Calculate MV and MVP matrices for all non-GUI graphics to be rendered
 		gr.CalculateMatrices(r.gs, &r.rinfo)
-
-		// Append all graphic materials of this graphic to list of graphic materials to be rendered
+		// Append all graphic materials of this graphic to lists of graphic materials to be rendered
 		materials := gr.Materials()
-		for i := 0; i < len(materials); i++ {
+		for i := range materials {
 			if materials[i].IMaterial().GetMaterial().Transparent() {
 				r.grmatsTransp = append(r.grmatsTransp, &materials[i])
 			} else {
@@ -296,258 +146,200 @@ func (r *Renderer) renderScene(iscene core.INode, icam camera.ICamera) error {
 
 	// Z-sort graphic materials (opaque front-to-back and transparent back-to-front)
 	if r.sortObjects {
-		// Internal function to render a list of graphic materials
-		var zSortGraphicMaterials func(grmats []*graphic.GraphicMaterial, backToFront bool)
-		zSortGraphicMaterials = func(grmats []*graphic.GraphicMaterial, backToFront bool) {
-			sort.Slice(grmats, func(i, j int) bool {
-				gr1 := grmats[i].IGraphic().GetGraphic()
-				gr2 := grmats[j].IGraphic().GetGraphic()
-
-				// Check for user-supplied render order
-				rO1 := gr1.RenderOrder()
-				rO2 := gr2.RenderOrder()
-				if rO1 != rO2 {
-					return  rO1 < rO2
-				}
-
-				mvm1 := gr1.ModelViewMatrix()
-				mvm2 := gr2.ModelViewMatrix()
-				g1pos := gr1.Position()
-				g2pos := gr2.Position()
-				g1pos.ApplyMatrix4(mvm1)
-				g2pos.ApplyMatrix4(mvm2)
-
-				if backToFront {
-					return g1pos.Z < g2pos.Z
-				}
-
-				return g1pos.Z > g2pos.Z
-			})
-		}
-
-		zSortGraphicMaterials(r.grmatsOpaque, false) // Sort opaque graphics front to back
-		zSortGraphicMaterials(r.grmatsTransp, true)  // Sort transparent graphics back to front
+		zSort(r.grmatsOpaque, false) // Sort opaque graphics front to back
+		zSort(r.grmatsTransp, true)  // Sort transparent graphics back to front
 	}
 
-	// Render other nodes (audio players, etc)
-	for i := 0; i < len(r.others); i++ {
-		inode := r.others[i]
-		if !inode.GetNode().Visible() {
-			continue
+	// Render GUI elements first
+	for i := len(r.ipanels) - 1; i > -1; i-- {
+		err := r.renderPanel(r.ipanels[i])
+		if err != nil {
+			return err
 		}
-		r.others[i].Render(r.gs)
-		r.stats.Others++
 	}
 
-	// If there is graphic material to render or there was in the previous frame
-	// it is necessary to clear the screen.
-	if len(r.grmatsOpaque) > 0 || len(r.grmatsTransp) > 0 || r.prevStats.Graphics > 0 {
-		// If the 3D scene to draw is to be confined to user specified panel
-		// sets scissor to avoid erasing gui elements outside of this panel
-		if r.panel3D != nil {
-			pos := r.panel3D.GetPanel().Pospix()
-			width, height := r.panel3D.GetPanel().Size()
-
-			// Get scale of window (for HiDPI support)
-			sX64, sY64 := r.panel3D.Root().Window().Scale()
-			sX := float32(sX64)
-			sY := float32(sY64)
-
-			// Modify position and height of scissor according to window scale (for HiDPI support)
-			width *= sX
-			height *= sY
-			pos.X *= sX
-			pos.Y *= sY
-
-			_, _, _, viewheight := r.gs.GetViewport()
-			r.gs.Enable(gls.SCISSOR_TEST)
-			r.gs.Scissor(int32(pos.X), viewheight-int32(pos.Y)-int32(height), uint32(width), uint32(height))
-		} else {
-			r.gs.Disable(gls.SCISSOR_TEST)
-			r.redrawGui = true
+	// Render opaque objects (already sorted front to back)
+	for _, grmat := range r.grmatsOpaque {
+		err := r.renderGraphicMaterial(grmat)
+		if err != nil {
+			return err
 		}
-		// Clears the area inside the current scissor
-		r.gs.Clear(gls.DEPTH_BUFFER_BIT | gls.STENCIL_BUFFER_BIT | gls.COLOR_BUFFER_BIT)
-		r.rendered = true
 	}
 
-	err := error(nil)
-
-	// Internal function to render a list of graphic materials
-	var renderGraphicMaterials func(grmats []*graphic.GraphicMaterial)
-	renderGraphicMaterials = func(grmats []*graphic.GraphicMaterial) {
-		// For each *GraphicMaterial
-		for _, grmat := range grmats {
-			mat := grmat.IMaterial().GetMaterial()
-			geom := grmat.IGraphic().GetGeometry()
-			gr := grmat.IGraphic().GetGraphic()
-
-			// Add defines from material and geometry
-			r.specs.Defines = *gls.NewShaderDefines()
-			r.specs.Defines.Add(&mat.ShaderDefines)
-			r.specs.Defines.Add(&geom.ShaderDefines)
-			r.specs.Defines.Add(&gr.ShaderDefines)
-
-			// Sets the shader specs for this material and sets shader program
-			r.specs.Name = mat.Shader()
-			r.specs.ShaderUnique = mat.ShaderUnique()
-			r.specs.UseLights = mat.UseLights()
-			r.specs.MatTexturesMax = mat.TextureCount()
-
-			// Set active program and apply shader specs
-			_, err = r.shaman.SetProgram(&r.specs)
-			if err != nil {
-				return
-			}
-
-			// Setup lights (transfer lights' uniforms)
-			for idx, l := range r.ambLights {
-				l.RenderSetup(r.gs, &r.rinfo, idx)
-				r.stats.Lights++
-			}
-			for idx, l := range r.dirLights {
-				l.RenderSetup(r.gs, &r.rinfo, idx)
-				r.stats.Lights++
-			}
-			for idx, l := range r.pointLights {
-				l.RenderSetup(r.gs, &r.rinfo, idx)
-				r.stats.Lights++
-			}
-			for idx, l := range r.spotLights {
-				l.RenderSetup(r.gs, &r.rinfo, idx)
-				r.stats.Lights++
-			}
-
-			// Render this graphic material
-			grmat.Render(r.gs, &r.rinfo)
-			r.stats.Graphics++
+	// Render transparent objects (already sorted back to front)
+	for _, grmat := range r.grmatsTransp {
+		err := r.renderGraphicMaterial(grmat)
+		if err != nil {
+			return err
 		}
 	}
 
-	renderGraphicMaterials(r.grmatsOpaque) // Render opaque objects (front to back)
-	if err != nil {
-		return err
+	// Render other nodes (audio players, etc)
+	for _, inode := range r.others {
+		inode.Render(r.gs)
+		r.stats.Others++
 	}
-	renderGraphicMaterials(r.grmatsTransp) // Render transparent objects (back to front)
 
-	return err
+	r.prevStats = r.stats
+	return nil
 }
 
-// renderGui renders the Gui
-func (r *Renderer) renderGui() error {
+// classifyAndCull classifies the provided INode and all of its descendents.
+// It ignores (culls) renderable IGraphics which are fully outside of the specified frustum.
+func (r *Renderer) classifyAndCull(inode core.INode, frustum *math32.Frustum) {
 
-	// If no 3D scene was rendered sets Gui panels as renderable for background
-	// User must define the colors
-	if (len(r.rgraphics) == 0) && (len(r.cgraphics) == 0) {
-		r.panelGui.SetRenderable(true)
-		if r.panel3D != nil {
-			r.panel3D.SetRenderable(true)
+	classifyChildren := true
+	// Ignore invisible nodes and their descendants
+	if !inode.Visible() {
+		return
+	}
+	// If node is an IPanel append it to appropriate list
+	if ipan, ok := inode.(gui.IPanel); ok {
+		r.ipanels = append(r.ipanels, ipan)
+		classifyChildren = false // Don't classify children since they must be IPanels
+		// Check if node is an IGraphic
+	} else if igr, ok := inode.(graphic.IGraphic); ok {
+		if igr.Renderable() {
+			gr := igr.GetGraphic()
+			// Frustum culling
+			if igr.Cullable() {
+				mw := gr.MatrixWorld()
+				geom := igr.GetGeometry()
+				bb := geom.BoundingBox()
+				bb.ApplyMatrix4(&mw)
+				if frustum.IntersectsBox(&bb) {
+					// Append graphic to list of graphics to be rendered
+					r.rgraphics = append(r.rgraphics, gr)
+				} else {
+					// Append graphic to list of culled graphics
+					r.cgraphics = append(r.cgraphics, gr)
+				}
+			} else {
+				// Append graphic to list of graphics to be rendered
+				r.rgraphics = append(r.rgraphics, gr)
+			}
 		}
+		// Node is not a Graphic
 	} else {
-		r.panelGui.SetRenderable(false)
-		if r.panel3D != nil {
-			r.panel3D.SetRenderable(false)
+		// Check if node is a Light
+		if il, ok := inode.(light.ILight); ok {
+			switch l := il.(type) {
+			case *light.Ambient:
+				r.ambLights = append(r.ambLights, l)
+			case *light.Directional:
+				r.dirLights = append(r.dirLights, l)
+			case *light.Point:
+				r.pointLights = append(r.pointLights, l)
+			case *light.Spot:
+				r.spotLights = append(r.spotLights, l)
+			default:
+				panic("Invalid light type")
+			}
+			// Other nodes
+		} else {
+			r.others = append(r.others, inode)
 		}
 	}
-
-	// Clears list of panels to render
-	r.panList = r.panList[0:0]
-	// Redraw all GUI elements elements (panel3D == nil and 3D scene drawn)
-	if r.redrawGui {
-		r.appendPanel(r.panelGui)
-		// Redraw GUI elements only if changed
-		// Set the number of frame buffers to draw these changes
-	} else if r.checkChanged(r.panelGui) {
-		r.appendPanel(r.panelGui)
-		r.frameCount = r.frameBuffers
-		// No change, but need to update frame buffers
-	} else if r.frameCount > 0 {
-		r.appendPanel(r.panelGui)
-		// No change, draw only panels over 3D if any
-	} else {
-		r.getPanelsOver3D()
-	}
-	if len(r.panList) == 0 {
-		return nil
+	// Classify children (if not an IPanel)
+	if classifyChildren {
+		for _, ichild := range inode.Children() {
+			r.classifyAndCull(ichild, frustum)
+		}
 	}
+}
 
-	// Updates panels bounds and relative positions
-	r.panelGui.GetPanel().UpdateMatrixWorld()
-	// Disable the scissor test which could have been set by the 3D scene renderer
-	// and then clear the depth buffer, so the panels will be rendered over the 3D scene.
-	r.gs.Disable(gls.SCISSOR_TEST)
-	r.gs.Clear(gls.DEPTH_BUFFER_BIT)
-
-	// Render panels
-	for i := 0; i < len(r.panList); i++ {
-		err := r.renderPanel(r.panList[i])
-		if err != nil {
-			return err
+// zSort sorts a list of graphic materials based on the
+// user-specified order first then based on their Z position relative to the camera
+func zSort(grmats []*graphic.GraphicMaterial, backToFront bool) {
+
+	sort.Slice(grmats, func(i, j int) bool {
+		gr1 := grmats[i].IGraphic().GetGraphic()
+		gr2 := grmats[j].IGraphic().GetGraphic()
+		// Check for user-supplied render order
+		rO1 := gr1.RenderOrder()
+		rO2 := gr2.RenderOrder()
+		if rO1 != rO2 {
+			return rO1 < rO2
 		}
-	}
-	r.frameCount--
-	r.rendered = true
-	return nil
+		mvm1 := gr1.ModelViewMatrix()
+		mvm2 := gr2.ModelViewMatrix()
+		g1pos := gr1.Position()
+		g2pos := gr2.Position()
+		g1pos.ApplyMatrix4(mvm1)
+		g2pos.ApplyMatrix4(mvm2)
+		if backToFront {
+			return g1pos.Z < g2pos.Z
+		}
+		return g1pos.Z > g2pos.Z
+	})
 }
 
-// getPanelsOver3D builds list of panels over 3D to be rendered
-func (r *Renderer) getPanelsOver3D() {
+// renderGraphicMaterial renders the specified graphic material.
+func (r *Renderer) renderGraphicMaterial(grmat *graphic.GraphicMaterial) error {
 
-	// If panel3D not set or renderable, nothing to do
-	if r.panel3D == nil || r.panel3D.Renderable() {
-		return
-	}
+	mat := grmat.IMaterial().GetMaterial()
+	geom := grmat.IGraphic().GetGeometry()
+	gr := grmat.IGraphic().GetGraphic()
 
-	// Internal recursive function to check if any child of the
-	// specified panel is unbounded and over 3D.
-	// If it is, it is inserted in the list of panels to render.
-	var checkUnbounded func(pan *gui.Panel)
-	checkUnbounded = func(pan *gui.Panel) {
-
-		for i := 0; i < len(pan.Children()); i++ {
-			child := pan.Children()[i].(gui.IPanel).GetPanel()
-			if !child.Bounded() && r.checkPanelOver3D(child) {
-				r.appendPanel(child)
-				continue
-			}
-			checkUnbounded(child)
-		}
+	// Add defines from material and geometry
+	r.specs.Defines = *gls.NewShaderDefines()
+	r.specs.Defines.Add(&mat.ShaderDefines)
+	r.specs.Defines.Add(&geom.ShaderDefines)
+	r.specs.Defines.Add(&gr.ShaderDefines)
+
+	// Set the shader specs for this material and sets shader program
+	r.specs.Name = mat.Shader()
+	r.specs.ShaderUnique = mat.ShaderUnique()
+	r.specs.UseLights = mat.UseLights()
+	r.specs.MatTexturesMax = mat.TextureCount()
+
+	// Set active program and apply shader specs
+	_, err := r.Shaman.SetProgram(&r.specs)
+	if err != nil {
+		return err
 	}
 
-	// For all children of the Gui, checks if it is over the 3D panel
-	children := r.panelGui.GetPanel().Children()
-	for i := 0; i < len(children); i++ {
-		pan := children[i].(gui.IPanel).GetPanel()
-		if !pan.Visible() {
-			continue
-		}
-		if r.checkPanelOver3D(pan) {
-			r.appendPanel(pan)
-			continue
-		}
-		// Current child is not over 3D but can have an unbounded child which is
-		checkUnbounded(pan)
+	// Set up lights (transfer lights' uniforms)
+	for idx, l := range r.ambLights {
+		l.RenderSetup(r.gs, &r.rinfo, idx)
+		r.stats.Lights++
+	}
+	for idx, l := range r.dirLights {
+		l.RenderSetup(r.gs, &r.rinfo, idx)
+		r.stats.Lights++
+	}
+	for idx, l := range r.pointLights {
+		l.RenderSetup(r.gs, &r.rinfo, idx)
+		r.stats.Lights++
+	}
+	for idx, l := range r.spotLights {
+		l.RenderSetup(r.gs, &r.rinfo, idx)
+		r.stats.Lights++
 	}
+
+	// Render this graphic material
+	grmat.Render(r.gs, &r.rinfo)
+	r.stats.Graphics++
+
+	return nil
 }
 
 // renderPanel renders the specified panel and all its children
 // and then sets the panel as not changed.
 func (r *Renderer) renderPanel(ipan gui.IPanel) error {
 
-	// If panel not visible, ignore it and all its children
-	pan := ipan.GetPanel()
-	if !pan.Visible() {
-		pan.SetChanged(false)
+	if !ipan.Visible() {
 		return nil
 	}
-	// If panel is renderable, renders it
-	if pan.Renderable() {
-		// Sets shader program for the panel's material
-		grmat := pan.GetGraphic().Materials()[0]
+
+	// If panel is renderable, render it
+	if ipan.Renderable() {
+		// Set shader program for the panel's material
+		grmat := ipan.GetGraphic().Materials()[0]
 		mat := grmat.IMaterial().GetMaterial()
 		r.specs.Name = mat.Shader()
 		r.specs.ShaderUnique = mat.ShaderUnique()
-		_, err := r.shaman.SetProgram(&r.specs)
+		_, err := r.Shaman.SetProgram(&r.specs)
 		if err != nil {
 			return err
 		}
@@ -555,59 +347,14 @@ func (r *Renderer) renderPanel(ipan gui.IPanel) error {
 		grmat.Render(r.gs, &r.rinfo)
 		r.stats.Panels++
 	}
-	pan.SetChanged(false)
-	// Renders this panel children
-	for i := 0; i < len(pan.Children()); i++ {
-		err := r.renderPanel(pan.Children()[i].(gui.IPanel))
+
+	// Render children panels
+	for i := 0; i < len(ipan.Children()); i++ {
+		err := r.renderPanel(ipan.Children()[i].(gui.IPanel))
 		if err != nil {
 			return err
 		}
 	}
-	return nil
-}
-
-// appendPanel appends the specified panel to the list of panels to render.
-// Currently there is no need to check for duplicates.
-func (r *Renderer) appendPanel(ipan gui.IPanel) {
-
-	r.panList = append(r.panList, ipan)
-}
-
-// checkChanged checks if the specified panel or any of its children is changed
-func (r *Renderer) checkChanged(ipan gui.IPanel) bool {
-
-	// Unbounded panels are checked even if not visible
-	pan := ipan.GetPanel()
-	if !pan.Bounded() && pan.Changed() {
-		pan.SetChanged(false)
-		return true
-	}
-	// Ignore invisible panel and its children
-	if !pan.Visible() {
-		return false
-	}
-	if pan.Changed() && pan.Renderable() {
-		return true
-	}
-	for i := 0; i < len(pan.Children()); i++ {
-		res := r.checkChanged(pan.Children()[i].(gui.IPanel))
-		if res {
-			return res
-		}
-	}
-	return false
-}
 
-// checkPanelOver3D checks if the specified panel is over
-// the area where the 3D scene will be rendered.
-func (r *Renderer) checkPanelOver3D(ipan gui.IPanel) bool {
-
-	pan := ipan.GetPanel()
-	if !pan.Visible() {
-		return false
-	}
-	if r.panel3D.GetPanel().Intersects(pan) {
-		return true
-	}
-	return false
+	return nil
 }