func TriangleIntersection(V1, V2, V3, O, D mgl.Vec3) (out float32, hit bool) { const EPSILON = 0.000001 var e1, e2 mgl.Vec3 //Edge1, Edge2 var P, Q, T mgl.Vec3 var det, inv_det, u, v, t float32 //Find vectors for two edges sharing V1 e1 = V2.Sub(V1) e2 = V3.Sub(V1) //Begin calculating determinant - also used to calculate u parameter P = D.Cross(e2) //if determinant is near zero, ray lies in plane of triangle det = e1.Dot(P) //NOT CULLING if det > -EPSILON && det < EPSILON { return 0, false } inv_det = 1 / det //calculate distance from V1 to ray origin T = O.Sub(V1) //Calculate u parameter and test bound u = T.Dot(P) * inv_det //The intersection lies outside of the triangle if u < 0 || u > 1 { return 0, false } //Prepare to test v parameter Q = T.Cross(e1) //Calculate V parameter and test bound v = D.Dot(Q) * inv_det //The intersection lies outside of the triangle if v < 0 || u+v > 1 { return 0, false } t = e2.Dot(Q) * inv_det if t > EPSILON { //ray intersection return t, true } // No hit, no win return 0, false }
func NewParticleSystem(w *gamestate.World, numParticles int, Origin mgl.Vec3, initialSpeed, MaxLifetime float32) *ParticleSystem { vertices := make([]ParticleVertex, numParticles) directions := make([]NonTransformBuffer, numParticles) for i := range vertices { dir := mgl.Vec3{rand.Float32()*2 - 1, rand.Float32()*2 - 1, rand.Float32()*2 - 1} for dir.Len() > 1 { dir = mgl.Vec3{rand.Float32()*2 - 1, rand.Float32()*2 - 1, rand.Float32()*2 - 1} } dir = dir.Mul(initialSpeed) vertices[i] = ParticleVertex{ Pos1: Origin, Pos2: Origin.Sub(dir), Lifetime: rand.Float32() * MaxLifetime, } directions[i] = NonTransformBuffer{dir} } buffer1, buffer2, nonTransformBuffer := gl.GenBuffer(), gl.GenBuffer(), gl.GenBuffer() nonTransformBuffer.Bind(gl.ARRAY_BUFFER) gl.BufferData(gl.ARRAY_BUFFER, helpers.ByteSizeOfSlice(directions), directions, gl.STATIC_DRAW) buffer1.Bind(gl.ARRAY_BUFFER) gl.BufferData(gl.ARRAY_BUFFER, helpers.ByteSizeOfSlice(vertices), vertices, gl.STREAM_DRAW) buffer2.Bind(gl.ARRAY_BUFFER) gl.BufferData(gl.ARRAY_BUFFER, helpers.ByteSizeOfSlice(vertices), uintptr(0), gl.STREAM_DRAW) shapeData := CreateShapeDataBuffer() TransformProg := gl.CreateProgram() shader := helpers.MakeShader(gl.VERTEX_SHADER, "ParticleTFF.vs") TransformProg.AttachShader(shader) TransformProg.TransformFeedbackVaryings([]string{"v_Pos1", "v_Pos2", "v_Lifetime"}, gl.INTERLEAVED_ATTRIBS) TransformProg.Link() shader.Delete() TransformProg.Use() TransformLoc := ProgramLocations{} helpers.BindLocations("particle transform", TransformProg, &TransformLoc) renderProgram := helpers.MakeProgram("Particle.vs", "Particle.fs") renderProgram.Use() RenderLoc := RenderProgramLocations{} helpers.BindLocations("particle render", renderProgram, &RenderLoc) vaoTff1 := gl.GenVertexArray() vaoTff2 := gl.GenVertexArray() vaoRender1 := gl.GenVertexArray() vaoRender2 := gl.GenVertexArray() ps := ParticleSystem{ TransformProg: TransformProg, TransformLoc: TransformLoc, RenderProg: renderProgram, RenderLoc: RenderLoc, VaoTff1: vaoTff1, VaoTff2: vaoTff2, VaoRender1: vaoRender1, VaoRender2: vaoRender2, Data1: buffer1, Data2: buffer2, ShapeData: shapeData, NonTransformBuffer: nonTransformBuffer, NumParticles: numParticles, Origin: Origin, Gravity: -9.81 / 200, InitialSpeed: initialSpeed, MaxLifetime: MaxLifetime, } min_h, max_h := w.HeightMap.Bounds() W := float32(w.HeightMap.W) H := float32(w.HeightMap.H) TransformProg.Use() ps.SetUniforms() ps.SetVaos() TransformProg.Use() ps.TransformLoc.HeightMap.Uniform1i(constants.TextureHeightMap) ps.TransformLoc.LowerBound.Uniform3f(0, 0, min_h) ps.TransformLoc.UpperBound.Uniform3f(W, H, max_h) return &ps }