如何将 3D 模型从 Cinema4D 导出到 Three.js?

发布于 2024-10-04 06:42:09 字数 207 浏览 9 评论 0原文

如果我有一个在 Cinema 4D 中建模的网格,如何将其导出到 Three.js 3D JS 引擎?

此外,导出多边形选择的材质颜色也会很方便。

If I have a mesh modeled in Cinema 4D, how can I export it for the three.js 3D JS Engine ?

Also, it would be handy to export material colors for polygon selections.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

当梦初醒 2024-10-11 06:42:09

为此,我刚刚为 Cinema4D 编写了另一个 python 脚本。

您可以在 打扰媒体博客wiki

DeltaInc Bot

十二面体

作为参考,我也在这里列出了源代码:

'''
author : "George Profenza"
url    : ("disturb", "disturbmedia.com/blog","My blog, http://tomaterial.blogspot.com")

Export meshes the three.js 3D Engine by mr.doob's et al.

More details on the engine here:
https://github.com/mrdoob/three.js

Currently supports UVs. If the model doesn't display correctly
you might need to reverse some normals/do some cleanup.
Also, if you use Selection Tags and basic ColorMaterials, 
the colours will be picked up as face colors. Call autoColor() on the
model you use for this.
The mesh transformations(position, rotation, scale) are saved
and you can get them using: getPosition(), getRotation() and getScale()
each returning a THREE.Vector3

In short
var myGeom = new myC4DGeom();
var myModel = new THREE.Mesh( myGeom, new THREE.MeshFaceMaterial());
//set transforms
model.position = myGeom.getPosition()
model.rotation = myGeom.getRotation()
model.scale    = myGeom.getScale()
//set selection tags colours
myGeom.autoColor()

More details on this exporter and more js examples here:
https://github.com/orgicus/three.js

Have fun!

This script requires Cinema 4D R11.5 minimum and the Py4D Plugin:
http://www.py4d.com/get-py4d/
'''

import c4d
from c4d import documents,UVWTag,storage
from c4d.utils import *
from c4d import symbols as sy, plugins, utils, bitmaps, gui
import math
import re

# utils
clean = lambda varStr: re.sub('\W|^(?=\d)','_', varStr)
# from Active State's Python recipies: http://code.activestate.com/recipes/266466-html-colors-tofrom-rgb-tuples/
def RGBToHTMLColor(rgb_tuple):
    return '0x%02x%02x%02x' % rgb_tuple
def Export():
    if not op: return
    if op.GetType() != 5100:
            print 'Selected Object is not an editable mesh'
            return
    unit = 0.001#for scale
    fps   = doc.GetFps()
    bd = doc.GetRenderBaseDraw()
    scr = bd.GetFrameScreen()
    rd = doc.GetActiveRenderData()
    name  = op.GetName()
    classname = clean(name)

    c4dPath = c4d.storage.GeGetC4DPath(sy.C4D_PATH_LIBRARY)
    jsFile = open(c4dPath+'/scripts/Three.js','r')
    js = jsFile.read()
    htmlFile = open(c4dPath+'/scripts/template.html','r')
    html = htmlFile.read()
    html = html.replace('%s',classname)
    code  = 'var %s = function () {\n\n\tvar scope = this;\n\n\tTHREE.Geometry.call(this);\n\n' % classname

    def GetMesh(code):
        # goto 0
        doc.SetTime(c4d.BaseTime(0, fps))
        c4d.DrawViews( c4d.DA_ONLY_ACTIVE_VIEW|c4d.DA_NO_THREAD|c4d.DA_NO_REDUCTION|c4d.DA_STATICBREAK )
        c4d.GeSyncMessage(c4d.EVMSG_TIMECHANGED)
        doc.SetTime(doc.GetTime())
        c4d.EventAdd(c4d.EVENT_ANIMATE)
        SendModelingCommand(command = MCOMMAND_REVERSENORMALS, list = [op], mode = MODIFY_ALL, bc = c4d.BaseContainer(), doc = doc)

        verts = op.GetPointAll()
        for v in verts:
            code += '\tv( %.6f, %.6f, %.6f );\n' % (v.x, -v.y, v.z)
        code += '\n'
        ncount = 0
        uvcount = 0
        faces = op.GetAllPolygons()
        normals = op.CreatePhongNormals()
        ndirection = 1
        hasUV = False
        for tag in op.GetTags():
            if tag.GetName() == "UVW":
                uvw = tag
                hasUV = True
        for f in faces:
            if(f.d == f.c):
                if(normals):
                    code += '\tf3( %d, %d, %d, %.6f, %.6f, %.6f );\n' % (f.a, f.b, f.c, normals[ncount].x*ndirection, normals[ncount].y*ndirection, normals[ncount].z*ndirection)
                else:
                    code += '\tf3( %d, %d, %d );\n' % (f.a, f.b, f.c)
            else:
                if(normals):
                    code += '\tf4( %d, %d, %d, %d, %.6f, %.6f, %.6f );\n' % (f.a, f.b, f.c, f.d, normals[ncount].x*ndirection, normals[ncount].y*ndirection, normals[ncount].z*ndirection)
                else:
                    code += '\tf4( %d, %d, %d, %d );\n' % (f.a, f.b, f.c, f.d)
            if hasUV:
                uv = uvw.Get(uvcount);
                # uvs  += '[Vector('+str(uv[0].x)+','+str(1.0-uv[0].y)+'),Vector('+str(uv[1].x)+','+str(1.0-uv[1].y)+'),Vector('+str(uv[2].x)+','+str(1.0-uv[2].y)+')],'
                if len(uv) == 4:
                    code += '\tuv( %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f);\n' % (uv[0].x, uv[0].y, uv[1].x, uv[1].y, uv[2].x, uv[2].y, uv[3].x, uv[3].y)
                else:
                    code += '\tuv( %.6f, %.6f, %.6f, %.6f, %.6f, %.6f);\n' % (uv[0].x, uv[0].y, uv[1].x, uv[1].y, uv[2].x, uv[2].y)
                ncount += 1
                uvcount += 1

        #selection color
        code +='\n\tscope.colors = {};\n'
        code +='\tscope.selections = {};\n'
        selName = ''
        for tag in op.GetTags():  
            if(tag.GetType() == 5616): #texture tag
               material = tag.GetMaterial()
               color = material[sy.MATERIAL_COLOR_COLOR]
               tag.SetBit(c4d.BIT_ACTIVE)
               selName = clean(tag[sy.TEXTURETAG_RESTRICTION])
               if len(selName) == 0:    print "*** WARNING! *** Missing selection name for material: " + material.GetName()
               code += '\tscope.colors["'+selName+'"] = '+str(RGBToHTMLColor((color.x*255,color.y*255,color.z*255)))+';\n'
            if tag.GetType() == 5673:  #selection tag
               # print 'selection: ' + tag.GetName()  
               sel = tag.GetSelection()
               selName = clean(tag.GetName())
               ids = sel.GetAll(op.GetPointCount())
               indices = [i for i, e in enumerate(ids) if e != 0]
               code += '\tscope.selections["'+selName+'"] = '+str(indices)+';\n'

        code += '\n\tscope.autoColor = function(){\n'
        code += '\t\tfor(var s in this.selections){\n'
        code += '\t\t\tfor(var i = 0 ; i < this.selections[s].length; i++) this.faces[this.selections[s][i]].material = [ new THREE.MeshColorFillMaterial( this.colors[s],1) ];\n'
        code += '\t\t}\n\t}\n'

        # model position, rotation, scale               rotation x,y,z = H,P,B => three.js x,y,z is P,H,B => y,x,z
        p = op.GetPos()
        r = op.GetRot()
        s = op.GetScale()
        code += '\n\tscope.getPosition = function(){\treturn new THREE.Vector3'+str((p.x,p.y,p.z))+';\t}\n'
        code += '\n\tscope.getRotation = function(){\treturn new THREE.Vector3'+str((r.y,r.x,r.z))+';\t}\n'
        code += '\n\tscope.getScale = function(){\treturn new THREE.Vector3'+str((s.x,s.y,s.z))+';\t}\n'

        code += '\n'
        code += '\tfunction v( x, y, z ) {\n\n'
        code += '\t\tscope.vertices.push( new THREE.Vertex( new THREE.Vector3( x, y, z ) ) );\n\n'
        code += '\t}\n\n'
        code += '\tfunction f3( a, b, c, nx, ny, nz ) {\n\n'
        code += '\t\tscope.faces.push( new THREE.Face3( a, b, c, nx && ny && nz ? new THREE.Vector3( nx, ny, nz ) : null ) );\n\n'
        code += '\t}\n\n'
        code += '\tfunction f4( a, b, c, d, nx, ny, nz ) {\n\n'
        code += '\t\tscope.faces.push( new THREE.Face4( a, b, c, d, nx && ny && nz ? new THREE.Vector3( nx, ny, nz ) : null ) );\n\n'
        code += '\t}\n\n'
        code += '\tfunction uv( u1, v1, u2, v2, u3, v3, u4, v4 ) {\n\n'
        code += '\t\tvar uv = [];\n'
        code += '\t\tuv.push( new THREE.UV( u1, v1 ) );\n'
        code += '\t\tuv.push( new THREE.UV( u2, v2 ) );\n'
        code += '\t\tuv.push( new THREE.UV( u3, v3 ) );\n'
        code += '\t\tif ( u4 && v4 ) uv.push( new THREE.UV( u4, v4 ) );\n'
        code += '\t\tscope.uvs.push( uv );\n'
        code += '\t}\n\n'
        code += '}\n\n'
        code += '%s.prototype = new THREE.Geometry();\n' % classname
        code += '%s.prototype.constructor = %s;' % (classname, classname)

        SendModelingCommand(command = MCOMMAND_REVERSENORMALS, list = [op], mode = MODIFY_ALL, bc = c4d.BaseContainer(), doc = doc)

        return code

    code = GetMesh(code)
    docPath = doc.GetDocumentPath() 
    jspath = docPath+'/'+classname+'.js'
    htmlpath = docPath+'/'+classname+'.html'
    file = open(jspath,'w')
    file.write(code)
    file.close()
    file = open(htmlpath,'w')
    file.write(html)
    file.close()
    file = open(docPath+'/Three.js','w')
    file.write(js)
    file.close()
    print 'Export Complete!'

Export()

另外,将“slim”导出器添加到 存储库 应该生成更小的 .js 文件
对于模型

Just wrote another python script for Cinema4D for this.

You can find details on the disturb media blog and wiki.

DeltaInc Bot

Dodecahedrons

For reference, I'm listing the source here too:

'''
author : "George Profenza"
url    : ("disturb", "disturbmedia.com/blog","My blog, http://tomaterial.blogspot.com")

Export meshes the three.js 3D Engine by mr.doob's et al.

More details on the engine here:
https://github.com/mrdoob/three.js

Currently supports UVs. If the model doesn't display correctly
you might need to reverse some normals/do some cleanup.
Also, if you use Selection Tags and basic ColorMaterials, 
the colours will be picked up as face colors. Call autoColor() on the
model you use for this.
The mesh transformations(position, rotation, scale) are saved
and you can get them using: getPosition(), getRotation() and getScale()
each returning a THREE.Vector3

In short
var myGeom = new myC4DGeom();
var myModel = new THREE.Mesh( myGeom, new THREE.MeshFaceMaterial());
//set transforms
model.position = myGeom.getPosition()
model.rotation = myGeom.getRotation()
model.scale    = myGeom.getScale()
//set selection tags colours
myGeom.autoColor()

More details on this exporter and more js examples here:
https://github.com/orgicus/three.js

Have fun!

This script requires Cinema 4D R11.5 minimum and the Py4D Plugin:
http://www.py4d.com/get-py4d/
'''

import c4d
from c4d import documents,UVWTag,storage
from c4d.utils import *
from c4d import symbols as sy, plugins, utils, bitmaps, gui
import math
import re

# utils
clean = lambda varStr: re.sub('\W|^(?=\d)','_', varStr)
# from Active State's Python recipies: http://code.activestate.com/recipes/266466-html-colors-tofrom-rgb-tuples/
def RGBToHTMLColor(rgb_tuple):
    return '0x%02x%02x%02x' % rgb_tuple
def Export():
    if not op: return
    if op.GetType() != 5100:
            print 'Selected Object is not an editable mesh'
            return
    unit = 0.001#for scale
    fps   = doc.GetFps()
    bd = doc.GetRenderBaseDraw()
    scr = bd.GetFrameScreen()
    rd = doc.GetActiveRenderData()
    name  = op.GetName()
    classname = clean(name)

    c4dPath = c4d.storage.GeGetC4DPath(sy.C4D_PATH_LIBRARY)
    jsFile = open(c4dPath+'/scripts/Three.js','r')
    js = jsFile.read()
    htmlFile = open(c4dPath+'/scripts/template.html','r')
    html = htmlFile.read()
    html = html.replace('%s',classname)
    code  = 'var %s = function () {\n\n\tvar scope = this;\n\n\tTHREE.Geometry.call(this);\n\n' % classname

    def GetMesh(code):
        # goto 0
        doc.SetTime(c4d.BaseTime(0, fps))
        c4d.DrawViews( c4d.DA_ONLY_ACTIVE_VIEW|c4d.DA_NO_THREAD|c4d.DA_NO_REDUCTION|c4d.DA_STATICBREAK )
        c4d.GeSyncMessage(c4d.EVMSG_TIMECHANGED)
        doc.SetTime(doc.GetTime())
        c4d.EventAdd(c4d.EVENT_ANIMATE)
        SendModelingCommand(command = MCOMMAND_REVERSENORMALS, list = [op], mode = MODIFY_ALL, bc = c4d.BaseContainer(), doc = doc)

        verts = op.GetPointAll()
        for v in verts:
            code += '\tv( %.6f, %.6f, %.6f );\n' % (v.x, -v.y, v.z)
        code += '\n'
        ncount = 0
        uvcount = 0
        faces = op.GetAllPolygons()
        normals = op.CreatePhongNormals()
        ndirection = 1
        hasUV = False
        for tag in op.GetTags():
            if tag.GetName() == "UVW":
                uvw = tag
                hasUV = True
        for f in faces:
            if(f.d == f.c):
                if(normals):
                    code += '\tf3( %d, %d, %d, %.6f, %.6f, %.6f );\n' % (f.a, f.b, f.c, normals[ncount].x*ndirection, normals[ncount].y*ndirection, normals[ncount].z*ndirection)
                else:
                    code += '\tf3( %d, %d, %d );\n' % (f.a, f.b, f.c)
            else:
                if(normals):
                    code += '\tf4( %d, %d, %d, %d, %.6f, %.6f, %.6f );\n' % (f.a, f.b, f.c, f.d, normals[ncount].x*ndirection, normals[ncount].y*ndirection, normals[ncount].z*ndirection)
                else:
                    code += '\tf4( %d, %d, %d, %d );\n' % (f.a, f.b, f.c, f.d)
            if hasUV:
                uv = uvw.Get(uvcount);
                # uvs  += '[Vector('+str(uv[0].x)+','+str(1.0-uv[0].y)+'),Vector('+str(uv[1].x)+','+str(1.0-uv[1].y)+'),Vector('+str(uv[2].x)+','+str(1.0-uv[2].y)+')],'
                if len(uv) == 4:
                    code += '\tuv( %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f);\n' % (uv[0].x, uv[0].y, uv[1].x, uv[1].y, uv[2].x, uv[2].y, uv[3].x, uv[3].y)
                else:
                    code += '\tuv( %.6f, %.6f, %.6f, %.6f, %.6f, %.6f);\n' % (uv[0].x, uv[0].y, uv[1].x, uv[1].y, uv[2].x, uv[2].y)
                ncount += 1
                uvcount += 1

        #selection color
        code +='\n\tscope.colors = {};\n'
        code +='\tscope.selections = {};\n'
        selName = ''
        for tag in op.GetTags():  
            if(tag.GetType() == 5616): #texture tag
               material = tag.GetMaterial()
               color = material[sy.MATERIAL_COLOR_COLOR]
               tag.SetBit(c4d.BIT_ACTIVE)
               selName = clean(tag[sy.TEXTURETAG_RESTRICTION])
               if len(selName) == 0:    print "*** WARNING! *** Missing selection name for material: " + material.GetName()
               code += '\tscope.colors["'+selName+'"] = '+str(RGBToHTMLColor((color.x*255,color.y*255,color.z*255)))+';\n'
            if tag.GetType() == 5673:  #selection tag
               # print 'selection: ' + tag.GetName()  
               sel = tag.GetSelection()
               selName = clean(tag.GetName())
               ids = sel.GetAll(op.GetPointCount())
               indices = [i for i, e in enumerate(ids) if e != 0]
               code += '\tscope.selections["'+selName+'"] = '+str(indices)+';\n'

        code += '\n\tscope.autoColor = function(){\n'
        code += '\t\tfor(var s in this.selections){\n'
        code += '\t\t\tfor(var i = 0 ; i < this.selections[s].length; i++) this.faces[this.selections[s][i]].material = [ new THREE.MeshColorFillMaterial( this.colors[s],1) ];\n'
        code += '\t\t}\n\t}\n'

        # model position, rotation, scale               rotation x,y,z = H,P,B => three.js x,y,z is P,H,B => y,x,z
        p = op.GetPos()
        r = op.GetRot()
        s = op.GetScale()
        code += '\n\tscope.getPosition = function(){\treturn new THREE.Vector3'+str((p.x,p.y,p.z))+';\t}\n'
        code += '\n\tscope.getRotation = function(){\treturn new THREE.Vector3'+str((r.y,r.x,r.z))+';\t}\n'
        code += '\n\tscope.getScale = function(){\treturn new THREE.Vector3'+str((s.x,s.y,s.z))+';\t}\n'

        code += '\n'
        code += '\tfunction v( x, y, z ) {\n\n'
        code += '\t\tscope.vertices.push( new THREE.Vertex( new THREE.Vector3( x, y, z ) ) );\n\n'
        code += '\t}\n\n'
        code += '\tfunction f3( a, b, c, nx, ny, nz ) {\n\n'
        code += '\t\tscope.faces.push( new THREE.Face3( a, b, c, nx && ny && nz ? new THREE.Vector3( nx, ny, nz ) : null ) );\n\n'
        code += '\t}\n\n'
        code += '\tfunction f4( a, b, c, d, nx, ny, nz ) {\n\n'
        code += '\t\tscope.faces.push( new THREE.Face4( a, b, c, d, nx && ny && nz ? new THREE.Vector3( nx, ny, nz ) : null ) );\n\n'
        code += '\t}\n\n'
        code += '\tfunction uv( u1, v1, u2, v2, u3, v3, u4, v4 ) {\n\n'
        code += '\t\tvar uv = [];\n'
        code += '\t\tuv.push( new THREE.UV( u1, v1 ) );\n'
        code += '\t\tuv.push( new THREE.UV( u2, v2 ) );\n'
        code += '\t\tuv.push( new THREE.UV( u3, v3 ) );\n'
        code += '\t\tif ( u4 && v4 ) uv.push( new THREE.UV( u4, v4 ) );\n'
        code += '\t\tscope.uvs.push( uv );\n'
        code += '\t}\n\n'
        code += '}\n\n'
        code += '%s.prototype = new THREE.Geometry();\n' % classname
        code += '%s.prototype.constructor = %s;' % (classname, classname)

        SendModelingCommand(command = MCOMMAND_REVERSENORMALS, list = [op], mode = MODIFY_ALL, bc = c4d.BaseContainer(), doc = doc)

        return code

    code = GetMesh(code)
    docPath = doc.GetDocumentPath() 
    jspath = docPath+'/'+classname+'.js'
    htmlpath = docPath+'/'+classname+'.html'
    file = open(jspath,'w')
    file.write(code)
    file.close()
    file = open(htmlpath,'w')
    file.write(html)
    file.close()
    file = open(docPath+'/Three.js','w')
    file.write(js)
    file.close()
    print 'Export Complete!'

Export()

Also, added 'slim' exporters to the repository which should produce smaller .js files
for the models

请恋爱 2024-10-11 06:42:09

另一种选择是导出为 COLLADA/DAE 或 OBJ 并使用 COLLADALoaderOBJLoader

Another option is to export as COLLADA/DAE or OBJ and use COLLADALoader or OBJLoader.

撞了怀 2024-10-11 06:42:09

好吧,要在这里尝试一下:

此插件不适用于 C4D R12。由于Maxon吸收了Py4D,因此他们选择将符号对象吸收到c4d对象中。我分叉了你的 代码 并进行了一些探索,尝试修复 11.5 的 Py4D 之间的微小差异和R12。

不管怎样,这是你发表的插件咖啡馆帖子,我在其中发表了更多评论关于问题。再次感谢您为精彩铺平道路!

Alirght, going to Try this here:

This plugin does not work with C4D R12. Since Maxon absorbed Py4D, they made a choice to absorb the symbols object into the c4d object. I forked your code and poked around a bit to try and fix the minute differences between 11.5's Py4D and R12.

Anyways, here's the plugin cafe post you made where I commented a bit more regarding the issues. Thanks again for paving the way for awesomeness!

や三分注定 2024-10-11 06:42:09

如果出现对象属性错误,则需要将 GetPos 调用与 third.js 导出器脚本 (c4d13+) 中的 GetAbsPos 交换。

If you get an object attribute error, you need to exchange the GetPos call with GetAbsPos in the three.js exporter script (c4d13+).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文