Пример #1
0
        /// <summary>
        /// Creates and displays a mesh that represents a connecting pipe between the source and the
        /// target parts.
        /// </summary>
        protected virtual void CreateLinkPipe()
        {
            var nrmTexture = pipeNormalsTexturePath != ""
        ? GetTexture(pipeNormalsTexturePath, asNormalMap: true)
        : null;
            var material = CreateMaterial(GetTexture(pipeTexturePath),
                                          mainTexNrm: nrmTexture,
                                          overrideShaderName: shaderNameOverride,
                                          overrideColor: colorOverride);

            linkPipe = Meshes.CreateCylinder(pipeDiameter, 1f, material, partModelTransform,
                                             colliderType: Colliders.PrimitiveCollider.Shape);
            Colliders.UpdateColliders(linkPipe, isPhysical: pipeColliderIsPhysical);
            if (pipeColliderIsPhysical)
            {
                CollisionManager.IgnoreCollidersOnVessel(
                    vessel, linkPipe.GetComponentsInChildren <Collider>());
                // TODO(ihsoft): Ignore the parts when migrated to the interfaces.
                Colliders.SetCollisionIgnores(sourceTransform.root, targetTransform.root, true);
            }
            linkPipeMR = linkPipe.GetComponent <Renderer>(); // To speedup OnUpdate() handling.
            SetupPipe(linkPipe.transform,
                      sourceJointNode.pipeAttach.position, targetJointNode.pipeAttach.position);
            RescaleTextureToLength(linkPipe, pipeTextureSamplesPerMeter,
                                   renderer: linkPipeMR, scaleRatio: 1 / stretchRatio);
            // Let the part know about the new mesh so that it could be properly highlighted.
            part.RefreshHighlighter();
        }
Пример #2
0
        /// <summary>
        /// Creates a mesh that represents the connecting pipe between the source and the target.
        /// </summary>
        /// <remarks>It's only called in the started state.</remarks>
        /// <seealso cref="CreatePipeMesh"/>
        /// <seealso cref="pipeTransform"/>
        protected virtual void CreateLinkPipe()
        {
            var colliderType = pipeColliderIsPhysical
        ? Colliders.PrimitiveCollider.Shape
        : Colliders.PrimitiveCollider.None;

            pipeTransform = Meshes.CreateCylinder(
                pipeDiameter, 1.0f, pipeMaterial, sourceTransform, colliderType: colliderType).transform;
            pipeTransform.GetComponent <Renderer>().sharedMaterial = pipeMaterial;
            pipeMeshRenderer = pipeTransform.GetComponent <Renderer>(); // To speedup OnUpdate() handling.
            SetupPipe(sourceJointNode.pipeAttach, targetJointNode.pipeAttach);
            var extraScale = 1.0f;

            if (pipeTextureRescaleMode == PipeTextureRescaleMode.Stretch)
            {
                extraScale /=
                    (sourceJointNode.pipeAttach.position - targetJointNode.pipeAttach.position).magnitude;
            }
            RescalePipeTexture(
                pipeTransform, pipeTransform.localScale.z * extraScale, renderer: pipeMeshRenderer);
        }
Пример #3
0
        /// <summary>Builds a model for the joint end basing on the configuration.</summary>
        /// <param name="node">The node to setup.</param>
        /// <param name="alignTo">
        /// The object to align the conenctor to. If it's <c>null</c>, then the model will be parked.
        /// </param>
        protected virtual void UpdateJointNode(ModelPipeEndNode node, Transform alignTo)
        {
            var config = node.config;
            var makeProceduralModels = alignTo != null || !config.parkPrefabOnly;

            // Return the models back to the owner part to make the search working properly.
            if (node.rootModel != null)
            {
                node.AlignToTransform(null);
            }

            node.parkRootObject = partModelTransform;

            // Create basic setup.
            var nodeName = ModelBasename + "-pipeNode" + node.name;

            node.rootModel = partModelTransform.Find(nodeName)
                             ?? new GameObject(nodeName).transform;
            node.rootModel.parent = partModelTransform;
            node.partAttach       = node.rootModel.Find(PartJointTransformName)
                                    ?? new GameObject(PartJointTransformName).transform;
            Hierarchy.MoveToParent(node.partAttach, node.rootModel,
                                   newPosition: Vector3.zero,
                                   newRotation: Quaternion.LookRotation(Vector3.back));
            node.pipeAttach = node.rootModel.Find(PipeJointTransformName)
                              ?? new GameObject(PipeJointTransformName).transform;
            Hierarchy.MoveToParent(node.pipeAttach, node.rootModel,
                                   newPosition: Vector3.zero,
                                   newRotation: Quaternion.LookRotation(Vector3.forward));

            // Add a pipe attachment sphere if set.
            const string sphereName = "pipeSphere";
            var          sphere     = node.pipeAttach.Find(sphereName);

            if (config.sphereDiameter > float.Epsilon && makeProceduralModels)
            {
                if (sphere == null)
                {
                    sphere = Meshes.CreateSphere(config.sphereDiameter, pipeMaterial, node.pipeAttach,
                                                 colliderType: Colliders.PrimitiveCollider.Shape).transform;
                    sphere.name     = sphereName;
                    sphere.rotation = Quaternion.LookRotation(node.partAttach.up, node.partAttach.forward);
                }
                sphere.GetComponent <Renderer>().sharedMaterial = pipeMaterial; // For performance.
                RescalePipeTexture(sphere, sphere.localScale.z * config.sphereDiameter * 2.0f);
            }
            else if (sphere != null)
            {
                Hierarchy.SafeDestory(sphere);
            }

            // Parking position, if defined.
            var parkObjectName = ModelBasename + "-park" + node.name;
            var parkAttach     = partModelTransform.Find(parkObjectName);

            if (config.parkAttachAt != null)
            {
                node.parkAttach = parkAttach ?? new GameObject(parkObjectName).transform;
                Hierarchy.MoveToParent(node.parkAttach, partModelTransform,
                                       newPosition: config.parkAttachAt.pos,
                                       newRotation: config.parkAttachAt.rot);
            }
            else if (parkAttach != null)
            {
                Hierarchy.SafeDestory(parkAttach);
            }

            // Place prefab between the part and the pipe if specified.
            if (!string.IsNullOrEmpty(config.modelPath))
            {
                // The prefab model can move to the part's model, so make a unique name for it.
                const string prefabName  = "prefabConnector";
                var          prefabModel = node.rootModel.Find(prefabName)
                                           ?? Hierarchy.FindTransformByPath(partModelTransform, config.modelPath);
                if (prefabModel != null)
                {
                    prefabModel.gameObject.SetActive(true);
                    prefabModel.name         = prefabName;
                    prefabModel.parent       = node.rootModel;
                    prefabModel.rotation     = node.partAttach.rotation * config.modelPartAttachAt.rot.Inverse();
                    prefabModel.position     = node.partAttach.TransformPoint(config.modelPartAttachAt.pos);
                    node.pipeAttach.rotation = prefabModel.rotation * config.modelPipeAttachAt.rot;
                    node.pipeAttach.position = prefabModel.TransformPoint(config.modelPipeAttachAt.pos);
                }
                else
                {
                    HostedDebugLog.Error(this, "Cannot find prefab model: {0}", config.modelPath);
                }
            }

            // The offset is intended for the sphere/arm models only.
            if (makeProceduralModels)
            {
                node.pipeAttach.localPosition += new Vector3(0, 0, config.sphereOffset);
            }

            // Add arm pipe.
            const string armName = "sphereArm";
            var          arm     = node.pipeAttach.Find(armName);

            if (config.armDiameter > float.Epsilon && config.sphereOffset > float.Epsilon &&
                makeProceduralModels)
            {
                if (arm == null)
                {
                    arm = Meshes.CreateCylinder(config.armDiameter, config.sphereOffset, pipeMaterial,
                                                node.pipeAttach,
                                                colliderType: Colliders.PrimitiveCollider.Shape).transform;
                    arm.name = armName;
                }
                arm.GetComponent <Renderer>().sharedMaterial = pipeMaterial; // For performance.
                arm.transform.localPosition = new Vector3(0, 0, -config.sphereOffset / 2);
                arm.transform.localRotation = Quaternion.LookRotation(Vector3.forward);
                RescalePipeTexture(arm.transform, arm.localScale.z * config.sphereOffset);
            }
            else if (arm != null)
            {
                Hierarchy.SafeDestory(arm);
            }

            // Adjust to the new target.
            node.AlignToTransform(alignTo);
        }
Пример #4
0
        /// <summary>Builds a model for the joint end basing on the procedural configuration.</summary>
        /// <param name="modelName">Joint transform name.</param>
        /// <param name="config">Joint configuration from the part's config.</param>
        protected virtual void CreateJointEndModels(string modelName, JointConfig config)
        {
            // FIXME: Prefix the model name with the renderer name.
            // Make or get the root.
            Transform root = null;

            if (config.type == PipeEndType.PrefabModel)
            {
                root = Hierarchy.FindTransformByPath(partModelTransform, config.modelPath);
                if (root != null)
                {
                    root.parent = partModelTransform; // We need the part's model to be the root.
                    var partAttach = new GameObject(PartJointTransformName).transform;
                    Hierarchy.MoveToParent(partAttach, root,
                                           newPosition: config.partAttachAt.pos,
                                           newRotation: config.partAttachAt.rot);
                    var pipeAttach = new GameObject(PipeJointTransformName);
                    Hierarchy.MoveToParent(pipeAttach.transform, root,
                                           newPosition: config.pipeAttachAt.pos,
                                           newRotation: config.pipeAttachAt.rot);
                }
                else
                {
                    HostedDebugLog.Error(this, "Cannot find model: {0}", config.modelPath);
                    config.type = PipeEndType.Simple; // Fallback.
                }
            }
            if (root == null)
            {
                root = new GameObject().transform;
                Hierarchy.MoveToParent(root, partModelTransform);
                var partJoint = new GameObject(PartJointTransformName).transform;
                Hierarchy.MoveToParent(partJoint, root);
                partJoint.rotation = Quaternion.LookRotation(Vector3.forward);
                if (config.type == PipeEndType.ProceduralModel)
                {
                    // Create procedural models at the point where the pipe connects to the part's node.
                    var material = CreateMaterial(
                        GetTexture(config.texture),
                        mainTexNrm: config.textureNrm != "" ? GetTexture(config.textureNrm) : null);
                    var sphere = Meshes.CreateSphere(config.sphereDiameter, material, root,
                                                     colliderType: Colliders.PrimitiveCollider.Shape);
                    sphere.name = PipeJointTransformName;
                    sphere.transform.rotation = Quaternion.LookRotation(Vector3.back);
                    RescaleTextureToLength(sphere, samplesPerMeter: config.textureSamplesPerMeter);
                    if (Mathf.Abs(config.sphereOffset) > float.Epsilon)
                    {
                        sphere.transform.localPosition += new Vector3(0, 0, config.sphereOffset);
                        if (config.armDiameter > float.Epsilon)
                        {
                            var arm = Meshes.CreateCylinder(
                                config.armDiameter, config.sphereOffset, material, root,
                                colliderType: Colliders.PrimitiveCollider.Shape);
                            arm.transform.localPosition += new Vector3(0, 0, config.sphereOffset / 2);
                            arm.transform.LookAt(sphere.transform.position);
                            RescaleTextureToLength(arm, samplesPerMeter: config.textureSamplesPerMeter);
                        }
                    }
                }
                else
                {
                    // No extra models are displayed at the joint, just attach the pipe to the part's node.
                    if (config.type != PipeEndType.Simple)
                    {
                        // Normally, this error should never pop up.
                        HostedDebugLog.Error(this, "Unknown joint type: {0}", config.type);
                    }
                    var pipeJoint = new GameObject(PipeJointTransformName);
                    Hierarchy.MoveToParent(pipeJoint.transform, root);
                    pipeJoint.transform.rotation = Quaternion.LookRotation(Vector3.back);
                }
            }
            Colliders.UpdateColliders(root.gameObject, isPhysical: config.colliderIsPhysical);
            root.gameObject.SetActive(false);
            root.name = modelName;
        }