miScalar lume_plane_ray_intersection(miVector *intersection, miVector *plane_point, miVector *plane_dir, miVector *ray_point, miVector *ray_dir) { miScalar q; miScalar t; q = mi_vector_dot(plane_dir, ray_dir); if (fabs(q) < 0.0001) return 0; /* parallel */ t = (mi_vector_dot(plane_point, plane_dir) - mi_vector_dot(plane_dir, ray_point)) / q; *intersection = *ray_dir; mi_vector_mul(intersection, t); mi_vector_add(intersection, intersection, ray_point); return t; }
static void raymarch( miColor *result, miState *state, struct mrm *p) { miVector step, pos, ppos; miVector old_point, old_normal; miScalar step_size; miColor col, prev; miBoolean has_prev = miFALSE; int i; step = state->dir; step_size = state->dist / ((miScalar)p->num - 1); mi_vector_mul(&step, step_size); old_point = state->point; old_normal = state->normal; pos = state->org; /* begin raymarch */ for (i=0; i < p->num; i++) { state->point = pos; state->normal = state->dir; state->pri = 0; /* cats rays from empty space */ mi_call_shader_x(&col, miSHADER_MATERIAL, state, p->s, NULL); if (has_prev && p->subdiv && color_contrast(&prev, &col, &p->contrast)) /* adaptive sampling */ recurse(result, state, ppos, state->dir, step_size, &prev, &col, 1, p); result->r += col.r; result->g += col.g; result->b += col.b; result->a += col.a; prev = col; ppos = pos; has_prev = miTRUE; mi_vector_add(&pos, &pos, &step); } state->point = old_point; state->normal = old_normal; }
static void recurse( miColor *result, miState *state, miVector from, miVector dir, miScalar dist, miColor *prev, miColor *next, miInteger level, struct mrm *p) { miVector step, pos; miColor col; if (level > p->subdiv) return; step = dir; mi_vector_mul(&step, dist*0.5); pos = from; mi_vector_add(&pos, &pos, &step); state->point = pos; state->normal = dir; state->pri = 0; /* required for ray casting from empty space */ mi_call_shader_x(&col, miSHADER_MATERIAL, state, p->s, NULL); /* recurse further if necessary */ if (color_contrast(prev, &col, &p->contrast)) recurse(result, state, from, dir, dist*0.5, prev, &col, level+1, p); if (color_contrast(next, &col, &p->contrast)) recurse(result, state, pos, dir, dist*0.5, &col, next, level+1, p); /* accumulate result */ result->r += 0.5*(col.r - 0.5*(prev->r - next->r)) * dist; result->g += 0.5*(col.g - 0.5*(prev->g - next->g)) * dist; result->b += 0.5*(col.b - 0.5*(prev->b - next->b)) * dist; result->a += 0.5*(col.a - 0.5*(prev->a - next->a)) * dist; }
miScalar worleynoise3d_val(miState *state,texture_worleynoise3d_t *param) { miScalar f1, f2, f3; miVector p1, p2, p3; // ways to get the current point: // state->tex_list[0]; // yields good results only in the x and y coordinate // state->point // usable for 3D, but problematic for getting a smooth 2D texture as x,y and z all have to be somehow incorporated in the 2D vector to use // state->tex // does not yield usable results / seems to be constant // // instead, we just take an u and v value explicitly; they would usually be provided by a 2D placement node. // note: getting current values must always be wrapped in mi_eval... calls! miVector pt; miScalar *m = mi_eval_transform(¶m->matrix); mi_point_transform(&pt,&state->point,m); point_distances3(state,param,&pt,&f1,&p1,&f2,&p2,&f3,&p3); miInteger dist_measure = *mi_eval_integer(¶m->distance_measure); miScalar scale = dist_scale(dist_measure) * (*mi_eval_scalar(¶m->scale)) * (*mi_eval_scalar(¶m->scaleX)); miBoolean jagged = *mi_eval_boolean(¶m->jagged_gap); miScalar s = 1.0; { miScalar gap_size = *mi_eval_scalar(¶m->gap_size); miVector ptX = pt; // jagged edges. useful for broken earth crusts if(jagged) { miVector seed = pt; mi_vector_mul(&seed,3 / scale); miScalar jaggingX = (mi_unoise_3d(&seed) - 0.5) * scale * 0.2; ptX.x += jaggingX; seed.x += 1000; miScalar jaggingY = (mi_unoise_3d(&seed) - 0.5) * scale * 0.2; ptX.y += jaggingY; seed.y += 1000; miScalar jaggingZ = (mi_unoise_3d(&seed) - 0.5) * scale * 0.2; ptX.z += jaggingZ; } miScalar f1X, f2X, f3X; miVector p1X, p2X, p3X; point_distances3(state,param,&ptX,&f1X,&p1X,&f2X,&p2X,&f3X,&p3X); // based on code from "Advanced Renderman" // this leads to gaps of equal width, in contrast to just simple thresholding of f2 - f1. miScalar scaleFactor = (distance3(dist_measure, &p1X, &p2X) * scale) / (f1X + f2X); // FIXME: there may be some adjustment needed for distance measures that are not just dist_linear if(gap_size * scaleFactor > f2X - f1X) // on left side s = -1.0; } { f1 /= scale; f2 /= scale; f3 /= scale; } miScalar dist = 0.0; { miInteger dist_mode = *mi_eval_integer(¶m->distance_mode); switch(dist_mode) { case DIST_F1: dist = f1; break; case DIST_F2_M_F1: dist = f2 - f1; break; case DIST_F1_P_F2: dist = (2 * f1 + f2) / 3; break; case DIST_F3_M_F2_M_F1: dist = (2 * f3 - f2 - f1) / 2; break; case DIST_F1_P_F2_P_F3: dist = (0.5 * f1 + 0.33 * f2 + (1 - 0.5 - 0.33) * f3); break; default: ; } } return s * scaling_function(dist); }
miTag createMeshParticles(miState *state, mrParticleGeoShader_paras *paras, PartioContainer& pc) { mi_info("Creating mesh particles for cache file: %s", pc.cacheFileName.c_str()); if( ! pc.good()) { mi_error("Invalid PartioContainer."); return miNULLTAG; } Partio::ParticleAttribute posAttr; if(!pc.assertAttribute("position", posAttr)) return miNULLTAG; Partio::ParticleAttribute idAttr; bool hasId = true; if(!pc.assertAttribute("id", idAttr)) hasId = false; Partio::ParticleAttribute radiusPPAttr; bool hasRadiusPP = true; if(!pc.assertAttribute("radiusPP", radiusPPAttr)) hasRadiusPP = false; Partio::ParticleAttribute velocityAttr; bool hasVelocity = true; if(!pc.assertAttribute("velocity", velocityAttr)) hasVelocity = false; miObject *obj = beginObject(); float *fpos; srand(123345); int numParticles = pc.data->numParticles(); float sizeMultiplier = *mi_eval_scalar(¶s->sizeMultiplier); float density = *mi_eval_scalar(¶s->density); float size = *mi_eval_scalar(¶s->size); float sizeVariation = *mi_eval_scalar(¶s->sizeVariation); // particle number can vary because of density value int numWrittenParticles = 0; // define vectors for(int vtxId = 0; vtxId < numParticles; vtxId++) { miVector pos; fpos = (float *)pc.data->data<float>(posAttr, vtxId); int id = vtxId; if( hasId) id = *pc.data->data<int>(idAttr, vtxId); float radiusPP = 1.0f; if( hasRadiusPP ) radiusPP = *pc.data->data<float>(radiusPPAttr, vtxId); miVector vel = {0.0, 0.0, 0.0}; if(hasVelocity) { float *v; v = (float *)pc.data->data<float>(velocityAttr, vtxId); vel.x = v[0]; vel.y = v[1]; vel.z = v[2]; // velocity ist distance/sekunde, eine velocity von 24 legt also eine Distanz von 1 Einheit pro frame bei 24fps zurück // zusätzlich muss man noch den shutter angle beachten, bei 140° sind das -.2 -> 0.2 also 0.4 * 1 und damit grob .4 Einheiten float factor = 1.0f/24.0f * 0.4f; mi_vector_mul(&vel, factor); } pos.x = fpos[0]; pos.y = fpos[1]; pos.z = fpos[2]; miVector camPos = pos; // ich transformiere das particle in camera space und gehe dann einfach size/2 nach rechts und oben miMatrix matrix; mi_matrix_ident(matrix); miInstance *inst = (miInstance *)mi_db_access(state->instance); mi_matrix_copy(matrix, inst->tf.global_to_local); mi_db_unpin(state->instance); mi_point_from_world(state, &camPos, &pos); mi_point_from_world(state, &camPos, &camPos); mi_point_to_camera(state, &camPos, &camPos); float psize = radiusPP * sizeMultiplier; int pId = vtxId; double rndVal = rnd(id * state->camera->frame + 5); if( rndVal > density) continue; float srndVal = (rndVal - 0.5f) * 2.0f; psize *= size + (size * srndVal * sizeVariation * 0.5f); psize = fabs(psize); if(psize == 0.0f) continue; miVector upRight, bottomLeft; upRight = camPos; upRight.x += psize/2.0f; upRight.y += psize/2.0f; bottomLeft = camPos; bottomLeft.x -= psize/2.0f; bottomLeft.y -= psize/2.0f; // checkScreenSpace in Screenspace und testet auf minPixelSize. if(!checkScreenSpace(state, paras, camPos, bottomLeft, upRight) ) continue; numWrittenParticles++; miVector v0, v1, v2, v3; v0 = bottomLeft; v2 = upRight; v1 = bottomLeft; v1.y = upRight.y; v3 = upRight; v3.y = bottomLeft.y; mi_point_from_camera(state, &v0, &v0); mi_point_from_camera(state, &v1, &v1); mi_point_from_camera(state, &v2, &v2); mi_point_from_camera(state, &v3, &v3); mi_point_to_world(state, &v0, &v0); mi_point_to_world(state, &v1, &v1); mi_point_to_world(state, &v2, &v2); mi_point_to_world(state, &v3, &v3); miVector v01, v02, v03; mi_vector_sub(&v01, &v0, &v1); mi_vector_sub(&v02, &v0, &v2); mi_vector_sub(&v03, &v0, &v3); mi_vector_transform(&v01, &v01, matrix); mi_vector_transform(&v02, &v02, matrix); mi_vector_transform(&v03, &v03, matrix); mi_vector_add(&v1, &v0, &v01); mi_vector_add(&v2, &v0, &v02); mi_vector_add(&v3, &v0, &v03); // add geometry vectors // e.g. -0.5 -0.5 0.5 add_vector(v0.x, v0.y, v0.z); add_vector(v1.x, v1.y, v1.z); add_vector(v2.x, v2.y, v2.z); add_vector(v3.x, v3.y, v3.z); // single motion vector per particle add_vector(vel.x, vel.y, vel.z); } // uv coordinates miVector uvw; uvw.x = uvw.y = uvw.z = 0.0f; uvw.z = 123.0f; mi_api_vector_xyz_add( &uvw ); uvw.x = 1.0; mi_api_vector_xyz_add( &uvw ); uvw.y = 1.0; mi_api_vector_xyz_add( &uvw ); uvw.x = 0.0; mi_api_vector_xyz_add( &uvw ); // define vertices // depending on the attributes we have x vectors per vertex: // 0: pos1 // 1: pos2 // 2: pos3 // 3: pos4 // 4: vel // tex0 = numWrittenParticles * 5 - 4 // num done particles für rnd density int texIndex = numWrittenParticles * 5; for(int vtxId = 0; vtxId < numWrittenParticles; vtxId++) { int vertexIndex = vtxId * 5; int mvIndex = vtxId * 5 + 4; // add vertex definitions // e.g. v 0 n 8 t 32 m 46 mi_api_vertex_add(vertexIndex); mi_api_vertex_tex_add( texIndex, -1, -1); mi_api_vertex_motion_add(mvIndex); mi_api_vertex_add(vertexIndex + 1); mi_api_vertex_tex_add( texIndex + 1, -1, -1); mi_api_vertex_motion_add(mvIndex); mi_api_vertex_add(vertexIndex + 2); mi_api_vertex_tex_add( texIndex + 2, -1, -1); mi_api_vertex_motion_add(mvIndex); mi_api_vertex_add(vertexIndex + 3); mi_api_vertex_tex_add( texIndex + 3, -1, -1); mi_api_vertex_motion_add(mvIndex); } // add poly for every particle for( int pId = 0; pId < numWrittenParticles; pId++) { int vtxId = pId * 4; mi_api_poly_begin_tag(1, miNULLTAG); mi_api_poly_index_add(vtxId); mi_api_poly_index_add(vtxId + 1); mi_api_poly_index_add(vtxId + 2); mi_api_poly_index_add(vtxId + 3); mi_api_poly_end(); } miTag objTag = finishObject(); return objTag; }