// RotateTo adjusts the yaw and pitch to face a point. func (c *QuatCamera) RotateTo(center mgl.Vec3) { direction := center.Sub(c.position).Normalize() right := direction.Cross(AxisUp) up := right.Cross(direction) c.rotation = mgl.QuatLookAtV(c.position, center, up) }
func safeNormalize(v mgl32.Vec3) mgl32.Vec3 { v = v.Normalize() if math.IsInf(float64(v[0]), 0) || math.IsNaN(float64(v[0])) { return mgl32.Vec3{} } return v }
func (e *Editor) MoveSelectedNodeModel(x, y float32, axisLock mgl32.Vec3) { selectedModel, _ := e.overviewMenu.getSelectedNode(e.currentMap.Root) if selectedModel != nil { selectedModel.Translation = selectedModel.Translation.Add(axisLock.Mul(x * mouseSpeed)) } updateMap(e.currentMap.Root) }
//PointToLineDist distance from line (a,b) to point func PointToLineDist(a, b, point mgl32.Vec3) float32 { ab := b.Sub(a) ap := point.Sub(a) prj := ap.Dot(ab) lenSq := ab.Dot(ab) t := prj / lenSq return ab.Mul(t).Add(a).Sub(point).Len() }
func (f *fPlane) setPoints(v1, v2, v3 mgl32.Vec3) { aux1 := v1.Sub(v2) aux2 := v3.Sub(v2) f.N = aux2.Cross(aux1) f.N = safeNormalize(f.N) f.P = v2 f.D = -(f.N.Dot(f.P)) }
// Lerp will interpolate between the desired position/center by amount. func (c *QuatCamera) Lerp(position mgl.Vec3, center mgl.Vec3, amount float32) { direction := center.Sub(position).Normalize() right := direction.Cross(AxisUp) up := right.Cross(direction) targetRot := mgl.QuatLookAtV(position, center, up) c.rotation = mgl.QuatNlerp(c.rotation, targetRot, amount) c.position = c.position.Add(position.Sub(c.position).Mul(amount)) }
func (self *pane) pix2Vec(evnt *js.Object) mgl32.Vec2 { v := mgl32.Vec3{ // generate vector from current pixel coords float32(evnt.Get("clientX").Float()), float32(evnt.Get("clientY").Float()), 1.0, // apply translations from transform matrix } v = self.untransform.Mul3x1(v) // apply pan & zoom untransform matrix return v.Vec2() // return vec2 }
func getIntersection(fDst1, fDst2 float32, P1, P2 mgl32.Vec3, Hit *mgl32.Vec3) bool { if (fDst1 * fDst2) >= 0.0 { return false } if fDst1 == fDst2 { return false } *Hit = P1.Add((P2.Sub(P1)).Mul(-fDst1 / (fDst2 - fDst1))) return true }
// Rotate adjusts the direction vectors by a delta vector of {pitch, yaw, roll}. // Roll is ignored for now. func (c *EulerCamera) Rotate(delta mgl.Vec3) { c.yaw += float64(delta.Y()) c.pitch += float64(delta.X()) // Limit vertical rotation to avoid gimbal lock if c.pitch > halfPi { c.pitch = halfPi } else if c.pitch < -halfPi { c.pitch = -halfPi } c.updateVectors() }
// CreateBeam - creates a square prism oriented along the vector func CreateBeam(width float32, vector mgl32.Vec3) *Geometry { direction := vector.Normalize() geo := CreateBoxWithOffset(width, width, -width*0.5, -width*0.5) geo2 := CreateBoxWithOffset(width, width, -width*0.5, -width*0.5) facingTx := util.Mat4From(mgl32.Vec3{1, 1, 1}, mgl32.Vec3{}, util.FacingOrientation(0, direction, mgl32.Vec3{0, 0, 1}, mgl32.Vec3{1, 0, 0})) geo.Transform(facingTx) facingTx = util.Mat4From(mgl32.Vec3{1, 1, 1}, vector, util.FacingOrientation(0, direction, mgl32.Vec3{0, 0, -1}, mgl32.Vec3{1, 0, 0})) geo2.Optimize(geo, facingTx) geo.Indicies = append(geo.Indicies, 0, 1, 4, 4, 5, 0) //top geo.Indicies = append(geo.Indicies, 1, 2, 7, 7, 4, 1) //side geo.Indicies = append(geo.Indicies, 2, 3, 6, 6, 7, 2) //bottom geo.Indicies = append(geo.Indicies, 3, 0, 5, 5, 6, 3) //side return geo }
func Upvote(tip mgl.Vec3, size float32) []float32 { a := tip.Add(mgl.Vec3{-size / 2, -size * 2, 0}) b := tip.Add(mgl.Vec3{size / 2, -size, 0}) return []float32{ tip[0], tip[1], tip[2], // Top tip[0] - size, tip[1] - size, tip[2], // Bottom left tip[0] + size, tip[1] - size, tip[2], // Bottom right // Arrow handle b[0], b[1], b[2], // Top Right a[0], b[1], a[2], // Top Left a[0], a[1], a[2], // Bottom Left a[0], a[1], a[2], // Bottom Left b[0], b[1], b[2], // Top Right b[0], a[1], b[2], // Bottom Right } }
func (p *fullPiano) GetKeyFromRay(rayStart, rayEnd mgl32.Vec3) *PianoKey { minDist := float32(10000) minDistIdx := -1 for i, k := range p.Keys { hit, pos := k.Hit(rayStart, rayEnd) if hit { dist := rayStart.Sub(pos).Len() if dist < minDist { minDistIdx = i minDist = dist } } } if minDistIdx != -1 { return &p.Keys[minDistIdx] } return nil }
//PointToPlaneDist distance from plane (a,b,c) to point func PointToPlaneDist(a, b, c, point mgl32.Vec3) float32 { ab := b.Sub(a) ac := c.Sub(a) ap := point.Sub(a) normal := ac.Cross(ab).Normalize() return float32(math.Abs(float64(ap.Dot(normal)))) }
// NewPianoKey returns a key for our piano. func NewPianoKey(pos mgl32.Vec3, lightColor mgl32.Vec3, white bool, freq float32) PianoKey { var color mgl32.Vec4 var keySize float32 if white { color = mgl32.Vec4{0.98, 0.97, 0.94} keySize = 2 } else { color = mgl32.Vec4{0.1, 0.1, 0.1, 1.0} keySize = 1 } pk := PianoKey{Pos: pos, Angle: 0, Color: color, Frequency: freq, Finger: -1, white: white, LightColor: lightColor} pk.BBox[0] = pos.Sub(mgl32.Vec3{0.5, 0.6, keySize}) pk.BBox[1] = pos.Add(mgl32.Vec3{0.5, 0.6, keySize}) pk.source = al.GenSources(1)[0] pk.source.SetGain(1.0) pk.source.SetPosition(al.Vector{pos.X(), pos.Y(), pos.Z()}) pk.source.SetVelocity(al.Vector{}) pk.buffers = al.GenBuffers(3) var samples [1024 * 16]int16 sampleRate := 44100 amplitude := float32(0.8 * 0x7FFF) for i := 0; i < len(samples); i++ { val := f32.Sin((2.0 * math.Pi * freq) / float32(sampleRate) * float32(i)) samples[i] = int16(amplitude * val) } buf := &bytes.Buffer{} binary.Write(buf, binary.LittleEndian, &samples) pk.buffers[0].BufferData(al.FormatMono16, buf.Bytes(), 44100) f, _ := os.Create("audio.raw") binary.Write(f, binary.LittleEndian, &samples) f.Close() return pk }
// updates the Colors of the model to fake lighting func esLightModel(p PositionComponent, s SizeComponent, m interface { Model() *render.StaticModel }) { if m.Model() == nil { return } xx, yy, zz := p.Position() bounds := s.Bounds() bounds = bounds.Shift(float32(xx), float32(yy), float32(zz)) c := mgl32.Vec3{float32(xx), float32(yy), float32(zz)} c[1] += bounds.Max.Sub(bounds.Min).Mul(0.5).Y() var light, skyLight float32 var count float32 for y := bounds.Min.Y(); y <= bounds.Max.Y(); y++ { for z := bounds.Min.Z() - 1; z <= bounds.Max.Z()+1; z++ { for x := bounds.Min.X() - 1; x <= bounds.Max.X()+1; x++ { bx, by, bz := int(math.Floor(float64(x))), int(math.Floor(float64(y))), int(math.Floor(float64(z))) bl := float32(chunkMap.BlockLight(bx, by, bz)) sl := float32(chunkMap.SkyLight(bx, by, bz)) dist := 1.0 - c.Sub(mgl32.Vec3{float32(bx) + 0.5, float32(by) + 0.5, float32(bz) + 0.5}).Len() if dist < 0 { continue } light += bl * dist skyLight += sl * dist count += dist } } } light /= count skyLight /= count model := m.Model() model.BlockLight, model.SkyLight = light, skyLight }
// Calculate normals by using cross products along the triangle strips // and averaging the normals for each vertex func (terrain *Terrain) CalculateNormals() { var element_pos uint32 = 0 var AB, AC, cross_product mgl32.Vec3 // Loop through each triangle strip for x := uint32(0); x < terrain.XSize-1; x++ { // Loop along the strip for tri := uint32(0); tri < terrain.ZSize*2-2; tri++ { // Extract the vertex indices from the element array v1 := terrain.Indices[element_pos] v2 := terrain.Indices[element_pos+1] v3 := terrain.Indices[element_pos+2] // Define the two vectors for the triangle AB = terrain.Vertices[v2].Sub(terrain.Vertices[v1]) AC = terrain.Vertices[v3].Sub(terrain.Vertices[v1]) // Calculate the cross product cross_product = AB.Cross(AC) // Add this normal to the vertex normal for all three vertices in the triangle terrain.Normals[v1] = terrain.Normals[v1].Add(cross_product) terrain.Normals[v2] = terrain.Normals[v2].Add(cross_product) terrain.Normals[v3] = terrain.Normals[v3].Add(cross_product) // Move on to the next vertex along the strip element_pos++ } // Jump past the lat two element positions to reach the start of the strip element_pos += 2 } // Normalise the normals for v := uint32(0); v < terrain.XSize*terrain.ZSize; v++ { terrain.Normals[v] = terrain.Normals[v].Normalize() } }
// Draw draws this to the target region. func (m *Model) Draw(r Region, delta float64) { if m.isNew || m.isDirty() || forceDirty { m.isNew = false data := m.data[:0] for _, v := range m.verts { vec := mgl32.Vec3{v.X - 0.5, v.Y - 0.5, v.Z - 0.5} vec = m.mat.Mul4x1(vec.Vec4(1)).Vec3(). Add(mgl32.Vec3{0.5, 0.5, 0.5}) vX, vY, vZ := vec[0], 1.0-vec[1], vec[2] dx := r.X + r.W*float64(vX) dy := r.Y + r.H*float64(vY) dx /= scaledWidth dy /= scaledHeight data = appendShort(data, int16(math.Floor((dx*float64(lastWidth))+0.5))) data = appendShort(data, int16(math.Floor((dy*float64(lastHeight))+0.5))) data = appendShort(data, 256*int16(m.Layer())+int16(256*vZ)) data = appendShort(data, 0) data = appendUnsignedShort(data, v.TX) data = appendUnsignedShort(data, v.TY) data = appendUnsignedShort(data, v.TW) data = appendUnsignedShort(data, v.TH) data = appendShort(data, v.TOffsetX) data = appendShort(data, v.TOffsetY) data = appendShort(data, v.TAtlas) data = appendShort(data, 0) data = appendUnsignedByte(data, v.R) data = appendUnsignedByte(data, v.G) data = appendUnsignedByte(data, v.B) data = appendUnsignedByte(data, v.A) } m.data = data } render.UIAddBytes(m.data) }
func TestTransformTranslate(t *testing.T) { transform := NewTransform() transform.SetPosition(10, 10, 10) vector := mgl32.Vec3{-5, 6, 3} expected := mgl32.Vec3{5, 16, 13} transform.Translate(vector) if transform.position != expected { t.Errorf("Expected position to be %v got %v", expected, transform.position) } if transform.matrix[12] != expected.X() || transform.matrix[13] != expected.Y() || transform.matrix[14] != expected.Z() { t.Error("Matrix was not updated correctly after translation.") } }
func (f *Frustum) SetCamera(p, l, u mgl32.Vec3) { Z := p.Sub(l) Z = safeNormalize(Z) X := u.Cross(Z) X = safeNormalize(X) Y := Z.Cross(X) nc := p.Sub(Z.Mul(f.near)) fc := p.Sub(Z.Mul(f.far)) ntl := nc.Add(Y.Mul(f.nh)).Sub(X.Mul(f.nw)) ntr := nc.Add(Y.Mul(f.nh)).Add(X.Mul(f.nw)) nbl := nc.Sub(Y.Mul(f.nh)).Sub(X.Mul(f.nw)) nbr := nc.Sub(Y.Mul(f.nh)).Add(X.Mul(f.nw)) ftl := fc.Add(Y.Mul(f.fh)).Sub(X.Mul(f.fw)) ftr := fc.Add(Y.Mul(f.fh)).Add(X.Mul(f.fw)) fbl := fc.Sub(Y.Mul(f.fh)).Sub(X.Mul(f.fw)) fbr := fc.Sub(Y.Mul(f.fh)).Add(X.Mul(f.fw)) const ( top = iota bottom left right nearP farP ) f.planes[top].setPoints(ntr, ntl, ftl) f.planes[bottom].setPoints(nbl, nbr, fbr) f.planes[left].setPoints(ntl, nbl, fbl) f.planes[right].setPoints(nbr, ntr, fbr) f.planes[nearP].setPoints(ntl, ntr, nbr) f.planes[farP].setPoints(ftr, ftl, fbl) }
func (w *Window) SetTranslation(translation mgl32.Vec3) { w.node.SetTranslation(translation) w.position = translation.Vec2() }
func (b bbox) Contains(pos mgl32.Vec3) bool { return pos.X() > b[0].X() && pos.Y() > b[0].Y() && pos.Z() > b[0].Z() && pos.X() < b[1].X() && pos.Y() < b[1].Y() && pos.Z() < b[1].Z() }
// returns true if line (L1, L2) intersects with the box (B1, B2) // returns intersection point in Hit func checkLineBox(B1, B2, L1, L2 mgl32.Vec3) (bool, mgl32.Vec3) { var Hit mgl32.Vec3 if L2.X() < B1.X() && L1.X() < B1.X() { return false, mgl32.Vec3{} } if L2.X() > B2.X() && L1.X() > B2.X() { return false, mgl32.Vec3{} } if L2.Y() < B1.Y() && L1.Y() < B1.Y() { return false, mgl32.Vec3{} } if L2.Y() > B2.Y() && L1.Y() > B2.Y() { return false, mgl32.Vec3{} } if L2.Z() < B1.Z() && L1.Z() < B1.Z() { return false, mgl32.Vec3{} } if L2.Z() > B2.Z() && L1.Z() > B2.Z() { return false, mgl32.Vec3{} } if L1.X() > B1.X() && L1.X() < B2.X() && L1.Y() > B1.Y() && L1.Y() < B2.Y() && L1.Z() > B1.Z() && L1.Z() < B2.Z() { Hit = L1 return true, Hit } if (getIntersection(L1.X()-B1.X(), L2.X()-B1.X(), L1, L2, &Hit) && inBox(Hit, B1, B2, 1)) || (getIntersection(L1.Y()-B1.Y(), L2.Y()-B1.Y(), L1, L2, &Hit) && inBox(Hit, B1, B2, 2)) || (getIntersection(L1.Z()-B1.Z(), L2.Z()-B1.Z(), L1, L2, &Hit) && inBox(Hit, B1, B2, 3)) || (getIntersection(L1.X()-B2.X(), L2.X()-B2.X(), L1, L2, &Hit) && inBox(Hit, B1, B2, 1)) || (getIntersection(L1.Y()-B2.Y(), L2.Y()-B2.Y(), L1, L2, &Hit) && inBox(Hit, B1, B2, 2)) || (getIntersection(L1.Z()-B2.Z(), L2.Z()-B2.Z(), L1, L2, &Hit) && inBox(Hit, B1, B2, 3)) { return true, Hit } return false, mgl32.Vec3{} }
func inBox(Hit, B1, B2 mgl32.Vec3, Axis int) bool { if Axis == 1 && Hit.Z() > B1.Z() && Hit.Z() < B2.Z() && Hit.Y() > B1.Y() && Hit.Y() < B2.Y() { return true } if Axis == 2 && Hit.Z() > B1.Z() && Hit.Z() < B2.Z() && Hit.X() > B1.X() && Hit.X() < B2.X() { return true } if Axis == 3 && Hit.X() > B1.X() && Hit.X() < B2.X() && Hit.Y() > B1.Y() && Hit.Y() < B2.Y() { return true } return false }
// Draw draws a single frame func Draw(width, height int, delta float64) { tickAnimatedTextures(delta) frameID++ sync: for { select { case f := <-syncChan: f() default: break sync } } // Only update the viewport if the window was resized if lastHeight != height || lastWidth != width || lastFOV != FOV.Value() { lastWidth = width lastHeight = height lastFOV = FOV.Value() perspectiveMatrix = mgl32.Perspective( (math.Pi/180)*float32(lastFOV), float32(width)/float32(height), 0.1, 500.0, ) gl.Viewport(0, 0, width, height) frustum.SetPerspective( (math.Pi/180)*float32(lastFOV), float32(width)/float32(height), 0.1, 500.0, ) initTrans() } mainFramebuffer.Bind() gl.Enable(gl.Multisample) gl.ActiveTexture(0) glTexture.Bind(gl.Texture2DArray) gl.ClearColor(ClearColour.R, ClearColour.G, ClearColour.B, 1.0) gl.Clear(gl.ColorBufferBit | gl.DepthBufferBit) chunkProgram.Use() viewVector = mgl32.Vec3{ float32(math.Cos(Camera.Yaw-math.Pi/2) * -math.Cos(Camera.Pitch)), float32(-math.Sin(Camera.Pitch)), float32(-math.Sin(Camera.Yaw-math.Pi/2) * -math.Cos(Camera.Pitch)), } cam := mgl32.Vec3{-float32(Camera.X), -float32(Camera.Y), float32(Camera.Z)} cameraMatrix = mgl32.LookAtV( cam, cam.Add(mgl32.Vec3{-viewVector.X(), -viewVector.Y(), viewVector.Z()}), mgl32.Vec3{0, -1, 0}, ) cameraMatrix = cameraMatrix.Mul4(mgl32.Scale3D(-1.0, 1.0, 1.0)) frustum.SetCamera( cam, cam.Add(mgl32.Vec3{-viewVector.X(), -viewVector.Y(), viewVector.Z()}), mgl32.Vec3{0, -1, 0}, ) shaderChunk.PerspectiveMatrix.Matrix4(&perspectiveMatrix) shaderChunk.CameraMatrix.Matrix4(&cameraMatrix) shaderChunk.Texture.Int(0) shaderChunk.LightLevel.Float(LightLevel) shaderChunk.SkyOffset.Float(SkyOffset) chunkPos := position{ X: int(Camera.X) >> 4, Y: int(Camera.Y) >> 4, Z: int(Camera.Z) >> 4, } nearestBuffer = buffers[chunkPos] for _, dir := range direction.Values { validDirs[dir] = viewVector.Dot(dir.AsVec()) > -0.8 } renderOrder = renderOrder[:0] renderBuffer(nearestBuffer, chunkPos, direction.Invalid, delta) drawLines() drawModels() clouds.tick(delta) chunkProgramT.Use() shaderChunkT.PerspectiveMatrix.Matrix4(&perspectiveMatrix) shaderChunkT.CameraMatrix.Matrix4(&cameraMatrix) shaderChunkT.Texture.Int(0) shaderChunkT.LightLevel.Float(LightLevel) shaderChunkT.SkyOffset.Float(SkyOffset) // Copy the depth buffer mainFramebuffer.BindRead() transFramebuffer.BindDraw() gl.BlitFramebuffer( 0, 0, lastWidth, lastHeight, 0, 0, lastWidth, lastHeight, gl.DepthBufferBit, gl.Nearest, ) gl.Enable(gl.Blend) gl.DepthMask(false) transFramebuffer.Bind() gl.ClearColor(0, 0, 0, 1) gl.Clear(gl.ColorBufferBit) gl.ClearBuffer(gl.Color, 0, []float32{0, 0, 0, 1}) gl.ClearBuffer(gl.Color, 1, []float32{0, 0, 0, 0}) gl.BlendFuncSeparate(gl.OneFactor, gl.OneFactor, gl.ZeroFactor, gl.OneMinusSrcAlpha) for _, chunk := range renderOrder { if chunk.countT > 0 && chunk.bufferT.IsValid() { shaderChunkT.Offset.Int3(chunk.X, chunk.Y*4096-chunk.Y*int(4096*(1-chunk.progress)), chunk.Z) chunk.arrayT.Bind() gl.DrawElements(gl.Triangles, chunk.countT, elementBufferType, 0) } } gl.UnbindFramebuffer() gl.Disable(gl.DepthTest) gl.Clear(gl.ColorBufferBit) gl.Disable(gl.Blend) transDraw() gl.Enable(gl.DepthTest) gl.DepthMask(true) gl.BlendFunc(gl.SrcAlpha, gl.OneMinusSrcAlpha) gl.Disable(gl.Multisample) drawUI() if debugFramebuffers.Value() { gl.Enable(gl.Multisample) blitBuffers() gl.Disable(gl.Multisample) } }
func programLoop(window *win.Window) error { // the linked shader program determines how the data will be rendered vertShader, err := gfx.NewShaderFromFile("shaders/phong.vert", gl.VERTEX_SHADER) if err != nil { return err } fragShader, err := gfx.NewShaderFromFile("shaders/phong.frag", gl.FRAGMENT_SHADER) if err != nil { return err } program, err := gfx.NewProgram(vertShader, fragShader) if err != nil { return err } defer program.Delete() lightFragShader, err := gfx.NewShaderFromFile("shaders/light.frag", gl.FRAGMENT_SHADER) if err != nil { return err } // special shader program so that lights themselves are not affected by lighting lightProgram, err := gfx.NewProgram(vertShader, lightFragShader) if err != nil { return err } VAO := createVAO(cubeVertices, nil) lightVAO := createVAO(cubeVertices, nil) // ensure that triangles that are "behind" others do not draw over top of them gl.Enable(gl.DEPTH_TEST) camera := cam.NewFpsCamera(mgl32.Vec3{0, 0, 3}, mgl32.Vec3{0, 1, 0}, -90, 0, window.InputManager()) for !window.ShouldClose() { // swaps in last buffer, polls for window events, and generally sets up for a new render frame window.StartFrame() // update camera position and direction from input evevnts camera.Update(window.SinceLastFrame()) // background color gl.ClearColor(0, 0, 0, 1.0) gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) // depth buffer needed for DEPTH_TEST // cube rotation matrices rotateX := (mgl32.Rotate3DX(mgl32.DegToRad(-45 * float32(glfw.GetTime())))) rotateY := (mgl32.Rotate3DY(mgl32.DegToRad(-45 * float32(glfw.GetTime())))) rotateZ := (mgl32.Rotate3DZ(mgl32.DegToRad(-45 * float32(glfw.GetTime())))) // creates perspective fov := float32(60.0) projectTransform := mgl32.Perspective(mgl32.DegToRad(fov), float32(window.Width())/float32(window.Height()), 0.1, 100.0) camTransform := camera.GetTransform() lightPos := mgl32.Vec3{0.6, 1, 0.1} lightTransform := mgl32.Translate3D(lightPos.X(), lightPos.Y(), lightPos.Z()).Mul4( mgl32.Scale3D(0.2, 0.2, 0.2)) program.Use() gl.UniformMatrix4fv(program.GetUniformLocation("view"), 1, false, &camTransform[0]) gl.UniformMatrix4fv(program.GetUniformLocation("project"), 1, false, &projectTransform[0]) gl.BindVertexArray(VAO) // draw each cube after all coordinate system transforms are bound // obj is colored, light is white gl.Uniform3f(program.GetUniformLocation("material.ambient"), 1.0, 0.5, 0.31) gl.Uniform3f(program.GetUniformLocation("material.diffuse"), 1.0, 0.5, 0.31) gl.Uniform3f(program.GetUniformLocation("material.specular"), 0.5, 0.5, 0.5) gl.Uniform1f(program.GetUniformLocation("material.shininess"), 32.0) lightColor := mgl32.Vec3{ float32(math.Sin(glfw.GetTime() * 1)), float32(math.Sin(glfw.GetTime() * 0.35)), float32(math.Sin(glfw.GetTime() * 0.65)), } diffuseColor := mgl32.Vec3{ 0.5 * lightColor[0], 0.5 * lightColor[1], 0.5 * lightColor[2], } ambientColor := mgl32.Vec3{ 0.2 * lightColor[0], 0.2 * lightColor[1], 0.2 * lightColor[2], } gl.Uniform3f(program.GetUniformLocation("light.ambient"), ambientColor[0], ambientColor[1], ambientColor[2]) gl.Uniform3f(program.GetUniformLocation("light.diffuse"), diffuseColor[0], diffuseColor[1], diffuseColor[2]) gl.Uniform3f(program.GetUniformLocation("light.specular"), 1.0, 1.0, 1.0) gl.Uniform3f(program.GetUniformLocation("light.position"), lightPos.X(), lightPos.Y(), lightPos.Z()) for _, pos := range cubePositions { // turn the cubes into rectangular prisms for more fun worldTranslate := mgl32.Translate3D(pos[0], pos[1], pos[2]) worldTransform := worldTranslate.Mul4( rotateX.Mul3(rotateY).Mul3(rotateZ).Mat4(), ) gl.UniformMatrix4fv(program.GetUniformLocation("model"), 1, false, &worldTransform[0]) gl.DrawArrays(gl.TRIANGLES, 0, 36) } gl.BindVertexArray(0) // Draw the light obj after the other boxes using its separate shader program // this means that we must re-bind any uniforms lightProgram.Use() gl.BindVertexArray(lightVAO) gl.UniformMatrix4fv(lightProgram.GetUniformLocation("model"), 1, false, &lightTransform[0]) gl.UniformMatrix4fv(lightProgram.GetUniformLocation("view"), 1, false, &camTransform[0]) gl.UniformMatrix4fv(lightProgram.GetUniformLocation("project"), 1, false, &projectTransform[0]) gl.DrawArrays(gl.TRIANGLES, 0, 36) gl.BindVertexArray(0) // end of draw loop } return nil }
// Since go has multiple return values, I just went ahead and made it return the view and perspective matrices (in that order) rather than messing with getter methods func (c *Camera) ComputeViewPerspective() (mgl32.Mat4, mgl32.Mat4) { if mgl64.FloatEqual(-1.0, c.time) { c.time = glfw.GetTime() } currTime := glfw.GetTime() deltaT := currTime - c.time xPos, yPos := c.window.GetCursorPosition() c.window.SetCursorPosition(width/2.0, height/2.0) c.hAngle += mouseSpeed * ((width / 2.0) - float64(xPos)) c.vAngle += mouseSpeed * ((height / 2.0) - float64(yPos)) dir := mgl32.Vec3{ float32(math.Cos(c.vAngle) * math.Sin(c.hAngle)), float32(math.Sin(c.vAngle)), float32(math.Cos(c.vAngle) * math.Cos(c.hAngle))} right := mgl32.Vec3{ float32(math.Sin(c.hAngle - math.Pi/2.0)), 0.0, float32(math.Cos(c.hAngle - math.Pi/2.0))} up := right.Cross(dir) if c.window.GetKey(glfw.KeyUp) == glfw.Press || c.window.GetKey('W') == glfw.Press { c.pos = c.pos.Add(dir.Mul(float32(deltaT * speed))) } if c.window.GetKey(glfw.KeyDown) == glfw.Press || c.window.GetKey('S') == glfw.Press { c.pos = c.pos.Sub(dir.Mul(float32(deltaT * speed))) } if c.window.GetKey(glfw.KeyRight) == glfw.Press || c.window.GetKey('D') == glfw.Press { c.pos = c.pos.Add(right.Mul(float32(deltaT * speed))) } if c.window.GetKey(glfw.KeyLeft) == glfw.Press || c.window.GetKey('A') == glfw.Press { c.pos = c.pos.Sub(right.Mul(float32(deltaT * speed))) } // Adding to the original tutorial, Space goes up if c.window.GetKey(glfw.KeySpace) == glfw.Press { c.pos = c.pos.Add(up.Mul(float32(deltaT * speed))) } // Adding to the original tutorial, left control goes down if c.window.GetKey(glfw.KeyLeftControl) == glfw.Press { c.pos = c.pos.Sub(up.Mul(float32(deltaT * speed))) } fov := initialFOV //- 5.0*float64(glfw.MouseWheel()) proj := mgl32.Perspective(float32(fov), 4.0/3.0, 0.1, 100.0) view := mgl32.LookAtV(c.pos, c.pos.Add(dir), up) c.time = currTime return view, proj }
func (a AABB) MoveOutOf(o AABB, dir mgl32.Vec3) AABB { if dir.X() != 0 { if dir.X() > 0 { ox := a.Max.X() a.Max[0] = o.Min.X() - 0.0001 a.Min[0] += a.Max.X() - ox } else { ox := a.Min.X() a.Min[0] = o.Max.X() + 0.0001 a.Max[0] += a.Min.X() - ox } } if dir.Y() != 0 { if dir.Y() > 0 { oy := a.Max.Y() a.Max[1] = o.Min.Y() - 0.0001 a.Min[1] += a.Max.Y() - oy } else { oy := a.Min.Y() a.Min[1] = o.Max.Y() + 0.0001 a.Max[1] += a.Min.Y() - oy } } if dir.Z() != 0 { if dir.Z() > 0 { oz := a.Max.Z() a.Max[2] = o.Min.Z() - 0.0001 a.Min[2] += a.Max.Z() - oz } else { oz := a.Min.Z() a.Min[2] = o.Max.Z() + 0.0001 a.Max[2] += a.Min.Z() - oz } } return a }
func randomVector(min, max mgl32.Vec3) mgl32.Vec3 { r1, r2, r3 := rand.Float32(), rand.Float32(), rand.Float32() return mgl32.Vec3{min.X()*(1.0-r1) + max.X()*r1, min.Y()*(1.0-r2) + max.Y()*r2, min.Z()*(1.0-r3) + max.Z()*r3} }
//given 3 vertices, returns the normal of the plane formed by this triangle //TODO: move to a math package func NormalToPlane(v1, v2, v3 glm.Vec3) glm.Vec3 { u := v2.Sub(v1) v := v3.Sub(v1) return glm.Vec3{u.Y()*v.Z() - u.Z()*v.Y(), u.Z()*v.X() - u.X()*v.Z(), u.X()*v.Y() - u.Y()*v.X()} }
func (w *Window) SetScale(scale mgl32.Vec3) { w.background.SetScale(scale) w.size = scale.Vec2() w.Render() }