func (g *Geometry) ComputeVertexNormals(areaWeighted bool) { vertices := make([]*math3d.Vector3, len(g.Vertices)) for v, _ := range g.Vertices { vertices[v] = math3d.NewEmptyVector3() } if areaWeighted { // vertex normals weighted by triangle areas // http://www.iquilezles.org/www/articles/normals/normals.htm var vA, vB, vC *math3d.Vector3 cb := math3d.NewEmptyVector3() ab := math3d.NewEmptyVector3() for _, face := range g.Faces { vA = g.Vertices[face.A] vB = g.Vertices[face.B] vC = g.Vertices[face.C] cb.SubVectors(vC, vB) ab.SubVectors(vA, vB) cb.Cross(ab) vertices[face.A].Add(cb) vertices[face.B].Add(cb) vertices[face.C].Add(cb) } } else { for _, face := range g.Faces { vertices[face.A].Add(face.Normal) vertices[face.B].Add(face.Normal) vertices[face.C].Add(face.Normal) } } for v, _ := range g.Vertices { vertices[v].Normalize() } for _, face := range g.Faces { vertexNormals := face.VertexNormals if len(vertexNormals) == 3 { vertexNormals[0].Copy(vertices[face.A]) vertexNormals[1].Copy(vertices[face.B]) vertexNormals[2].Copy(vertices[face.C]) } else { vertexNormals[0] = vertices[face.A].Clone() vertexNormals[1] = vertices[face.B].Clone() vertexNormals[2] = vertices[face.C].Clone() } } }
func (g *Geometry) ComputeFaceNormals() { cb := math3d.NewEmptyVector3() ab := math3d.NewEmptyVector3() for _, face := range g.Faces { var vA = g.Vertices[face.A] var vB = g.Vertices[face.B] var vC = g.Vertices[face.C] cb.SubVectors(vC, vB) ab.SubVectors(vA, vB) cb.Cross(ab) cb.Normalize() face.Normal.Copy(cb) } }
func (o *Object3D) buildGetWorldQuaternion() func(*math.Vector3) *math.Quaternion { position := math.NewEmptyVector3() scale := math.NewEmptyVector3() return func(optionalTarget *math.Vector3) *math.Quaternion { var result = optionalTarget if result == nil { result = math.NewEmptyQuaternion() } o.UpdateMatrixWorld(true) o.MatrixWorld.Decompose(position, result, scale) return result } }
func (o *Object3D) buildGetWorldScale() func(*math.Vector3) *math.Vector3 { var position = math.NewEmptyVector3() var quaternion = math.NewEmptyQuaternion() return func(optionalTarget *math.Vector3) *math.Vector3 { result := optionalTarget if result == nil { result = math.NewEmptyVector3() } o.UpdateMatrixWorld(true) o.MatrixWorld.Decompose(position, quaternion, result) return result } }
func (o *Object3D) GetWorldPosition(optionalTarget *math.Vector3) *math.Vector3 { result := optionalTarget if result == nil { result = math.NewEmptyVector3() } o.UpdateMatrixWorld(true) return result.SetFromMatrixPosition(o.MatrixWorld) }
func NewArraysFace3(a, b, c int, normals []*math.Vector3, colors []*math.Color, materialIndex int) *Face3 { return &Face3{ A: a, B: b, C: c, Normal: math.NewEmptyVector3(), VertexNormals: normals, Color: math.NewDefaultColor(), VertexColors: colors, MaterialIndex: materialIndex, } }
func NewObject3D() *Object3D { Object3DIdCount++ object3d := Object3D{ NewEventDispatcher(), Id: Object3DIdCount, Uuid: math.GenerateUUID(), Name: "", Type: "Object3D", Parent: nil, Channels: NewChannels(), Children: make([]Object3D, 0), Up: DefaultUp.Clone(), Position: math.NewEmptyVector3(), Rotation: math.NewEmptyEuler(), Quaternion: math.NewEmptyQuaternion(), Scale: math.NewVector3(1.0, 1.0, 1.0), RotationAutoUpdate: true, Matrix: math.NewMatrix4(), MatrixWorld: math.NewMatrix4(), MatrixAutoUpdate: DefaultMatrixAutoUpdate, MatrixWorldNeedsUpdate: false, Visible: true, CastShadow: false, ReceiveShadow: false, FrustumCulled: true, RenderOrder: 0, UserData: make(map[string]string), ModelViewMatrix: math.NewMatrix4(), NormalMatrix: *math.NewMatrix3(), Geometry: nil, } onRotationChange := func() { object3d.Quaternion.SetFromEuler(object3d.Rotation, false) } onQuaternionChange := func() { object3d.Rotation.SetFromQuaternion(object3d.Quaternion, nil, false) } object3d.Rotation.OnChange(onRotationChange) object3d.Quaternion.OnChange(onQuaternionChange) object3d.GetWorldQuaternion = object3d.buildGetWorldQuaternion() object3d.GetWorldRotation = object3d.buildGetWorldRotation() object3d.GetWorldScale() = object3d.buildGetWorldScale() object3d.GetWorldDirection = object3d.buildGetWorldDirection() object3d.LookAt = object3d.buildLookAt() return &object3d }
func (c *Camera) GetWorldDirection(optionalTarget *math.Vector3) *math.Vector3 { var quaternion = math.NewEmptyQuaternion() var result = optionalTarget if result == nil { result = math.NewEmptyVector3() } c.GetWorldQuaternion(quaternion) return result.Set(0, 0, -1).ApplyQuaternion(quaternion) }
func (o *Object3D) buildGetWorldDirection() func(*math.Vector3) *math.Vector3 { var quaternion = math.NewEmptyQuaternion() return func(optionalTarget *math.Vector3) *math.Vector3 { result := optionalTarget if result == nil { result = math.NewEmptyVector3() } o.GetWorldQuaternion(quaternion) return result.Set(0, 0, 1).ApplyQuaternion(quaternion) } }
func NewDefaultFace3(a, b, c int) *Face3 { return NewFace3(a, b, c, math.NewEmptyVector3(), math.NewDefaultColor(), 0) }
func NewBoxGeometry(width, height, depth float64, widthSegments, heightSegments, depthSegments int) *BoxGeometry { g := &BoxGeometry{ core.NewGeometry(), Width: width, Height: height, Depth: depth, WidthSegments: widthSegments, HeightSegments: heightSegments, DepthSegments: depthSegments, } g.Type = "BoxGeometry" g.Parameters = map[string]interface{}{ "width": width, "height": height, "depth": depth, "widthSegments": widthSegments, "heightSegments": heightSegments, "depthSegments": depthSegments, } scope := g width_half := width / 2 height_half := height / 2 depth_half := depth / 2 buildPlane := func(u, v string, udir, vdir int, width, height, depth float64, materialIndex int) { // w, ix, iy, var w string gridX := scope.WidthSegments gridY := scope.HeightSegments width_half := width / 2 height_half := height / 2 offset := len(scope.Vertices) if (u == "x" && v == "y") || (u == "y" && v == "x") { w = "z" } else if (u == "x" && v == "z") || (u == "z" && v == "x") { w = "y" gridY = scope.DepthSegments } else if (u == "z" && v == "y") || (u == "y" && v == "z") { w = "x" gridX = scope.DepthSegments } gridX1 := gridX + 1 gridY1 := gridY + 1 segment_width := width / gridX segment_height := height / gridY normal := math3d.NewEmptyVector3() if depth > 0 { three.SetField(normal, w, 1) } else { three.SetField(normal, w, -1) } for iy := 0; iy < gridY1; iy++ { for ix := 0; ix < gridX1; ix++ { var vector = math3d.NewEmptyVector3() three.SetField(vector, u, (ix*segment_width-width_half)*udir) three.SetField(vector, v, (iy*segment_height-height_half)*vdir) three.SetField(vector, w, depth) scope.Vertices = append(scope.Vertices, vector) } } for iy := 0; iy < gridY; iy++ { for ix := 0; ix < gridX; ix++ { a := ix + gridX1*iy b := ix + gridX1*(iy+1) c := (ix + 1) + gridX1*(iy+1) d := (ix + 1) + gridX1*iy uva := math3d.NewVector2(ix/gridX, 1-iy/gridY) uvb := math3d.NewVector2(ix/gridX, 1-(iy+1)/gridY) uvc := math3d.NewVector2((ix+1)/gridX, 1-(iy+1)/gridY) uvd := math3d.NewVector2((ix+1)/gridX, 1-iy/gridY) face := core.NewDefaultFace3(a+offset, b+offset, d+offset) face.Normal.Copy(normal) face.VertexNormals = append(face.VertexNormals, normal.Clone(), normal.Clone(), normal.Clone()) face.MaterialIndex = materialIndex scope.Faces = append(scope.Faces, face) scope.FaceVertexUvs[0] = append(scope.FaceVertexUvs[0], []*math3d.Vector2{uva, uvb, uvd}) face = core.NewDefaultFace3(b+offset, c+offset, d+offset) face.Normal.Copy(normal) face.VertexNormals = append(face.VertexNormals, normal.Clone(), normal.Clone(), normal.Clone()) face.MaterialIndex = materialIndex scope.Faces = append(scope.Faces, face) scope.FaceVertexUvs[0] = append(scope.FaceVertexUvs[0], []*math3d.Vector2{uvb.Clone(), uvc, uvd.Clone()}) } } } buildPlane("z", "y", -1, -1, depth, height, width_half, 0) // px buildPlane("z", "y", 1, -1, depth, height, -width_half, 1) // nx buildPlane("x", "z", 1, 1, width, depth, height_half, 2) // py buildPlane("x", "z", 1, -1, width, depth, -height_half, 3) // ny buildPlane("x", "y", 1, -1, width, height, depth_half, 4) // pz buildPlane("x", "y", -1, -1, width, height, -depth_half, 5) // nz g.MergeVertices() return g }