/// <summary> /// IRenderer interface method /// Renders a model in a viewport /// </summary> public bool RenderModel(RMModel model, Rhino.DocObjects.ViewportInfo viewport) { if (null == model || null == viewport || !model.IsReadyForRendering) { return(false); } Model = model; CheckGLError("intro call"); //HACK: necessary on some Android GPUs (don't delete this check) viewport.SetFrustumNearFar(model.BBox); // Disable Blending and set the depth function GL.DepthFunc(DepthFunction.Gequal); GL.Disable(EnableCap.Blend); // Get the shader... ActiveShader = FastDrawing ? GetShader("PerVertexLighting") : GetShader("PerPixelLighting"); // Render calls... if (model != null) { // First, render all opaque objects that are not instances foreach (var obj in model.DisplayMeshes) { if (obj != null) { RenderObject(obj, viewport, false); } } // Second, render all opaque objects that are instances foreach (var obj in model.DisplayInstanceMeshes) { if (obj != null) { RenderObject(obj, viewport, true); } } // Third, we're done drawing our instances, so set the ModelViewMatrix's XForm back to the identity matrix. ActiveShader.SetModelViewMatrix(Rhino.Geometry.Transform.Identity); // Fourth, render all transparent meshes... RenderTransparentObjects(model); } // Disable the shader ActiveShader.Disable(); return(true); }
public static bool CalcClippingPlanes(ViewportInfo vp, ClippingInfo m_Clipping) { // Initialize m_Clipping frustum info. // (left,right,top,bottom are not used but should be initialized). //const ON::view_projection projection = vp.Projection(); vp.GetFrustum(out m_Clipping.left, out m_Clipping.right, out m_Clipping.bottom, out m_Clipping.top, out m_Clipping.bbox_near, out m_Clipping.bbox_far); m_Clipping.min_near_dist = 0.000100; m_Clipping.min_near_over_far = 0.000100; m_Clipping.target_dist = (vp.CameraLocation - vp.TargetPoint)*vp.CameraZ; // Call virtual function that looks at m_Clipping.bbox and sets // m_Clipping.bbox_near and m_Clipping.bbox_far if ( !CalcClippingPlanesInternal( vp, m_Clipping ) ) return false; if ( double.IsNaN(m_Clipping.bbox_far) || double.IsNaN(m_Clipping.bbox_near) || m_Clipping.bbox_far <= m_Clipping.bbox_near || (vp.IsPerspectiveProjection && m_Clipping.bbox_near <= 1.0e-12) || (vp.IsPerspectiveProjection && m_Clipping.bbox_far > 1.0e16*m_Clipping.bbox_near) || m_Clipping.bbox_near > 1.0e30 || m_Clipping.bbox_far > 1.0e30 ) { // Restore settings to something more sane vp.GetFrustum(out m_Clipping.left, out m_Clipping.right, out m_Clipping.bottom, out m_Clipping.top, out m_Clipping.bbox_near, out m_Clipping.bbox_far); m_Clipping.min_near_dist = 0.000100; m_Clipping.min_near_over_far = 0.000100; m_Clipping.target_dist = (vp.CameraLocation - vp.TargetPoint)*vp.CameraZ; } return true; }
/// <summary> /// StartRestoreViewTo is a helper method that is called by ZoomExtentsWithGesture to /// return the viewport back to it's "home" view. /// </summary> private void StartRestoreViewTo(Rhino.DocObjects.ViewportInfo targetPosition) { if (Camera == null) { return; } IsInAnimatedRestoreView = true; View.UserInteractionEnabled = false; RestoreViewStartTime = DateTime.Now; RestoreViewTotalTime = new TimeSpan(0, 0, 0, 0, 500); RestoreViewStartViewport = new ViewportInfo(Camera); // start from current position RestoreViewFinishViewport = new ViewportInfo(targetPosition); // end on the target position // fix frustum aspect to match current screen aspect RestoreViewFinishViewport.FrustumAspect = Camera.FrustumAspect; AnimationTimer = NSTimer.CreateScheduledTimer(0.0, this, new Selector("AnimateRestoreView"), null, true); AnimationTimer.Fire(); }
/// <summary> /// Renders the object in a viewport /// </summary> private void RenderObject(DisplayObject obj, Rhino.DocObjects.ViewportInfo viewport, bool isInstance) { // If the object is invisible, return. if (!obj.IsVisible) { return; } // If the layer that the object is on is turned off, return. if (!Model.LayerIsVisibleAtIndex(obj.LayerIndex)) { return; } DisplayMesh displayMesh = isInstance ? ((DisplayInstanceMesh)obj).Mesh : (DisplayMesh)obj; if (displayMesh.WillFitOnGPU == false) { return; } uint vertex_buffer = 0; uint index_buffer = 0; if (displayMesh != null) { // Material setup, if necessary... displayMesh.Material.AmbientColor = new [] { 0.0f, 0.0f, 0.0f, 1.0f }; //We want to ignore the ambient color if (CurrentMaterial.RuntimeId != displayMesh.Material.RuntimeId) { ActiveShader.SetupMaterial(displayMesh.Material); } CurrentMaterial = displayMesh.Material; if (displayMesh.IndexBufferHandle == Globals.UNSET_HANDLE) { // Generate the Index VBO GL.GenBuffers(1, out index_buffer); GL.BindBuffer(BufferTarget.ElementArrayBuffer, index_buffer); displayMesh.IndexBufferHandle = index_buffer; } if (displayMesh.VertexBufferHandle == Globals.UNSET_HANDLE) { // Generate the VertexBuffer GL.GenBuffers(1, out vertex_buffer); GL.BindBuffer(BufferTarget.ArrayBuffer, vertex_buffer); displayMesh.VertexBufferHandle = vertex_buffer; displayMesh.LoadDataForVBOs(displayMesh.Mesh); // If CheckGLError turns up an error (likely an OutOfMemory warning because the mesh won't fit on the GPU) // we need to delete the buffers associated with that displayMesh and mark it as too big. bool causesGLError = CheckGLError("GL.BufferData"); if (causesGLError) { GL.DeleteBuffers(1, ref vertex_buffer); GL.DeleteBuffers(1, ref index_buffer); displayMesh.WillFitOnGPU = false; GC.Collect(); } else { displayMesh.WillFitOnGPU = true; } // If we have drawn all the partitions associated with the underlying openNURBS mesh in the ModelFile, we can delete it... if (displayMesh.Mesh.PartitionCount == displayMesh.PartitionIndex + 1) { Model.ModelFile.Objects.Delete(displayMesh.FileObjectId); } displayMesh.Mesh = null; } if (displayMesh.WillFitOnGPU == false) { return; } // Vertices // ORDER MATTERS...if you don't do things in this order, you will get very frusterated. // First, enable the VertexAttribArray for positions int rglVertex = ActiveShader.RglVertexIndex; GL.EnableVertexAttribArray(rglVertex); // Second, Bind the ArrayBuffer GL.BindBuffer(BufferTarget.ArrayBuffer, displayMesh.VertexBufferHandle); // Third, tell GL where to look for the data... GL.VertexAttribPointer(rglVertex, 3, VertexAttribPointerType.Float, false, displayMesh.Stride, IntPtr.Zero); CheckGLError("GL.VertexAttribPointer"); // Normals if (displayMesh.HasVertexNormals) { int rglNormal = ActiveShader.RglNormalIndex; GL.EnableVertexAttribArray(rglNormal); GL.VertexAttribPointer(rglNormal, 3, VertexAttribPointerType.Float, false, displayMesh.Stride, (IntPtr)(Marshal.SizeOf(typeof(Rhino.Geometry.Point3f)))); CheckGLError("GL.VertexAttribPointer"); } // Colors if (displayMesh.HasVertexColors) { int rglColor = ActiveShader.RglColorIndex; GL.EnableVertexAttribArray(rglColor); GL.VertexAttribPointer(rglColor, 4, VertexAttribPointerType.Float, false, displayMesh.Stride, (IntPtr)(Marshal.SizeOf(typeof(Rhino.Display.Color4f)))); CheckGLError("GL.VertexAttribPointer"); } if (isInstance) { if (!FastDrawing) { // Check for inversions on transforms, but only if we are drawing the final "high-quality" frame // (because our PerPixel shader does not flip normals based on modelView matrices). if ((obj as DisplayInstanceMesh).XForm.Determinant < -Globals.ON_ZERO_TOLERANCE) { // an inversion (happens in mirrored instances, etc.) // this means the transformation will turn the mesh // inside out, so we have to reverse our front face // convention. GL.FrontFace(FrontFaceDirection.Cw); } else { GL.FrontFace(FrontFaceDirection.Ccw); } } ActiveShader.SetModelViewMatrix((obj as DisplayInstanceMesh).XForm); } // Bind Indices GL.BindBuffer(BufferTarget.ElementArrayBuffer, displayMesh.IndexBufferHandle); CheckGLError("GL.BindBuffer"); // Draw... #if __ANDROID__ GL.DrawElements(All.Triangles, displayMesh.IndexBufferLength, All.UnsignedShort, IntPtr.Zero); #endif #if __IOS__ GL.DrawElements(BeginMode.Triangles, displayMesh.IndexBufferLength, DrawElementsType.UnsignedShort, IntPtr.Zero); #endif // Disable any and all arrays and buffers we might have used... GL.BindBuffer(BufferTarget.ArrayBuffer, displayMesh.VertexBufferHandle); GL.DisableVertexAttribArray(ActiveShader.RglColorIndex); GL.DisableVertexAttribArray(ActiveShader.RglNormalIndex); GL.DisableVertexAttribArray(ActiveShader.RglVertexIndex); GL.BindBuffer(BufferTarget.ElementArrayBuffer, displayMesh.IndexBufferHandle); GL.BindBuffer(BufferTarget.ArrayBuffer, 0); GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0); } }
/// <summary> /// Creates a default light and enables the active shader /// </summary> private void SetupShader(RhGLShaderProgram shader, RMModel model, ViewportInfo viewport) { // Check to make sure we actually have an active shader... if (shader != null) { // Enable... shader.Enable (); // Now setup and initialize frustum and lighting... int near, far; viewport.GetScreenPort (out near, out far); viewport.SetScreenPort ((int)Frame.Left, (int)Frame.Right, (int)Frame.Bottom, (int)Frame.Top, near, far); shader.SetupViewport (viewport); Rhino.Geometry.Light light = CreateDefaultLight (); shader.SetupLight (light); light.Dispose (); } }
/// <summary> /// Sets up and initializes the viewport by setting the Uniforms /// </summary> public void SetupViewport(ViewportInfo viewport) { Transform mv = new Transform(); bool haveModelView = false; if (m_Uniforms.rglModelViewProjectionMatrix >= 0) { Transform mvp = viewport.GetXform (CoordinateSystem.World, CoordinateSystem.Clip); m_MVPXform = mvp; float[] modelViewProjection = mvp.ToFloatArray(false); GL.UniformMatrix4 (m_Uniforms.rglModelViewProjectionMatrix, 1, false, modelViewProjection); } if (m_Uniforms.rglModelViewMatrix >= 0) { mv = viewport.GetXform (CoordinateSystem.World, CoordinateSystem.Camera); m_MVXform = mv; haveModelView = true; float[] modelView = mv.ToFloatArray(false); GL.UniformMatrix4 (m_Uniforms.rglModelViewMatrix, 1, false, modelView); } if (m_Uniforms.rglProjectionMatrix >= 0) { Transform pr = viewport.GetXform (CoordinateSystem.Camera, CoordinateSystem.Clip); float[] projection = pr.ToFloatArray(false); GL.UniformMatrix4 (m_Uniforms.rglProjectionMatrix, 1, false, projection); } if (m_Uniforms.rglNormalMatrix >= 0) { float[] normalMatrix = new float[9]; if (!haveModelView) { mv = viewport.GetXform (CoordinateSystem.World, CoordinateSystem.Camera); m_MVXform = mv; } Matrix4Dto3F (mv, ref normalMatrix, false); GL.UniformMatrix3 (m_Uniforms.rglNormalMatrix, 1, false, normalMatrix); } }
/// <summary> /// Returns a bounding box for the custom render meshes for the given object. /// </summary> /// <param name="vp">The viewport being rendered.</param> /// <param name="obj">The Rhino object of interest.</param> /// <param name="requestingPlugIn">UUID of the RDK plug-in requesting the meshes.</param> /// <param name="preview">Type of mesh to build.</param> /// <returns>A bounding box value.</returns> public virtual BoundingBox BoundingBox(ViewportInfo vp, RhinoObject obj, Guid requestingPlugIn, bool preview) { var min = new Point3d(); var max = new Point3d(); if (UnsafeNativeMethods.Rdk_RMPBoundingBoxImpl(m_runtime_serial_number, vp.ConstPointer(), obj.ConstPointer(), requestingPlugIn, preview ? 1 : 0, ref min, ref max)) return new BoundingBox(min, max); return new BoundingBox(); }
private static bool AdjustFrustum(ViewportInfo vp, ClippingInfo clipping) { vp.SetFrustumNearFar (vp.FrustumNear * 0.1, vp.FrustumFar * 10); return true; }
/// <summary> /// Determines if custom render meshes will be built for a particular object. /// </summary> /// <param name="vp">The viewport being rendered.</param> /// <param name="obj">The Rhino object of interest.</param> /// <param name="requestingPlugIn">UUID of the RDK plug-in requesting the meshes.</param> /// <param name="preview">Type of mesh to build.</param> /// <returns>true if custom meshes will be built.</returns> public abstract bool WillBuildCustomMeshes(ViewportInfo vp, RhinoObject obj, Guid requestingPlugIn, bool preview);
public override bool StartRenderer(int w, int h, RhinoDoc doc, ViewInfo rhinoView, ViewportInfo viewportInfo, bool forCapture, RenderWindow renderWindow) { _started = true; if (forCapture) { ModalRenderEngine mre = new ModalRenderEngine(doc, PlugIn.IdFromName("RhinoCycles"), rhinoView, viewportInfo); _cycles = null; _modal = mre; mre.Settings = RcCore.It.EngineSettings; mre.Settings.UseInteractiveRenderer = false; mre.Settings.SetQuality(doc.RenderSettings.AntialiasLevel); var rs = new Size(w, h); mre.RenderWindow = renderWindow; mre.RenderDimension = rs; mre.Database.RenderDimension = rs; mre.Settings.Verbose = true; mre.StatusTextUpdated += Mre_StatusTextUpdated; mre.Database.LinearWorkflowChanged += DatabaseLinearWorkflowChanged; mre.SetFloatTextureAsByteTexture(false); // mre.Settings.RenderDeviceIsOpenCl); mre.CreateWorld(); // has to be done on main thread, so lets do this just before starting render session _modalThread = new Thread(RenderOffscreen) { Name = $"Cycles offscreen viewport rendering with ModalRenderEngine {_serial}" }; _modalThread.Start(mre); return true; } _available = false; // the renderer hasn't started yet. It'll tell us when it has. _frameAvailable = false; _cycles = new ViewportRenderEngine(doc.RuntimeSerialNumber, PlugIn.IdFromName("RhinoCycles"), rhinoView); _cycles.StatusTextUpdated += CyclesStatusTextUpdated; // render engine tells us status texts for the hud _cycles.RenderStarted += CyclesRenderStarted; // render engine tells us when it actually is rendering _cycles.StartSynchronizing += CyclesStartSynchronizing; _cycles.Synchronized += CyclesSynchronized; _cycles.PassRendered += CyclesPassRendered; _cycles.Database.LinearWorkflowChanged += DatabaseLinearWorkflowChanged; _cycles.SamplesChanged += CyclesSamplesChanged; _cycles.Settings = RcCore.It.EngineSettings; _cycles.Settings.SetQuality(doc.RenderSettings.AntialiasLevel); var renderSize = Rhino.Render.RenderPipeline.RenderSize(doc); _cycles.RenderWindow = renderWindow; _cycles.RenderDimension = renderSize; _cycles.Settings.Verbose = true; _maxSamples = _cycles.Settings.Samples; _cycles.SetFloatTextureAsByteTexture(false); // m_cycles.Settings.RenderDeviceIsOpenCl); _cycles.CreateWorld(); // has to be done on main thread, so lets do this just before starting render session _startTime = DateTime.UtcNow; _cycles.StartRenderThread(_cycles.Renderer, $"A cool Cycles viewport rendering thread {_serial}"); return true; }
public RenderEngine(Guid pluginId, uint docRuntimeSerialnumber, ViewInfo view, ViewportInfo vp, bool interactive) { PluginId = pluginId; m_doc_serialnumber = docRuntimeSerialnumber; m_view = view; m_vp = vp; m_interactive = interactive; Database = new ChangeDatabase(PluginId, this, m_doc_serialnumber, m_view, !m_interactive); RegisterEventHandler(); }
private static void NegativeNearClippingHelper(double near_dist, double far_dist, ViewportInfo vp) { double n = near_dist; double f = far_dist; double min_near_dist = 0.000100; if ( double.IsNaN(min_near_dist) || min_near_dist < 1.0e-6 ) min_near_dist = 1.0e-6; if ( vp.IsParallelProjection && n < min_near_dist ) { // move camera back in ortho projection so everything shows double d = 1.00001*min_near_dist - n; if ( d < 0.005 ) d = 0.005; n += d; f += d; if ( double.IsNaN(d) || d <= 0.0 || double.IsNaN(n) || double.IsNaN(f) || n < min_near_dist || f <= n ) { // Just give up but ... refuse to accept garbage n = 0.005; f = 1000.0; } else { Rhino.Geometry.Point3d new_loc = vp.CameraLocation + d*vp.CameraZ; vp.SetCameraLocation( new_loc ); } near_dist = n; far_dist = f; } }
private static bool CalcClippingPlanesInternal(ViewportInfo vp, ClippingInfo clipping) { bool isPerspective = vp.IsPerspectiveProjection; // iCalcBoundingBox() has set clipping.bbox and it cannot // be changed or ignored. GetBoundingBoxNearFarHelper ( clipping.bbox, isPerspective, vp.CameraLocation, vp.CameraZ, clipping.bbox_near, clipping.bbox_far ); // Do sanity checks and update ON_Viewport frustum if it uses // parallel projection and near <= 0.0 CalcClippingPlanesHelper(clipping.bbox_near, clipping.bbox_far, vp); // Set target_dist clipping.target_dist = (vp.CameraLocation - vp.TargetPoint)* vp.CameraZ; if ( double.IsNaN(clipping.target_dist) ) clipping.target_dist = 0.5*(clipping.bbox_near + clipping.bbox_far); return true; }
static void CalcClippingPlanesHelper(double near_dist, double far_dist, ViewportInfo vp) { // The only thing this function should do is make sure ortho cameras are // moved so near is > 0. Everything else should be considered and emergency // fix for garbage input. double n = near_dist; double f = far_dist; double min_near_dist = 0.000100; if ( double.IsNaN(min_near_dist) || min_near_dist < 1.0e-6 ) min_near_dist = 1.0e-6; if (!double.IsNaN(n) && !double.IsNaN(f) ) { NegativeNearClippingHelper(n,f,vp); if ( n < min_near_dist ) n = min_near_dist; if ( f <= 1.00001*n ) f = 10.0 + 100.0*n; } else { // If being nice didn't work - refuse to accept garbage n = 0.005; f = 1000.0; } near_dist = n; far_dist = f; }
public ModalRenderEngine(RhinoDoc doc, Guid pluginId, ViewInfo view, ViewportInfo viewport) : base(pluginId, doc.RuntimeSerialNumber, view, viewport, false) { ModalRenderEngineCommonConstruct(); }
/// <summary> /// Build custom render mesh(es). /// </summary> /// <param name="vp">The viewport being rendered.</param> /// <param name="objMeshes">The meshes class to populate with custom meshes.</param> /// <param name="requestingPlugIn">UUID of the RDK plug-in requesting the meshes.</param> /// <param name="meshType">Type of mesh to build.</param> /// <returns>true if operation was successful.</returns> public abstract bool BuildCustomMeshes(ViewportInfo vp, RenderPrimitiveList objMeshes, Guid requestingPlugIn, bool meshType);
/// <summary> /// Initializes a new instance by copying values from another instance. /// </summary> /// <param name="other">The other viewport info.</param> public ViewportInfo(ViewportInfo other) { IntPtr pOther = other.ConstPointer(); m_pViewportPointer = UnsafeNativeMethods.ON_Viewport_New(pOther); }
public static bool SetupFrustum(ViewportInfo vp, ClippingInfo clipping) { double n0 = vp.FrustumNear; double f0 = vp.FrustumFar; // Because picking relies heavily on the projection, we first set the // viewport frustum here, capture and save it, then let the conduits // do what ever they want with it...eventually the viewport will be put // back to the captured state before leaving the pipeline... ClippingInfo m_SavedClipping = clipping; vp.SetFrustumNearFar(clipping.bbox_near, clipping.bbox_far, clipping.min_near_dist, clipping.min_near_over_far, clipping.target_dist ); vp.GetFrustum(out m_SavedClipping.left, out m_SavedClipping.right, out m_SavedClipping.bottom, out m_SavedClipping.top, out m_SavedClipping.bbox_near, out m_SavedClipping.bbox_far); // Next, set the values that the pipeline will actually use... if (!(AdjustFrustum(vp, clipping))) return false; return true; }