Skip to content

Commit

Permalink
Lighting optimizations.
Browse files Browse the repository at this point in the history
Lighting is now done on a per-triangle basis rather than a per-vertex basis, as Sun lights color all vertices the same (as they all belong to the same triangle, which has just one normal).
Point lights are also optimized - rather than transforming each vertex by the model's transform, it's faster to transform the point light's position by the model's inverted transform.
Light.Light() returns an array of 9 floats, indicating the R, G, and B values for the light for each vertex of a given triangle.
Adding toggle-able lighting in the lighting example.
  • Loading branch information
SolarLune committed Jan 7, 2022
1 parent 8046ef3 commit 59cf471
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 98 deletions.
97 changes: 60 additions & 37 deletions camera.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ type DebugInfo struct {
TotalObjects int // Total number of objects
DrawnTris int // Number of drawn triangles, excluding those hidden from backface culling
TotalTris int // Total number of triangles
LightCount int // Total number of lights
ActiveLightCount int // Total active number of lights
}

// Camera represents a camera (where you look from) in Tetra3D.
Expand Down Expand Up @@ -281,7 +283,8 @@ func (camera *Camera) Clear() {
camera.DebugInfo.TotalObjects = 0
camera.DebugInfo.TotalTris = 0
camera.DebugInfo.DrawnTris = 0

camera.DebugInfo.LightCount = 0
camera.DebugInfo.ActiveLightCount = 0
}

// RenderNodes renders all nodes starting with the provided rootNode using the Scene's properties (fog, for example).
Expand Down Expand Up @@ -332,9 +335,13 @@ func (camera *Camera) Render(scene *Scene, models ...*Model) {
if scene.LightingOn {

for _, l := range scene.Root.ChildrenRecursive() {
if light, isLight := l.(Light); isLight && light.isOn() {
lights = append(lights, light)
light.begin()
if light, isLight := l.(Light); isLight {
camera.DebugInfo.LightCount++
if light.isOn() {
lights = append(lights, light)
light.beginRender()
camera.DebugInfo.ActiveLightCount++
}
}
}

Expand Down Expand Up @@ -544,58 +551,72 @@ func (camera *Camera) Render(scene *Scene, models ...*Model) {

index := 0

modelTrans := model.Transform()

lighting := scene.LightingOn
if model.Mesh.Material != nil {
lighting = scene.LightingOn && model.Mesh.Material.EnableLighting
}

for _, tri := range triList[:vertexListIndex/3] {

for _, vert := range tri.Vertices {

// Vertex colors

if lighting {
vertexList[index].ColorR = vert.Color.R
vertexList[index].ColorG = vert.Color.G
vertexList[index].ColorB = vert.Color.B

vertexList[index].ColorA = vert.Color.A

vertexList[index].SrcX = float32(vert.UV[0] * srcW)

// We do 1 - v here (aka Y in texture coordinates) because 1.0 is the top of the texture while 0 is the bottom in UV coordinates,
// but when drawing textures 0 is the top, and the sourceHeight is the bottom.
vertexList[index].SrcY = float32((1 - vert.UV[1]) * srcH)

t := time.Now()
index++

r := float32(0)
g := float32(0)
b := float32(0)
}

for _, light := range lights {
lr, lg, lb := light.Light(vert, modelTrans)
r += lr
g += lg
b += lb
}
}

camera.DebugInfo.lightTime += time.Since(t)
lighting := scene.LightingOn
if model.Mesh.Material != nil {
lighting = scene.LightingOn && model.Mesh.Material.EnableLighting
}

if lighting {

index = 0

t := time.Now()

for _, light := range lights {
light.beginModel(model)
}

lightColors := [9]float32{}

vertexList[index].ColorR = vert.Color.R * r
vertexList[index].ColorG = vert.Color.G * g
vertexList[index].ColorB = vert.Color.B * b
for _, tri := range triList[:vertexListIndex/3] {

} else {
vertexList[index].ColorR = vert.Color.R
vertexList[index].ColorG = vert.Color.G
vertexList[index].ColorB = vert.Color.B
for i := range lightColors {
lightColors[i] = 0
}

vertexList[index].ColorA = vert.Color.A
for _, light := range lights {
for i, v := range light.Light(tri) {
lightColors[i] += v
}
}

vertexList[index].SrcX = float32(vert.UV[0] * srcW)
for vertIndex := range tri.Vertices {

// We do 1 - v here (aka Y in texture coordinates) because 1.0 is the top of the texture while 0 is the bottom in UV coordinates,
// but when drawing textures 0 is the top, and the sourceHeight is the bottom.
vertexList[index].SrcY = float32((1 - vert.UV[1]) * srcH)
vertexList[index].ColorR *= lightColors[(vertIndex)*3]
vertexList[index].ColorG *= lightColors[(vertIndex)*3+1]
vertexList[index].ColorB *= lightColors[(vertIndex)*3+2]
index++

index++
}

}

camera.DebugInfo.lightTime += time.Since(t)

}

var img *ebiten.Image
Expand Down Expand Up @@ -670,10 +691,12 @@ func (camera *Camera) DrawDebugText(screen *ebiten.Image, textScale float64) {
lt := fmt.Sprintf("%.2fms", float32(m)/1000)

text.DrawWithOptions(screen, fmt.Sprintf(
"FPS: %f\nTotal frame time: %s\nSkinned mesh animation time: %s\nLighting time:%s\nRendered objects:%d/%d\nRendered triangles: %d/%d",
"FPS: %f\nTotal frame time: %s\nSkinned mesh animation time: %s\nActive Lights:%d/%d\nLighting time:%s\nRendered objects:%d/%d\nRendered triangles: %d/%d",
ebiten.CurrentFPS(),
ft,
at,
camera.DebugInfo.ActiveLightCount,
camera.DebugInfo.LightCount,
lt,
camera.DebugInfo.DrawnObjects,
camera.DebugInfo.TotalObjects,
Expand Down
8 changes: 6 additions & 2 deletions examples/lighting/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,10 @@ func (g *Game) Update() error {
g.DrawDebugDepth = !g.DrawDebugDepth
}

if inpututil.IsKeyJustPressed(ebiten.Key1) {
g.Scene.LightingOn = !g.Scene.LightingOn
}

return err
}

Expand All @@ -211,8 +215,8 @@ func (g *Game) Draw(screen *ebiten.Image) {

if g.DrawDebugText {
g.Camera.DrawDebugText(screen, 1)
txt := "F1 to toggle this text\nWASD: Move, Mouse: Look\nThis example simply shows dynamic vertex-based lighting.\nF5: Toggle depth debug view\nF4: Toggle fullscreen\nESC: Quit"
text.Draw(screen, txt, basicfont.Face7x13, 0, 100, color.RGBA{255, 0, 0, 255})
txt := "F1 to toggle this text\nWASD: Move, Mouse: Look\nThis example simply shows dynamic vertex-based lighting.\n1 Key: Toggle lighting\nF5: Toggle depth debug view\nF4: Toggle fullscreen\nESC: Quit"
text.Draw(screen, txt, basicfont.Face7x13, 0, 150, color.RGBA{255, 0, 0, 255})
}
}

Expand Down
Loading

0 comments on commit 59cf471

Please sign in to comment.