Applying OCS texture mapping

Hi,
I am trying to apply WCS/OCS mapping to an object using RhinoCommon

I followed some steps from this post

.
my sample code below

 RhinoObject obj = objref1.Object();
 if (obj == null)
     return;

 // fetching the texture from RhinoObject
 RenderMaterial objRenderMaterial = obj.RenderMaterial;
 RenderTexture texture = objRenderMaterial.GetTextureFromUsage(RenderMaterial.StandardChildSlots.Diffuse);

// creating and applying ocs texture mapping
 texture.SetProjectionMode(TextureProjectionMode.Wcs, RenderContent.ChangeContexts.Ignore);
 TextureMapping ocsMapping = TextureMapping.CreateOcsMapping(ocsOriginPlane);
 int ocsMappingChannel = ObjectAttributes.OCSMappingChannelId;
 obj.SetTextureMapping(ocsMappingChannel, ocsMapping);

The code above fails to apply OCS mapping but instead applies Planar Mapping as seen below.
Any suggestions are appreciated.

Thanks,
Srujan

Hi @svichare from my understanding you need to use WcsBox instead of Wcs

1 Like

Thanks for getting back @Gijs
I still get the same result

I don’t think you can set to ocsmapping channel, if I interpret this correctly:
https://developer.rhino3d.com/api/rhinocommon/rhino.docobjects.texture/wcsboxprojected#

This seems to work:

using System;
using Rhino;
using Rhino.Commands;
using Rhino.DocObjects;
using Rhino.Geometry;
using Rhino.Input;
using Rhino.Input.Custom;
using Rhino.Render;

Result ApplyWcsTest(RhinoDoc doc)
{
    // Select an object with a texture
    if (RhinoGet.GetOneObject("Select an object with a texture", false, ObjectType.AnyObject, out ObjRef objRef)!=Result.Success)
        return Result.Failure;

    // Get the selected RhinoObject
    var obj = objRef.Object();
    if (obj == null)
        return Result.Failure;

    // Fetch the texture from the selected object's RenderMaterial
    var objRenderMaterial = obj.RenderMaterial;
    if (objRenderMaterial == null)
    {
        RhinoApp.WriteLine("The selected object has no render material.");
        return Result.Failure;
    }

    // Get the texture associated with the Diffuse channel
    var texture = objRenderMaterial.GetTextureFromUsage(RenderMaterial.StandardChildSlots.Diffuse);
    if (texture == null)
    {
        RhinoApp.WriteLine("No texture found on the selected object's diffuse channel.");
        return Result.Failure;
    }

    // Define the origin plane for the OCS texture mapping
    var ocsOriginPlane = Plane.WorldXY;

    // Set up OCS texture mapping
    texture.SetProjectionMode(TextureProjectionMode.WcsBox, RenderContent.ChangeContexts.Ignore);
    float size = 100;
    texture.SetRepeat(new Vector3d(1/size, 1/size, 0), RenderContent.ChangeContexts.Ignore);

    // Set the texture mapping to the object
    obj.RenderMaterial = objRenderMaterial;
    obj.CommitChanges();
    doc.Views.Redraw();

    return Result.Success;
}

ApplyWcsTest(RhinoDoc.ActiveDoc);

@Gijs I tried your sample code.
it still doesnt do what I want yet…

.
Below is my expected result of applying OCS mapping to the object (ignore the texture repeat for now).

After reading that link, I guess the more appropriate question to ask might be - how to define an ocs frame on an object mapping channel (per object) ?

I can get the OCSMappingChanellId.

var ocsMappingChannel = ObjectAttributes.OCSMappingChannelId;

I was under impression CreateOcsMapping and SetTextureMapping with ocsMappingChannel will do the trick but no luck.

In that case you need to figure out the orientation of your object first and align it to that, I think, but I might be missing something.
Are you expecting that the texture stays aligned with the object when you rotate it?

@Gijs
Yes, I want the texture to stay aligned with the object.
Which I have been able to achieve in Rhino by using ApplyOcsMapping Command.
Essentially it lets me define a plane (i think) and then orients the material when the object is transformed (scaled, rotated etc.)

I have found a way to define a plane aligned with the object.

// create ocs mapping
var ocsFrame = /* example plane oriented to the object face*/;
var ocsMapping = TextureMapping.CreateOcsMapping(ocsFrame);

// set ocs mapping for object
var ocsMappingChannel = ObjectAttributes.OCSMappingChannelId;
rhinoObj.SetTextureMapping(ocsMappingChannel, ocsMapping);
rhinoObj.CommitChanges();
doc.Views.Redraw();

I am getting the ocsframe from the front face of the box. essentially i use the brepface and get plane from there.

The sample code above sets the object mapping channel of type Planar instead of OCS frame.

found something interesting.
CreateOcsMapping method creates a TextureMapping object of TextureMappingType.PlaneMapping instead of TextureMappingType.OcsMapping
Not sure if thats intentional and I am missing something.

https://developer.rhino3d.com/api/rhinocommon/rhino.render.texturemappingtype
@nathanletwory would you have any suggestions? thanks in advance

1 Like

OCS Mapping is essentially a plane - it expresses the frame. It is interpreted as OCS frame when it is set in OCSMappingChannelId - this is the same for any object that wants an OCS frame set. And there can be only one per object.

It is a bit hacky, but that is how OCS frame is set on an object.

@svichare sorry for the delay, it took me a little while to see what is going on. I logged:
RH-84574 Cannot apply OCS mapping in script

1 Like

A fix for this bug is cooking. It will be available when 8.14 becomes the next service release candidate.

1 Like

Thanks for this @Gijs and @nathanletwory
Appreciate your help!
Will wait for the release.

RH-84574 is fixed in Rhino 8 Service Release 14